src/2d.c

changeset 158
f650994ec543
parent 151
42960d0c879b
--- a/src/2d.c	Tue Jun 17 19:00:20 2025 +0200
+++ b/src/2d.c	Tue Jun 17 20:11:53 2025 +0200
@@ -39,14 +39,24 @@
     GLint color;
     GLint size;
     GLint thickness;
+    GLint radius;
 } AscRectangleShader;
 
-static void *asc_rectangle_shader_create(bool fill) {
+#define ASC_RECTANGLE_SHADER_FLAG_FILL  1
+#define ASC_RECTANGLE_SHADER_FLAG_ROUND 2
+
+static AscShaderProgram *asc_rectangle_shader_create(int flags) {
     AscShaderCodes codes;
+    const char * const defines[] = {
+        "",
+        "#define FILL",
+        "#define ROUNDED_CORNERS",
+        "#define FILL\n#define ROUNDED_CORNERS",
+    };
     if (asc_shader_load_code_files((AscShaderCodeInfo){
         .files.vtx = "sprite_vtx.glsl",
         .files.frag = "rectangle_frag.glsl",
-        .defines.frag = fill ? "#define FILL" : NULL,
+        .defines.frag = defines[flags],
     }, &codes)) {
         asc_error("Loading sprite shader failed.");
         return NULL;
@@ -58,32 +68,21 @@
     }
     shader->color = glGetUniformLocation(shader->program.gl_id, "color");
     shader->size = glGetUniformLocation(shader->program.gl_id, "size");
-    if (fill) {
+    if (asc_test_flag(flags, ASC_RECTANGLE_SHADER_FLAG_FILL)) {
         shader->thickness = -1;
     } else {
         shader->thickness = glGetUniformLocation(shader->program.gl_id, "thickness");
     }
+    if (asc_test_flag(flags, ASC_RECTANGLE_SHADER_FLAG_ROUND)) {
+        shader->radius = glGetUniformLocation(shader->program.gl_id, "radius");
+    } else {
+        shader->radius = -1;
+    }
     asc_shader_free_codes(codes);
 
     asc_error_catch_all_gl();
 
-    return shader;
-}
-
-static AscShaderProgram *asc_rectangle_shader_fill_create() {
-    return asc_rectangle_shader_create(true);
-}
-
-static AscShaderProgram *asc_rectangle_shader_draw_create() {
-    return asc_rectangle_shader_create(false);
-}
-
-static const AscRectangleShader *asc_rectangle_shader_draw(void) {
-    return asc_shader_lookup_or_create(ASC_SHADER_RECTANGLE_DRAW, asc_rectangle_shader_draw_create);
-}
-
-static const AscRectangleShader *asc_rectangle_shader_fill(void) {
-    return asc_shader_lookup_or_create(ASC_SHADER_RECTANGLE_FILL, asc_rectangle_shader_fill_create);
+    return (AscShaderProgram*) shader;
 }
 
 static void asc_rectangle_destroy(AscSceneNode *node) {
@@ -99,13 +98,25 @@
 
 static void asc_rectangle_draw(const AscCamera *camera, const AscSceneNode *node) {
     asc_ptr_cast(AscRectangle, rectangle, node);
-    bool filled = asc_test_flag(rectangle->flags, ASC_RECTANGLE_FILLED);
+    const bool filled = asc_test_flag(rectangle->flags, ASC_RECTANGLE_FILLED);
+    const bool round = rectangle->radius > 0;
+
+    // Compute shader flags
+    int shader_flags = 0;
+    if (filled) shader_flags |= ASC_RECTANGLE_SHADER_FLAG_FILL;
+    if (round) shader_flags |= ASC_RECTANGLE_SHADER_FLAG_ROUND;
 
-    // Activate shader
-    // TODO: scene should know which shader we are going to activate s.t. it can pre-sort nodes
-    const AscRectangleShader *shader = filled
-                                         ? asc_rectangle_shader_fill()
-                                         : asc_rectangle_shader_draw();
+    // Compute shader ID
+    const int shader_ids[] = {
+        ASC_SHADER_RECTANGLE_DRAW,
+        ASC_SHADER_RECTANGLE_FILL,
+        ASC_SHADER_RECTANGLE_DRAW_ROUND,
+        ASC_SHADER_RECTANGLE_FILL_ROUND,
+    };
+
+    // Look up and activate shader
+    const AscRectangleShader *shader = asc_shader_lookup_or_create(
+        shader_ids[shader_flags], asc_rectangle_shader_create, shader_flags);
     asc_shader_use(&shader->program, camera);
 
     // Upload uniforms
@@ -119,11 +130,13 @@
         rectangle->color.blue,
         rectangle->color.alpha
     );
-    glUniform2f(shader->size, (float) rectangle->width, (float) rectangle->height);
+    glUniform2f(shader->size, rectangle->width, rectangle->height);
 
     if (!filled) {
-        // TODO: implement thickness
-        glUniform1f(shader->thickness, 1);
+        glUniform1f(shader->thickness, rectangle->thickness);
+    }
+    if (round) {
+        glUniform1f(shader->radius, rectangle->radius);
     }
 
     // Draw mesh
@@ -136,15 +149,17 @@
     if (args.bounds.size.width + args.bounds.size.height > 0) {
         rectangle->node.position.x = (float) args.bounds.pos.x;
         rectangle->node.position.y = (float) args.bounds.pos.y;
-        rectangle->width = args.bounds.size.width;
-        rectangle->height = args.bounds.size.height;
+        rectangle->width = (float) args.bounds.size.width;
+        rectangle->height = (float) args.bounds.size.height;
     } else {
         rectangle->node.position.x = (float) args.x;
         rectangle->node.position.y = (float) args.y;
-        rectangle->width = args.width;
-        rectangle->height = args.height;
+        rectangle->width = (float) args.width;
+        rectangle->height = (float) args.height;
     }
 
+    rectangle->thickness = ASC_NONZERO_OR(1.f, args.thickness);
+    rectangle->radius = (float)args.radius;
     rectangle->color = asc_col_itof(asc_context.ink);
 
     if (args.filled) {

mercurial