diff --git a/build.c b/build.c index 17ffc8e..6c305bc 100644 --- a/build.c +++ b/build.c @@ -37,10 +37,10 @@ typedef struct Context_Extra { // #include "oogabooga/examples/text_rendering.c" // #include "oogabooga/examples/custom_logger.c" -#include "oogabooga/examples/renderer_stress_test.c" +// #include "oogabooga/examples/renderer_stress_test.c" // #include "oogabooga/examples/tile_game.c" // #include "oogabooga/examples/audio_test.c" -// #include "oogabooga/examples/custom_shader.c" +#include "oogabooga/examples/custom_shader.c" // This is where you swap in your own project! // #include "entry_yourepicgamename.c" diff --git a/oogabooga/examples/custom_shader.c b/oogabooga/examples/custom_shader.c index accd413..5784cf6 100644 --- a/oogabooga/examples/custom_shader.c +++ b/oogabooga/examples/custom_shader.c @@ -10,12 +10,15 @@ typedef struct My_Cbuffer { // We implement these details which we implement in the shader #define DETAIL_TYPE_ROUNDED_CORNERS 1 #define DETAIL_TYPE_OUTLINED 2 +#define DETAIL_TYPE_OUTLINED_CIRCLE 3 // With custom shading we can extend the rendering library! Draw_Quad *draw_rounded_rect(Vector2 p, Vector2 size, Vector4 color, float radius); Draw_Quad *draw_rounded_rect_xform(Matrix4 xform, Vector2 size, Vector4 color, float radius); -Draw_Quad *draw_outlined_rect(Vector2 p, Vector2 size, Vector4 color, float line_width); -Draw_Quad *draw_outlined_rect_xform(Matrix4 xform, Vector2 size, Vector4 color, float line_width); +Draw_Quad *draw_outlined_rect(Vector2 p, Vector2 size, Vector4 color, float line_width_pixels); +Draw_Quad *draw_outlined_rect_xform(Matrix4 xform, Vector2 size, Vector4 color, float line_width_pixels); +Draw_Quad *draw_outlined_circle(Vector2 p, Vector2 size, Vector4 color, float line_width_pixels); +Draw_Quad *draw_outlined_circle_xform(Matrix4 xform, Vector2 size, Vector4 color, float line_width_pixels); int entry(int argc, char **argv) { @@ -64,7 +67,9 @@ int entry(int argc, char **argv) { rect_xform = m4_translate(rect_xform, v3(-.25f, -.25f, 0)); Draw_Quad *q = draw_rounded_rect_xform(rect_xform, v2(.5f, .5f), COLOR_GREEN, 0.1); - draw_outlined_rect(v2(sin(now), -.8), v2(.5, .25), COLOR_RED, 15); + draw_outlined_rect(v2(sin(now), -.8), v2(.5, .25), COLOR_RED, 2); + + draw_outlined_circle(v2(-sin(now), -.8), v2(.6, .6), COLOR_BLUE, 2); // Shader hot reloading @@ -82,6 +87,34 @@ int entry(int argc, char **argv) { return 0; } +Vector2 world_to_screen(Vector2 p) { + Vector4 in_view_space = m4_transform(draw_frame.view, v4(p.x, p.y, 0.0, 1.0)); + Vector4 in_clip_space = m4_transform(draw_frame.projection, in_view_space); + + Vector4 ndc = { + .x = in_clip_space.x / in_clip_space.w, + .y = in_clip_space.y / in_clip_space.w, + .z = in_clip_space.z / in_clip_space.w, + .w = in_clip_space.w + }; + + return v2( + (ndc.x + 1.0f) * 0.5f * (f32)window.width, + (ndc.y + 1.0f) * 0.5f * (f32)window.height + ); +} +Vector2 world_size_to_screen_size(Vector2 s) { + Vector2 origin = v2(0, 0); + + Vector2 screen_origin = world_to_screen(origin); + Vector2 screen_size_point = world_to_screen(s); + + return v2( + screen_size_point.x - screen_origin.x, + screen_size_point.y - screen_origin.y + ); +} + Draw_Quad *draw_rounded_rect(Vector2 p, Vector2 size, Vector4 color, float radius) { Draw_Quad *q = draw_rect(p, size, color); // detail_type @@ -98,19 +131,44 @@ Draw_Quad *draw_rounded_rect_xform(Matrix4 xform, Vector2 size, Vector4 color, f q->userdata[0].y = radius; return q; } -Draw_Quad *draw_outlined_rect(Vector2 p, Vector2 size, Vector4 color, float line_width) { +Draw_Quad *draw_outlined_rect(Vector2 p, Vector2 size, Vector4 color, float line_width_pixels) { Draw_Quad *q = draw_rect(p, size, color); // detail_type q->userdata[0].x = DETAIL_TYPE_OUTLINED; - // line_width - q->userdata[0].y = line_width; + // line_width_pixels + q->userdata[0].y = line_width_pixels; + // rect_size + q->userdata[0].zw = world_size_to_screen_size(size); return q; } -Draw_Quad *draw_outlined_rect_xform(Matrix4 xform, Vector2 size, Vector4 color, float line_width) { +Draw_Quad *draw_outlined_rect_xform(Matrix4 xform, Vector2 size, Vector4 color, float line_width_pixels) { Draw_Quad *q = draw_rect_xform(xform, size, color); // detail_type q->userdata[0].x = DETAIL_TYPE_OUTLINED; - // line_width - q->userdata[0].y = line_width; + // line_width_pixels + q->userdata[0].y = line_width_pixels; + // rect_size + q->userdata[0].zw = world_size_to_screen_size(size); + return q; +} +Draw_Quad *draw_outlined_circle(Vector2 p, Vector2 size, Vector4 color, float line_width_pixels) { + Draw_Quad *q = draw_rect(p, size, color); + // detail_type + q->userdata[0].x = DETAIL_TYPE_OUTLINED_CIRCLE; + // line_width_pixels + q->userdata[0].y = line_width_pixels; + // rect_size_pixels + q->userdata[0].zw = world_size_to_screen_size(size); // Transform world space to screen space + return q; +} +Draw_Quad *draw_outlined_circle_xform(Matrix4 xform, Vector2 size, Vector4 color, float line_width_pixels) { + Draw_Quad *q = draw_rect_xform(xform, size, color); + // detail_type + q->userdata[0].x = DETAIL_TYPE_OUTLINED_CIRCLE; + // line_width_pixels + q->userdata[0].y = line_width_pixels; + // rect_size_pixels + q->userdata[0].zw = world_size_to_screen_size(size); // Transform world space to screen space + return q; } \ No newline at end of file diff --git a/oogabooga/examples/custom_shader.hlsl b/oogabooga/examples/custom_shader.hlsl index eeff558..9d1650d 100644 --- a/oogabooga/examples/custom_shader.hlsl +++ b/oogabooga/examples/custom_shader.hlsl @@ -10,6 +10,7 @@ cbuffer some_cbuffer : register(b0) { #define DETAIL_TYPE_ROUNDED_CORNERS 1 #define DETAIL_TYPE_OUTLINED 2 +#define DETAIL_TYPE_OUTLINED_CIRCLE 3 float4 get_light_contribution(PS_INPUT input) { @@ -30,6 +31,9 @@ float4 get_light_contribution(PS_INPUT input) { float4 pixel_shader_extension(PS_INPUT input, float4 color) { float detail_type = input.userdata[0].x; + + // Assumes rect with 90deg corners + float2 rect_size_pixels = input.userdata[0].zw; if (detail_type == DETAIL_TYPE_ROUNDED_CORNERS) { float corner_radius = input.userdata[0].y; @@ -44,23 +48,45 @@ float4 pixel_shader_extension(PS_INPUT input, float4 color) { color *= mask; } else if (detail_type == DETAIL_TYPE_OUTLINED) { - float line_width = input.userdata[0].y; + float line_width_pixels = input.userdata[0].y; - float2 pixel_pos = round(input.self_uv*window_size); + float2 pixel_pos = round(input.self_uv*rect_size_pixels); - float xcenter = window_size.x/2; - float ycenter = window_size.y/2; + float xcenter = rect_size_pixels.x/2; + float ycenter = rect_size_pixels.y/2; - float xedge = pixel_pos.x < xcenter ? 0.0 : window_size.x; - float yedge = pixel_pos.y < ycenter ? 0.0 : window_size.y; + float xedge = pixel_pos.x < xcenter ? 0.0 : rect_size_pixels.x; + float yedge = pixel_pos.y < ycenter ? 0.0 : rect_size_pixels.y; float xdist = abs(xedge-pixel_pos.x); float ydist = abs(yedge-pixel_pos.y); - if (xdist >= line_width && ydist >= line_width) { + if (xdist > line_width_pixels && ydist > line_width_pixels) { discard; } - } + } else if (detail_type == DETAIL_TYPE_OUTLINED_CIRCLE) { + float line_width_pixels = input.userdata[0].y; + float2 rect_size_pixels = input.userdata[0].zw; + float line_width_uv = line_width_pixels / min(rect_size_pixels.x, rect_size_pixels.y); + + // For some simple anti-aliasing, we add a little bit of padding around the outline + // and fade that padding outwards with a smooth curve towards 0. + // Very arbitrary smooth equation that I got from just testing different sizes of the circle. + // It's kinda meh. + float smooth = ((4.0/line_width_pixels)*6.0)/window_size.x; + + float2 center = float2(0.5, 0.5); + float dist = length(input.self_uv - center); + + float mask; + if (dist > 0.5-smooth) { + mask = 1.0-lerp(0, 1.0, max(dist-0.5+smooth, 0.0)/smooth); + } else if (dist < 0.5-line_width_uv+smooth) { + mask = smoothstep(0, 1.0, max(dist-0.5+line_width_uv+smooth, 0.0)/smooth); + } + if (mask <= 0) discard; + color *= mask; + } float4 light = get_light_contribution(input); diff --git a/oogabooga/gfx_impl_d3d11.c b/oogabooga/gfx_impl_d3d11.c index 2e08937..342615c 100644 --- a/oogabooga/gfx_impl_d3d11.c +++ b/oogabooga/gfx_impl_d3d11.c @@ -132,12 +132,13 @@ void d3d11_update_swapchain() { DXGI_SWAP_CHAIN_DESC1 scd = ZERO(DXGI_SWAP_CHAIN_DESC1); scd.Format = DXGI_FORMAT_R8G8B8A8_UNORM; scd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING; + //scd.BufferDesc.RefreshRate.Numerator = 0; //scd.BufferDesc.RefreshRate.Denominator = 1; scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; scd.SampleDesc.Count = 1; - scd.SampleDesc.Quality = 0; + scd.SampleDesc.Quality = 0; // #Portability if (d3d11_feature_level < D3D_FEATURE_LEVEL_11_0) { scd.Scaling = DXGI_SCALING_STRETCH; // for compatability with 7 }