Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.

273 righe
11 KiB

  1. /*******************************************************************************************
  2. *
  3. * raylib [shapes] example - splines drawing
  4. *
  5. * Example originally created with raylib 5.0, last time updated with raylib 5.0
  6. *
  7. * Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
  8. * BSD-like license that allows static linking with closed source software
  9. *
  10. * Copyright (c) 2023 Ramon Santamaria (@raysan5)
  11. *
  12. ********************************************************************************************/
  13. #include "raylib.h"
  14. #define RAYGUI_IMPLEMENTATION
  15. #include "raygui.h" // Required for UI controls
  16. #include <stdlib.h> // Required for: NULL
  17. #define MAX_SPLINE_POINTS 32
  18. // Cubic Bezier spline control points
  19. // NOTE: Every segment has two control points
  20. typedef struct {
  21. Vector2 start;
  22. Vector2 end;
  23. } ControlPoint;
  24. // Spline types
  25. typedef enum {
  26. SPLINE_LINEAR = 0, // Linear
  27. SPLINE_BASIS, // B-Spline
  28. SPLINE_CATMULLROM, // Catmull-Rom
  29. SPLINE_BEZIER // Cubic Bezier
  30. } SplineType;
  31. //------------------------------------------------------------------------------------
  32. // Program main entry point
  33. //------------------------------------------------------------------------------------
  34. int main(void)
  35. {
  36. // Initialization
  37. //--------------------------------------------------------------------------------------
  38. const int screenWidth = 800;
  39. const int screenHeight = 450;
  40. SetConfigFlags(FLAG_MSAA_4X_HINT);
  41. InitWindow(screenWidth, screenHeight, "raylib [shapes] example - splines drawing");
  42. Vector2 points[MAX_SPLINE_POINTS] = {
  43. { 50.0f, 400.0f },
  44. { 160.0f, 220.0f },
  45. { 340.0f, 380.0f },
  46. { 520.0f, 60.0f },
  47. { 710.0f, 260.0f },
  48. };
  49. // Array required for spline bezier-cubic,
  50. // including control points interleaved with start-end segment points
  51. Vector2 pointsInterleaved[3*(MAX_SPLINE_POINTS - 1) + 1] = { 0 };
  52. int pointCount = 5;
  53. int selectedPoint = -1;
  54. int focusedPoint = -1;
  55. Vector2 *selectedControlPoint = NULL;
  56. Vector2 *focusedControlPoint = NULL;
  57. // Cubic Bezier control points initialization
  58. ControlPoint control[MAX_SPLINE_POINTS-1] = { 0 };
  59. for (int i = 0; i < pointCount - 1; i++)
  60. {
  61. control[i].start = (Vector2){ points[i].x + 50, points[i].y };
  62. control[i].end = (Vector2){ points[i + 1].x - 50, points[i + 1].y };
  63. }
  64. // Spline config variables
  65. float splineThickness = 8.0f;
  66. int splineTypeActive = SPLINE_LINEAR; // 0-Linear, 1-BSpline, 2-CatmullRom, 3-Bezier
  67. bool splineTypeEditMode = false;
  68. bool splineHelpersActive = true;
  69. SetTargetFPS(60); // Set our game to run at 60 frames-per-second
  70. //--------------------------------------------------------------------------------------
  71. // Main game loop
  72. while (!WindowShouldClose()) // Detect window close button or ESC key
  73. {
  74. // Update
  75. //----------------------------------------------------------------------------------
  76. // Spline points creation logic (at the end of spline)
  77. if (IsMouseButtonPressed(MOUSE_RIGHT_BUTTON) && (pointCount < MAX_SPLINE_POINTS))
  78. {
  79. points[pointCount] = GetMousePosition();
  80. int i = pointCount - 1;
  81. control[i].start = (Vector2){ points[i].x + 50, points[i].y };
  82. control[i].end = (Vector2){ points[i + 1].x - 50, points[i + 1].y };
  83. pointCount++;
  84. }
  85. // Spline point focus and selection logic
  86. for (int i = 0; i < pointCount; i++)
  87. {
  88. if (CheckCollisionPointCircle(GetMousePosition(), points[i], 8.0f))
  89. {
  90. focusedPoint = i;
  91. if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) selectedPoint = i;
  92. break;
  93. }
  94. else focusedPoint = -1;
  95. }
  96. // Spline point movement logic
  97. if (selectedPoint >= 0)
  98. {
  99. points[selectedPoint] = GetMousePosition();
  100. if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) selectedPoint = -1;
  101. }
  102. // Cubic Bezier spline control points logic
  103. if ((splineTypeActive == SPLINE_BEZIER) && (focusedPoint == -1))
  104. {
  105. // Spline control point focus and selection logic
  106. for (int i = 0; i < pointCount - 1; i++)
  107. {
  108. if (CheckCollisionPointCircle(GetMousePosition(), control[i].start, 6.0f))
  109. {
  110. focusedControlPoint = &control[i].start;
  111. if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) selectedControlPoint = &control[i].start;
  112. break;
  113. }
  114. else if (CheckCollisionPointCircle(GetMousePosition(), control[i].end, 6.0f))
  115. {
  116. focusedControlPoint = &control[i].end;
  117. if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) selectedControlPoint = &control[i].end;
  118. break;
  119. }
  120. else focusedControlPoint = NULL;
  121. }
  122. // Spline control point movement logic
  123. if (selectedControlPoint != NULL)
  124. {
  125. *selectedControlPoint = GetMousePosition();
  126. if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) selectedControlPoint = NULL;
  127. }
  128. }
  129. // Spline selection logic
  130. if (IsKeyPressed(KEY_ONE)) splineTypeActive = 0;
  131. else if (IsKeyPressed(KEY_TWO)) splineTypeActive = 1;
  132. else if (IsKeyPressed(KEY_THREE)) splineTypeActive = 2;
  133. else if (IsKeyPressed(KEY_FOUR)) splineTypeActive = 3;
  134. //----------------------------------------------------------------------------------
  135. // Draw
  136. //----------------------------------------------------------------------------------
  137. BeginDrawing();
  138. ClearBackground(RAYWHITE);
  139. if (splineTypeActive == SPLINE_LINEAR)
  140. {
  141. // Draw spline: linear
  142. DrawSplineLinear(points, pointCount, splineThickness, RED);
  143. }
  144. else if (splineTypeActive == SPLINE_BASIS)
  145. {
  146. // Draw spline: basis
  147. DrawSplineBasis(points, pointCount, splineThickness, RED); // Provide connected points array
  148. /*
  149. for (int i = 0; i < (pointCount - 3); i++)
  150. {
  151. // Drawing individual segments, not considering thickness connection compensation
  152. DrawSplineSegmentBasis(points[i], points[i + 1], points[i + 2], points[i + 3], splineThickness, MAROON);
  153. }
  154. */
  155. }
  156. else if (splineTypeActive == SPLINE_CATMULLROM)
  157. {
  158. // Draw spline: catmull-rom
  159. DrawSplineCatmullRom(points, pointCount, splineThickness, RED); // Provide connected points array
  160. /*
  161. for (int i = 0; i < (pointCount - 3); i++)
  162. {
  163. // Drawing individual segments, not considering thickness connection compensation
  164. DrawSplineSegmentCatmullRom(points[i], points[i + 1], points[i + 2], points[i + 3], splineThickness, MAROON);
  165. }
  166. */
  167. }
  168. else if (splineTypeActive == SPLINE_BEZIER)
  169. {
  170. // NOTE: Cubic-bezier spline requires the 2 control points of each segnment to be
  171. // provided interleaved with the start and end point of every segment
  172. for (int i = 0; i < (pointCount - 1); i++)
  173. {
  174. pointsInterleaved[3*i] = points[i];
  175. pointsInterleaved[3*i + 1] = control[i].start;
  176. pointsInterleaved[3*i + 2] = control[i].end;
  177. }
  178. pointsInterleaved[3*(pointCount - 1)] = points[pointCount - 1];
  179. // Draw spline: cubic-bezier (with control points)
  180. DrawSplineBezierCubic(pointsInterleaved, 3*(pointCount - 1) + 1, splineThickness, RED);
  181. /*
  182. for (int i = 0; i < 3*(pointCount - 1); i += 3)
  183. {
  184. // Drawing individual segments, not considering thickness connection compensation
  185. DrawSplineSegmentBezierCubic(pointsInterleaved[i], pointsInterleaved[i + 1], pointsInterleaved[i + 2], pointsInterleaved[i + 3], splineThickness, MAROON);
  186. }
  187. */
  188. // Draw spline control points
  189. for (int i = 0; i < pointCount - 1; i++)
  190. {
  191. // Every cubic bezier point have two control points
  192. DrawCircleV(control[i].start, 6, GOLD);
  193. DrawCircleV(control[i].end, 6, GOLD);
  194. if (focusedControlPoint == &control[i].start) DrawCircleV(control[i].start, 8, GREEN);
  195. else if (focusedControlPoint == &control[i].end) DrawCircleV(control[i].end, 8, GREEN);
  196. DrawLineEx(points[i], control[i].start, 1.0f, LIGHTGRAY);
  197. DrawLineEx(points[i + 1], control[i].end, 1.0f, LIGHTGRAY);
  198. // Draw spline control lines
  199. DrawLineV(points[i], control[i].start, GRAY);
  200. //DrawLineV(control[i].start, control[i].end, LIGHTGRAY);
  201. DrawLineV(control[i].end, points[i + 1], GRAY);
  202. }
  203. }
  204. if (splineHelpersActive)
  205. {
  206. // Draw spline point helpers
  207. for (int i = 0; i < pointCount; i++)
  208. {
  209. DrawCircleLinesV(points[i], (focusedPoint == i)? 12.0f : 8.0f, (focusedPoint == i)? BLUE: DARKBLUE);
  210. if ((splineTypeActive != SPLINE_LINEAR) &&
  211. (splineTypeActive != SPLINE_BEZIER) &&
  212. (i < pointCount - 1)) DrawLineV(points[i], points[i + 1], GRAY);
  213. DrawText(TextFormat("[%.0f, %.0f]", points[i].x, points[i].y), (int)points[i].x, (int)points[i].y + 10, 10, BLACK);
  214. }
  215. }
  216. // Check all possible UI states that require controls lock
  217. if (splineTypeEditMode) GuiLock();
  218. // Draw spline config
  219. GuiLabel((Rectangle){ 12, 62, 140, 24 }, TextFormat("Spline thickness: %i", (int)splineThickness));
  220. GuiSliderBar((Rectangle){ 12, 60 + 24, 140, 16 }, NULL, NULL, &splineThickness, 1.0f, 40.0f);
  221. GuiCheckBox((Rectangle){ 12, 110, 20, 20 }, "Show point helpers", &splineHelpersActive);
  222. GuiUnlock();
  223. GuiLabel((Rectangle){ 12, 10, 140, 24 }, "Spline type:");
  224. if (GuiDropdownBox((Rectangle){ 12, 8 + 24, 140, 28 }, "LINEAR;BSPLINE;CATMULLROM;BEZIER", &splineTypeActive, splineTypeEditMode)) splineTypeEditMode = !splineTypeEditMode;
  225. EndDrawing();
  226. //----------------------------------------------------------------------------------
  227. }
  228. // De-Initialization
  229. //--------------------------------------------------------------------------------------
  230. CloseWindow(); // Close window and OpenGL context
  231. //--------------------------------------------------------------------------------------
  232. return 0;
  233. }