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