summaryrefslogtreecommitdiffhomepage
path: root/src/shapes.c
diff options
context:
space:
mode:
authorDemizdor <[email protected]>2019-03-30 22:18:29 +0200
committerDemizdor <[email protected]>2019-03-30 22:18:29 +0200
commita28023b58f172559228a07da29d8cac417d2e6bd (patch)
treef0a872fcdd1d71998ba22f1bf11e50d2c4d776ca /src/shapes.c
parent2217c04ecf426cc2011c864fa788354ffa1de307 (diff)
downloadraylib-a28023b58f172559228a07da29d8cac417d2e6bd.tar.gz
raylib-a28023b58f172559228a07da29d8cac417d2e6bd.zip
Added DrawRoundedRect()
Diffstat (limited to 'src/shapes.c')
-rw-r--r--src/shapes.c194
1 files changed, 194 insertions, 0 deletions
diff --git a/src/shapes.c b/src/shapes.c
index 8c1eb1f0..9eb690d3 100644
--- a/src/shapes.c
+++ b/src/shapes.c
@@ -698,6 +698,200 @@ void DrawRectangleLinesEx(Rectangle rec, int lineThick, Color color)
DrawRectangle( (int)rec.x, (int)(rec.y + lineThick), lineThick, (int)(rec.height - lineThick*2), color);
}
+// Draw rectangle with rounded edges.
+void DrawRoundedRect(Rectangle rec, float roundness, int segments, Color color)
+{
+ // Not a rounded rectangle
+ // NOTE: Make sure we have at least 1px space left to render the rectangles near the corners
+ if(roundness <= 0.0f || rec.width <= 1 || rec.height <= 1 )
+ {
+ DrawRectangleRec(rec, color);
+ return;
+ }
+
+ if(roundness >= 1.0f) roundness = 1.0f;
+
+ // Calculate corner radius
+ // NOTE: Make sure we have at least 1px space left to render the rectangles near the corners
+ float radius = rec.width > rec.height ? ((rec.height-1)*roundness)/2 : ((rec.width-1)*roundness)/2;
+ if(radius <= 0.0f) return;
+
+ // Calculate number of segments to use for the corners
+ if (segments < 4)
+ {
+ // Calculate how many segments we need to draw a smooth circle, taken from https://stackoverflow.com/a/2244088
+ #ifndef CIRCLE_ERROR_RATE
+ #define CIRCLE_ERROR_RATE 0.5f
+ #endif
+ // Calculate the maximum angle between segments based on the error rate.
+ float th = acosf(2*powf(1 - CIRCLE_ERROR_RATE/radius, 2) - 1);
+ segments = ceilf(2*PI/th)/4;
+ if (segments <= 0) segments = 4;
+ }
+
+ float stepLength = 90.0f/(float)segments;
+
+ /* Quick sketch to make sense of all of this (there are 9 parts to draw, also mark the 12 points we'll use below)
+ * Not my best attempt at ASCII art, just preted it's a rounded rectangle :)
+ * P0 P1
+ * ____________________
+ * /| |\
+ * /1| 2 |3\
+ *P7 /__|____________________|__\ P2
+ * | |P8 P9| |
+ * | 8 | 9 | 4 |
+ * | __|____________________|__ |
+ *P6 \ |P11 P10| / P3
+ * \7| 6 |5/
+ * \|____________________|/
+ * P5 P4
+ */
+
+ const Vector2 point[12] = { // coordinates of the 12 points that define the rounded rect (the idea here is to make things easier)
+ {(float)rec.x + radius, rec.y}, {(float)(rec.x + rec.width) - radius, rec.y}, { rec.x + rec.width, (float)rec.y + radius }, // PO, P1, P2
+ {rec.x + rec.width, (float)(rec.y + rec.height) - radius}, {(float)(rec.x + rec.width) - radius, rec.y + rec.height}, // P3, P4
+ {(float)rec.x + radius, rec.y + rec.height}, { rec.x, (float)(rec.y + rec.height) - radius}, {rec.x, (float)rec.y + radius}, // P5, P6, P7
+ {(float)rec.x + radius, (float)rec.y + radius}, {(float)(rec.x + rec.width) - radius, (float)rec.y + radius}, // P8, P9
+ {(float)(rec.x + rec.width) - radius, (float)(rec.y + rec.height) - radius}, {(float)rec.x + radius, (float)(rec.y + rec.height) - radius} // P10, P11
+ };
+
+#if defined(SUPPORT_QUADS_DRAW_MODE)
+ if (rlCheckBufferLimit(16*segments/2 + 5*4)) rlglDraw();
+
+ rlBegin(RL_QUADS);
+ // Draw all of the 4 corners: [1] Upper Left Corner, [3] Upper Right Corner, [5] Lower Right Corner, [7] Lower Left Corner
+ const Vector2 centers[4] = { point[8], point[9], point[10], point[11] };
+ const float angles[4] = {180.0f, 90.0f, 0.0f, 270.0f };
+ for(int k = 0; k < 4; ++k) // Hope the compiler is smart enough to unroll this loop
+ {
+ float angle = angles[k];
+ const Vector2 center = centers[k];
+ // NOTE: Every QUAD actually represents two segments
+ for (int i = 0; i < segments/2; i++)
+ {
+ rlColor4ub(color.r, color.g, color.b, color.a);
+ rlVertex2f(center.x, center.y);
+ rlVertex2f(center.x + sinf(DEG2RAD*angle)*radius, center.y + cosf(DEG2RAD*angle)*radius);
+ rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*radius, center.y + cosf(DEG2RAD*(angle + stepLength))*radius);
+ rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength*2))*radius, center.y + cosf(DEG2RAD*(angle + stepLength*2))*radius);
+ angle += (stepLength*2);
+ }
+ // NOTE: In case number of segments is odd, we add one last piece to the cake
+ if (segments%2)
+ {
+ rlColor4ub(color.r, color.g, color.b, color.a);
+ rlVertex2f(center.x, center.y);
+ rlVertex2f(center.x + sinf(DEG2RAD*angle)*radius, center.y + cosf(DEG2RAD*angle)*radius);
+ rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*radius, center.y + cosf(DEG2RAD*(angle + stepLength))*radius);
+ rlVertex2f(center.x, center.y);
+ }
+ }
+
+ // [2] Upper Rectangle
+ rlColor4ub(color.r, color.g, color.b, color.a);
+ rlVertex2f(point[0].x, point[0].y);
+ rlVertex2f(point[8].x, point[8].y);
+ rlVertex2f(point[9].x, point[9].y);
+ rlVertex2f(point[1].x, point[1].y);
+
+ // [4] Right Rectangle
+ rlColor4ub(color.r, color.g, color.b, color.a);
+ rlVertex2f(point[2].x, point[2].y);
+ rlVertex2f(point[9].x, point[9].y);
+ rlVertex2f(point[10].x, point[10].y);
+ rlVertex2f(point[3].x, point[3].y);
+
+ // [6] Bottom Rectangle
+ rlColor4ub(color.r, color.g, color.b, color.a);
+ rlVertex2f(point[11].x, point[11].y);
+ rlVertex2f(point[5].x, point[5].y);
+ rlVertex2f(point[4].x, point[4].y);
+ rlVertex2f(point[10].x, point[10].y);
+
+ // [8] Left Rectangle
+ rlColor4ub(color.r, color.g, color.b, color.a);
+ rlVertex2f(point[7].x, point[7].y);
+ rlVertex2f(point[6].x, point[6].y);
+ rlVertex2f(point[11].x, point[11].y);
+ rlVertex2f(point[8].x, point[8].y);
+
+ // [9] Middle Rectangle
+ rlColor4ub(color.r, color.g, color.b, color.a);
+ rlVertex2f(point[8].x, point[8].y);
+ rlVertex2f(point[11].x, point[11].y);
+ rlVertex2f(point[10].x, point[10].y);
+ rlVertex2f(point[9].x, point[9].y);
+
+ rlEnd();
+#else
+ if (rlCheckBufferLimit(12*segments + 5*6)) rlglDraw(); // 4 corners with 3 vertices per segment + 5 rectangles with 6 vertices each
+
+ rlBegin(RL_TRIANGLES);
+ // Draw all of the 4 corners: [1] Upper Left Corner, [3] Upper Right Corner, [5] Lower Right Corner, [7] Lower Left Corner
+ const Vector2 centers[4] = { point[8], point[9], point[10], point[11] };
+ const float angles[4] = {180.0f, 90.0f, 0.0f, 270.0f };
+ for(int k = 0; k < 4; ++k) // Hope the compiler is smart enough to unroll this loop
+ {
+ float angle = angles[k];
+ const Vector2 center = centers[k];
+ for (int i = 0; i < segments; i++)
+ {
+ rlColor4ub(color.r, color.g, color.b, color.a);
+ rlVertex2f(center.x, center.y);
+ rlVertex2f(center.x + sinf(DEG2RAD*angle)*radius, center.y + cosf(DEG2RAD*angle)*radius);
+ rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*radius, center.y + cosf(DEG2RAD*(angle + stepLength))*radius);
+ angle += stepLength;
+ }
+ }
+
+ // [2] Upper Rectangle
+ rlColor4ub(color.r, color.g, color.b, color.a);
+ rlVertex2f(point[0].x, point[0].y);
+ rlVertex2f(point[8].x, point[8].y);
+ rlVertex2f(point[9].x, point[9].y);
+ rlVertex2f(point[1].x, point[1].y);
+ rlVertex2f(point[0].x, point[0].y);
+ rlVertex2f(point[9].x, point[9].y);
+
+ // [4] Right Rectangle
+ rlColor4ub(color.r, color.g, color.b, color.a);
+ rlVertex2f(point[9].x, point[9].y);
+ rlVertex2f(point[10].x, point[10].y);
+ rlVertex2f(point[3].x, point[3].y);
+ rlVertex2f(point[2].x, point[2].y);
+ rlVertex2f(point[9].x, point[9].y);
+ rlVertex2f(point[3].x, point[3].y);
+
+ // [6] Bottom Rectangle
+ rlColor4ub(color.r, color.g, color.b, color.a);
+ rlVertex2f(point[11].x, point[11].y);
+ rlVertex2f(point[5].x, point[5].y);
+ rlVertex2f(point[4].x, point[4].y);
+ rlVertex2f(point[10].x, point[10].y);
+ rlVertex2f(point[11].x, point[11].y);
+ rlVertex2f(point[4].x, point[4].y);
+
+ // [8] Left Rectangle
+ rlColor4ub(color.r, color.g, color.b, color.a);
+ rlVertex2f(point[7].x, point[7].y);
+ rlVertex2f(point[6].x, point[6].y);
+ rlVertex2f(point[11].x, point[11].y);
+ rlVertex2f(point[8].x, point[8].y);
+ rlVertex2f(point[7].x, point[7].y);
+ rlVertex2f(point[11].x, point[11].y);
+
+ // [9] Middle Rectangle
+ rlColor4ub(color.r, color.g, color.b, color.a);
+ rlVertex2f(point[8].x, point[8].y);
+ rlVertex2f(point[11].x, point[11].y);
+ rlVertex2f(point[10].x, point[10].y);
+ rlVertex2f(point[9].x, point[9].y);
+ rlVertex2f(point[8].x, point[8].y);
+ rlVertex2f(point[10].x, point[10].y);
+ rlEnd();
+#endif
+}
+
// Draw a triangle
void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color)
{