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 | //---------------------------------------------------------------------------------- |
65 | static float EaseCubicInOut(float t, float b, float c, float d); // Cubic easing |
66 | |
67 | //---------------------------------------------------------------------------------- |
68 | // Module Functions Definition |
69 | //---------------------------------------------------------------------------------- |
70 | |
71 | // Draw a pixel |
72 | void 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) |
82 | void 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 |
92 | void 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) |
102 | void 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 |
112 | void 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 |
156 | void 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 |
177 | void 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 |
196 | void 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 |
202 | void 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 | |
294 | void 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) |
360 | void 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) |
379 | void DrawCircleV(Vector2 center, float radius, Color color) |
380 | { |
381 | DrawCircleSector(center, radius, 0, 360, 36, color); |
382 | } |
383 | |
384 | // Draw circle outline |
385 | void 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 |
402 | void 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 |
418 | void 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 | |
432 | void 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 | |
528 | void 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 |
611 | void 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) |
618 | void 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 |
624 | void 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 |
630 | void 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) |
662 | void 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) |
669 | void 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 |
676 | void 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) |
708 | void 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 |
734 | void 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 |
749 | void 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 |
971 | void 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 |
1211 | void 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 |
1247 | void 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 |
1266 | void 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 |
1297 | void 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) |
1326 | void 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 |
1378 | void 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 |
1407 | bool 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 |
1417 | bool 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) |
1423 | bool 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 |
1441 | bool 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 |
1452 | bool 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 |
1468 | bool 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 |
1489 | Rectangle 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() |
1561 | static 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 | |