From 4729bd0fa88e6b1eebeefb996ae18d1aed11805e Mon Sep 17 00:00:00 2001
From: Stephen T <xxlennygamerxx@gmail.com>
Date: Fri, 31 Jan 2025 02:35:12 -0600
Subject: [PATCH] Port over SDL_RenderFIllRoundedRect from SDL3 renderer.

---
 renderers/SDL2/clay_renderer_SDL2.c | 113 +++++++++++++++++++++++++++-
 1 file changed, 112 insertions(+), 1 deletion(-)

diff --git a/renderers/SDL2/clay_renderer_SDL2.c b/renderers/SDL2/clay_renderer_SDL2.c
index 811c6ef..b1a80cc 100644
--- a/renderers/SDL2/clay_renderer_SDL2.c
+++ b/renderers/SDL2/clay_renderer_SDL2.c
@@ -33,6 +33,112 @@ static Clay_Dimensions SDL2_MeasureText(Clay_StringSlice text, Clay_TextElementC
     };
 }
 
+/* Global for convenience. Even in 4K this is enough for smooth curves (low radius or rect size coupled with
+ * no AA or low resolution might make it appear as jagged curves) */
+static int NUM_CIRCLE_SEGMENTS = 16;
+
+//all rendering is performed by a single SDL call, avoiding multiple RenderRect + plumbing choice for circles.
+static void SDL_RenderFillRoundedRect(SDL_Renderer* renderer, const SDL_FRect rect, const float cornerRadius, const Clay_Color _color) {
+    const SDL_Color color = { (Uint8)(_color.r), (Uint8)(_color.g), (Uint8)(_color.b), (Uint8)(_color.a), };
+
+    int indexCount = 0, vertexCount = 0;
+
+    const float minRadius = SDL_min(rect.w, rect.h) / 2.0f;
+    const float clampedRadius = SDL_min(cornerRadius, minRadius);
+
+    const int numCircleSegments = SDL_max(NUM_CIRCLE_SEGMENTS, (int)clampedRadius * 0.5f);
+
+    int totalVertices = 4 + (4 * (numCircleSegments * 2)) + 2 * 4;
+    int totalIndices = 6 + (4 * (numCircleSegments * 3)) + 6 * 4;
+
+    SDL_Vertex vertices[totalVertices];
+    int indices[totalIndices];
+
+    //define center rectangle
+    vertices[vertexCount++] = (SDL_Vertex){ {rect.x + clampedRadius, rect.y + clampedRadius}, color, {0, 0} }; //0 center TL
+    vertices[vertexCount++] = (SDL_Vertex){ {rect.x + rect.w - clampedRadius, rect.y + clampedRadius}, color, {1, 0} }; //1 center TR
+    vertices[vertexCount++] = (SDL_Vertex){ {rect.x + rect.w - clampedRadius, rect.y + rect.h - clampedRadius}, color, {1, 1} }; //2 center BR
+    vertices[vertexCount++] = (SDL_Vertex){ {rect.x + clampedRadius, rect.y + rect.h - clampedRadius}, color, {0, 1} }; //3 center BL
+
+    indices[indexCount++] = 0;
+    indices[indexCount++] = 1;
+    indices[indexCount++] = 3;
+    indices[indexCount++] = 1;
+    indices[indexCount++] = 2;
+    indices[indexCount++] = 3;
+
+    //define rounded corners as triangle fans
+    const float step = (M_PI / 2) / numCircleSegments;
+    for (int i = 0; i < numCircleSegments; i++) {
+        const float angle1 = (float)i * step;
+        const float angle2 = ((float)i + 1.0f) * step;
+
+        for (int j = 0; j < 4; j++) {  // Iterate over four corners
+            float cx, cy, signX, signY;
+
+            switch (j) {
+            case 0: cx = rect.x + clampedRadius; cy = rect.y + clampedRadius; signX = -1; signY = -1; break; // Top-left
+            case 1: cx = rect.x + rect.w - clampedRadius; cy = rect.y + clampedRadius; signX = 1; signY = -1; break; // Top-right
+            case 2: cx = rect.x + rect.w - clampedRadius; cy = rect.y + rect.h - clampedRadius; signX = 1; signY = 1; break; // Bottom-right
+            case 3: cx = rect.x + clampedRadius; cy = rect.y + rect.h - clampedRadius; signX = -1; signY = 1; break; // Bottom-left
+            default: return;
+            }
+
+            vertices[vertexCount++] = (SDL_Vertex){ {cx + SDL_cosf(angle1) * clampedRadius * signX, cy + SDL_sinf(angle1) * clampedRadius * signY}, color, {0, 0} };
+            vertices[vertexCount++] = (SDL_Vertex){ {cx + SDL_cosf(angle2) * clampedRadius * signX, cy + SDL_sinf(angle2) * clampedRadius * signY}, color, {0, 0} };
+
+            indices[indexCount++] = j;  // Connect to corresponding central rectangle vertex
+            indices[indexCount++] = vertexCount - 2;
+            indices[indexCount++] = vertexCount - 1;
+        }
+    }
+
+    //Define edge rectangles
+    // Top edge
+    vertices[vertexCount++] = (SDL_Vertex){ {rect.x + clampedRadius, rect.y}, color, {0, 0} }; //TL
+    vertices[vertexCount++] = (SDL_Vertex){ {rect.x + rect.w - clampedRadius, rect.y}, color, {1, 0} }; //TR
+
+    indices[indexCount++] = 0;
+    indices[indexCount++] = vertexCount - 2; //TL
+    indices[indexCount++] = vertexCount - 1; //TR
+    indices[indexCount++] = 1;
+    indices[indexCount++] = 0;
+    indices[indexCount++] = vertexCount - 1; //TR
+    // Right edge
+    vertices[vertexCount++] = (SDL_Vertex){ {rect.x + rect.w, rect.y + clampedRadius}, color, {1, 0} }; //RT
+    vertices[vertexCount++] = (SDL_Vertex){ {rect.x + rect.w, rect.y + rect.h - clampedRadius}, color, {1, 1} }; //RB
+
+    indices[indexCount++] = 1;
+    indices[indexCount++] = vertexCount - 2; //RT
+    indices[indexCount++] = vertexCount - 1; //RB
+    indices[indexCount++] = 2;
+    indices[indexCount++] = 1;
+    indices[indexCount++] = vertexCount - 1; //RB
+    // Bottom edge
+    vertices[vertexCount++] = (SDL_Vertex){ {rect.x + rect.w - clampedRadius, rect.y + rect.h}, color, {1, 1} }; //BR
+    vertices[vertexCount++] = (SDL_Vertex){ {rect.x + clampedRadius, rect.y + rect.h}, color, {0, 1} }; //BL
+
+    indices[indexCount++] = 2;
+    indices[indexCount++] = vertexCount - 2; //BR
+    indices[indexCount++] = vertexCount - 1; //BL
+    indices[indexCount++] = 3;
+    indices[indexCount++] = 2;
+    indices[indexCount++] = vertexCount - 1; //BL
+    // Left edge
+    vertices[vertexCount++] = (SDL_Vertex){ {rect.x, rect.y + rect.h - clampedRadius}, color, {0, 1} }; //LB
+    vertices[vertexCount++] = (SDL_Vertex){ {rect.x, rect.y + clampedRadius}, color, {0, 0} }; //LT
+
+    indices[indexCount++] = 3;
+    indices[indexCount++] = vertexCount - 2; //LB
+    indices[indexCount++] = vertexCount - 1; //LT
+    indices[indexCount++] = 0;
+    indices[indexCount++] = 3;
+    indices[indexCount++] = vertexCount - 1; //LT
+
+    // Render everything
+    SDL_RenderGeometry(renderer, NULL, vertices, vertexCount, indices, indexCount);
+}
+
 SDL_Rect currentClippingRectangle;
 
 static void Clay_SDL2_Render(SDL_Renderer *renderer, Clay_RenderCommandArray renderCommands, SDL2_Font *fonts)
@@ -53,7 +159,12 @@ static void Clay_SDL2_Render(SDL_Renderer *renderer, Clay_RenderCommandArray ren
                         .w = boundingBox.width,
                         .h = boundingBox.height,
                 };
-                SDL_RenderFillRectF(renderer, &rect);
+                if (config->cornerRadius.topLeft > 0) {
+                    SDL_RenderFillRoundedRect(renderer, rect, config->cornerRadius.topLeft, color);
+                }
+                else {
+                    SDL_RenderFillRectF(renderer, &rect);
+                }
                 break;
             }
             case CLAY_RENDER_COMMAND_TYPE_TEXT: {