Better pixel art rendering

main
Cameron Murphy Reikes 2 years ago
parent d8b8f2c925
commit 421bb99952

@ -235,6 +235,7 @@
<ClCompile Include="thirdparty\minilzo\minilzo.c" /> <ClCompile Include="thirdparty\minilzo\minilzo.c" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="goodpixel.gen.h" />
<ClInclude Include="hueshift.gen.h" /> <ClInclude Include="hueshift.gen.h" />
<ClInclude Include="ipsettings.h" /> <ClInclude Include="ipsettings.h" />
<ClInclude Include="queue.h" /> <ClInclude Include="queue.h" />

@ -197,6 +197,9 @@
<ClInclude Include="queue.h"> <ClInclude Include="queue.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="goodpixel.gen.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="thirdparty\enet\enet_dll.cbp" /> <None Include="thirdparty\enet\enet_dll.cbp" />

@ -1519,6 +1519,7 @@ EntityID create_spacestation(GameState *gs)
box_create(gs, explosion_box, grid, (V2){0}); box_create(gs, explosion_box, grid, (V2){0});
explosion_box->is_explosion_unlock = true; explosion_box->is_explosion_unlock = true;
explosion_box->no_save_to_disk = true; explosion_box->no_save_to_disk = true;
explosion_box->always_visible = true;
BOX_AT_TYPE(grid, ((V2){BOX_SIZE, 0}), BoxExplosive); BOX_AT_TYPE(grid, ((V2){BOX_SIZE, 0}), BoxExplosive);
BOX_AT_TYPE(grid, ((V2){BOX_SIZE * 2, 0}), BoxHullpiece); BOX_AT_TYPE(grid, ((V2){BOX_SIZE * 2, 0}), BoxHullpiece);
BOX_AT_TYPE(grid, ((V2){BOX_SIZE * 3, 0}), BoxHullpiece); BOX_AT_TYPE(grid, ((V2){BOX_SIZE * 3, 0}), BoxHullpiece);

@ -0,0 +1,34 @@
@module goodpixel
@vs vs
in vec4 coord;
out vec2 texUV;
void main() {
gl_Position = vec4(coord.xy, 0.0, 1.0);
texUV = coord.zw;
}
@end
@fs fs
uniform sampler2D iChannel0;
uniform fs_params {
vec4 iColor;
};
in vec2 texUV;
out vec4 fragColor;
vec4 texture2DAA(sampler2D tex, vec2 uv) {
vec2 texsize = vec2(textureSize(tex,0));
vec2 uv_texspace = uv*texsize;
vec2 seam = floor(uv_texspace+.5);
uv_texspace = (uv_texspace-seam)/fwidth(uv_texspace)+seam;
uv_texspace = clamp(uv_texspace, seam-.5, seam+.5);
return texture(tex, uv_texspace/texsize);
}
void main() {
fragColor = texture2DAA(iChannel0, texUV) * iColor;
}
@end
@program program vs fs

@ -29,6 +29,15 @@ vec3 rgb2hsv(vec3 c)
return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
} }
vec4 texture2DAA(sampler2D tex, vec2 uv) {
vec2 texsize = vec2(textureSize(tex,0));
vec2 uv_texspace = uv*texsize;
vec2 seam = floor(uv_texspace+.5);
uv_texspace = (uv_texspace-seam)/fwidth(uv_texspace)+seam;
uv_texspace = clamp(uv_texspace, seam-.5, seam+.5);
return texture(tex, uv_texspace/texsize);
}
vec3 hsv2rgb(vec3 c) vec3 hsv2rgb(vec3 c)
{ {
vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
@ -37,7 +46,7 @@ vec3 hsv2rgb(vec3 c)
} }
void main() { void main() {
vec4 outColor = texture(iChannel0, texUV); vec4 outColor = texture2DAA(iChannel0, texUV);
vec3 hsv = rgb2hsv(outColor.rgb); vec3 hsv = rgb2hsv(outColor.rgb);
if(is_colorless > 0) if(is_colorless > 0)

101
main.c

@ -31,8 +31,10 @@
#include "miniaudio.h" #include "miniaudio.h"
// shaders // shaders
#include "goodpixel.gen.h"
#include "hueshift.gen.h" #include "hueshift.gen.h"
static sg_pipeline pip; static sg_pipeline hueshift_pipeline;
static sg_pipeline goodpixel_pipeline;
static struct GameState gs = {0}; static struct GameState gs = {0};
static int my_player_index = -1; static int my_player_index = -1;
@ -240,8 +242,8 @@ static sg_image load_image(const char *path)
&(sg_image_desc){.width = x, &(sg_image_desc){.width = x,
.height = y, .height = y,
.pixel_format = SG_PIXELFORMAT_RGBA8, .pixel_format = SG_PIXELFORMAT_RGBA8,
.min_filter = SG_FILTER_NEAREST, .min_filter = SG_FILTER_LINEAR,
.mag_filter = SG_FILTER_NEAREST, .mag_filter = SG_FILTER_LINEAR,
.wrap_u = SG_WRAP_CLAMP_TO_EDGE, .wrap_u = SG_WRAP_CLAMP_TO_EDGE,
.data.subimage[0][0] = { .data.subimage[0][0] = {
.ptr = image_data, .ptr = image_data,
@ -441,14 +443,30 @@ static void init(void)
// shaders // shaders
{ {
// initialize shader // initialize shader
{
{
sgp_pipeline_desc pip_desc = { sgp_pipeline_desc pip_desc = {
.shader = *hueshift_program_shader_desc(sg_query_backend()), .shader = *hueshift_program_shader_desc(sg_query_backend()),
.blend_mode = SGP_BLENDMODE_BLEND, .blend_mode = SGP_BLENDMODE_BLEND,
}; };
pip = sgp_make_pipeline(&pip_desc); hueshift_pipeline = sgp_make_pipeline(&pip_desc);
if (sg_query_pipeline_state(pip) != SG_RESOURCESTATE_VALID) if (sg_query_pipeline_state(hueshift_pipeline) != SG_RESOURCESTATE_VALID)
{
fprintf(stderr, "failed to make hueshift pipeline\n");
exit(-1);
}
}
{
sgp_pipeline_desc pip_desc = {
.shader = *goodpixel_program_shader_desc(sg_query_backend()),
.blend_mode = SGP_BLENDMODE_BLEND,
};
goodpixel_pipeline = sgp_make_pipeline(&pip_desc);
if (sg_query_pipeline_state(goodpixel_pipeline) != SG_RESOURCESTATE_VALID)
{ {
fprintf(stderr, "failed to make custom pipeline\n"); fprintf(stderr, "failed to make goodpixel pipeline\n");
exit(-1); exit(-1);
} }
} }
@ -528,24 +546,31 @@ static void init(void)
exit(-1); exit(-1);
} }
} }
}
}
} }
#define transform_scope DeferLoop(sgp_push_transform(), sgp_pop_transform()) #define transform_scope DeferLoop(sgp_push_transform(), sgp_pop_transform())
static void set_pipeline_and_pull_color(sg_pipeline pip)
{
sgp_set_pipeline(pip);
sgp_set_uniform(&sgp_query_state()->color, sizeof(sgp_query_state()->color));
}
#define pipeline_scope(pipeline) DeferLoop(set_pipeline_and_pull_color(pipeline), sgp_reset_pipeline())
static void draw_color_rect_centered(V2 center, float size) static void draw_color_rect_centered(V2 center, float size)
{ {
float halfbox = size / 2.0f; float halfbox = size / 2.0f;
sgp_draw_filled_rect(center.x - halfbox, center.y - halfbox, size, size); sgp_draw_filled_rect(center.x - halfbox, center.y - halfbox, size, size);
} }
static void draw_texture_rectangle_centered(V2 center, V2 width_height) static void draw_texture_rectangle_centered(V2 center, V2 width_height)
{ {
V2 halfsize = V2scale(width_height, 0.5f); V2 halfsize = V2scale(width_height, 0.5f);
sgp_draw_textured_rect(center.x - halfsize.x, center.y - halfsize.y, sgp_draw_textured_rect(center.x - halfsize.x, center.y - halfsize.y, width_height.x, width_height.y);
width_height.x, width_height.y);
} }
static void draw_texture_centered(V2 center, float size) static void draw_texture_centered(V2 center, float size)
{ {
draw_texture_rectangle_centered(center, (V2){size, size}); draw_texture_rectangle_centered(center, (V2){size, size});
@ -659,19 +684,20 @@ static void ui(bool draw, float dt, float width, float height)
transform_scope transform_scope
{ {
sgp_set_pipeline(pip); pipeline_scope(hueshift_pipeline)
{
struct SquadMeta meta = squad_meta(draw_as_squad); struct SquadMeta meta = squad_meta(draw_as_squad);
hueshift_uniforms_t uniform = {0}; hueshift_uniforms_t uniform = {
uniform.is_colorless = meta.is_colorless; .is_colorless = meta.is_colorless,
uniform.target_hue = meta.hue; .target_hue = meta.hue,
};
sgp_set_uniform(&uniform, sizeof(hueshift_uniforms_t)); sgp_set_uniform(&uniform, sizeof(hueshift_uniforms_t));
sgp_scale_at(1.0f, -1.0f, x, sgp_scale_at(1.0f, -1.0f, x,
invite_y); // images upside down by default :( invite_y); // images upside down by default :(
sgp_set_image(0, image_squad_invite); sgp_set_image(0, image_squad_invite);
draw_texture_centered((V2){x, invite_y}, size); draw_texture_centered((V2){x, invite_y}, size);
sgp_reset_image(0); sgp_reset_image(0);
sgp_reset_pipeline(); }
} }
// yes // yes
@ -680,7 +706,10 @@ static void ui(bool draw, float dt, float width, float height)
sgp_set_color(1.0f, 1.0f, 1.0f, 1.0f); sgp_set_color(1.0f, 1.0f, 1.0f, 1.0f);
sgp_scale_at(1.0f, -1.0f, yes_x, buttons_y); sgp_scale_at(1.0f, -1.0f, yes_x, buttons_y);
sgp_set_image(0, image_check); sgp_set_image(0, image_check);
pipeline_scope(goodpixel_pipeline)
{
draw_texture_centered((V2){yes_x, buttons_y}, yes_size); draw_texture_centered((V2){yes_x, buttons_y}, yes_size);
}
sgp_reset_image(0); sgp_reset_image(0);
} }
@ -690,7 +719,10 @@ static void ui(bool draw, float dt, float width, float height)
sgp_set_color(1.0f, 1.0f, 1.0f, 1.0f); sgp_set_color(1.0f, 1.0f, 1.0f, 1.0f);
sgp_scale_at(1.0f, -1.0f, no_x, buttons_y); sgp_scale_at(1.0f, -1.0f, no_x, buttons_y);
sgp_set_image(0, image_no); sgp_set_image(0, image_no);
pipeline_scope(goodpixel_pipeline)
{
draw_texture_centered((V2){no_x, buttons_y}, no_size); draw_texture_centered((V2){no_x, buttons_y}, no_size);
}
sgp_reset_image(0); sgp_reset_image(0);
} }
} }
@ -728,7 +760,8 @@ static void ui(bool draw, float dt, float width, float height)
size); size);
sgp_set_color(1.0f, 1.0f, 1.0f, 1.0f); sgp_set_color(1.0f, 1.0f, 1.0f, 1.0f);
} }
sgp_set_pipeline(pip); pipeline_scope(hueshift_pipeline)
{
struct SquadMeta meta = squad_meta(myplayer()->squad); struct SquadMeta meta = squad_meta(myplayer()->squad);
hueshift_uniforms_t uniform = {0}; hueshift_uniforms_t uniform = {0};
uniform.is_colorless = meta.is_colorless; uniform.is_colorless = meta.is_colorless;
@ -740,7 +773,7 @@ static void ui(bool draw, float dt, float width, float height)
sgp_set_image(0, image_squad_invite); sgp_set_image(0, image_squad_invite);
draw_texture_centered(pos, size); draw_texture_centered(pos, size);
sgp_reset_image(0); sgp_reset_image(0);
sgp_reset_pipeline(); }
} }
} }
} }
@ -855,7 +888,8 @@ static void ui(bool draw, float dt, float width, float height)
sgp_set_image(0, image_flag_taken); sgp_set_image(0, image_flag_taken);
} }
sgp_set_pipeline(pip); pipeline_scope(hueshift_pipeline)
{
struct SquadMeta meta = squad_meta(this_squad); struct SquadMeta meta = squad_meta(this_squad);
hueshift_uniforms_t uniform = {0}; hueshift_uniforms_t uniform = {0};
uniform.is_colorless = meta.is_colorless; uniform.is_colorless = meta.is_colorless;
@ -868,7 +902,7 @@ static void ui(bool draw, float dt, float width, float height)
draw_texture_centered(flag_pos[i], size); draw_texture_centered(flag_pos[i], size);
sgp_reset_image(0); sgp_reset_image(0);
sgp_reset_pipeline(); }
} }
} }
} }
@ -973,6 +1007,7 @@ static void ui(bool draw, float dt, float width, float height)
{ {
sgp_set_image(0, image_itemframe); sgp_set_image(0, image_itemframe);
} }
pipeline_scope(goodpixel_pipeline)
sgp_draw_textured_rect(x, y, itemframe_width, itemframe_height); sgp_draw_textured_rect(x, y, itemframe_width, itemframe_height);
struct BoxInfo info = boxinfo((enum BoxType)i); struct BoxInfo info = boxinfo((enum BoxType)i);
if (can_build(i)) if (can_build(i))
@ -990,6 +1025,7 @@ static void ui(bool draw, float dt, float width, float height)
sgp_scale_at(1.0f, -1.0f, item_x + item_width / 2.0f, sgp_scale_at(1.0f, -1.0f, item_x + item_width / 2.0f,
item_y + item_height / 2.0f); item_y + item_height / 2.0f);
// sgp_scale(1.0f, -1.0f); // sgp_scale(1.0f, -1.0f);
pipeline_scope(goodpixel_pipeline)
sgp_draw_textured_rect(item_x, item_y, item_width, item_height); sgp_draw_textured_rect(item_x, item_y, item_width, item_height);
} }
sgp_reset_image(0); sgp_reset_image(0);
@ -1409,8 +1445,8 @@ static void frame(void)
(float)sg_query_image_info(image_stars).width; (float)sg_query_image_info(image_stars).width;
const float stars_width = 35.0f; const float stars_width = 35.0f;
float stars_height = stars_width * stars_height_over_width; float stars_height = stars_width * stars_height_over_width;
sgp_draw_textured_rect(-stars_width / 2.0f, -stars_height / 2.0f, pipeline_scope(goodpixel_pipeline)
stars_width, stars_height); sgp_draw_textured_rect(-stars_width / 2.0f, -stars_height / 2.0f, stars_width, stars_height);
// sgp_draw_textured_rect(0, 0, stars_width, stars_height); // sgp_draw_textured_rect(0, 0, stars_width, stars_height);
sgp_reset_image(0); sgp_reset_image(0);
} }
@ -1426,8 +1462,8 @@ static void frame(void)
(float)sg_query_image_info(image_stars).width; (float)sg_query_image_info(image_stars).width;
const float stars_width = 35.0f; const float stars_width = 35.0f;
float stars_height = stars_width * stars_height_over_width; float stars_height = stars_width * stars_height_over_width;
sgp_draw_textured_rect(-stars_width / 2.0f, -stars_height / 2.0f, pipeline_scope(goodpixel_pipeline)
stars_width, stars_height); sgp_draw_textured_rect(-stars_width / 2.0f, -stars_height / 2.0f, stars_width, stars_height);
// sgp_draw_textured_rect(0, 0, stars_width, stars_height); // sgp_draw_textured_rect(0, 0, stars_width, stars_height);
sgp_reset_image(0); sgp_reset_image(0);
} }
@ -1493,6 +1529,7 @@ static void frame(void)
sgp_rotate_at(build_preview.grid_rotation + sgp_rotate_at(build_preview.grid_rotation +
rotangle(cur_editing_rotation), rotangle(cur_editing_rotation),
global_hand_pos.x, global_hand_pos.y); global_hand_pos.x, global_hand_pos.y);
pipeline_scope(goodpixel_pipeline)
draw_texture_centered(global_hand_pos, BOX_SIZE); draw_texture_centered(global_hand_pos, BOX_SIZE);
// drawbox(hand_pos, build_preview.grid_rotation, 0.0f, // drawbox(hand_pos, build_preview.grid_rotation, 0.0f,
// cur_editing_boxtype, cur_editing_rotation); // cur_editing_boxtype, cur_editing_rotation);
@ -1538,7 +1575,10 @@ static void frame(void)
sgp_set_image(0, image_thrusterburn); sgp_set_image(0, image_thrusterburn);
float scaling = 0.95f + lerp(0.0f, 0.3f, b->thrust); float scaling = 0.95f + lerp(0.0f, 0.3f, b->thrust);
sgp_scale_at(scaling, 1.0f, entity_pos(b).x, entity_pos(b).y); sgp_scale_at(scaling, 1.0f, entity_pos(b).x, entity_pos(b).y);
pipeline_scope(goodpixel_pipeline)
{
draw_texture_centered(entity_pos(b), BOX_SIZE); draw_texture_centered(entity_pos(b), BOX_SIZE);
}
sgp_reset_image(0); sgp_reset_image(0);
} }
} }
@ -1557,7 +1597,10 @@ static void frame(void)
{ {
sgp_set_image(0, image_solarpanel_charging); sgp_set_image(0, image_solarpanel_charging);
sgp_set_color(1.0f, 1.0f, 1.0f, b->sun_amount); sgp_set_color(1.0f, 1.0f, 1.0f, b->sun_amount);
pipeline_scope(goodpixel_pipeline)
{
draw_texture_centered(entity_pos(b), BOX_SIZE); draw_texture_centered(entity_pos(b), BOX_SIZE);
}
sgp_reset_image(0); sgp_reset_image(0);
sgp_set_color(1.0f, 1.0f, 1.0f, 1.0f - b->sun_amount); sgp_set_color(1.0f, 1.0f, 1.0f, 1.0f - b->sun_amount);
/* Color to_set = colhexcode(0xeb9834); /* Color to_set = colhexcode(0xeb9834);
@ -1572,7 +1615,10 @@ static void frame(void)
{ {
sgp_set_color(0.2f, 0.2f, 0.2f, 1.0f); sgp_set_color(0.2f, 0.2f, 0.2f, 1.0f);
} }
pipeline_scope(goodpixel_pipeline)
{
draw_texture_centered(entity_pos(b), BOX_SIZE); draw_texture_centered(entity_pos(b), BOX_SIZE);
}
sgp_reset_image(0); sgp_reset_image(0);
sgp_set_color(0.5f, 0.1f, 0.1f, b->damage); sgp_set_color(0.5f, 0.1f, 0.1f, b->damage);
@ -1590,7 +1636,8 @@ static void frame(void)
sgp_rotate_at(entity_rotation(e), entity_pos(e).x, entity_pos(e).y); sgp_rotate_at(entity_rotation(e), entity_pos(e).x, entity_pos(e).y);
sgp_set_color(1.0f, 1.0f, 1.0f, 1.0f); sgp_set_color(1.0f, 1.0f, 1.0f, 1.0f);
sgp_set_pipeline(pip); pipeline_scope(hueshift_pipeline)
{
struct SquadMeta meta = squad_meta(e->presenting_squad); struct SquadMeta meta = squad_meta(e->presenting_squad);
hueshift_uniforms_t uniform = {0}; hueshift_uniforms_t uniform = {0};
uniform.is_colorless = meta.is_colorless; uniform.is_colorless = meta.is_colorless;
@ -1600,7 +1647,7 @@ static void frame(void)
draw_texture_rectangle_centered( draw_texture_rectangle_centered(
entity_pos(e), V2scale(PLAYER_SIZE, player_scaling)); entity_pos(e), V2scale(PLAYER_SIZE, player_scaling));
sgp_reset_image(0); sgp_reset_image(0);
sgp_reset_pipeline(); }
} }
} }
if (e->is_explosion) if (e->is_explosion)
@ -1659,7 +1706,7 @@ static void frame(void)
void cleanup(void) void cleanup(void)
{ {
sg_destroy_pipeline(pip); sg_destroy_pipeline(hueshift_pipeline);
ma_mutex_lock(&server_info.info_mutex); ma_mutex_lock(&server_info.info_mutex);
server_info.should_quit = true; server_info.should_quit = true;

@ -1,6 +1,8 @@
@echo off
WHERE sokol-shdc.exe WHERE sokol-shdc.exe
IF %ERRORLEVEL% NEQ 0 ECHO ERROR download sokol-shdc from https://github.com/floooh/sokol-tools-bin/blob/master/bin/win32/sokol-shdc.exe and put it in this folder IF %ERRORLEVEL% NEQ 0 ECHO ERROR download sokol-shdc from https://github.com/floooh/sokol-tools-bin/blob/master/bin/win32/sokol-shdc.exe and put it in this folder
@REM example of how to compile shaders: sokol-shdc.exe --input triangle.glsl --output triangle.gen.h --slang glsl330:hlsl5:metal_macos @REM example of how to compile shaders: sokol-shdc.exe --input triangle.glsl --output triangle.gen.h --slang glsl330:hlsl5:metal_macos
sokol-shdc.exe --format sokol --input hueshift.glsl --output hueshift.gen.h --slang glsl330:hlsl5:metal_macos sokol-shdc.exe --format sokol --input hueshift.glsl --output hueshift.gen.h --slang glsl330:hlsl5:metal_macos
sokol-shdc.exe --format sokol --input goodpixel.glsl --output goodpixel.gen.h --slang glsl330:hlsl5:metal_macos
Loading…
Cancel
Save