1 /**********************************************************************************************
3 * raylib.shapes - Basic functions to draw 2d Shapes and check collisions
7 * #define SUPPORT_QUADS_DRAW_MODE
8 * Use QUADS instead of TRIANGLES for drawing when possible.
9 * Some lines-based shapes could still use lines
11 * LICENSE: zlib/libpng
13 * Copyright (c) 2013-2021 Ramon Santamaria (@raysan5)
15 * This software is provided "as-is", without any express or implied warranty. In no event
16 * will the authors be held liable for any damages arising from the use of this software.
18 * Permission is granted to anyone to use this software for any purpose, including commercial
19 * applications, and to alter it and redistribute it freely, subject to the following restrictions:
21 * 1. The origin of this software must not be misrepresented; you must not claim that you
22 * wrote the original software. If you use this software in a product, an acknowledgment
23 * in the product documentation would be appreciated but is not required.
25 * 2. Altered source versions must be plainly marked as such, and must not be misrepresented
26 * as being the original software.
28 * 3. This notice may not be removed or altered from any source distribution.
30 **********************************************************************************************/
32 #include "raylib.h" // Declares module functions
34 // Check if config flags have been externally provided on compilation line
35 #if !defined(EXTERNAL_CONFIG_FLAGS)
36 #include "config.h" // Defines module configuration flags
39 #include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2
41 #include <math.h> // Required for: sinf(), asinf(), cosf(), acosf(), sqrtf(), fabsf()
43 //----------------------------------------------------------------------------------
45 //----------------------------------------------------------------------------------
47 // Error rate to calculate how many segments we need to draw a smooth circle,
48 // taken from https://stackoverflow.com/a/2244088
49 #ifndef SMOOTH_CIRCLE_ERROR_RATE
50 #define SMOOTH_CIRCLE_ERROR_RATE 0.5f
53 //----------------------------------------------------------------------------------
54 // Types and Structures Definition
55 //----------------------------------------------------------------------------------
58 //----------------------------------------------------------------------------------
59 // Global Variables Definition
60 //----------------------------------------------------------------------------------
61 Texture2D texShapes = { 1, 1, 1, 1, 7 }; // Texture used on shapes drawing (usually a white pixel)
62 Rectangle texShapesRec = { 0, 0, 1, 1 }; // Texture source rectangle used on shapes drawing
64 //----------------------------------------------------------------------------------
65 // Module specific Functions Declaration
66 //----------------------------------------------------------------------------------
67 static float EaseCubicInOut(float t, float b, float c, float d); // Cubic easing
69 //----------------------------------------------------------------------------------
70 // Module Functions Definition
71 //----------------------------------------------------------------------------------
73 // Set texture and rectangle to be used on shapes drawing
74 // NOTE: It can be useful when using basic shapes and one single font,
75 // defining a font char white rectangle would allow drawing everything in a single draw call
76 void SetShapesTexture(Texture2D texture, Rectangle source)
79 texShapesRec = source;
83 void DrawPixel(int posX, int posY, Color color)
86 rlColor4ub(color.r, color.g, color.b, color.a);
87 rlVertex2i(posX, posY);
88 rlVertex2i(posX + 1, posY + 1);
92 // Draw a pixel (Vector version)
93 void DrawPixelV(Vector2 position, Color color)
96 rlColor4ub(color.r, color.g, color.b, color.a);
97 rlVertex2f(position.x, position.y);
98 rlVertex2f(position.x + 1.0f, position.y + 1.0f);
103 void DrawLine(int startPosX, int startPosY, int endPosX, int endPosY, Color color)
106 rlColor4ub(color.r, color.g, color.b, color.a);
107 rlVertex2i(startPosX, startPosY);
108 rlVertex2i(endPosX, endPosY);
112 // Draw a line (Vector version)
113 void DrawLineV(Vector2 startPos, Vector2 endPos, Color color)
116 rlColor4ub(color.r, color.g, color.b, color.a);
117 rlVertex2f(startPos.x, startPos.y);
118 rlVertex2f(endPos.x, endPos.y);
122 // Draw a line defining thickness
123 void DrawLineEx(Vector2 startPos, Vector2 endPos, float thick, Color color)
125 Vector2 delta = {endPos.x-startPos.x, endPos.y-startPos.y};
126 float length = sqrtf(delta.x*delta.x + delta.y*delta.y);
128 if (length > 0 && thick > 0)
130 float scale = thick/(2*length);
131 Vector2 radius = {-scale*delta.y, scale*delta.x};
132 Vector2 strip[] = {{startPos.x-radius.x, startPos.y-radius.y}, {startPos.x+radius.x, startPos.y+radius.y},
133 {endPos.x-radius.x, endPos.y-radius.y}, {endPos.x+radius.x, endPos.y+radius.y}};
135 DrawTriangleStrip(strip, 4, color);
139 // Draw line using cubic-bezier curves in-out
140 void DrawLineBezier(Vector2 startPos, Vector2 endPos, float thick, Color color)
142 #ifndef BEZIER_LINE_DIVISIONS
143 #define BEZIER_LINE_DIVISIONS 24 // Bezier line divisions
146 Vector2 previous = startPos;
149 for (int i = 1; i <= BEZIER_LINE_DIVISIONS; i++)
151 // Cubic easing in-out
152 // NOTE: Easing is calculated only for y position value
153 current.y = EaseCubicInOut((float)i, startPos.y, endPos.y - startPos.y, (float)BEZIER_LINE_DIVISIONS);
154 current.x = previous.x + (endPos.x - startPos.x)/ (float)BEZIER_LINE_DIVISIONS;
156 DrawLineEx(previous, current, thick, color);
162 // Draw line using quadratic bezier curves with a control point
163 void DrawLineBezierQuad(Vector2 startPos, Vector2 endPos, Vector2 controlPos, float thick, Color color)
165 const float step = 1.0f/BEZIER_LINE_DIVISIONS;
167 Vector2 previous = startPos;
168 Vector2 current = { 0 };
171 for (int i = 0; i <= BEZIER_LINE_DIVISIONS; i++)
174 float a = powf(1 - t, 2);
175 float b = 2*(1 - t)*t;
176 float c = powf(t, 2);
178 // NOTE: The easing functions aren't suitable here because they don't take a control point
179 current.y = a*startPos.y + b*controlPos.y + c*endPos.y;
180 current.x = a*startPos.x + b*controlPos.x + c*endPos.x;
182 DrawLineEx(previous, current, thick, color);
188 // Draw lines sequence
189 void DrawLineStrip(Vector2 *points, int pointsCount, Color color)
191 if (pointsCount >= 2)
193 rlCheckRenderBatchLimit(pointsCount);
196 rlColor4ub(color.r, color.g, color.b, color.a);
198 for (int i = 0; i < pointsCount - 1; i++)
200 rlVertex2f(points[i].x, points[i].y);
201 rlVertex2f(points[i + 1].x, points[i + 1].y);
207 // Draw a color-filled circle
208 void DrawCircle(int centerX, int centerY, float radius, Color color)
210 DrawCircleV((Vector2){ (float)centerX, (float)centerY }, radius, color);
213 // Draw a piece of a circle
214 void DrawCircleSector(Vector2 center, float radius, float startAngle, float endAngle, int segments, Color color)
216 if (radius <= 0.0f) radius = 0.1f; // Avoid div by zero
218 // Function expects (endAngle > startAngle)
219 if (endAngle < startAngle)
222 float tmp = startAngle;
223 startAngle = endAngle;
227 int minSegments = (int)ceilf((endAngle - startAngle)/90);
229 if (segments < minSegments)
231 // Calculate the maximum angle between segments based on the error rate (usually 0.5f)
232 float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/radius, 2) - 1);
233 segments = (int)((endAngle - startAngle)*ceilf(2*PI/th)/360);
235 if (segments <= 0) segments = minSegments;
238 float stepLength = (endAngle - startAngle)/(float)segments;
239 float angle = startAngle;
241 #if defined(SUPPORT_QUADS_DRAW_MODE)
242 rlCheckRenderBatchLimit(4*segments/2);
244 rlSetTexture(texShapes.id);
247 // NOTE: Every QUAD actually represents two segments
248 for (int i = 0; i < segments/2; i++)
250 rlColor4ub(color.r, color.g, color.b, color.a);
252 rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height);
253 rlVertex2f(center.x, center.y);
255 rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
256 rlVertex2f(center.x + sinf(DEG2RAD*angle)*radius, center.y + cosf(DEG2RAD*angle)*radius);
258 rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
259 rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*radius, center.y + cosf(DEG2RAD*(angle + stepLength))*radius);
261 rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height);
262 rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength*2))*radius, center.y + cosf(DEG2RAD*(angle + stepLength*2))*radius);
264 angle += (stepLength*2);
267 // NOTE: In case number of segments is odd, we add one last piece to the cake
270 rlColor4ub(color.r, color.g, color.b, color.a);
272 rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height);
273 rlVertex2f(center.x, center.y);
275 rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
276 rlVertex2f(center.x + sinf(DEG2RAD*angle)*radius, center.y + cosf(DEG2RAD*angle)*radius);
278 rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
279 rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*radius, center.y + cosf(DEG2RAD*(angle + stepLength))*radius);
281 rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height);
282 rlVertex2f(center.x, center.y);
288 rlCheckRenderBatchLimit(3*segments);
290 rlBegin(RL_TRIANGLES);
291 for (int i = 0; i < segments; i++)
293 rlColor4ub(color.r, color.g, color.b, color.a);
295 rlVertex2f(center.x, center.y);
296 rlVertex2f(center.x + sinf(DEG2RAD*angle)*radius, center.y + cosf(DEG2RAD*angle)*radius);
297 rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*radius, center.y + cosf(DEG2RAD*(angle + stepLength))*radius);
305 void DrawCircleSectorLines(Vector2 center, float radius, float startAngle, float endAngle, int segments, Color color)
307 if (radius <= 0.0f) radius = 0.1f; // Avoid div by zero issue
309 // Function expects (endAngle > startAngle)
310 if (endAngle < startAngle)
313 float tmp = startAngle;
314 startAngle = endAngle;
318 int minSegments = (int)ceilf((endAngle - startAngle)/90);
320 if (segments < minSegments)
322 // Calculate the maximum angle between segments based on the error rate (usually 0.5f)
323 float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/radius, 2) - 1);
324 segments = (int)((endAngle - startAngle)*ceilf(2*PI/th)/360);
326 if (segments <= 0) segments = minSegments;
329 float stepLength = (endAngle - startAngle)/(float)segments;
330 float angle = startAngle;
332 // Hide the cap lines when the circle is full
333 bool showCapLines = true;
334 int limit = 2*(segments + 2);
335 if ((int)(endAngle - startAngle)%360 == 0) { limit = 2*segments; showCapLines = false; }
337 rlCheckRenderBatchLimit(limit);
342 rlColor4ub(color.r, color.g, color.b, color.a);
343 rlVertex2f(center.x, center.y);
344 rlVertex2f(center.x + sinf(DEG2RAD*angle)*radius, center.y + cosf(DEG2RAD*angle)*radius);
347 for (int i = 0; i < segments; i++)
349 rlColor4ub(color.r, color.g, color.b, color.a);
351 rlVertex2f(center.x + sinf(DEG2RAD*angle)*radius, center.y + cosf(DEG2RAD*angle)*radius);
352 rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*radius, center.y + cosf(DEG2RAD*(angle + stepLength))*radius);
359 rlColor4ub(color.r, color.g, color.b, color.a);
360 rlVertex2f(center.x, center.y);
361 rlVertex2f(center.x + sinf(DEG2RAD*angle)*radius, center.y + cosf(DEG2RAD*angle)*radius);
366 // Draw a gradient-filled circle
367 // NOTE: Gradient goes from center (color1) to border (color2)
368 void DrawCircleGradient(int centerX, int centerY, float radius, Color color1, Color color2)
370 rlCheckRenderBatchLimit(3*36);
372 rlBegin(RL_TRIANGLES);
373 for (int i = 0; i < 360; i += 10)
375 rlColor4ub(color1.r, color1.g, color1.b, color1.a);
376 rlVertex2f((float)centerX, (float)centerY);
377 rlColor4ub(color2.r, color2.g, color2.b, color2.a);
378 rlVertex2f((float)centerX + sinf(DEG2RAD*i)*radius, (float)centerY + cosf(DEG2RAD*i)*radius);
379 rlColor4ub(color2.r, color2.g, color2.b, color2.a);
380 rlVertex2f((float)centerX + sinf(DEG2RAD*(i + 10))*radius, (float)centerY + cosf(DEG2RAD*(i + 10))*radius);
385 // Draw a color-filled circle (Vector version)
386 // NOTE: On OpenGL 3.3 and ES2 we use QUADS to avoid drawing order issues
387 void DrawCircleV(Vector2 center, float radius, Color color)
389 DrawCircleSector(center, radius, 0, 360, 36, color);
392 // Draw circle outline
393 void DrawCircleLines(int centerX, int centerY, float radius, Color color)
395 rlCheckRenderBatchLimit(2*36);
398 rlColor4ub(color.r, color.g, color.b, color.a);
400 // NOTE: Circle outline is drawn pixel by pixel every degree (0 to 360)
401 for (int i = 0; i < 360; i += 10)
403 rlVertex2f(centerX + sinf(DEG2RAD*i)*radius, centerY + cosf(DEG2RAD*i)*radius);
404 rlVertex2f(centerX + sinf(DEG2RAD*(i + 10))*radius, centerY + cosf(DEG2RAD*(i + 10))*radius);
410 void DrawEllipse(int centerX, int centerY, float radiusH, float radiusV, Color color)
412 rlCheckRenderBatchLimit(3*36);
414 rlBegin(RL_TRIANGLES);
415 for (int i = 0; i < 360; i += 10)
417 rlColor4ub(color.r, color.g, color.b, color.a);
418 rlVertex2f((float)centerX, (float)centerY);
419 rlVertex2f((float)centerX + sinf(DEG2RAD*i)*radiusH, (float)centerY + cosf(DEG2RAD*i)*radiusV);
420 rlVertex2f((float)centerX + sinf(DEG2RAD*(i + 10))*radiusH, (float)centerY + cosf(DEG2RAD*(i + 10))*radiusV);
425 // Draw ellipse outline
426 void DrawEllipseLines(int centerX, int centerY, float radiusH, float radiusV, Color color)
428 rlCheckRenderBatchLimit(2*36);
431 for (int i = 0; i < 360; i += 10)
433 rlColor4ub(color.r, color.g, color.b, color.a);
434 rlVertex2f(centerX + sinf(DEG2RAD*i)*radiusH, centerY + cosf(DEG2RAD*i)*radiusV);
435 rlVertex2f(centerX + sinf(DEG2RAD*(i + 10))*radiusH, centerY + cosf(DEG2RAD*(i + 10))*radiusV);
440 void DrawRing(Vector2 center, float innerRadius, float outerRadius, float startAngle, float endAngle, int segments, Color color)
442 if (startAngle == endAngle) return;
444 // Function expects (outerRadius > innerRadius)
445 if (outerRadius < innerRadius)
447 float tmp = outerRadius;
448 outerRadius = innerRadius;
451 if (outerRadius <= 0.0f) outerRadius = 0.1f;
454 // Function expects (endAngle > startAngle)
455 if (endAngle < startAngle)
458 float tmp = startAngle;
459 startAngle = endAngle;
463 int minSegments = (int)ceilf((endAngle - startAngle)/90);
465 if (segments < minSegments)
467 // Calculate the maximum angle between segments based on the error rate (usually 0.5f)
468 float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/outerRadius, 2) - 1);
469 segments = (int)((endAngle - startAngle)*ceilf(2*PI/th)/360);
471 if (segments <= 0) segments = minSegments;
475 if (innerRadius <= 0.0f)
477 DrawCircleSector(center, outerRadius, startAngle, endAngle, segments, color);
481 float stepLength = (endAngle - startAngle)/(float)segments;
482 float angle = startAngle;
484 #if defined(SUPPORT_QUADS_DRAW_MODE)
485 rlCheckRenderBatchLimit(4*segments);
487 rlSetTexture(texShapes.id);
490 for (int i = 0; i < segments; i++)
492 rlColor4ub(color.r, color.g, color.b, color.a);
494 rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height);
495 rlVertex2f(center.x + sinf(DEG2RAD*angle)*innerRadius, center.y + cosf(DEG2RAD*angle)*innerRadius);
497 rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
498 rlVertex2f(center.x + sinf(DEG2RAD*angle)*outerRadius, center.y + cosf(DEG2RAD*angle)*outerRadius);
500 rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
501 rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*outerRadius);
503 rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height);
504 rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*innerRadius);
512 rlCheckRenderBatchLimit(6*segments);
514 rlBegin(RL_TRIANGLES);
515 for (int i = 0; i < segments; i++)
517 rlColor4ub(color.r, color.g, color.b, color.a);
519 rlVertex2f(center.x + sinf(DEG2RAD*angle)*innerRadius, center.y + cosf(DEG2RAD*angle)*innerRadius);
520 rlVertex2f(center.x + sinf(DEG2RAD*angle)*outerRadius, center.y + cosf(DEG2RAD*angle)*outerRadius);
521 rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*innerRadius);
523 rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*innerRadius);
524 rlVertex2f(center.x + sinf(DEG2RAD*angle)*outerRadius, center.y + cosf(DEG2RAD*angle)*outerRadius);
525 rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*outerRadius);
533 void DrawRingLines(Vector2 center, float innerRadius, float outerRadius, float startAngle, float endAngle, int segments, Color color)
535 if (startAngle == endAngle) return;
537 // Function expects (outerRadius > innerRadius)
538 if (outerRadius < innerRadius)
540 float tmp = outerRadius;
541 outerRadius = innerRadius;
544 if (outerRadius <= 0.0f) outerRadius = 0.1f;
547 // Function expects (endAngle > startAngle)
548 if (endAngle < startAngle)
551 float tmp = startAngle;
552 startAngle = endAngle;
556 int minSegments = (int)ceilf((endAngle - startAngle)/90);
558 if (segments < minSegments)
560 // Calculate the maximum angle between segments based on the error rate (usually 0.5f)
561 float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/outerRadius, 2) - 1);
562 segments = (int)((endAngle - startAngle)*ceilf(2*PI/th)/360);
564 if (segments <= 0) segments = minSegments;
567 if (innerRadius <= 0.0f)
569 DrawCircleSectorLines(center, outerRadius, startAngle, endAngle, segments, color);
573 float stepLength = (endAngle - startAngle)/(float)segments;
574 float angle = startAngle;
576 bool showCapLines = true;
577 int limit = 4*(segments + 1);
578 if ((int)(endAngle - startAngle)%360 == 0) { limit = 4*segments; showCapLines = false; }
580 rlCheckRenderBatchLimit(limit);
585 rlColor4ub(color.r, color.g, color.b, color.a);
586 rlVertex2f(center.x + sinf(DEG2RAD*angle)*outerRadius, center.y + cosf(DEG2RAD*angle)*outerRadius);
587 rlVertex2f(center.x + sinf(DEG2RAD*angle)*innerRadius, center.y + cosf(DEG2RAD*angle)*innerRadius);
590 for (int i = 0; i < segments; i++)
592 rlColor4ub(color.r, color.g, color.b, color.a);
594 rlVertex2f(center.x + sinf(DEG2RAD*angle)*outerRadius, center.y + cosf(DEG2RAD*angle)*outerRadius);
595 rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*outerRadius);
597 rlVertex2f(center.x + sinf(DEG2RAD*angle)*innerRadius, center.y + cosf(DEG2RAD*angle)*innerRadius);
598 rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*innerRadius);
605 rlColor4ub(color.r, color.g, color.b, color.a);
606 rlVertex2f(center.x + sinf(DEG2RAD*angle)*outerRadius, center.y + cosf(DEG2RAD*angle)*outerRadius);
607 rlVertex2f(center.x + sinf(DEG2RAD*angle)*innerRadius, center.y + cosf(DEG2RAD*angle)*innerRadius);
612 // Draw a color-filled rectangle
613 void DrawRectangle(int posX, int posY, int width, int height, Color color)
615 DrawRectangleV((Vector2){ (float)posX, (float)posY }, (Vector2){ (float)width, (float)height }, color);
618 // Draw a color-filled rectangle (Vector version)
619 // NOTE: On OpenGL 3.3 and ES2 we use QUADS to avoid drawing order issues
620 void DrawRectangleV(Vector2 position, Vector2 size, Color color)
622 DrawRectanglePro((Rectangle){ position.x, position.y, size.x, size.y }, (Vector2){ 0.0f, 0.0f }, 0.0f, color);
625 // Draw a color-filled rectangle
626 void DrawRectangleRec(Rectangle rec, Color color)
628 DrawRectanglePro(rec, (Vector2){ 0.0f, 0.0f }, 0.0f, color);
631 // Draw a color-filled rectangle with pro parameters
632 void DrawRectanglePro(Rectangle rec, Vector2 origin, float rotation, Color color)
634 rlCheckRenderBatchLimit(4);
636 Vector2 topLeft = { 0 };
637 Vector2 topRight = { 0 };
638 Vector2 bottomLeft = { 0 };
639 Vector2 bottomRight = { 0 };
641 // Only calculate rotation if needed
642 if (rotation == 0.0f)
644 float x = rec.x - origin.x;
645 float y = rec.y - origin.y;
646 topLeft = (Vector2){ x, y };
647 topRight = (Vector2){ x + rec.width, y };
648 bottomLeft = (Vector2){ x, y + rec.height };
649 bottomRight = (Vector2){ x + rec.width, y + rec.height };
653 float sinRotation = sinf(rotation*DEG2RAD);
654 float cosRotation = cosf(rotation*DEG2RAD);
657 float dx = -origin.x;
658 float dy = -origin.y;
660 topLeft.x = x + dx*cosRotation - dy*sinRotation;
661 topLeft.y = y + dx*sinRotation + dy*cosRotation;
663 topRight.x = x + (dx + rec.width)*cosRotation - dy*sinRotation;
664 topRight.y = y + (dx + rec.width)*sinRotation + dy*cosRotation;
666 bottomLeft.x = x + dx*cosRotation - (dy + rec.height)*sinRotation;
667 bottomLeft.y = y + dx*sinRotation + (dy + rec.height)*cosRotation;
669 bottomRight.x = x + (dx + rec.width)*cosRotation - (dy + rec.height)*sinRotation;
670 bottomRight.y = y + (dx + rec.width)*sinRotation + (dy + rec.height)*cosRotation;
673 rlSetTexture(texShapes.id);
676 rlNormal3f(0.0f, 0.0f, 1.0f);
677 rlColor4ub(color.r, color.g, color.b, color.a);
679 rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height);
680 rlVertex2f(topLeft.x, topLeft.y);
682 rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
683 rlVertex2f(bottomLeft.x, bottomLeft.y);
685 rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
686 rlVertex2f(bottomRight.x, bottomRight.y);
688 rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height);
689 rlVertex2f(topRight.x, topRight.y);
695 // Draw a vertical-gradient-filled rectangle
696 // NOTE: Gradient goes from bottom (color1) to top (color2)
697 void DrawRectangleGradientV(int posX, int posY, int width, int height, Color color1, Color color2)
699 DrawRectangleGradientEx((Rectangle){ (float)posX, (float)posY, (float)width, (float)height }, color1, color2, color2, color1);
702 // Draw a horizontal-gradient-filled rectangle
703 // NOTE: Gradient goes from bottom (color1) to top (color2)
704 void DrawRectangleGradientH(int posX, int posY, int width, int height, Color color1, Color color2)
706 DrawRectangleGradientEx((Rectangle){ (float)posX, (float)posY, (float)width, (float)height }, color1, color1, color2, color2);
709 // Draw a gradient-filled rectangle
710 // NOTE: Colors refer to corners, starting at top-lef corner and counter-clockwise
711 void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3, Color col4)
713 rlSetTexture(texShapes.id);
717 rlNormal3f(0.0f, 0.0f, 1.0f);
719 // NOTE: Default raylib font character 95 is a white square
720 rlColor4ub(col1.r, col1.g, col1.b, col1.a);
721 rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height);
722 rlVertex2f(rec.x, rec.y);
724 rlColor4ub(col2.r, col2.g, col2.b, col2.a);
725 rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
726 rlVertex2f(rec.x, rec.y + rec.height);
728 rlColor4ub(col3.r, col3.g, col3.b, col3.a);
729 rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
730 rlVertex2f(rec.x + rec.width, rec.y + rec.height);
732 rlColor4ub(col4.r, col4.g, col4.b, col4.a);
733 rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height);
734 rlVertex2f(rec.x + rec.width, rec.y);
741 // Draw rectangle outline
742 // NOTE: On OpenGL 3.3 and ES2 we use QUADS to avoid drawing order issues
743 void DrawRectangleLines(int posX, int posY, int width, int height, Color color)
745 #if defined(SUPPORT_QUADS_DRAW_MODE)
746 DrawRectangle(posX, posY, width, 1, color);
747 DrawRectangle(posX + width - 1, posY + 1, 1, height - 2, color);
748 DrawRectangle(posX, posY + height - 1, width, 1, color);
749 DrawRectangle(posX, posY + 1, 1, height - 2, color);
752 rlColor4ub(color.r, color.g, color.b, color.a);
753 rlVertex2i(posX + 1, posY + 1);
754 rlVertex2i(posX + width, posY + 1);
756 rlVertex2i(posX + width, posY + 1);
757 rlVertex2i(posX + width, posY + height);
759 rlVertex2i(posX + width, posY + height);
760 rlVertex2i(posX + 1, posY + height);
762 rlVertex2i(posX + 1, posY + height);
763 rlVertex2i(posX + 1, posY + 1);
768 // Draw rectangle outline with extended parameters
769 void DrawRectangleLinesEx(Rectangle rec, int lineThick, Color color)
771 if ((lineThick > rec.width) || (lineThick > rec.height))
773 if (rec.width > rec.height) lineThick = (int)rec.height/2;
774 else if (rec.width < rec.height) lineThick = (int)rec.width/2;
777 // When rec = { x, y, 8.0f, 6.0f } and lineThick = 2, the following
778 // four rectangles are drawn ([T]op, [B]ottom, [L]eft, [R]ight):
787 float thick = (float)lineThick;
788 Rectangle top = { rec.x, rec.y, rec.width, thick };
789 Rectangle bottom = { rec.x, rec.y - thick + rec.height, rec.width, thick };
790 Rectangle left = { rec.x, rec.y + thick, thick, rec.height - thick*2.0f };
791 Rectangle right = { rec.x - thick + rec.width, rec.y + thick, thick, rec.height - thick*2.0f };
793 DrawRectangleRec(top, color);
794 DrawRectangleRec(bottom, color);
795 DrawRectangleRec(left, color);
796 DrawRectangleRec(right, color);
799 // Draw rectangle with rounded edges
800 void DrawRectangleRounded(Rectangle rec, float roundness, int segments, Color color)
802 // Not a rounded rectangle
803 if ((roundness <= 0.0f) || (rec.width < 1) || (rec.height < 1 ))
805 DrawRectangleRec(rec, color);
809 if (roundness >= 1.0f) roundness = 1.0f;
811 // Calculate corner radius
812 float radius = (rec.width > rec.height)? (rec.height*roundness)/2 : (rec.width*roundness)/2;
813 if (radius <= 0.0f) return;
815 // Calculate number of segments to use for the corners
818 // Calculate the maximum angle between segments based on the error rate (usually 0.5f)
819 float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/radius, 2) - 1);
820 segments = (int)(ceilf(2*PI/th)/4.0f);
821 if (segments <= 0) segments = 4;
824 float stepLength = 90.0f/(float)segments;
827 Quick sketch to make sense of all of this,
828 there are 9 parts to draw, also mark the 12 points we'll use
830 P0____________________P1
833 P7 /__|____________________|__\ P2
836 | __|____________________|__ |
839 \|____________________|/
842 // Coordinates of the 12 points that define the rounded rect
843 const Vector2 point[12] = {
844 {(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
845 {rec.x + rec.width, (float)(rec.y + rec.height) - radius}, {(float)(rec.x + rec.width) - radius, rec.y + rec.height}, // P3, P4
846 {(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
847 {(float)rec.x + radius, (float)rec.y + radius}, {(float)(rec.x + rec.width) - radius, (float)rec.y + radius}, // P8, P9
848 {(float)(rec.x + rec.width) - radius, (float)(rec.y + rec.height) - radius}, {(float)rec.x + radius, (float)(rec.y + rec.height) - radius} // P10, P11
851 const Vector2 centers[4] = { point[8], point[9], point[10], point[11] };
852 const float angles[4] = { 180.0f, 90.0f, 0.0f, 270.0f };
854 #if defined(SUPPORT_QUADS_DRAW_MODE)
855 rlCheckRenderBatchLimit(16*segments/2 + 5*4);
857 rlSetTexture(texShapes.id);
860 // Draw all of the 4 corners: [1] Upper Left Corner, [3] Upper Right Corner, [5] Lower Right Corner, [7] Lower Left Corner
861 for (int k = 0; k < 4; ++k) // Hope the compiler is smart enough to unroll this loop
863 float angle = angles[k];
864 const Vector2 center = centers[k];
866 // NOTE: Every QUAD actually represents two segments
867 for (int i = 0; i < segments/2; i++)
869 rlColor4ub(color.r, color.g, color.b, color.a);
870 rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height);
871 rlVertex2f(center.x, center.y);
872 rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
873 rlVertex2f(center.x + sinf(DEG2RAD*angle)*radius, center.y + cosf(DEG2RAD*angle)*radius);
874 rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
875 rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*radius, center.y + cosf(DEG2RAD*(angle + stepLength))*radius);
876 rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height);
877 rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength*2))*radius, center.y + cosf(DEG2RAD*(angle + stepLength*2))*radius);
878 angle += (stepLength*2);
881 // NOTE: In case number of segments is odd, we add one last piece to the cake
884 rlColor4ub(color.r, color.g, color.b, color.a);
885 rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height);
886 rlVertex2f(center.x, center.y);
887 rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
888 rlVertex2f(center.x + sinf(DEG2RAD*angle)*radius, center.y + cosf(DEG2RAD*angle)*radius);
889 rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
890 rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*radius, center.y + cosf(DEG2RAD*(angle + stepLength))*radius);
891 rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height);
892 rlVertex2f(center.x, center.y);
896 // [2] Upper Rectangle
897 rlColor4ub(color.r, color.g, color.b, color.a);
898 rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height);
899 rlVertex2f(point[0].x, point[0].y);
900 rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
901 rlVertex2f(point[8].x, point[8].y);
902 rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
903 rlVertex2f(point[9].x, point[9].y);
904 rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height);
905 rlVertex2f(point[1].x, point[1].y);
907 // [4] Right Rectangle
908 rlColor4ub(color.r, color.g, color.b, color.a);
909 rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height);
910 rlVertex2f(point[2].x, point[2].y);
911 rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
912 rlVertex2f(point[9].x, point[9].y);
913 rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
914 rlVertex2f(point[10].x, point[10].y);
915 rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height);
916 rlVertex2f(point[3].x, point[3].y);
918 // [6] Bottom Rectangle
919 rlColor4ub(color.r, color.g, color.b, color.a);
920 rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height);
921 rlVertex2f(point[11].x, point[11].y);
922 rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
923 rlVertex2f(point[5].x, point[5].y);
924 rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
925 rlVertex2f(point[4].x, point[4].y);
926 rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height);
927 rlVertex2f(point[10].x, point[10].y);
929 // [8] Left Rectangle
930 rlColor4ub(color.r, color.g, color.b, color.a);
931 rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height);
932 rlVertex2f(point[7].x, point[7].y);
933 rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
934 rlVertex2f(point[6].x, point[6].y);
935 rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
936 rlVertex2f(point[11].x, point[11].y);
937 rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height);
938 rlVertex2f(point[8].x, point[8].y);
940 // [9] Middle Rectangle
941 rlColor4ub(color.r, color.g, color.b, color.a);
942 rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height);
943 rlVertex2f(point[8].x, point[8].y);
944 rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
945 rlVertex2f(point[11].x, point[11].y);
946 rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
947 rlVertex2f(point[10].x, point[10].y);
948 rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height);
949 rlVertex2f(point[9].x, point[9].y);
954 rlCheckRenderBatchLimit(12*segments + 5*6); // 4 corners with 3 vertices per segment + 5 rectangles with 6 vertices each
956 rlBegin(RL_TRIANGLES);
958 // Draw all of the 4 corners: [1] Upper Left Corner, [3] Upper Right Corner, [5] Lower Right Corner, [7] Lower Left Corner
959 for (int k = 0; k < 4; ++k) // Hope the compiler is smart enough to unroll this loop
961 float angle = angles[k];
962 const Vector2 center = centers[k];
963 for (int i = 0; i < segments; i++)
965 rlColor4ub(color.r, color.g, color.b, color.a);
966 rlVertex2f(center.x, center.y);
967 rlVertex2f(center.x + sinf(DEG2RAD*angle)*radius, center.y + cosf(DEG2RAD*angle)*radius);
968 rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*radius, center.y + cosf(DEG2RAD*(angle + stepLength))*radius);
973 // [2] Upper Rectangle
974 rlColor4ub(color.r, color.g, color.b, color.a);
975 rlVertex2f(point[0].x, point[0].y);
976 rlVertex2f(point[8].x, point[8].y);
977 rlVertex2f(point[9].x, point[9].y);
978 rlVertex2f(point[1].x, point[1].y);
979 rlVertex2f(point[0].x, point[0].y);
980 rlVertex2f(point[9].x, point[9].y);
982 // [4] Right Rectangle
983 rlColor4ub(color.r, color.g, color.b, color.a);
984 rlVertex2f(point[9].x, point[9].y);
985 rlVertex2f(point[10].x, point[10].y);
986 rlVertex2f(point[3].x, point[3].y);
987 rlVertex2f(point[2].x, point[2].y);
988 rlVertex2f(point[9].x, point[9].y);
989 rlVertex2f(point[3].x, point[3].y);
991 // [6] Bottom Rectangle
992 rlColor4ub(color.r, color.g, color.b, color.a);
993 rlVertex2f(point[11].x, point[11].y);
994 rlVertex2f(point[5].x, point[5].y);
995 rlVertex2f(point[4].x, point[4].y);
996 rlVertex2f(point[10].x, point[10].y);
997 rlVertex2f(point[11].x, point[11].y);
998 rlVertex2f(point[4].x, point[4].y);
1000 // [8] Left Rectangle
1001 rlColor4ub(color.r, color.g, color.b, color.a);
1002 rlVertex2f(point[7].x, point[7].y);
1003 rlVertex2f(point[6].x, point[6].y);
1004 rlVertex2f(point[11].x, point[11].y);
1005 rlVertex2f(point[8].x, point[8].y);
1006 rlVertex2f(point[7].x, point[7].y);
1007 rlVertex2f(point[11].x, point[11].y);
1009 // [9] Middle Rectangle
1010 rlColor4ub(color.r, color.g, color.b, color.a);
1011 rlVertex2f(point[8].x, point[8].y);
1012 rlVertex2f(point[11].x, point[11].y);
1013 rlVertex2f(point[10].x, point[10].y);
1014 rlVertex2f(point[9].x, point[9].y);
1015 rlVertex2f(point[8].x, point[8].y);
1016 rlVertex2f(point[10].x, point[10].y);
1021 // Draw rectangle with rounded edges outline
1022 void DrawRectangleRoundedLines(Rectangle rec, float roundness, int segments, int lineThick, Color color)
1024 if (lineThick < 0) lineThick = 0;
1026 // Not a rounded rectangle
1027 if (roundness <= 0.0f)
1029 DrawRectangleLinesEx((Rectangle){rec.x-lineThick, rec.y-lineThick, rec.width+2*lineThick, rec.height+2*lineThick}, lineThick, color);
1033 if (roundness >= 1.0f) roundness = 1.0f;
1035 // Calculate corner radius
1036 float radius = (rec.width > rec.height)? (rec.height*roundness)/2 : (rec.width*roundness)/2;
1037 if (radius <= 0.0f) return;
1039 // Calculate number of segments to use for the corners
1042 // Calculate the maximum angle between segments based on the error rate (usually 0.5f)
1043 float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/radius, 2) - 1);
1044 segments = (int)(ceilf(2*PI/th)/2.0f);
1045 if (segments <= 0) segments = 4;
1048 float stepLength = 90.0f/(float)segments;
1049 const float outerRadius = radius + (float)lineThick, innerRadius = radius;
1052 Quick sketch to make sense of all of this,
1053 marks the 16 + 4(corner centers P16-19) points we'll use
1055 P0 ================== P1
1062 P6 \\ *P19 P18* // P3
1065 P5 ================== P4
1067 const Vector2 point[16] = {
1068 {(float)rec.x + innerRadius, rec.y - lineThick}, {(float)(rec.x + rec.width) - innerRadius, rec.y - lineThick}, { rec.x + rec.width + lineThick, (float)rec.y + innerRadius }, // PO, P1, P2
1069 {rec.x + rec.width + lineThick, (float)(rec.y + rec.height) - innerRadius}, {(float)(rec.x + rec.width) - innerRadius, rec.y + rec.height + lineThick}, // P3, P4
1070 {(float)rec.x + innerRadius, rec.y + rec.height + lineThick}, { rec.x - lineThick, (float)(rec.y + rec.height) - innerRadius}, {rec.x - lineThick, (float)rec.y + innerRadius}, // P5, P6, P7
1071 {(float)rec.x + innerRadius, rec.y}, {(float)(rec.x + rec.width) - innerRadius, rec.y}, // P8, P9
1072 { rec.x + rec.width, (float)rec.y + innerRadius }, {rec.x + rec.width, (float)(rec.y + rec.height) - innerRadius}, // P10, P11
1073 {(float)(rec.x + rec.width) - innerRadius, rec.y + rec.height}, {(float)rec.x + innerRadius, rec.y + rec.height}, // P12, P13
1074 { rec.x, (float)(rec.y + rec.height) - innerRadius}, {rec.x, (float)rec.y + innerRadius} // P14, P15
1077 const Vector2 centers[4] = {
1078 {(float)rec.x + innerRadius, (float)rec.y + innerRadius}, {(float)(rec.x + rec.width) - innerRadius, (float)rec.y + innerRadius}, // P16, P17
1079 {(float)(rec.x + rec.width) - innerRadius, (float)(rec.y + rec.height) - innerRadius}, {(float)rec.x + innerRadius, (float)(rec.y + rec.height) - innerRadius} // P18, P19
1082 const float angles[4] = { 180.0f, 90.0f, 0.0f, 270.0f };
1086 #if defined(SUPPORT_QUADS_DRAW_MODE)
1087 rlCheckRenderBatchLimit(4*4*segments + 4*4); // 4 corners with 4 vertices for each segment + 4 rectangles with 4 vertices each
1089 rlSetTexture(texShapes.id);
1093 // Draw all of the 4 corners first: Upper Left Corner, Upper Right Corner, Lower Right Corner, Lower Left Corner
1094 for (int k = 0; k < 4; ++k) // Hope the compiler is smart enough to unroll this loop
1096 float angle = angles[k];
1097 const Vector2 center = centers[k];
1098 for (int i = 0; i < segments; i++)
1100 rlColor4ub(color.r, color.g, color.b, color.a);
1101 rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height);
1102 rlVertex2f(center.x + sinf(DEG2RAD*angle)*innerRadius, center.y + cosf(DEG2RAD*angle)*innerRadius);
1103 rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
1104 rlVertex2f(center.x + sinf(DEG2RAD*angle)*outerRadius, center.y + cosf(DEG2RAD*angle)*outerRadius);
1105 rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
1106 rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*outerRadius);
1107 rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height);
1108 rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*innerRadius);
1110 angle += stepLength;
1115 rlColor4ub(color.r, color.g, color.b, color.a);
1116 rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height);
1117 rlVertex2f(point[0].x, point[0].y);
1118 rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
1119 rlVertex2f(point[8].x, point[8].y);
1120 rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
1121 rlVertex2f(point[9].x, point[9].y);
1122 rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height);
1123 rlVertex2f(point[1].x, point[1].y);
1126 rlColor4ub(color.r, color.g, color.b, color.a);
1127 rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height);
1128 rlVertex2f(point[2].x, point[2].y);
1129 rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
1130 rlVertex2f(point[10].x, point[10].y);
1131 rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
1132 rlVertex2f(point[11].x, point[11].y);
1133 rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height);
1134 rlVertex2f(point[3].x, point[3].y);
1137 rlColor4ub(color.r, color.g, color.b, color.a);
1138 rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height);
1139 rlVertex2f(point[13].x, point[13].y);
1140 rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
1141 rlVertex2f(point[5].x, point[5].y);
1142 rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
1143 rlVertex2f(point[4].x, point[4].y);
1144 rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height);
1145 rlVertex2f(point[12].x, point[12].y);
1148 rlColor4ub(color.r, color.g, color.b, color.a);
1149 rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height);
1150 rlVertex2f(point[15].x, point[15].y);
1151 rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
1152 rlVertex2f(point[7].x, point[7].y);
1153 rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
1154 rlVertex2f(point[6].x, point[6].y);
1155 rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height);
1156 rlVertex2f(point[14].x, point[14].y);
1161 rlCheckRenderBatchLimit(4*6*segments + 4*6); // 4 corners with 6(2*3) vertices for each segment + 4 rectangles with 6 vertices each
1163 rlBegin(RL_TRIANGLES);
1165 // Draw all of the 4 corners first: Upper Left Corner, Upper Right Corner, Lower Right Corner, Lower Left Corner
1166 for (int k = 0; k < 4; ++k) // Hope the compiler is smart enough to unroll this loop
1168 float angle = angles[k];
1169 const Vector2 center = centers[k];
1171 for (int i = 0; i < segments; i++)
1173 rlColor4ub(color.r, color.g, color.b, color.a);
1175 rlVertex2f(center.x + sinf(DEG2RAD*angle)*innerRadius, center.y + cosf(DEG2RAD*angle)*innerRadius);
1176 rlVertex2f(center.x + sinf(DEG2RAD*angle)*outerRadius, center.y + cosf(DEG2RAD*angle)*outerRadius);
1177 rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*innerRadius);
1179 rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*innerRadius);
1180 rlVertex2f(center.x + sinf(DEG2RAD*angle)*outerRadius, center.y + cosf(DEG2RAD*angle)*outerRadius);
1181 rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*outerRadius);
1183 angle += stepLength;
1188 rlColor4ub(color.r, color.g, color.b, color.a);
1189 rlVertex2f(point[0].x, point[0].y);
1190 rlVertex2f(point[8].x, point[8].y);
1191 rlVertex2f(point[9].x, point[9].y);
1192 rlVertex2f(point[1].x, point[1].y);
1193 rlVertex2f(point[0].x, point[0].y);
1194 rlVertex2f(point[9].x, point[9].y);
1197 rlColor4ub(color.r, color.g, color.b, color.a);
1198 rlVertex2f(point[10].x, point[10].y);
1199 rlVertex2f(point[11].x, point[11].y);
1200 rlVertex2f(point[3].x, point[3].y);
1201 rlVertex2f(point[2].x, point[2].y);
1202 rlVertex2f(point[10].x, point[10].y);
1203 rlVertex2f(point[3].x, point[3].y);
1206 rlColor4ub(color.r, color.g, color.b, color.a);
1207 rlVertex2f(point[13].x, point[13].y);
1208 rlVertex2f(point[5].x, point[5].y);
1209 rlVertex2f(point[4].x, point[4].y);
1210 rlVertex2f(point[12].x, point[12].y);
1211 rlVertex2f(point[13].x, point[13].y);
1212 rlVertex2f(point[4].x, point[4].y);
1215 rlColor4ub(color.r, color.g, color.b, color.a);
1216 rlVertex2f(point[7].x, point[7].y);
1217 rlVertex2f(point[6].x, point[6].y);
1218 rlVertex2f(point[14].x, point[14].y);
1219 rlVertex2f(point[15].x, point[15].y);
1220 rlVertex2f(point[7].x, point[7].y);
1221 rlVertex2f(point[14].x, point[14].y);
1227 // Use LINES to draw the outline
1228 rlCheckRenderBatchLimit(8*segments + 4*2); // 4 corners with 2 vertices for each segment + 4 rectangles with 2 vertices each
1232 // Draw all of the 4 corners first: Upper Left Corner, Upper Right Corner, Lower Right Corner, Lower Left Corner
1233 for (int k = 0; k < 4; ++k) // Hope the compiler is smart enough to unroll this loop
1235 float angle = angles[k];
1236 const Vector2 center = centers[k];
1238 for (int i = 0; i < segments; i++)
1240 rlColor4ub(color.r, color.g, color.b, color.a);
1241 rlVertex2f(center.x + sinf(DEG2RAD*angle)*outerRadius, center.y + cosf(DEG2RAD*angle)*outerRadius);
1242 rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*outerRadius);
1243 angle += stepLength;
1247 // And now the remaining 4 lines
1248 for (int i = 0; i < 8; i += 2)
1250 rlColor4ub(color.r, color.g, color.b, color.a);
1251 rlVertex2f(point[i].x, point[i].y);
1252 rlVertex2f(point[i + 1].x, point[i + 1].y);
1260 // NOTE: Vertex must be provided in counter-clockwise order
1261 void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color)
1263 rlCheckRenderBatchLimit(4);
1265 #if defined(SUPPORT_QUADS_DRAW_MODE)
1266 rlSetTexture(texShapes.id);
1269 rlColor4ub(color.r, color.g, color.b, color.a);
1271 rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height);
1272 rlVertex2f(v1.x, v1.y);
1274 rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
1275 rlVertex2f(v2.x, v2.y);
1277 rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
1278 rlVertex2f(v2.x, v2.y);
1280 rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height);
1281 rlVertex2f(v3.x, v3.y);
1286 rlBegin(RL_TRIANGLES);
1287 rlColor4ub(color.r, color.g, color.b, color.a);
1288 rlVertex2f(v1.x, v1.y);
1289 rlVertex2f(v2.x, v2.y);
1290 rlVertex2f(v3.x, v3.y);
1295 // Draw a triangle using lines
1296 // NOTE: Vertex must be provided in counter-clockwise order
1297 void DrawTriangleLines(Vector2 v1, Vector2 v2, Vector2 v3, Color color)
1299 rlCheckRenderBatchLimit(6);
1302 rlColor4ub(color.r, color.g, color.b, color.a);
1303 rlVertex2f(v1.x, v1.y);
1304 rlVertex2f(v2.x, v2.y);
1306 rlVertex2f(v2.x, v2.y);
1307 rlVertex2f(v3.x, v3.y);
1309 rlVertex2f(v3.x, v3.y);
1310 rlVertex2f(v1.x, v1.y);
1314 // Draw a triangle fan defined by points
1315 // NOTE: First vertex provided is the center, shared by all triangles
1316 // By default, following vertex should be provided in counter-clockwise order
1317 void DrawTriangleFan(Vector2 *points, int pointsCount, Color color)
1319 if (pointsCount >= 3)
1321 rlCheckRenderBatchLimit((pointsCount - 2)*4);
1323 rlSetTexture(texShapes.id);
1325 rlColor4ub(color.r, color.g, color.b, color.a);
1327 for (int i = 1; i < pointsCount - 1; i++)
1329 rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height);
1330 rlVertex2f(points[0].x, points[0].y);
1332 rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
1333 rlVertex2f(points[i].x, points[i].y);
1335 rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
1336 rlVertex2f(points[i + 1].x, points[i + 1].y);
1338 rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height);
1339 rlVertex2f(points[i + 1].x, points[i + 1].y);
1346 // Draw a triangle strip defined by points
1347 // NOTE: Every new vertex connects with previous two
1348 void DrawTriangleStrip(Vector2 *points, int pointsCount, Color color)
1350 if (pointsCount >= 3)
1352 rlCheckRenderBatchLimit(3*(pointsCount - 2));
1354 rlBegin(RL_TRIANGLES);
1355 rlColor4ub(color.r, color.g, color.b, color.a);
1357 for (int i = 2; i < pointsCount; i++)
1361 rlVertex2f(points[i].x, points[i].y);
1362 rlVertex2f(points[i - 2].x, points[i - 2].y);
1363 rlVertex2f(points[i - 1].x, points[i - 1].y);
1367 rlVertex2f(points[i].x, points[i].y);
1368 rlVertex2f(points[i - 1].x, points[i - 1].y);
1369 rlVertex2f(points[i - 2].x, points[i - 2].y);
1376 // Draw a regular polygon of n sides (Vector version)
1377 void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color color)
1379 if (sides < 3) sides = 3;
1380 float centralAngle = 0.0f;
1382 rlCheckRenderBatchLimit(4*(360/sides));
1385 rlTranslatef(center.x, center.y, 0.0f);
1386 rlRotatef(rotation, 0.0f, 0.0f, 1.0f);
1388 #if defined(SUPPORT_QUADS_DRAW_MODE)
1389 rlSetTexture(texShapes.id);
1392 for (int i = 0; i < sides; i++)
1394 rlColor4ub(color.r, color.g, color.b, color.a);
1396 rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height);
1399 rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
1400 rlVertex2f(sinf(DEG2RAD*centralAngle)*radius, cosf(DEG2RAD*centralAngle)*radius);
1402 rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
1403 rlVertex2f(sinf(DEG2RAD*centralAngle)*radius, cosf(DEG2RAD*centralAngle)*radius);
1405 centralAngle += 360.0f/(float)sides;
1406 rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height);
1407 rlVertex2f(sinf(DEG2RAD*centralAngle)*radius, cosf(DEG2RAD*centralAngle)*radius);
1412 rlBegin(RL_TRIANGLES);
1413 for (int i = 0; i < sides; i++)
1415 rlColor4ub(color.r, color.g, color.b, color.a);
1418 rlVertex2f(sinf(DEG2RAD*centralAngle)*radius, cosf(DEG2RAD*centralAngle)*radius);
1420 centralAngle += 360.0f/(float)sides;
1421 rlVertex2f(sinf(DEG2RAD*centralAngle)*radius, cosf(DEG2RAD*centralAngle)*radius);
1428 // Draw a polygon outline of n sides
1429 void DrawPolyLines(Vector2 center, int sides, float radius, float rotation, Color color)
1431 if (sides < 3) sides = 3;
1432 float centralAngle = 0.0f;
1434 rlCheckRenderBatchLimit(3*(360/sides));
1437 rlTranslatef(center.x, center.y, 0.0f);
1438 rlRotatef(rotation, 0.0f, 0.0f, 1.0f);
1441 for (int i = 0; i < sides; i++)
1443 rlColor4ub(color.r, color.g, color.b, color.a);
1445 rlVertex2f(sinf(DEG2RAD*centralAngle)*radius, cosf(DEG2RAD*centralAngle)*radius);
1446 centralAngle += 360.0f/(float)sides;
1447 rlVertex2f(sinf(DEG2RAD*centralAngle)*radius, cosf(DEG2RAD*centralAngle)*radius);
1453 //----------------------------------------------------------------------------------
1454 // Module Functions Definition - Collision Detection functions
1455 //----------------------------------------------------------------------------------
1457 // Check if point is inside rectangle
1458 bool CheckCollisionPointRec(Vector2 point, Rectangle rec)
1460 bool collision = false;
1462 if ((point.x >= rec.x) && (point.x <= (rec.x + rec.width)) && (point.y >= rec.y) && (point.y <= (rec.y + rec.height))) collision = true;
1467 // Check if point is inside circle
1468 bool CheckCollisionPointCircle(Vector2 point, Vector2 center, float radius)
1470 return CheckCollisionCircles(point, 0, center, radius);
1473 // Check if point is inside a triangle defined by three points (p1, p2, p3)
1474 bool CheckCollisionPointTriangle(Vector2 point, Vector2 p1, Vector2 p2, Vector2 p3)
1476 bool collision = false;
1478 float alpha = ((p2.y - p3.y)*(point.x - p3.x) + (p3.x - p2.x)*(point.y - p3.y)) /
1479 ((p2.y - p3.y)*(p1.x - p3.x) + (p3.x - p2.x)*(p1.y - p3.y));
1481 float beta = ((p3.y - p1.y)*(point.x - p3.x) + (p1.x - p3.x)*(point.y - p3.y)) /
1482 ((p2.y - p3.y)*(p1.x - p3.x) + (p3.x - p2.x)*(p1.y - p3.y));
1484 float gamma = 1.0f - alpha - beta;
1486 if ((alpha > 0) && (beta > 0) && (gamma > 0)) collision = true;
1491 // Check collision between two rectangles
1492 bool CheckCollisionRecs(Rectangle rec1, Rectangle rec2)
1494 bool collision = false;
1496 if ((rec1.x < (rec2.x + rec2.width) && (rec1.x + rec1.width) > rec2.x) &&
1497 (rec1.y < (rec2.y + rec2.height) && (rec1.y + rec1.height) > rec2.y)) collision = true;
1502 // Check collision between two circles
1503 bool CheckCollisionCircles(Vector2 center1, float radius1, Vector2 center2, float radius2)
1505 bool collision = false;
1507 float dx = center2.x - center1.x; // X distance between centers
1508 float dy = center2.y - center1.y; // Y distance between centers
1510 float distance = sqrtf(dx*dx + dy*dy); // Distance between centers
1512 if (distance <= (radius1 + radius2)) collision = true;
1517 // Check collision between circle and rectangle
1518 // NOTE: Reviewed version to take into account corner limit case
1519 bool CheckCollisionCircleRec(Vector2 center, float radius, Rectangle rec)
1521 int recCenterX = (int)(rec.x + rec.width/2.0f);
1522 int recCenterY = (int)(rec.y + rec.height/2.0f);
1524 float dx = fabsf(center.x - (float)recCenterX);
1525 float dy = fabsf(center.y - (float)recCenterY);
1527 if (dx > (rec.width/2.0f + radius)) { return false; }
1528 if (dy > (rec.height/2.0f + radius)) { return false; }
1530 if (dx <= (rec.width/2.0f)) { return true; }
1531 if (dy <= (rec.height/2.0f)) { return true; }
1533 float cornerDistanceSq = (dx - rec.width/2.0f)*(dx - rec.width/2.0f) +
1534 (dy - rec.height/2.0f)*(dy - rec.height/2.0f);
1536 return (cornerDistanceSq <= (radius*radius));
1539 // Check the collision between two lines defined by two points each, returns collision point by reference
1540 bool CheckCollisionLines(Vector2 startPos1, Vector2 endPos1, Vector2 startPos2, Vector2 endPos2, Vector2 *collisionPoint)
1542 const float div = (endPos2.y - startPos2.y)*(endPos1.x - startPos1.x) - (endPos2.x - startPos2.x)*(endPos1.y - startPos1.y);
1544 if (div == 0.0f) return false; // WARNING: This check could not work due to float precision rounding issues...
1546 const float xi = ((startPos2.x - endPos2.x)*(startPos1.x*endPos1.y - startPos1.y*endPos1.x) - (startPos1.x - endPos1.x)*(startPos2.x*endPos2.y - startPos2.y*endPos2.x))/div;
1547 const float yi = ((startPos2.y - endPos2.y)*(startPos1.x*endPos1.y - startPos1.y*endPos1.x) - (startPos1.y - endPos1.y)*(startPos2.x*endPos2.y - startPos2.y*endPos2.x))/div;
1549 if (xi < fminf(startPos1.x, endPos1.x) || xi > fmaxf(startPos1.x, endPos1.x)) return false;
1550 if (xi < fminf(startPos2.x, endPos2.x) || xi > fmaxf(startPos2.x, endPos2.x)) return false;
1551 if (yi < fminf(startPos1.y, endPos1.y) || yi > fmaxf(startPos1.y, endPos1.y)) return false;
1552 if (yi < fminf(startPos2.y, endPos2.y) || yi > fmaxf(startPos2.y, endPos2.y)) return false;
1554 if (collisionPoint != 0)
1556 collisionPoint->x = xi;
1557 collisionPoint->y = yi;
1563 // Check if point belongs to line created between two points [p1] and [p2] with defined margin in pixels [threshold]
1564 bool CheckCollisionPointLine(Vector2 point, Vector2 p1, Vector2 p2, int threshold)
1566 bool collision = false;
1567 float dxc = point.x - p1.x;
1568 float dyc = point.y - p1.y;
1569 float dxl = p2.x - p1.x;
1570 float dyl = p2.y - p1.y;
1571 float cross = dxc*dyl - dyc*dxl;
1573 if (fabsf(cross) < (threshold*fmaxf(fabsf(dxl), fabsf(dyl))))
1575 if (fabsf(dxl) >= fabsf(dyl)) collision = (dxl > 0)? ((p1.x <= point.x) && (point.x <= p2.x)) : ((p2.x <= point.x) && (point.x <= p1.x));
1576 else collision = (dyl > 0)? ((p1.y <= point.y) && (point.y <= p2.y)) : ((p2.y <= point.y) && (point.y <= p1.y));
1582 // Get collision rectangle for two rectangles collision
1583 Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2)
1585 Rectangle rec = { 0, 0, 0, 0 };
1587 if (CheckCollisionRecs(rec1, rec2))
1589 float dxx = fabsf(rec1.x - rec2.x);
1590 float dyy = fabsf(rec1.y - rec2.y);
1592 if (rec1.x <= rec2.x)
1594 if (rec1.y <= rec2.y)
1598 rec.width = rec1.width - dxx;
1599 rec.height = rec1.height - dyy;
1605 rec.width = rec1.width - dxx;
1606 rec.height = rec2.height - dyy;
1611 if (rec1.y <= rec2.y)
1615 rec.width = rec2.width - dxx;
1616 rec.height = rec1.height - dyy;
1622 rec.width = rec2.width - dxx;
1623 rec.height = rec2.height - dyy;
1627 if (rec1.width > rec2.width)
1629 if (rec.width >= rec2.width) rec.width = rec2.width;
1633 if (rec.width >= rec1.width) rec.width = rec1.width;
1636 if (rec1.height > rec2.height)
1638 if (rec.height >= rec2.height) rec.height = rec2.height;
1642 if (rec.height >= rec1.height) rec.height = rec1.height;
1649 //----------------------------------------------------------------------------------
1650 // Module specific Functions Definition
1651 //----------------------------------------------------------------------------------
1653 // Cubic easing in-out
1654 // NOTE: Required for DrawLineBezier()
1655 static float EaseCubicInOut(float t, float b, float c, float d)
1657 if ((t /= 0.5f*d) < 1) return 0.5f*c*t*t*t + b;
1661 return 0.5f*c*(t*t*t + 2.0f) + b;