1/**********************************************************************************************
2*
3* raylib.shapes - Basic functions to draw 2d Shapes and check collisions
4*
5* CONFIGURATION:
6*
7* #define SUPPORT_FONT_TEXTURE
8* Draw rectangle shapes using font texture white character instead of default white texture
9* Allows drawing rectangles and text with a single draw call, very useful for GUI systems!
10*
11* #define SUPPORT_QUADS_DRAW_MODE
12* Use QUADS instead of TRIANGLES for drawing when possible.
13* Some lines-based shapes could still use lines
14*
15* LICENSE: zlib/libpng
16*
17* Copyright (c) 2013-2020 Ramon Santamaria (@raysan5)
18*
19* This software is provided "as-is", without any express or implied warranty. In no event
20* will the authors be held liable for any damages arising from the use of this software.
21*
22* Permission is granted to anyone to use this software for any purpose, including commercial
23* applications, and to alter it and redistribute it freely, subject to the following restrictions:
24*
25* 1. The origin of this software must not be misrepresented; you must not claim that you
26* wrote the original software. If you use this software in a product, an acknowledgment
27* in the product documentation would be appreciated but is not required.
28*
29* 2. Altered source versions must be plainly marked as such, and must not be misrepresented
30* as being the original software.
31*
32* 3. This notice may not be removed or altered from any source distribution.
33*
34**********************************************************************************************/
35
36#include "raylib.h" // Declares module functions
37
38// Check if config flags have been externally provided on compilation line
39#if !defined(EXTERNAL_CONFIG_FLAGS)
40 #include "config.h" // Defines module configuration flags
41#endif
42
43#include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2
44
45#include <math.h> // Required for: sinf(), asinf(), cosf(), acosf(), sqrtf(), fabsf()
46
47//----------------------------------------------------------------------------------
48// Defines and Macros
49//----------------------------------------------------------------------------------
50// Nop...
51
52//----------------------------------------------------------------------------------
53// Types and Structures Definition
54//----------------------------------------------------------------------------------
55// Not here...
56
57//----------------------------------------------------------------------------------
58// Global Variables Definition
59//----------------------------------------------------------------------------------
60// ...
61
62//----------------------------------------------------------------------------------
63// Module specific Functions Declaration
64//----------------------------------------------------------------------------------
65static float EaseCubicInOut(float t, float b, float c, float d); // Cubic easing
66
67//----------------------------------------------------------------------------------
68// Module Functions Definition
69//----------------------------------------------------------------------------------
70
71// Draw a pixel
72void DrawPixel(int posX, int posY, Color color)
73{
74 rlBegin(RL_LINES);
75 rlColor4ub(color.r, color.g, color.b, color.a);
76 rlVertex2i(posX, posY);
77 rlVertex2i(posX + 1, posY + 1);
78 rlEnd();
79}
80
81// Draw a pixel (Vector version)
82void DrawPixelV(Vector2 position, Color color)
83{
84 rlBegin(RL_LINES);
85 rlColor4ub(color.r, color.g, color.b, color.a);
86 rlVertex2f(position.x, position.y);
87 rlVertex2f(position.x + 1.0f, position.y + 1.0f);
88 rlEnd();
89}
90
91// Draw a line
92void DrawLine(int startPosX, int startPosY, int endPosX, int endPosY, Color color)
93{
94 rlBegin(RL_LINES);
95 rlColor4ub(color.r, color.g, color.b, color.a);
96 rlVertex2i(startPosX, startPosY);
97 rlVertex2i(endPosX, endPosY);
98 rlEnd();
99}
100
101// Draw a line (Vector version)
102void DrawLineV(Vector2 startPos, Vector2 endPos, Color color)
103{
104 rlBegin(RL_LINES);
105 rlColor4ub(color.r, color.g, color.b, color.a);
106 rlVertex2f(startPos.x, startPos.y);
107 rlVertex2f(endPos.x, endPos.y);
108 rlEnd();
109}
110
111// Draw a line defining thickness
112void DrawLineEx(Vector2 startPos, Vector2 endPos, float thick, Color color)
113{
114 if (startPos.x > endPos.x)
115 {
116 Vector2 tempPos = startPos;
117 startPos = endPos;
118 endPos = tempPos;
119 }
120
121 float dx = endPos.x - startPos.x;
122 float dy = endPos.y - startPos.y;
123
124 float d = sqrtf(dx*dx + dy*dy);
125 float angle = asinf(dy/d);
126
127 rlEnableTexture(GetShapesTexture().id);
128
129 rlPushMatrix();
130 rlTranslatef((float)startPos.x, (float)startPos.y, 0.0f);
131 rlRotatef(RAD2DEG*angle, 0.0f, 0.0f, 1.0f);
132 rlTranslatef(0, (thick > 1.0f)? -thick/2.0f : -1.0f, 0.0f);
133
134 rlBegin(RL_QUADS);
135 rlColor4ub(color.r, color.g, color.b, color.a);
136 rlNormal3f(0.0f, 0.0f, 1.0f);
137
138 rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
139 rlVertex2f(0.0f, 0.0f);
140
141 rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
142 rlVertex2f(0.0f, thick);
143
144 rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
145 rlVertex2f(d, thick);
146
147 rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
148 rlVertex2f(d, 0.0f);
149 rlEnd();
150 rlPopMatrix();
151
152 rlDisableTexture();
153}
154
155// Draw line using cubic-bezier curves in-out
156void DrawLineBezier(Vector2 startPos, Vector2 endPos, float thick, Color color)
157{
158 #define LINE_DIVISIONS 24 // Bezier line divisions
159
160 Vector2 previous = startPos;
161 Vector2 current;
162
163 for (int i = 1; i <= LINE_DIVISIONS; i++)
164 {
165 // Cubic easing in-out
166 // NOTE: Easing is calculated only for y position value
167 current.y = EaseCubicInOut((float)i, startPos.y, endPos.y - startPos.y, (float)LINE_DIVISIONS);
168 current.x = previous.x + (endPos.x - startPos.x)/ (float)LINE_DIVISIONS;
169
170 DrawLineEx(previous, current, thick, color);
171
172 previous = current;
173 }
174}
175
176// Draw lines sequence
177void DrawLineStrip(Vector2 *points, int pointsCount, Color color)
178{
179 if (pointsCount >= 2)
180 {
181 if (rlCheckBufferLimit(pointsCount)) rlglDraw();
182
183 rlBegin(RL_LINES);
184 rlColor4ub(color.r, color.g, color.b, color.a);
185
186 for (int i = 0; i < pointsCount - 1; i++)
187 {
188 rlVertex2f(points[i].x, points[i].y);
189 rlVertex2f(points[i + 1].x, points[i + 1].y);
190 }
191 rlEnd();
192 }
193}
194
195// Draw a color-filled circle
196void DrawCircle(int centerX, int centerY, float radius, Color color)
197{
198 DrawCircleV((Vector2){ (float)centerX, (float)centerY }, radius, color);
199}
200
201// Draw a piece of a circle
202void DrawCircleSector(Vector2 center, float radius, int startAngle, int endAngle, int segments, Color color)
203{
204 if (radius <= 0.0f) radius = 0.1f; // Avoid div by zero
205
206 // Function expects (endAngle > startAngle)
207 if (endAngle < startAngle)
208 {
209 // Swap values
210 int tmp = startAngle;
211 startAngle = endAngle;
212 endAngle = tmp;
213 }
214
215 if (segments < 4)
216 {
217 // Calculate how many segments we need to draw a smooth circle, taken from https://stackoverflow.com/a/2244088
218 #define CIRCLE_ERROR_RATE 0.5f
219
220 // Calculate the maximum angle between segments based on the error rate.
221 float th = acosf(2*powf(1 - CIRCLE_ERROR_RATE/radius, 2) - 1);
222 segments = (endAngle - startAngle)*ceilf(2*PI/th)/360;
223
224 if (segments <= 0) segments = 4;
225 }
226
227 float stepLength = (float)(endAngle - startAngle)/(float)segments;
228 float angle = startAngle;
229
230#if defined(SUPPORT_QUADS_DRAW_MODE)
231 if (rlCheckBufferLimit(4*segments/2)) rlglDraw();
232
233 rlEnableTexture(GetShapesTexture().id);
234
235 rlBegin(RL_QUADS);
236 // NOTE: Every QUAD actually represents two segments
237 for (int i = 0; i < segments/2; i++)
238 {
239 rlColor4ub(color.r, color.g, color.b, color.a);
240
241 rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
242 rlVertex2f(center.x, center.y);
243
244 rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
245 rlVertex2f(center.x + sinf(DEG2RAD*angle)*radius, center.y + cosf(DEG2RAD*angle)*radius);
246
247 rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
248 rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*radius, center.y + cosf(DEG2RAD*(angle + stepLength))*radius);
249
250 rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
251 rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength*2))*radius, center.y + cosf(DEG2RAD*(angle + stepLength*2))*radius);
252
253 angle += (stepLength*2);
254 }
255
256 // NOTE: In case number of segments is odd, we add one last piece to the cake
257 if (segments%2)
258 {
259 rlColor4ub(color.r, color.g, color.b, color.a);
260
261 rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
262 rlVertex2f(center.x, center.y);
263
264 rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
265 rlVertex2f(center.x + sinf(DEG2RAD*angle)*radius, center.y + cosf(DEG2RAD*angle)*radius);
266
267 rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
268 rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*radius, center.y + cosf(DEG2RAD*(angle + stepLength))*radius);
269
270 rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
271 rlVertex2f(center.x, center.y);
272 }
273 rlEnd();
274
275 rlDisableTexture();
276#else
277 if (rlCheckBufferLimit(3*segments)) rlglDraw();
278
279 rlBegin(RL_TRIANGLES);
280 for (int i = 0; i < segments; i++)
281 {
282 rlColor4ub(color.r, color.g, color.b, color.a);
283
284 rlVertex2f(center.x, center.y);
285 rlVertex2f(center.x + sinf(DEG2RAD*angle)*radius, center.y + cosf(DEG2RAD*angle)*radius);
286 rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*radius, center.y + cosf(DEG2RAD*(angle + stepLength))*radius);
287
288 angle += stepLength;
289 }
290 rlEnd();
291#endif
292}
293
294void DrawCircleSectorLines(Vector2 center, float radius, int startAngle, int endAngle, int segments, Color color)
295{
296 if (radius <= 0.0f) radius = 0.1f; // Avoid div by zero issue
297
298 // Function expects (endAngle > startAngle)
299 if (endAngle < startAngle)
300 {
301 // Swap values
302 int tmp = startAngle;
303 startAngle = endAngle;
304 endAngle = tmp;
305 }
306
307 if (segments < 4)
308 {
309 // Calculate how many segments we need to draw a smooth circle, taken from https://stackoverflow.com/a/2244088
310 #ifndef CIRCLE_ERROR_RATE
311 #define CIRCLE_ERROR_RATE 0.5f
312 #endif
313
314 // Calculate the maximum angle between segments based on the error rate.
315 float th = acosf(2*powf(1 - CIRCLE_ERROR_RATE/radius, 2) - 1);
316 segments = (endAngle - startAngle)*ceilf(2*PI/th)/360;
317
318 if (segments <= 0) segments = 4;
319 }
320
321 float stepLength = (float)(endAngle - startAngle)/(float)segments;
322 float angle = startAngle;
323
324 // Hide the cap lines when the circle is full
325 bool showCapLines = true;
326 int limit = 2*(segments + 2);
327 if ((endAngle - startAngle)%360 == 0) { limit = 2*segments; showCapLines = false; }
328
329 if (rlCheckBufferLimit(limit)) rlglDraw();
330
331 rlBegin(RL_LINES);
332 if (showCapLines)
333 {
334 rlColor4ub(color.r, color.g, color.b, color.a);
335 rlVertex2f(center.x, center.y);
336 rlVertex2f(center.x + sinf(DEG2RAD*angle)*radius, center.y + cosf(DEG2RAD*angle)*radius);
337 }
338
339 for (int i = 0; i < segments; i++)
340 {
341 rlColor4ub(color.r, color.g, color.b, color.a);
342
343 rlVertex2f(center.x + sinf(DEG2RAD*angle)*radius, center.y + cosf(DEG2RAD*angle)*radius);
344 rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*radius, center.y + cosf(DEG2RAD*(angle + stepLength))*radius);
345
346 angle += stepLength;
347 }
348
349 if (showCapLines)
350 {
351 rlColor4ub(color.r, color.g, color.b, color.a);
352 rlVertex2f(center.x, center.y);
353 rlVertex2f(center.x + sinf(DEG2RAD*angle)*radius, center.y + cosf(DEG2RAD*angle)*radius);
354 }
355 rlEnd();
356}
357
358// Draw a gradient-filled circle
359// NOTE: Gradient goes from center (color1) to border (color2)
360void DrawCircleGradient(int centerX, int centerY, float radius, Color color1, Color color2)
361{
362 if (rlCheckBufferLimit(3*36)) rlglDraw();
363
364 rlBegin(RL_TRIANGLES);
365 for (int i = 0; i < 360; i += 10)
366 {
367 rlColor4ub(color1.r, color1.g, color1.b, color1.a);
368 rlVertex2f(centerX, centerY);
369 rlColor4ub(color2.r, color2.g, color2.b, color2.a);
370 rlVertex2f(centerX + sinf(DEG2RAD*i)*radius, centerY + cosf(DEG2RAD*i)*radius);
371 rlColor4ub(color2.r, color2.g, color2.b, color2.a);
372 rlVertex2f(centerX + sinf(DEG2RAD*(i + 10))*radius, centerY + cosf(DEG2RAD*(i + 10))*radius);
373 }
374 rlEnd();
375}
376
377// Draw a color-filled circle (Vector version)
378// NOTE: On OpenGL 3.3 and ES2 we use QUADS to avoid drawing order issues (view rlglDraw)
379void DrawCircleV(Vector2 center, float radius, Color color)
380{
381 DrawCircleSector(center, radius, 0, 360, 36, color);
382}
383
384// Draw circle outline
385void DrawCircleLines(int centerX, int centerY, float radius, Color color)
386{
387 if (rlCheckBufferLimit(2*36)) rlglDraw();
388
389 rlBegin(RL_LINES);
390 rlColor4ub(color.r, color.g, color.b, color.a);
391
392 // NOTE: Circle outline is drawn pixel by pixel every degree (0 to 360)
393 for (int i = 0; i < 360; i += 10)
394 {
395 rlVertex2f(centerX + sinf(DEG2RAD*i)*radius, centerY + cosf(DEG2RAD*i)*radius);
396 rlVertex2f(centerX + sinf(DEG2RAD*(i + 10))*radius, centerY + cosf(DEG2RAD*(i + 10))*radius);
397 }
398 rlEnd();
399}
400
401// Draw ellipse
402void DrawEllipse(int centerX, int centerY, float radiusH, float radiusV, Color color)
403{
404 if (rlCheckBufferLimit(3*36)) rlglDraw();
405
406 rlBegin(RL_TRIANGLES);
407 for (int i = 0; i < 360; i += 10)
408 {
409 rlColor4ub(color.r, color.g, color.b, color.a);
410 rlVertex2f(centerX, centerY);
411 rlVertex2f(centerX + sinf(DEG2RAD*i)*radiusH, centerY + cosf(DEG2RAD*i)*radiusV);
412 rlVertex2f(centerX + sinf(DEG2RAD*(i + 10))*radiusH, centerY + cosf(DEG2RAD*(i + 10))*radiusV);
413 }
414 rlEnd();
415}
416
417// Draw ellipse outline
418void DrawEllipseLines(int centerX, int centerY, float radiusH, float radiusV, Color color)
419{
420 if (rlCheckBufferLimit(2*36)) rlglDraw();
421
422 rlBegin(RL_LINES);
423 for (int i = 0; i < 360; i += 10)
424 {
425 rlColor4ub(color.r, color.g, color.b, color.a);
426 rlVertex2f(centerX + sinf(DEG2RAD*i)*radiusH, centerY + cosf(DEG2RAD*i)*radiusV);
427 rlVertex2f(centerX + sinf(DEG2RAD*(i + 10))*radiusH, centerY + cosf(DEG2RAD*(i + 10))*radiusV);
428 }
429 rlEnd();
430}
431
432void DrawRing(Vector2 center, float innerRadius, float outerRadius, int startAngle, int endAngle, int segments, Color color)
433{
434 if (startAngle == endAngle) return;
435
436 // Function expects (outerRadius > innerRadius)
437 if (outerRadius < innerRadius)
438 {
439 float tmp = outerRadius;
440 outerRadius = innerRadius;
441 innerRadius = tmp;
442
443 if (outerRadius <= 0.0f) outerRadius = 0.1f;
444 }
445
446 // Function expects (endAngle > startAngle)
447 if (endAngle < startAngle)
448 {
449 // Swap values
450 int tmp = startAngle;
451 startAngle = endAngle;
452 endAngle = tmp;
453 }
454
455 if (segments < 4)
456 {
457 // Calculate how many segments we need to draw a smooth circle, taken from https://stackoverflow.com/a/2244088
458 #ifndef CIRCLE_ERROR_RATE
459 #define CIRCLE_ERROR_RATE 0.5f
460 #endif
461
462 // Calculate the maximum angle between segments based on the error rate.
463 float th = acosf(2*powf(1 - CIRCLE_ERROR_RATE/outerRadius, 2) - 1);
464 segments = (endAngle - startAngle)*ceilf(2*PI/th)/360;
465
466 if (segments <= 0) segments = 4;
467 }
468
469 // Not a ring
470 if (innerRadius <= 0.0f)
471 {
472 DrawCircleSector(center, outerRadius, startAngle, endAngle, segments, color);
473 return;
474 }
475
476 float stepLength = (float)(endAngle - startAngle)/(float)segments;
477 float angle = startAngle;
478
479#if defined(SUPPORT_QUADS_DRAW_MODE)
480 if (rlCheckBufferLimit(4*segments)) rlglDraw();
481
482 rlEnableTexture(GetShapesTexture().id);
483
484 rlBegin(RL_QUADS);
485 for (int i = 0; i < segments; i++)
486 {
487 rlColor4ub(color.r, color.g, color.b, color.a);
488
489 rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
490 rlVertex2f(center.x + sinf(DEG2RAD*angle)*innerRadius, center.y + cosf(DEG2RAD*angle)*innerRadius);
491
492 rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
493 rlVertex2f(center.x + sinf(DEG2RAD*angle)*outerRadius, center.y + cosf(DEG2RAD*angle)*outerRadius);
494
495 rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
496 rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*outerRadius);
497
498 rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
499 rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*innerRadius);
500
501 angle += stepLength;
502 }
503 rlEnd();
504
505 rlDisableTexture();
506#else
507 if (rlCheckBufferLimit(6*segments)) rlglDraw();
508
509 rlBegin(RL_TRIANGLES);
510 for (int i = 0; i < segments; i++)
511 {
512 rlColor4ub(color.r, color.g, color.b, color.a);
513
514 rlVertex2f(center.x + sinf(DEG2RAD*angle)*innerRadius, center.y + cosf(DEG2RAD*angle)*innerRadius);
515 rlVertex2f(center.x + sinf(DEG2RAD*angle)*outerRadius, center.y + cosf(DEG2RAD*angle)*outerRadius);
516 rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*innerRadius);
517
518 rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*innerRadius);
519 rlVertex2f(center.x + sinf(DEG2RAD*angle)*outerRadius, center.y + cosf(DEG2RAD*angle)*outerRadius);
520 rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*outerRadius);
521
522 angle += stepLength;
523 }
524 rlEnd();
525#endif
526}
527
528void DrawRingLines(Vector2 center, float innerRadius, float outerRadius, int startAngle, int endAngle, int segments, Color color)
529{
530 if (startAngle == endAngle) return;
531
532 // Function expects (outerRadius > innerRadius)
533 if (outerRadius < innerRadius)
534 {
535 float tmp = outerRadius;
536 outerRadius = innerRadius;
537 innerRadius = tmp;
538
539 if (outerRadius <= 0.0f) outerRadius = 0.1f;
540 }
541
542 // Function expects (endAngle > startAngle)
543 if (endAngle < startAngle)
544 {
545 // Swap values
546 int tmp = startAngle;
547 startAngle = endAngle;
548 endAngle = tmp;
549 }
550
551 if (segments < 4)
552 {
553 // Calculate how many segments we need to draw a smooth circle, taken from https://stackoverflow.com/a/2244088
554 #ifndef CIRCLE_ERROR_RATE
555 #define CIRCLE_ERROR_RATE 0.5f
556 #endif
557
558 // Calculate the maximum angle between segments based on the error rate.
559 float th = acosf(2*powf(1 - CIRCLE_ERROR_RATE/outerRadius, 2) - 1);
560 segments = (endAngle - startAngle)*ceilf(2*PI/th)/360;
561
562 if (segments <= 0) segments = 4;
563 }
564
565 if (innerRadius <= 0.0f)
566 {
567 DrawCircleSectorLines(center, outerRadius, startAngle, endAngle, segments, color);
568 return;
569 }
570
571 float stepLength = (float)(endAngle - startAngle)/(float)segments;
572 float angle = startAngle;
573
574 bool showCapLines = true;
575 int limit = 4*(segments + 1);
576 if ((endAngle - startAngle)%360 == 0) { limit = 4*segments; showCapLines = false; }
577
578 if (rlCheckBufferLimit(limit)) rlglDraw();
579
580 rlBegin(RL_LINES);
581 if (showCapLines)
582 {
583 rlColor4ub(color.r, color.g, color.b, color.a);
584 rlVertex2f(center.x + sinf(DEG2RAD*angle)*outerRadius, center.y + cosf(DEG2RAD*angle)*outerRadius);
585 rlVertex2f(center.x + sinf(DEG2RAD*angle)*innerRadius, center.y + cosf(DEG2RAD*angle)*innerRadius);
586 }
587
588 for (int i = 0; i < segments; i++)
589 {
590 rlColor4ub(color.r, color.g, color.b, color.a);
591
592 rlVertex2f(center.x + sinf(DEG2RAD*angle)*outerRadius, center.y + cosf(DEG2RAD*angle)*outerRadius);
593 rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*outerRadius);
594
595 rlVertex2f(center.x + sinf(DEG2RAD*angle)*innerRadius, center.y + cosf(DEG2RAD*angle)*innerRadius);
596 rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*innerRadius);
597
598 angle += stepLength;
599 }
600
601 if (showCapLines)
602 {
603 rlColor4ub(color.r, color.g, color.b, color.a);
604 rlVertex2f(center.x + sinf(DEG2RAD*angle)*outerRadius, center.y + cosf(DEG2RAD*angle)*outerRadius);
605 rlVertex2f(center.x + sinf(DEG2RAD*angle)*innerRadius, center.y + cosf(DEG2RAD*angle)*innerRadius);
606 }
607 rlEnd();
608}
609
610// Draw a color-filled rectangle
611void DrawRectangle(int posX, int posY, int width, int height, Color color)
612{
613 DrawRectangleV((Vector2){ (float)posX, (float)posY }, (Vector2){ (float)width, (float)height }, color);
614}
615
616// Draw a color-filled rectangle (Vector version)
617// NOTE: On OpenGL 3.3 and ES2 we use QUADS to avoid drawing order issues (view rlglDraw)
618void DrawRectangleV(Vector2 position, Vector2 size, Color color)
619{
620 DrawRectanglePro((Rectangle){ position.x, position.y, size.x, size.y }, (Vector2){ 0.0f, 0.0f }, 0.0f, color);
621}
622
623// Draw a color-filled rectangle
624void DrawRectangleRec(Rectangle rec, Color color)
625{
626 DrawRectanglePro(rec, (Vector2){ 0.0f, 0.0f }, 0.0f, color);
627}
628
629// Draw a color-filled rectangle with pro parameters
630void DrawRectanglePro(Rectangle rec, Vector2 origin, float rotation, Color color)
631{
632 rlEnableTexture(GetShapesTexture().id);
633
634 rlPushMatrix();
635 rlTranslatef(rec.x, rec.y, 0.0f);
636 rlRotatef(rotation, 0.0f, 0.0f, 1.0f);
637 rlTranslatef(-origin.x, -origin.y, 0.0f);
638
639 rlBegin(RL_QUADS);
640 rlNormal3f(0.0f, 0.0f, 1.0f);
641 rlColor4ub(color.r, color.g, color.b, color.a);
642
643 rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
644 rlVertex2f(0.0f, 0.0f);
645
646 rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
647 rlVertex2f(0.0f, rec.height);
648
649 rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
650 rlVertex2f(rec.width, rec.height);
651
652 rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
653 rlVertex2f(rec.width, 0.0f);
654 rlEnd();
655 rlPopMatrix();
656
657 rlDisableTexture();
658}
659
660// Draw a vertical-gradient-filled rectangle
661// NOTE: Gradient goes from bottom (color1) to top (color2)
662void DrawRectangleGradientV(int posX, int posY, int width, int height, Color color1, Color color2)
663{
664 DrawRectangleGradientEx((Rectangle){ (float)posX, (float)posY, (float)width, (float)height }, color1, color2, color2, color1);
665}
666
667// Draw a horizontal-gradient-filled rectangle
668// NOTE: Gradient goes from bottom (color1) to top (color2)
669void DrawRectangleGradientH(int posX, int posY, int width, int height, Color color1, Color color2)
670{
671 DrawRectangleGradientEx((Rectangle){ (float)posX, (float)posY, (float)width, (float)height }, color1, color1, color2, color2);
672}
673
674// Draw a gradient-filled rectangle
675// NOTE: Colors refer to corners, starting at top-lef corner and counter-clockwise
676void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3, Color col4)
677{
678 rlEnableTexture(GetShapesTexture().id);
679
680 rlPushMatrix();
681 rlBegin(RL_QUADS);
682 rlNormal3f(0.0f, 0.0f, 1.0f);
683
684 // NOTE: Default raylib font character 95 is a white square
685 rlColor4ub(col1.r, col1.g, col1.b, col1.a);
686 rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
687 rlVertex2f(rec.x, rec.y);
688
689 rlColor4ub(col2.r, col2.g, col2.b, col2.a);
690 rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
691 rlVertex2f(rec.x, rec.y + rec.height);
692
693 rlColor4ub(col3.r, col3.g, col3.b, col3.a);
694 rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
695 rlVertex2f(rec.x + rec.width, rec.y + rec.height);
696
697 rlColor4ub(col4.r, col4.g, col4.b, col4.a);
698 rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
699 rlVertex2f(rec.x + rec.width, rec.y);
700 rlEnd();
701 rlPopMatrix();
702
703 rlDisableTexture();
704}
705
706// Draw rectangle outline
707// NOTE: On OpenGL 3.3 and ES2 we use QUADS to avoid drawing order issues (view rlglDraw)
708void DrawRectangleLines(int posX, int posY, int width, int height, Color color)
709{
710#if defined(SUPPORT_QUADS_DRAW_MODE)
711 DrawRectangle(posX, posY, width, 1, color);
712 DrawRectangle(posX + width - 1, posY + 1, 1, height - 2, color);
713 DrawRectangle(posX, posY + height - 1, width, 1, color);
714 DrawRectangle(posX, posY + 1, 1, height - 2, color);
715#else
716 rlBegin(RL_LINES);
717 rlColor4ub(color.r, color.g, color.b, color.a);
718 rlVertex2i(posX + 1, posY + 1);
719 rlVertex2i(posX + width, posY + 1);
720
721 rlVertex2i(posX + width, posY + 1);
722 rlVertex2i(posX + width, posY + height);
723
724 rlVertex2i(posX + width, posY + height);
725 rlVertex2i(posX + 1, posY + height);
726
727 rlVertex2i(posX + 1, posY + height);
728 rlVertex2i(posX + 1, posY + 1);
729 rlEnd();
730#endif
731}
732
733// Draw rectangle outline with extended parameters
734void DrawRectangleLinesEx(Rectangle rec, int lineThick, Color color)
735{
736 if (lineThick > rec.width || lineThick > rec.height)
737 {
738 if (rec.width > rec.height) lineThick = (int)rec.height/2;
739 else if (rec.width < rec.height) lineThick = (int)rec.width/2;
740 }
741
742 DrawRectangle( (int)rec.x, (int)rec.y, (int)rec.width, lineThick, color);
743 DrawRectangle( (int)(rec.x - lineThick + rec.width), (int)(rec.y + lineThick), lineThick, (int)(rec.height - lineThick*2.0f), color);
744 DrawRectangle( (int)rec.x, (int)(rec.y + rec.height - lineThick), (int)rec.width, lineThick, color);
745 DrawRectangle( (int)rec.x, (int)(rec.y + lineThick), lineThick, (int)(rec.height - lineThick*2), color);
746}
747
748// Draw rectangle with rounded edges
749void DrawRectangleRounded(Rectangle rec, float roundness, int segments, Color color)
750{
751 // Not a rounded rectangle
752 if ((roundness <= 0.0f) || (rec.width < 1) || (rec.height < 1 ))
753 {
754 DrawRectangleRec(rec, color);
755 return;
756 }
757
758 if (roundness >= 1.0f) roundness = 1.0f;
759
760 // Calculate corner radius
761 float radius = (rec.width > rec.height)? (rec.height*roundness)/2 : (rec.width*roundness)/2;
762 if (radius <= 0.0f) return;
763
764 // Calculate number of segments to use for the corners
765 if (segments < 4)
766 {
767 // Calculate how many segments we need to draw a smooth circle, taken from https://stackoverflow.com/a/2244088
768 #ifndef CIRCLE_ERROR_RATE
769 #define CIRCLE_ERROR_RATE 0.5f
770 #endif
771 // Calculate the maximum angle between segments based on the error rate.
772 float th = acosf(2*powf(1 - CIRCLE_ERROR_RATE/radius, 2) - 1);
773 segments = ceilf(2*PI/th)/4;
774 if (segments <= 0) segments = 4;
775 }
776
777 float stepLength = 90.0f/(float)segments;
778
779 /* Quick sketch to make sense of all of this (there are 9 parts to draw, also mark the 12 points we'll use below)
780 * Not my best attempt at ASCII art, just preted it's rounded rectangle :)
781 * P0 P1
782 * ____________________
783 * /| |\
784 * /1| 2 |3\
785 *P7 /__|____________________|__\ P2
786 * | |P8 P9| |
787 * | 8 | 9 | 4 |
788 * | __|____________________|__ |
789 *P6 \ |P11 P10| / P3
790 * \7| 6 |5/
791 * \|____________________|/
792 * P5 P4
793 */
794
795 const Vector2 point[12] = { // coordinates of the 12 points that define the rounded rect (the idea here is to make things easier)
796 {(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
797 {rec.x + rec.width, (float)(rec.y + rec.height) - radius}, {(float)(rec.x + rec.width) - radius, rec.y + rec.height}, // P3, P4
798 {(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
799 {(float)rec.x + radius, (float)rec.y + radius}, {(float)(rec.x + rec.width) - radius, (float)rec.y + radius}, // P8, P9
800 {(float)(rec.x + rec.width) - radius, (float)(rec.y + rec.height) - radius}, {(float)rec.x + radius, (float)(rec.y + rec.height) - radius} // P10, P11
801 };
802
803 const Vector2 centers[4] = { point[8], point[9], point[10], point[11] };
804 const float angles[4] = { 180.0f, 90.0f, 0.0f, 270.0f };
805
806#if defined(SUPPORT_QUADS_DRAW_MODE)
807 if (rlCheckBufferLimit(16*segments/2 + 5*4)) rlglDraw();
808
809 rlEnableTexture(GetShapesTexture().id);
810
811 rlBegin(RL_QUADS);
812 // Draw all of the 4 corners: [1] Upper Left Corner, [3] Upper Right Corner, [5] Lower Right Corner, [7] Lower Left Corner
813 for (int k = 0; k < 4; ++k) // Hope the compiler is smart enough to unroll this loop
814 {
815 float angle = angles[k];
816 const Vector2 center = centers[k];
817 // NOTE: Every QUAD actually represents two segments
818 for (int i = 0; i < segments/2; i++)
819 {
820 rlColor4ub(color.r, color.g, color.b, color.a);
821 rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
822 rlVertex2f(center.x, center.y);
823 rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
824 rlVertex2f(center.x + sinf(DEG2RAD*angle)*radius, center.y + cosf(DEG2RAD*angle)*radius);
825 rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
826 rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*radius, center.y + cosf(DEG2RAD*(angle + stepLength))*radius);
827 rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
828 rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength*2))*radius, center.y + cosf(DEG2RAD*(angle + stepLength*2))*radius);
829 angle += (stepLength*2);
830 }
831 // NOTE: In case number of segments is odd, we add one last piece to the cake
832 if (segments%2)
833 {
834 rlColor4ub(color.r, color.g, color.b, color.a);
835 rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
836 rlVertex2f(center.x, center.y);
837 rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
838 rlVertex2f(center.x + sinf(DEG2RAD*angle)*radius, center.y + cosf(DEG2RAD*angle)*radius);
839 rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
840 rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*radius, center.y + cosf(DEG2RAD*(angle + stepLength))*radius);
841 rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
842 rlVertex2f(center.x, center.y);
843 }
844 }
845
846 // [2] Upper Rectangle
847 rlColor4ub(color.r, color.g, color.b, color.a);
848 rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
849 rlVertex2f(point[0].x, point[0].y);
850 rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
851 rlVertex2f(point[8].x, point[8].y);
852 rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
853 rlVertex2f(point[9].x, point[9].y);
854 rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
855 rlVertex2f(point[1].x, point[1].y);
856
857 // [4] Right Rectangle
858 rlColor4ub(color.r, color.g, color.b, color.a);
859 rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
860 rlVertex2f(point[2].x, point[2].y);
861 rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
862 rlVertex2f(point[9].x, point[9].y);
863 rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
864 rlVertex2f(point[10].x, point[10].y);
865 rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
866 rlVertex2f(point[3].x, point[3].y);
867
868 // [6] Bottom Rectangle
869 rlColor4ub(color.r, color.g, color.b, color.a);
870 rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
871 rlVertex2f(point[11].x, point[11].y);
872 rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
873 rlVertex2f(point[5].x, point[5].y);
874 rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
875 rlVertex2f(point[4].x, point[4].y);
876 rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
877 rlVertex2f(point[10].x, point[10].y);
878
879 // [8] Left Rectangle
880 rlColor4ub(color.r, color.g, color.b, color.a);
881 rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
882 rlVertex2f(point[7].x, point[7].y);
883 rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
884 rlVertex2f(point[6].x, point[6].y);
885 rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
886 rlVertex2f(point[11].x, point[11].y);
887 rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
888 rlVertex2f(point[8].x, point[8].y);
889
890 // [9] Middle Rectangle
891 rlColor4ub(color.r, color.g, color.b, color.a);
892 rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
893 rlVertex2f(point[8].x, point[8].y);
894 rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
895 rlVertex2f(point[11].x, point[11].y);
896 rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
897 rlVertex2f(point[10].x, point[10].y);
898 rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
899 rlVertex2f(point[9].x, point[9].y);
900
901 rlEnd();
902 rlDisableTexture();
903#else
904 if (rlCheckBufferLimit(12*segments + 5*6)) rlglDraw(); // 4 corners with 3 vertices per segment + 5 rectangles with 6 vertices each
905
906 rlBegin(RL_TRIANGLES);
907 // Draw all of the 4 corners: [1] Upper Left Corner, [3] Upper Right Corner, [5] Lower Right Corner, [7] Lower Left Corner
908 for (int k = 0; k < 4; ++k) // Hope the compiler is smart enough to unroll this loop
909 {
910 float angle = angles[k];
911 const Vector2 center = centers[k];
912 for (int i = 0; i < segments; i++)
913 {
914 rlColor4ub(color.r, color.g, color.b, color.a);
915 rlVertex2f(center.x, center.y);
916 rlVertex2f(center.x + sinf(DEG2RAD*angle)*radius, center.y + cosf(DEG2RAD*angle)*radius);
917 rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*radius, center.y + cosf(DEG2RAD*(angle + stepLength))*radius);
918 angle += stepLength;
919 }
920 }
921
922 // [2] Upper Rectangle
923 rlColor4ub(color.r, color.g, color.b, color.a);
924 rlVertex2f(point[0].x, point[0].y);
925 rlVertex2f(point[8].x, point[8].y);
926 rlVertex2f(point[9].x, point[9].y);
927 rlVertex2f(point[1].x, point[1].y);
928 rlVertex2f(point[0].x, point[0].y);
929 rlVertex2f(point[9].x, point[9].y);
930
931 // [4] Right Rectangle
932 rlColor4ub(color.r, color.g, color.b, color.a);
933 rlVertex2f(point[9].x, point[9].y);
934 rlVertex2f(point[10].x, point[10].y);
935 rlVertex2f(point[3].x, point[3].y);
936 rlVertex2f(point[2].x, point[2].y);
937 rlVertex2f(point[9].x, point[9].y);
938 rlVertex2f(point[3].x, point[3].y);
939
940 // [6] Bottom Rectangle
941 rlColor4ub(color.r, color.g, color.b, color.a);
942 rlVertex2f(point[11].x, point[11].y);
943 rlVertex2f(point[5].x, point[5].y);
944 rlVertex2f(point[4].x, point[4].y);
945 rlVertex2f(point[10].x, point[10].y);
946 rlVertex2f(point[11].x, point[11].y);
947 rlVertex2f(point[4].x, point[4].y);
948
949 // [8] Left Rectangle
950 rlColor4ub(color.r, color.g, color.b, color.a);
951 rlVertex2f(point[7].x, point[7].y);
952 rlVertex2f(point[6].x, point[6].y);
953 rlVertex2f(point[11].x, point[11].y);
954 rlVertex2f(point[8].x, point[8].y);
955 rlVertex2f(point[7].x, point[7].y);
956 rlVertex2f(point[11].x, point[11].y);
957
958 // [9] Middle Rectangle
959 rlColor4ub(color.r, color.g, color.b, color.a);
960 rlVertex2f(point[8].x, point[8].y);
961 rlVertex2f(point[11].x, point[11].y);
962 rlVertex2f(point[10].x, point[10].y);
963 rlVertex2f(point[9].x, point[9].y);
964 rlVertex2f(point[8].x, point[8].y);
965 rlVertex2f(point[10].x, point[10].y);
966 rlEnd();
967#endif
968}
969
970// Draw rectangle with rounded edges outline
971void DrawRectangleRoundedLines(Rectangle rec, float roundness, int segments, int lineThick, Color color)
972{
973 if (lineThick < 0) lineThick = 0;
974
975 // Not a rounded rectangle
976 if (roundness <= 0.0f)
977 {
978 DrawRectangleLinesEx((Rectangle){rec.x-lineThick, rec.y-lineThick, rec.width+2*lineThick, rec.height+2*lineThick}, lineThick, color);
979 return;
980 }
981
982 if (roundness >= 1.0f) roundness = 1.0f;
983
984 // Calculate corner radius
985 float radius = (rec.width > rec.height)? (rec.height*roundness)/2 : (rec.width*roundness)/2;
986 if (radius <= 0.0f) return;
987
988 // Calculate number of segments to use for the corners
989 if (segments < 4)
990 {
991 // Calculate how many segments we need to draw a smooth circle, taken from https://stackoverflow.com/a/2244088
992 #ifndef CIRCLE_ERROR_RATE
993 #define CIRCLE_ERROR_RATE 0.5f
994 #endif
995 // Calculate the maximum angle between segments based on the error rate.
996 float th = acosf(2*powf(1 - CIRCLE_ERROR_RATE/radius, 2) - 1);
997 segments = ceilf(2*PI/th)/2;
998 if (segments <= 0) segments = 4;
999 }
1000
1001 float stepLength = 90.0f/(float)segments;
1002 const float outerRadius = radius + (float)lineThick, innerRadius = radius;
1003
1004 /* Quick sketch to make sense of all of this (mark the 16 + 4(corner centers P16-19) points we'll use below)
1005 * Not my best attempt at ASCII art, just preted it's rounded rectangle :)
1006 * P0 P1
1007 * ====================
1008 * // P8 P9 \\
1009 * // \\
1010 *P7 // P15 P10 \\ P2
1011 * || *P16 P17* ||
1012 * || ||
1013 * || P14 P11 ||
1014 *P6 \\ *P19 P18* // P3
1015 * \\ //
1016 * \\ P13 P12 //
1017 * ====================
1018 * P5 P4
1019 */
1020 const Vector2 point[16] = {
1021 {(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
1022 {rec.x + rec.width + lineThick, (float)(rec.y + rec.height) - innerRadius}, {(float)(rec.x + rec.width) - innerRadius, rec.y + rec.height + lineThick}, // P3, P4
1023 {(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
1024 {(float)rec.x + innerRadius, rec.y}, {(float)(rec.x + rec.width) - innerRadius, rec.y}, // P8, P9
1025 { rec.x + rec.width, (float)rec.y + innerRadius }, {rec.x + rec.width, (float)(rec.y + rec.height) - innerRadius}, // P10, P11
1026 {(float)(rec.x + rec.width) - innerRadius, rec.y + rec.height}, {(float)rec.x + innerRadius, rec.y + rec.height}, // P12, P13
1027 { rec.x, (float)(rec.y + rec.height) - innerRadius}, {rec.x, (float)rec.y + innerRadius} // P14, P15
1028 };
1029
1030 const Vector2 centers[4] = {
1031 {(float)rec.x + innerRadius, (float)rec.y + innerRadius}, {(float)(rec.x + rec.width) - innerRadius, (float)rec.y + innerRadius}, // P16, P17
1032 {(float)(rec.x + rec.width) - innerRadius, (float)(rec.y + rec.height) - innerRadius}, {(float)rec.x + innerRadius, (float)(rec.y + rec.height) - innerRadius} // P18, P19
1033 };
1034
1035 const float angles[4] = { 180.0f, 90.0f, 0.0f, 270.0f };
1036
1037 if (lineThick > 1)
1038 {
1039#if defined(SUPPORT_QUADS_DRAW_MODE)
1040 if (rlCheckBufferLimit(4*4*segments + 4*4)) rlglDraw(); // 4 corners with 4 vertices for each segment + 4 rectangles with 4 vertices each
1041
1042 rlEnableTexture(GetShapesTexture().id);
1043
1044 rlBegin(RL_QUADS);
1045 // Draw all of the 4 corners first: Upper Left Corner, Upper Right Corner, Lower Right Corner, Lower Left Corner
1046 for (int k = 0; k < 4; ++k) // Hope the compiler is smart enough to unroll this loop
1047 {
1048 float angle = angles[k];
1049 const Vector2 center = centers[k];
1050 for (int i = 0; i < segments; i++)
1051 {
1052 rlColor4ub(color.r, color.g, color.b, color.a);
1053 rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
1054 rlVertex2f(center.x + sinf(DEG2RAD*angle)*innerRadius, center.y + cosf(DEG2RAD*angle)*innerRadius);
1055 rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
1056 rlVertex2f(center.x + sinf(DEG2RAD*angle)*outerRadius, center.y + cosf(DEG2RAD*angle)*outerRadius);
1057 rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
1058 rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*outerRadius);
1059 rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
1060 rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*innerRadius);
1061
1062 angle += stepLength;
1063 }
1064 }
1065
1066 // Upper rectangle
1067 rlColor4ub(color.r, color.g, color.b, color.a);
1068 rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
1069 rlVertex2f(point[0].x, point[0].y);
1070 rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
1071 rlVertex2f(point[8].x, point[8].y);
1072 rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
1073 rlVertex2f(point[9].x, point[9].y);
1074 rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
1075 rlVertex2f(point[1].x, point[1].y);
1076
1077 // Right rectangle
1078 rlColor4ub(color.r, color.g, color.b, color.a);
1079 rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
1080 rlVertex2f(point[2].x, point[2].y);
1081 rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
1082 rlVertex2f(point[10].x, point[10].y);
1083 rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
1084 rlVertex2f(point[11].x, point[11].y);
1085 rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
1086 rlVertex2f(point[3].x, point[3].y);
1087
1088 // Lower rectangle
1089 rlColor4ub(color.r, color.g, color.b, color.a);
1090 rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
1091 rlVertex2f(point[13].x, point[13].y);
1092 rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
1093 rlVertex2f(point[5].x, point[5].y);
1094 rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
1095 rlVertex2f(point[4].x, point[4].y);
1096 rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
1097 rlVertex2f(point[12].x, point[12].y);
1098
1099 // Left rectangle
1100 rlColor4ub(color.r, color.g, color.b, color.a);
1101 rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
1102 rlVertex2f(point[15].x, point[15].y);
1103 rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
1104 rlVertex2f(point[7].x, point[7].y);
1105 rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
1106 rlVertex2f(point[6].x, point[6].y);
1107 rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
1108 rlVertex2f(point[14].x, point[14].y);
1109
1110 rlEnd();
1111 rlDisableTexture();
1112#else
1113 if (rlCheckBufferLimit(4*6*segments + 4*6)) rlglDraw(); // 4 corners with 6(2*3) vertices for each segment + 4 rectangles with 6 vertices each
1114
1115 rlBegin(RL_TRIANGLES);
1116
1117 // Draw all of the 4 corners first: Upper Left Corner, Upper Right Corner, Lower Right Corner, Lower Left Corner
1118 for (int k = 0; k < 4; ++k) // Hope the compiler is smart enough to unroll this loop
1119 {
1120 float angle = angles[k];
1121 const Vector2 center = centers[k];
1122
1123 for (int i = 0; i < segments; i++)
1124 {
1125 rlColor4ub(color.r, color.g, color.b, color.a);
1126
1127 rlVertex2f(center.x + sinf(DEG2RAD*angle)*innerRadius, center.y + cosf(DEG2RAD*angle)*innerRadius);
1128 rlVertex2f(center.x + sinf(DEG2RAD*angle)*outerRadius, center.y + cosf(DEG2RAD*angle)*outerRadius);
1129 rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*innerRadius);
1130
1131 rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*innerRadius);
1132 rlVertex2f(center.x + sinf(DEG2RAD*angle)*outerRadius, center.y + cosf(DEG2RAD*angle)*outerRadius);
1133 rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*outerRadius);
1134
1135 angle += stepLength;
1136 }
1137 }
1138
1139 // Upper rectangle
1140 rlColor4ub(color.r, color.g, color.b, color.a);
1141 rlVertex2f(point[0].x, point[0].y);
1142 rlVertex2f(point[8].x, point[8].y);
1143 rlVertex2f(point[9].x, point[9].y);
1144 rlVertex2f(point[1].x, point[1].y);
1145 rlVertex2f(point[0].x, point[0].y);
1146 rlVertex2f(point[9].x, point[9].y);
1147
1148 // Right rectangle
1149 rlColor4ub(color.r, color.g, color.b, color.a);
1150 rlVertex2f(point[10].x, point[10].y);
1151 rlVertex2f(point[11].x, point[11].y);
1152 rlVertex2f(point[3].x, point[3].y);
1153 rlVertex2f(point[2].x, point[2].y);
1154 rlVertex2f(point[10].x, point[10].y);
1155 rlVertex2f(point[3].x, point[3].y);
1156
1157 // Lower rectangle
1158 rlColor4ub(color.r, color.g, color.b, color.a);
1159 rlVertex2f(point[13].x, point[13].y);
1160 rlVertex2f(point[5].x, point[5].y);
1161 rlVertex2f(point[4].x, point[4].y);
1162 rlVertex2f(point[12].x, point[12].y);
1163 rlVertex2f(point[13].x, point[13].y);
1164 rlVertex2f(point[4].x, point[4].y);
1165
1166 // Left rectangle
1167 rlColor4ub(color.r, color.g, color.b, color.a);
1168 rlVertex2f(point[7].x, point[7].y);
1169 rlVertex2f(point[6].x, point[6].y);
1170 rlVertex2f(point[14].x, point[14].y);
1171 rlVertex2f(point[15].x, point[15].y);
1172 rlVertex2f(point[7].x, point[7].y);
1173 rlVertex2f(point[14].x, point[14].y);
1174 rlEnd();
1175#endif
1176 }
1177 else
1178 {
1179 // Use LINES to draw the outline
1180 if (rlCheckBufferLimit(8*segments + 4*2)) rlglDraw(); // 4 corners with 2 vertices for each segment + 4 rectangles with 2 vertices each
1181
1182 rlBegin(RL_LINES);
1183
1184 // Draw all of the 4 corners first: Upper Left Corner, Upper Right Corner, Lower Right Corner, Lower Left Corner
1185 for (int k = 0; k < 4; ++k) // Hope the compiler is smart enough to unroll this loop
1186 {
1187 float angle = angles[k];
1188 const Vector2 center = centers[k];
1189
1190 for (int i = 0; i < segments; i++)
1191 {
1192 rlColor4ub(color.r, color.g, color.b, color.a);
1193 rlVertex2f(center.x + sinf(DEG2RAD*angle)*outerRadius, center.y + cosf(DEG2RAD*angle)*outerRadius);
1194 rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*outerRadius);
1195 angle += stepLength;
1196 }
1197 }
1198 // And now the remaining 4 lines
1199 for(int i = 0; i < 8; i += 2)
1200 {
1201 rlColor4ub(color.r, color.g, color.b, color.a);
1202 rlVertex2f(point[i].x, point[i].y);
1203 rlVertex2f(point[i + 1].x, point[i + 1].y);
1204 }
1205 rlEnd();
1206 }
1207}
1208
1209// Draw a triangle
1210// NOTE: Vertex must be provided in counter-clockwise order
1211void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color)
1212{
1213 if (rlCheckBufferLimit(4)) rlglDraw();
1214
1215#if defined(SUPPORT_QUADS_DRAW_MODE)
1216 rlEnableTexture(GetShapesTexture().id);
1217
1218 rlBegin(RL_QUADS);
1219 rlColor4ub(color.r, color.g, color.b, color.a);
1220
1221 rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
1222 rlVertex2f(v1.x, v1.y);
1223
1224 rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
1225 rlVertex2f(v2.x, v2.y);
1226
1227 rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
1228 rlVertex2f(v2.x, v2.y);
1229
1230 rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
1231 rlVertex2f(v3.x, v3.y);
1232 rlEnd();
1233
1234 rlDisableTexture();
1235#else
1236 rlBegin(RL_TRIANGLES);
1237 rlColor4ub(color.r, color.g, color.b, color.a);
1238 rlVertex2f(v1.x, v1.y);
1239 rlVertex2f(v2.x, v2.y);
1240 rlVertex2f(v3.x, v3.y);
1241 rlEnd();
1242#endif
1243}
1244
1245// Draw a triangle using lines
1246// NOTE: Vertex must be provided in counter-clockwise order
1247void DrawTriangleLines(Vector2 v1, Vector2 v2, Vector2 v3, Color color)
1248{
1249 if (rlCheckBufferLimit(6)) rlglDraw();
1250
1251 rlBegin(RL_LINES);
1252 rlColor4ub(color.r, color.g, color.b, color.a);
1253 rlVertex2f(v1.x, v1.y);
1254 rlVertex2f(v2.x, v2.y);
1255
1256 rlVertex2f(v2.x, v2.y);
1257 rlVertex2f(v3.x, v3.y);
1258
1259 rlVertex2f(v3.x, v3.y);
1260 rlVertex2f(v1.x, v1.y);
1261 rlEnd();
1262}
1263
1264// Draw a triangle fan defined by points
1265// NOTE: First vertex provided is the center, shared by all triangles
1266void DrawTriangleFan(Vector2 *points, int pointsCount, Color color)
1267{
1268 if (pointsCount >= 3)
1269 {
1270 if (rlCheckBufferLimit((pointsCount - 2)*4)) rlglDraw();
1271
1272 rlEnableTexture(GetShapesTexture().id);
1273 rlBegin(RL_QUADS);
1274 rlColor4ub(color.r, color.g, color.b, color.a);
1275
1276 for (int i = 1; i < pointsCount - 1; i++)
1277 {
1278 rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
1279 rlVertex2f(points[0].x, points[0].y);
1280
1281 rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
1282 rlVertex2f(points[i].x, points[i].y);
1283
1284 rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
1285 rlVertex2f(points[i + 1].x, points[i + 1].y);
1286
1287 rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
1288 rlVertex2f(points[i + 1].x, points[i + 1].y);
1289 }
1290 rlEnd();
1291 rlDisableTexture();
1292 }
1293}
1294
1295// Draw a triangle strip defined by points
1296// NOTE: Every new vertex connects with previous two
1297void DrawTriangleStrip(Vector2 *points, int pointsCount, Color color)
1298{
1299 if (pointsCount >= 3)
1300 {
1301 if (rlCheckBufferLimit(pointsCount)) rlglDraw();
1302
1303 rlBegin(RL_TRIANGLES);
1304 rlColor4ub(color.r, color.g, color.b, color.a);
1305
1306 for (int i = 2; i < pointsCount; i++)
1307 {
1308 if ((i%2) == 0)
1309 {
1310 rlVertex2f(points[i].x, points[i].y);
1311 rlVertex2f(points[i - 2].x, points[i - 2].y);
1312 rlVertex2f(points[i - 1].x, points[i - 1].y);
1313 }
1314 else
1315 {
1316 rlVertex2f(points[i].x, points[i].y);
1317 rlVertex2f(points[i - 1].x, points[i - 1].y);
1318 rlVertex2f(points[i - 2].x, points[i - 2].y);
1319 }
1320 }
1321 rlEnd();
1322 }
1323}
1324
1325// Draw a regular polygon of n sides (Vector version)
1326void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color color)
1327{
1328 if (sides < 3) sides = 3;
1329 float centralAngle = 0.0f;
1330
1331 if (rlCheckBufferLimit(4*(360/sides))) rlglDraw();
1332
1333 rlPushMatrix();
1334 rlTranslatef(center.x, center.y, 0.0f);
1335 rlRotatef(rotation, 0.0f, 0.0f, 1.0f);
1336
1337#if defined(SUPPORT_QUADS_DRAW_MODE)
1338 rlEnableTexture(GetShapesTexture().id);
1339
1340 rlBegin(RL_QUADS);
1341 for (int i = 0; i < sides; i++)
1342 {
1343 rlColor4ub(color.r, color.g, color.b, color.a);
1344
1345 rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
1346 rlVertex2f(0, 0);
1347
1348 rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
1349 rlVertex2f(sinf(DEG2RAD*centralAngle)*radius, cosf(DEG2RAD*centralAngle)*radius);
1350
1351 rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
1352 rlVertex2f(sinf(DEG2RAD*centralAngle)*radius, cosf(DEG2RAD*centralAngle)*radius);
1353
1354 centralAngle += 360.0f/(float)sides;
1355 rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
1356 rlVertex2f(sinf(DEG2RAD*centralAngle)*radius, cosf(DEG2RAD*centralAngle)*radius);
1357 }
1358 rlEnd();
1359 rlDisableTexture();
1360#else
1361 rlBegin(RL_TRIANGLES);
1362 for (int i = 0; i < sides; i++)
1363 {
1364 rlColor4ub(color.r, color.g, color.b, color.a);
1365
1366 rlVertex2f(0, 0);
1367 rlVertex2f(sinf(DEG2RAD*centralAngle)*radius, cosf(DEG2RAD*centralAngle)*radius);
1368
1369 centralAngle += 360.0f/(float)sides;
1370 rlVertex2f(sinf(DEG2RAD*centralAngle)*radius, cosf(DEG2RAD*centralAngle)*radius);
1371 }
1372 rlEnd();
1373#endif
1374 rlPopMatrix();
1375}
1376
1377// Draw a polygon outline of n sides
1378void DrawPolyLines(Vector2 center, int sides, float radius, float rotation, Color color)
1379{
1380 if (sides < 3) sides = 3;
1381 float centralAngle = 0.0f;
1382
1383 if (rlCheckBufferLimit(3*(360/sides))) rlglDraw();
1384
1385 rlPushMatrix();
1386 rlTranslatef(center.x, center.y, 0.0f);
1387 rlRotatef(rotation, 0.0f, 0.0f, 1.0f);
1388
1389 rlBegin(RL_LINES);
1390 for (int i = 0; i < sides; i++)
1391 {
1392 rlColor4ub(color.r, color.g, color.b, color.a);
1393
1394 rlVertex2f(sinf(DEG2RAD*centralAngle)*radius, cosf(DEG2RAD*centralAngle)*radius);
1395 centralAngle += 360.0f/(float)sides;
1396 rlVertex2f(sinf(DEG2RAD*centralAngle)*radius, cosf(DEG2RAD*centralAngle)*radius);
1397 }
1398 rlEnd();
1399 rlPopMatrix();
1400}
1401
1402//----------------------------------------------------------------------------------
1403// Module Functions Definition - Collision Detection functions
1404//----------------------------------------------------------------------------------
1405
1406// Check if point is inside rectangle
1407bool CheckCollisionPointRec(Vector2 point, Rectangle rec)
1408{
1409 bool collision = false;
1410
1411 if ((point.x >= rec.x) && (point.x <= (rec.x + rec.width)) && (point.y >= rec.y) && (point.y <= (rec.y + rec.height))) collision = true;
1412
1413 return collision;
1414}
1415
1416// Check if point is inside circle
1417bool CheckCollisionPointCircle(Vector2 point, Vector2 center, float radius)
1418{
1419 return CheckCollisionCircles(point, 0, center, radius);
1420}
1421
1422// Check if point is inside a triangle defined by three points (p1, p2, p3)
1423bool CheckCollisionPointTriangle(Vector2 point, Vector2 p1, Vector2 p2, Vector2 p3)
1424{
1425 bool collision = false;
1426
1427 float alpha = ((p2.y - p3.y)*(point.x - p3.x) + (p3.x - p2.x)*(point.y - p3.y)) /
1428 ((p2.y - p3.y)*(p1.x - p3.x) + (p3.x - p2.x)*(p1.y - p3.y));
1429
1430 float beta = ((p3.y - p1.y)*(point.x - p3.x) + (p1.x - p3.x)*(point.y - p3.y)) /
1431 ((p2.y - p3.y)*(p1.x - p3.x) + (p3.x - p2.x)*(p1.y - p3.y));
1432
1433 float gamma = 1.0f - alpha - beta;
1434
1435 if ((alpha > 0) && (beta > 0) & (gamma > 0)) collision = true;
1436
1437 return collision;
1438}
1439
1440// Check collision between two rectangles
1441bool CheckCollisionRecs(Rectangle rec1, Rectangle rec2)
1442{
1443 bool collision = false;
1444
1445 if ((rec1.x < (rec2.x + rec2.width) && (rec1.x + rec1.width) > rec2.x) &&
1446 (rec1.y < (rec2.y + rec2.height) && (rec1.y + rec1.height) > rec2.y)) collision = true;
1447
1448 return collision;
1449}
1450
1451// Check collision between two circles
1452bool CheckCollisionCircles(Vector2 center1, float radius1, Vector2 center2, float radius2)
1453{
1454 bool collision = false;
1455
1456 float dx = center2.x - center1.x; // X distance between centers
1457 float dy = center2.y - center1.y; // Y distance between centers
1458
1459 float distance = sqrtf(dx*dx + dy*dy); // Distance between centers
1460
1461 if (distance <= (radius1 + radius2)) collision = true;
1462
1463 return collision;
1464}
1465
1466// Check collision between circle and rectangle
1467// NOTE: Reviewed version to take into account corner limit case
1468bool CheckCollisionCircleRec(Vector2 center, float radius, Rectangle rec)
1469{
1470 int recCenterX = (int)(rec.x + rec.width/2.0f);
1471 int recCenterY = (int)(rec.y + rec.height/2.0f);
1472
1473 float dx = fabsf(center.x - (float)recCenterX);
1474 float dy = fabsf(center.y - (float)recCenterY);
1475
1476 if (dx > (rec.width/2.0f + radius)) { return false; }
1477 if (dy > (rec.height/2.0f + radius)) { return false; }
1478
1479 if (dx <= (rec.width/2.0f)) { return true; }
1480 if (dy <= (rec.height/2.0f)) { return true; }
1481
1482 float cornerDistanceSq = (dx - rec.width/2.0f)*(dx - rec.width/2.0f) +
1483 (dy - rec.height/2.0f)*(dy - rec.height/2.0f);
1484
1485 return (cornerDistanceSq <= (radius*radius));
1486}
1487
1488// Get collision rectangle for two rectangles collision
1489Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2)
1490{
1491 Rectangle retRec = { 0, 0, 0, 0 };
1492
1493 if (CheckCollisionRecs(rec1, rec2))
1494 {
1495 float dxx = fabsf(rec1.x - rec2.x);
1496 float dyy = fabsf(rec1.y - rec2.y);
1497
1498 if (rec1.x <= rec2.x)
1499 {
1500 if (rec1.y <= rec2.y)
1501 {
1502 retRec.x = rec2.x;
1503 retRec.y = rec2.y;
1504 retRec.width = rec1.width - dxx;
1505 retRec.height = rec1.height - dyy;
1506 }
1507 else
1508 {
1509 retRec.x = rec2.x;
1510 retRec.y = rec1.y;
1511 retRec.width = rec1.width - dxx;
1512 retRec.height = rec2.height - dyy;
1513 }
1514 }
1515 else
1516 {
1517 if (rec1.y <= rec2.y)
1518 {
1519 retRec.x = rec1.x;
1520 retRec.y = rec2.y;
1521 retRec.width = rec2.width - dxx;
1522 retRec.height = rec1.height - dyy;
1523 }
1524 else
1525 {
1526 retRec.x = rec1.x;
1527 retRec.y = rec1.y;
1528 retRec.width = rec2.width - dxx;
1529 retRec.height = rec2.height - dyy;
1530 }
1531 }
1532
1533 if (rec1.width > rec2.width)
1534 {
1535 if (retRec.width >= rec2.width) retRec.width = rec2.width;
1536 }
1537 else
1538 {
1539 if (retRec.width >= rec1.width) retRec.width = rec1.width;
1540 }
1541
1542 if (rec1.height > rec2.height)
1543 {
1544 if (retRec.height >= rec2.height) retRec.height = rec2.height;
1545 }
1546 else
1547 {
1548 if (retRec.height >= rec1.height) retRec.height = rec1.height;
1549 }
1550 }
1551
1552 return retRec;
1553}
1554
1555//----------------------------------------------------------------------------------
1556// Module specific Functions Definition
1557//----------------------------------------------------------------------------------
1558
1559// Cubic easing in-out
1560// NOTE: Required for DrawLineBezier()
1561static float EaseCubicInOut(float t, float b, float c, float d)
1562{
1563 if ((t /= 0.5f*d) < 1) return 0.5f*c*t*t*t + b;
1564
1565 t -= 2;
1566
1567 return 0.5f*c*(t*t*t + 2.0f) + b;
1568}
1569