From c69b89cc42747d5bb3e7dd7c0088a229820e75ae Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 9 Nov 2023 02:01:00 +0100 Subject: [PATCH] Update example: shapes_splines_drawing --- examples/shapes/shapes_splines_drawing.c | 107 ++++++++++++++------- examples/shapes/shapes_splines_drawing.png | Bin 0 -> 26123 bytes 2 files changed, 73 insertions(+), 34 deletions(-) create mode 100644 examples/shapes/shapes_splines_drawing.png diff --git a/examples/shapes/shapes_splines_drawing.c b/examples/shapes/shapes_splines_drawing.c index 17dd00752..435ff79b9 100644 --- a/examples/shapes/shapes_splines_drawing.c +++ b/examples/shapes/shapes_splines_drawing.c @@ -13,6 +13,9 @@ #include "raylib.h" +#define RAYGUI_IMPLEMENTATION +#include "raygui.h" // Required for UI controls + #include // Required for: NULL #define MAX_SPLINE_POINTS 32 @@ -46,11 +49,11 @@ int main(void) InitWindow(screenWidth, screenHeight, "raylib [shapes] example - splines drawing"); Vector2 points[MAX_SPLINE_POINTS] = { - { 100.0f, 200.0f }, - { 300.0f, 400.0f }, - { 500.0f, 300.0f }, - { 700.0f, 100.0f }, - { 200.0f, 100.0f }, + { 50.0f, 400.0f }, + { 160.0f, 220.0f }, + { 340.0f, 380.0f }, + { 520.0f, 60.0f }, + { 710.0f, 260.0f }, }; int pointCount = 5; @@ -59,15 +62,19 @@ int main(void) Vector2 *selectedControlPoint = NULL; Vector2 *focusedControlPoint = NULL; - int splineType = SPLINE_LINEAR; // 0-Linear, 1-BSpline, 2-CatmullRom, 3-Bezier - // Cubic Bezier control points initialization ControlPoint control[MAX_SPLINE_POINTS] = { 0 }; for (int i = 0; i < pointCount - 1; i++) { - control[i].start = (Vector2){ points[i].x - 20, points[i].y - 20 }; - control[i].end = (Vector2){ points[i + 1].x + 20, points[i + 1].y + 20 }; + control[i].start = (Vector2){ points[i].x + 50, points[i].y }; + control[i].end = (Vector2){ points[i + 1].x - 50, points[i + 1].y }; } + + // Spline config variables + float splineThickness = 8.0f; + int splineTypeActive = SPLINE_LINEAR; // 0-Linear, 1-BSpline, 2-CatmullRom, 3-Bezier + bool splineTypeEditMode = false; + bool splineHelpersActive = true; SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- @@ -104,7 +111,7 @@ int main(void) } // Cubic Bezier spline control points logic - if ((splineType == SPLINE_BEZIER) && (focusedPoint == -1)) + if ((splineTypeActive == SPLINE_BEZIER) && (focusedPoint == -1)) { // Spline control point focus and selection logic for (int i = 0; i < pointCount; i++) @@ -133,10 +140,10 @@ int main(void) } // Spline selection logic - if (IsKeyPressed(KEY_ONE)) splineType = 0; - else if (IsKeyPressed(KEY_TWO)) splineType = 1; - else if (IsKeyPressed(KEY_THREE)) splineType = 2; - else if (IsKeyPressed(KEY_FOUR)) splineType = 3; + if (IsKeyPressed(KEY_ONE)) splineTypeActive = 0; + else if (IsKeyPressed(KEY_TWO)) splineTypeActive = 1; + else if (IsKeyPressed(KEY_THREE)) splineTypeActive = 2; + else if (IsKeyPressed(KEY_FOUR)) splineTypeActive = 3; //---------------------------------------------------------------------------------- // Draw @@ -145,29 +152,44 @@ int main(void) ClearBackground(RAYWHITE); - if (splineType == SPLINE_LINEAR) + if (splineTypeActive == SPLINE_LINEAR) { // Draw spline: linear - DrawSplineLinear(points, pointCount, 2.0f, RED); + DrawSplineLinear(points, pointCount, splineThickness, RED); } - else if (splineType == SPLINE_BASIS) + else if (splineTypeActive == SPLINE_BASIS) { // Draw spline: basis - DrawSplineBasis(points, pointCount, 2.0f, RED); - //for (int i = 0; i < (pointCount - 3); i++) DrawSplineBasisSegment(points[i], points[i + 1], points[i + 2], points[i + 3], 24.0f, BLUE); + DrawSplineBasis(points, pointCount, splineThickness, RED); // Provide connected points array + + /* + for (int i = 0; i < (pointCount - 3); i++) + { + // Drawing individual segments, not considering thickness connection compensation + DrawSplineSegmentBasis(points[i], points[i + 1], points[i + 2], points[i + 3], splineThickness, MAROON); + } + */ } - else if (splineType == SPLINE_CATMULLROM) + else if (splineTypeActive == SPLINE_CATMULLROM) { // Draw spline: catmull-rom - DrawSplineCatmullRom(points, pointCount, 2.0f, RED); - //for (int i = 0; i < (pointCount - 3); i++) DrawSplineCatmullRomSegment(points[i], points[i + 1], points[i + 2], points[i + 3], 24.0f, Fade(BLUE, 0.4f)); + DrawSplineCatmullRom(points, pointCount, splineThickness, RED); // Provide connected points array + + /* + for (int i = 0; i < (pointCount - 3); i++) + { + // Drawing individual segments, not considering thickness connection compensation + DrawSplineSegmentCatmullRom(points[i], points[i + 1], points[i + 2], points[i + 3], splineThickness, MAROON); + } + */ } - else if (splineType == SPLINE_BEZIER) + else if (splineTypeActive == SPLINE_BEZIER) { // Draw spline: cubic-bezier (with control points) for (int i = 0; i < pointCount - 1; i++) { - DrawSplineSegmentBezierCubic(points[i], control[i].start, control[i].end, points[i + 1], 10.0f, RED); + // Drawing individual segments, not considering thickness connection compensation + DrawSplineSegmentBezierCubic(points[i], control[i].start, control[i].end, points[i + 1], splineThickness, RED); // Every cubic bezier point should have two control points DrawCircleV(control[i].start, 4, GOLD); @@ -178,22 +200,39 @@ int main(void) DrawLineEx(points[i + 1], control[i].end, 1.0, LIGHTGRAY); // Draw spline control lines - DrawLineV(points[i], control[i].start, LIGHTGRAY); - DrawLineV(control[i].start, control[i].end, LIGHTGRAY); - DrawLineV(control[i].end, points[i + 1], LIGHTGRAY); + DrawLineV(points[i], control[i].start, GRAY); + //DrawLineV(control[i].start, control[i].end, LIGHTGRAY); + DrawLineV(control[i].end, points[i + 1], GRAY); } } - // Draw spline key-points - for (int i = 0; i < pointCount; i++) + if (splineHelpersActive) { - DrawCircleV(points[i], (focusedPoint == i)? 8.0f : 5.0f, (focusedPoint == i)? BLUE: RED); - if ((splineType != SPLINE_LINEAR) && - (splineType != SPLINE_BEZIER) && - (i < pointCount - 1)) DrawLineV(points[i], points[i + 1], LIGHTGRAY); + // Draw spline point helpers + for (int i = 0; i < pointCount; i++) + { + DrawCircleLinesV(points[i], (focusedPoint == i)? 12.0f : 8.0f, (focusedPoint == i)? BLUE: DARKBLUE); + if ((splineTypeActive != SPLINE_LINEAR) && + (splineTypeActive != SPLINE_BEZIER) && + (i < pointCount - 1)) DrawLineV(points[i], points[i + 1], GRAY); + + DrawText(TextFormat("[%.0f, %.0f]", points[i].x, points[i].y), points[i].x, points[i].y + 10, 10, BLACK); + } } + + // Check all possible UI states that require controls lock + if (splineTypeEditMode) GuiLock(); - // TODO: Draw help + // Draw spline config + GuiLabel((Rectangle){ 12, 62, 140, 24 }, TextFormat("Spline thickness: %i", (int)splineThickness)); + GuiSliderBar((Rectangle){ 12, 60 + 24, 140, 16 }, NULL, NULL, &splineThickness, 1.0f, 40.0f); + + GuiCheckBox((Rectangle){ 12, 110, 20, 20 }, "Show point helpers", &splineHelpersActive); + + GuiUnlock(); + + GuiLabel((Rectangle){ 12, 10, 140, 24 }, "Spline type:"); + if (GuiDropdownBox((Rectangle){ 12, 8 + 24, 140, 28 }, "LINEAR;BSPLINE;CATMULLROM;BEZIER", &splineTypeActive, splineTypeEditMode)) splineTypeEditMode = !splineTypeEditMode; EndDrawing(); //---------------------------------------------------------------------------------- diff --git a/examples/shapes/shapes_splines_drawing.png b/examples/shapes/shapes_splines_drawing.png new file mode 100644 index 0000000000000000000000000000000000000000..686f04c11831316662f22dd8d9ebd7d180eee5fd GIT binary patch literal 26123 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
E zvX5`Jfkn+<*~1H8=S$wYcAxS0%9wZB%$qmb&B^DE$qSWTaf)G)`(%_;3t%TSSOhU= zXtHJaT9}&6?VtDBe%4brFOCiN9}Yy69sR?*3Dhq6yFKIU2A-~KrQ09=+jLokZL_G~Z4Et*C>W7!!z zK$r2+?QJ)kyZO9+F# zu4X)W@W+lTkGUOd$`-tCzS-+5b5j;+2pSX#8L~{ypOl;ejxR3#o68o#&QfxUM`MA* zY)40lBkXGrtEKUp=~~GtZ0{+vb2EOQ!O`nGU^Vo zcDwu$Q5AtViMPeDvuwF3eC6bgz|?aI(W)&%a+bL-6YAb)YqRkOW`FoN{pqI(O9d84 zcR5a4z{lRv7Hj3!J^QS?wftg9qE=kH1WvFnELVe<`rtR74y zdiEUb_1y_Sets2X{$%-giyy}V<#NkQkK8ZA>Ij1evyLjHl{MdZu((}zaUjwTS}CS0 zJdKK%85woAGo7tTcwN)L#B$q*?ZvVr&>4lN^ZO;&G|Z5j+kf%5otyCskS7^*ST^XE zE2U?O?GuoV%`%;Zyj3QO!+=+mz1eKm;crzF9z8SV4>xGY(^=MT5Aql*q%{pP1cmj0 zzfsYcxhek}^L%kfV|m4xO+3dNW=z|xu;4VCyD-cT2b>z_q=x;N7My5(OMJfUV(-mv zmyymxN#Jc%yvXRdFI6Jk;h$}F;(g(&5onNI{d?+(-3|$_3Rb$? zZxgpHDSW9II%igOklW?|$gUFL0y)SjFsDEqQ8o zb`Sfjnx1z*CC>hXByQBavRKg}ii4+l*Le~XrPnkFrohe z>-h$TbVrE=o8_OEgd9|StnqPHV&6RT=8I3G6YMNED=+q5=eGGKa&SP6IFJEaZtA>< zIcc@#5r#txb~`wjXvW?9?=)rMjE5S{-@ghc;G^CwQh??u7zyceV zwlh2)r3xdb=BMM$A8W>Qt7=S?s|D@~a|CTL?SLllTC2mJ&_H7ZGtcmVN10 z^V4u-+*M-0a^ok1?0)Z@=gcV#zjBUmOrFqp`s3r{k}0XFk|`-E2fp=`dANPPhdmf4 zh%-5_V`loKmZ5(FRFFH!3JUB8mE$i|bS@NW3&?NrSE)a4!WLsbzu8J^!-FIC**sw%Um##^B6>m(74%7}@Apf}A#(GoMRjozSvJGo(&m8#kR)D$1 z?#zeiEnN@wr^_C;&%1r`4$4AkL{4wkVrhFSr1M3`IZ18=X$*)STXP;c3Ul z$rp-rBc3;ZEtPI7w0~0GQ|9Ex4H{VnHA)aEUxK&MQIu)1_Xf7gCY3EQ-f=JNnuU%V zu~jOvJy_EYISJH#&H8A`x}x_IXNwS4qp&iZ5+ceRKIqOor0Ra|4U66848g-Urez!M zjXP5CVWTp5K%`9Tx8$2pK{MleYnxeDVUdRt2hIrrtp{G%DjayBu>7-QmQK;-7xRQb zEv4l$d)}T%Sp1(oRqV;^Yu7L8m_wV6D6WuVYF1;J(dHe~@U3jZ?u&Eeri%wXva2cl zGM#(l#XE7O_FX|2(!N~WgX0+TW=)nEZi|yM+7IMk%o5>0FfI0=-yx~q``BXgqJV^t zqCw8Igx)79tu;bo8Ez~kf8M`~pTohOk4IYp1#dTb` z6jKR!rF=#b_M8K1%wrzrfgINl#X%E*i&uizkD=!wP&72;fqGYxqfP+L;*EyFhzJD+ Z-NNf4&nI>ZFfcGMc)I$ztaD0e0suTL`pN(R literal 0 HcmV?d00001