diff --git a/resources/shaders/source/rect.frag.glsl b/resources/shaders/source/rect.frag.glsl index 3466a16..b724988 100644 --- a/resources/shaders/source/rect.frag.glsl +++ b/resources/shaders/source/rect.frag.glsl @@ -1,9 +1,55 @@ #version 450 -layout(location = 0) in vec4 col; +layout(location = 0) in vec4 color; +layout(location = 1) in vec2 local_position; +layout(location = 2) in vec2 global_position; +layout(location = 3) in float radius; + layout(location = 0) out vec4 fragColor; +// SDF for a rounded rectangle given the centerpoint, half size and radius, all in pixels +float sdf_rr(vec2 p, vec2 center, vec2 half_size, float radius) { + // Translate fragment position to rectangle's coordinate system + p -= center; + // Adjust for rounded corners: shrink the rectangle by the radius + vec2 q = abs(p) - half_size + radius; + // Combine distance components: + // - max(q, 0.0) handles regions outside the rounded corners + // - min(max(q.x, q.y), 0.0) handles regions inside the rectangle + return length(max(q, 0.0)) + min(max(q.x, q.y), 0.0) - radius; +} + void main() { - fragColor = col; + // local_position are normalized coordinates in the rectangle, passed from the + // vertex shader + /* + * Window + * +-----------------------+ + * | (1,1) | + * | +----------x | + * | | | | + * | | | | + * | | Rect | | + * | | | | + * | | | | + * | x----------+ | + * | (-1,-1) | + * | | + * +-----------------------+ + */ + + vec2 dx = dFdx(local_position); + vec2 dy = dFdy(local_position); + // Conversion from normalized coordinates to pixels + vec2 norm_to_px = 1.0 / vec2(length(dx), length(dy)); + + vec2 centerpoint = global_position - local_position * norm_to_px; + // the half size of the rectangle is also norm_to_px + vec2 half_size = 1.0 * norm_to_px; + + float distance = sdf_rr(global_position, centerpoint, half_size, radius); + float alpha = 1.0 - smoothstep(0.0, 1.0, max(distance, 0.0)); + + fragColor = vec4(color.rgb, color.a * alpha); } \ No newline at end of file diff --git a/resources/shaders/source/rect.vert.glsl b/resources/shaders/source/rect.vert.glsl index 0fab590..b52a60d 100644 --- a/resources/shaders/source/rect.vert.glsl +++ b/resources/shaders/source/rect.vert.glsl @@ -10,6 +10,9 @@ layout(location = 1) in ivec2 uv; layout(location = 2) in ivec4 color; layout(location = 0) out vec4 col; +layout(location = 1) out vec2 local_position; +layout(location = 2) out vec2 global_position; +layout(location = 3) out float radius; void main() { @@ -24,5 +27,10 @@ void main() pos.y = -(float(position.y)*2.0 / view.y - 1.0); gl_Position = vec4(pos+shift, 0.0, 1.0); + + local_position = vec2(sign(uv)); + global_position = gl_Position.xy; + radius = abs(float(uv.x)); + col = vec4(color) / 255.0; } diff --git a/src/renderer.c3 b/src/renderer.c3 index ebcfd54..a65864a 100644 --- a/src/renderer.c3 +++ b/src/renderer.c3 @@ -566,7 +566,7 @@ fn bool Renderer.push_sprite(&self, short x, short y, short w, short h, short u, } // Push a quad into the quad buffer, return true on success and false on failure -fn bool Renderer.push_quad(&self, short x, short y, short w, short h, uint color) +fn bool Renderer.push_quad(&self, short x, short y, short w, short h, uint color, ushort radius = 0) { if (self.quad_buffer.count >= MAX_QUAD_BATCH) { return false; @@ -600,11 +600,14 @@ fn bool Renderer.push_quad(&self, short x, short y, short w, short h, uint color * |/ | * +-------------+ * v2 v3 - */ - quad.vertices.v1 = {.pos = {.x = x, .y = y}, .col.u = color}; - quad.vertices.v2 = {.pos = {.x = x, .y = y+h}, .col.u = color}; - quad.vertices.v3 = {.pos = {.x = x+w, .y = y+h}, .col.u = color}; - quad.vertices.v4 = {.pos = {.x = x+w, .y = y}, .col.u = color}; + */ + // the wanted radius is pushed into the uv coordinates, the vertex shader then extracts the absolute value + // and passes it to the fragment shader, then it uses the sign to give the fragment shader local coordinates + // into the quad. + quad.vertices.v1 = {.pos = {.x = x, .y = y}, .uv = {.u = -radius, .v = +radius}, .col.u = color}; + quad.vertices.v2 = {.pos = {.x = x, .y = y+h}, .uv = {.u = -radius, .v = -radius}, .col.u = color}; + quad.vertices.v3 = {.pos = {.x = x+w, .y = y+h}, .uv = {.u = +radius, .v = -radius}, .col.u = color}; + quad.vertices.v4 = {.pos = {.x = x+w, .y = y}, .uv = {.u = +radius, .v = +radius}, .col.u = color}; // triangle 1 indices quad.indices.i1 = 0; // v1 quad.indices.i2 = 1; // v2 diff --git a/test_renderer.c3 b/test_renderer.c3 index e9c6302..d5fd95b 100644 --- a/test_renderer.c3 +++ b/test_renderer.c3 @@ -62,7 +62,7 @@ fn int main() } // rect 1 - ren.push_quad(100,100,100,100,0xff00ff00); + ren.push_quad(100,100,100,100,0xff00ff00, 20); // rect 2 ren.push_quad(0,0,20,20,0xff0000ff); // rect 3