--- 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) {