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" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="goodpixel.gen.h" />
<ClInclude Include="hueshift.gen.h" />
<ClInclude Include="ipsettings.h" />
<ClInclude Include="queue.h" />

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

@ -1519,6 +1519,7 @@ EntityID create_spacestation(GameState *gs)
box_create(gs, explosion_box, grid, (V2){0});
explosion_box->is_explosion_unlock = 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 * 2, 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);
}
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)
{
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() {
vec4 outColor = texture(iChannel0, texUV);
vec4 outColor = texture2DAA(iChannel0, texUV);
vec3 hsv = rgb2hsv(outColor.rgb);
if(is_colorless > 0)

101
main.c

@ -31,8 +31,10 @@
#include "miniaudio.h"
// shaders
#include "goodpixel.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 int my_player_index = -1;
@ -240,8 +242,8 @@ static sg_image load_image(const char *path)
&(sg_image_desc){.width = x,
.height = y,
.pixel_format = SG_PIXELFORMAT_RGBA8,
.min_filter = SG_FILTER_NEAREST,
.mag_filter = SG_FILTER_NEAREST,
.min_filter = SG_FILTER_LINEAR,
.mag_filter = SG_FILTER_LINEAR,
.wrap_u = SG_WRAP_CLAMP_TO_EDGE,
.data.subimage[0][0] = {
.ptr = image_data,
@ -441,14 +443,30 @@ static void init(void)
// shaders
{
// initialize shader
{
{
sgp_pipeline_desc pip_desc = {
.shader = *hueshift_program_shader_desc(sg_query_backend()),
.blend_mode = SGP_BLENDMODE_BLEND,
};
pip = sgp_make_pipeline(&pip_desc);
if (sg_query_pipeline_state(pip) != SG_RESOURCESTATE_VALID)
hueshift_pipeline = sgp_make_pipeline(&pip_desc);
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);
}
}
@ -528,24 +546,31 @@ static void init(void)
exit(-1);
}
}
}
}
}
#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)
{
float halfbox = size / 2.0f;
sgp_draw_filled_rect(center.x - halfbox, center.y - halfbox, size, size);
}
static void draw_texture_rectangle_centered(V2 center, V2 width_height)
{
V2 halfsize = V2scale(width_height, 0.5f);
sgp_draw_textured_rect(center.x - halfsize.x, center.y - halfsize.y,
width_height.x, width_height.y);
sgp_draw_textured_rect(center.x - halfsize.x, center.y - halfsize.y, width_height.x, width_height.y);
}
static void draw_texture_centered(V2 center, float 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
{
sgp_set_pipeline(pip);
pipeline_scope(hueshift_pipeline)
{
struct SquadMeta meta = squad_meta(draw_as_squad);
hueshift_uniforms_t uniform = {0};
uniform.is_colorless = meta.is_colorless;
uniform.target_hue = meta.hue;
hueshift_uniforms_t uniform = {
.is_colorless = meta.is_colorless,
.target_hue = meta.hue,
};
sgp_set_uniform(&uniform, sizeof(hueshift_uniforms_t));
sgp_scale_at(1.0f, -1.0f, x,
invite_y); // images upside down by default :(
sgp_set_image(0, image_squad_invite);
draw_texture_centered((V2){x, invite_y}, size);
sgp_reset_image(0);
sgp_reset_pipeline();
}
}
// 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_scale_at(1.0f, -1.0f, yes_x, buttons_y);
sgp_set_image(0, image_check);
pipeline_scope(goodpixel_pipeline)
{
draw_texture_centered((V2){yes_x, buttons_y}, yes_size);
}
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_scale_at(1.0f, -1.0f, no_x, buttons_y);
sgp_set_image(0, image_no);
pipeline_scope(goodpixel_pipeline)
{
draw_texture_centered((V2){no_x, buttons_y}, no_size);
}
sgp_reset_image(0);
}
}
@ -728,7 +760,8 @@ static void ui(bool draw, float dt, float width, float height)
size);
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);
hueshift_uniforms_t uniform = {0};
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);
draw_texture_centered(pos, size);
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_pipeline(pip);
pipeline_scope(hueshift_pipeline)
{
struct SquadMeta meta = squad_meta(this_squad);
hueshift_uniforms_t uniform = {0};
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);
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);
}
pipeline_scope(goodpixel_pipeline)
sgp_draw_textured_rect(x, y, itemframe_width, itemframe_height);
struct BoxInfo info = boxinfo((enum BoxType)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,
item_y + item_height / 2.0f);
// sgp_scale(1.0f, -1.0f);
pipeline_scope(goodpixel_pipeline)
sgp_draw_textured_rect(item_x, item_y, item_width, item_height);
}
sgp_reset_image(0);
@ -1409,8 +1445,8 @@ static void frame(void)
(float)sg_query_image_info(image_stars).width;
const float stars_width = 35.0f;
float stars_height = stars_width * stars_height_over_width;
sgp_draw_textured_rect(-stars_width / 2.0f, -stars_height / 2.0f,
stars_width, stars_height);
pipeline_scope(goodpixel_pipeline)
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_reset_image(0);
}
@ -1426,8 +1462,8 @@ static void frame(void)
(float)sg_query_image_info(image_stars).width;
const float stars_width = 35.0f;
float stars_height = stars_width * stars_height_over_width;
sgp_draw_textured_rect(-stars_width / 2.0f, -stars_height / 2.0f,
stars_width, stars_height);
pipeline_scope(goodpixel_pipeline)
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_reset_image(0);
}
@ -1493,6 +1529,7 @@ static void frame(void)
sgp_rotate_at(build_preview.grid_rotation +
rotangle(cur_editing_rotation),
global_hand_pos.x, global_hand_pos.y);
pipeline_scope(goodpixel_pipeline)
draw_texture_centered(global_hand_pos, BOX_SIZE);
// drawbox(hand_pos, build_preview.grid_rotation, 0.0f,
// cur_editing_boxtype, cur_editing_rotation);
@ -1538,7 +1575,10 @@ static void frame(void)
sgp_set_image(0, image_thrusterburn);
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);
pipeline_scope(goodpixel_pipeline)
{
draw_texture_centered(entity_pos(b), BOX_SIZE);
}
sgp_reset_image(0);
}
}
@ -1557,7 +1597,10 @@ static void frame(void)
{
sgp_set_image(0, image_solarpanel_charging);
sgp_set_color(1.0f, 1.0f, 1.0f, b->sun_amount);
pipeline_scope(goodpixel_pipeline)
{
draw_texture_centered(entity_pos(b), BOX_SIZE);
}
sgp_reset_image(0);
sgp_set_color(1.0f, 1.0f, 1.0f, 1.0f - b->sun_amount);
/* Color to_set = colhexcode(0xeb9834);
@ -1572,7 +1615,10 @@ static void frame(void)
{
sgp_set_color(0.2f, 0.2f, 0.2f, 1.0f);
}
pipeline_scope(goodpixel_pipeline)
{
draw_texture_centered(entity_pos(b), BOX_SIZE);
}
sgp_reset_image(0);
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_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);
hueshift_uniforms_t uniform = {0};
uniform.is_colorless = meta.is_colorless;
@ -1600,7 +1647,7 @@ static void frame(void)
draw_texture_rectangle_centered(
entity_pos(e), V2scale(PLAYER_SIZE, player_scaling));
sgp_reset_image(0);
sgp_reset_pipeline();
}
}
}
if (e->is_explosion)
@ -1659,7 +1706,7 @@ static void frame(void)
void cleanup(void)
{
sg_destroy_pipeline(pip);
sg_destroy_pipeline(hueshift_pipeline);
ma_mutex_lock(&server_info.info_mutex);
server_info.should_quit = true;

@ -1,6 +1,8 @@
@echo off
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
@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 goodpixel.glsl --output goodpixel.gen.h --slang glsl330:hlsl5:metal_macos
Loading…
Cancel
Save