From 6dfaf9fe7edfee08eac7bfabcc3dabcc5147530d Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 30 Dec 2025 21:19:54 +0100 Subject: [PATCH] REVIEWED: example `shapes_hilbert_curve` #5454 Make it more didactic and dynamic, avoid global variables --- examples/shapes/shapes_hilbert_curve.c | 233 ++++++++++++----------- examples/shapes/shapes_hilbert_curve.png | Bin 15288 -> 16975 bytes 2 files changed, 121 insertions(+), 112 deletions(-) diff --git a/examples/shapes/shapes_hilbert_curve.c b/examples/shapes/shapes_hilbert_curve.c index 1af263b34..8ea03c7c5 100644 --- a/examples/shapes/shapes_hilbert_curve.c +++ b/examples/shapes/shapes_hilbert_curve.c @@ -6,7 +6,7 @@ * * Example originally created with raylib 5.6, last time updated with raylib 5.6 * -* Example contributed by Hamza RAHAL (@hmz-rhl) +* Example contributed by Hamza RAHAL (@hmz-rhl) and reviewed by Ramon Santamaria (@raysan5) * * Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, * BSD-like license that allows static linking with closed source software @@ -17,48 +17,18 @@ #include "raylib.h" -#include "raymath.h" -#include -#include -const int screenWidth = 800; +#define RAYGUI_IMPLEMENTATION +#include "raygui.h" -const int screenHeight = 450; - -int order = 2; - -int total; - -int counter = 0; - -Vector2 *hilbertPath = 0; - -const Vector2 hilbertPoints[4] = -{ - [0] = { - .x = 0, - .y = 0 - }, - [1] = { - .x = 0, - .y = 1 - }, - [2] = { - .x = 1, - .y = 1 - }, - [3] = { - .x = 1, - .y = 0 - }, -}; +#include // Required for: calloc(), free() //------------------------------------------------------------------------------------ // Module Functions Declaration //------------------------------------------------------------------------------------ -Vector2 Hilbert(int index); - -void InitHilbertPath(void); +static Vector2 *LoadHilbertPath(int order, float size, int *strokeCount); +static void UnloadHilbertPath(Vector2 *hilbertPath); +static Vector2 ComputeHilbertStep(int order, int index); //------------------------------------------------------------------------------------ // Program main entry point @@ -67,13 +37,23 @@ int main(void) { // Initialization //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; - InitWindow(screenWidth, screenHeight, "raylib [shapes] example - hilbert curve example"); + InitWindow(screenWidth, screenHeight, "raylib [shapes] example - hilbert curve"); - SetTargetFPS(60); // Set our game to run at 60 frames-per-second - - InitHilbertPath(); + int order = 2; + float size = GetScreenHeight(); + int strokeCount = 0; + Vector2 *hilbertPath = LoadHilbertPath(order, size, &strokeCount); + int prevOrder = order; + int prevSize = (int)size; // NOTE: Size from slider is float but for comparison we use int + int counter = 0; + float thick = 2.0f; + bool animate = true; + + SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- // Main game loop @@ -82,34 +62,52 @@ int main(void) { // Update //---------------------------------------------------------------------------------- - if ((IsKeyPressed(KEY_UP)) && (order < 8)) + // Check if order or size have changed to regenerate + // NOTE: Size from slider is float but for comparison we use int + if ((prevOrder != order) || (prevSize != (int)size)) { - counter = 0; - ++order; - InitHilbertPath(); - } - else if((IsKeyPressed(KEY_DOWN)) && (order > 1)) - { - counter = 0; - --order; - InitHilbertPath(); + UnloadHilbertPath(hilbertPath); + hilbertPath = LoadHilbertPath(order, size, &strokeCount); + + if (animate) counter = 0; + else counter = strokeCount; + + prevOrder = order; + prevSize = size; } //---------------------------------------------------------------------------------- // Draw //-------------------------------------------------------------------------- BeginDrawing(); - DrawText(TextFormat("(press UP or DOWN to change)\norder : %d", order), screenWidth/2 + 70, 25, 20, WHITE); - if(counter < total) - { - ClearBackground(BLACK); - for (int i = 1; i <= counter; i++) + ClearBackground(RAYWHITE); + + if (counter < strokeCount) { - DrawLineV(hilbertPath[i], hilbertPath[i-1], ColorFromHSV(((float)i / total) * 360.0f, 1.0f, 1.0f)); + // Draw Hilbert path animation, one stroke every frame + for (int i = 1; i <= counter; i++) + { + DrawLineEx(hilbertPath[i], hilbertPath[i - 1], thick, ColorFromHSV(((float)i/strokeCount)*360.0f, 1.0f, 1.0f)); + } + + counter += 1; } - counter += 1; - } + else + { + // Draw full Hilbert path + for (int i = 1; i < strokeCount; i++) + { + DrawLineEx(hilbertPath[i], hilbertPath[i - 1], thick, ColorFromHSV(((float)i/strokeCount)*360.0f, 1.0f, 1.0f)); + } + } + + // Draw UI using raygui + GuiCheckBox((Rectangle){ 450, 50, 20, 20 }, "ANIMATE GENERATION ON CHANGE", &animate); + GuiSpinner((Rectangle){ 585, 100, 180, 30 }, "HILBERT CURVE ORDER: ", &order, 2, 8, false); + GuiSlider((Rectangle){ 524, 150, 240, 24 }, "THICKNESS: ", NULL, &thick, 1.0f, 10.0f); + GuiSlider((Rectangle){ 524, 190, 240, 24 }, "TOTAL SIZE: ", NULL, &size, 10.0f, GetScreenHeight()*1.5f); + EndDrawing(); //-------------------------------------------------------------------------- } @@ -117,8 +115,9 @@ int main(void) // De-Initialization //-------------------------------------------------------------------------------------- + UnloadHilbertPath(hilbertPath); + CloseWindow(); // Close window and OpenGL context - MemFree(hilbertPath); //-------------------------------------------------------------------------------------- return 0; } @@ -126,62 +125,72 @@ int main(void) //------------------------------------------------------------------------------------ // Module Functions Definition //------------------------------------------------------------------------------------ - -// calculate U positions -Vector2 Hilbert(int index) +// Load the whole Hilbert Path (including each U and their link) +static Vector2 *LoadHilbertPath(int order, float size, int *strokeCount) { + int N = 1 << order; + float len = size/N; + *strokeCount = N*N; - int hiblertIndex = index&3; - Vector2 vect = hilbertPoints[hiblertIndex]; - float temp; - int len; - - for (int j = 1; j < order; j++) + Vector2 *hilbertPath = (Vector2 *)RL_CALLOC(*strokeCount, sizeof(Vector2)); + + for (int i = 0; i < *strokeCount; i++) { - index = index>>2; - hiblertIndex = index&3; - len = 1<> 2; + hilbertIndex = index&3; + len = 1 << j; + + switch (hilbertIndex) + { + case 0: + { + temp = vect.x; + vect.x = vect.y; + vect.y = temp; + } break; + case 2: vect.x += len; + case 1: vect.y += len; break; + case 3: + { + temp = len - 1 - vect.x; + vect.x = 2*len - 1 - vect.y; + vect.y = temp; + } break; + default: break; + } + } + + return vect; } diff --git a/examples/shapes/shapes_hilbert_curve.png b/examples/shapes/shapes_hilbert_curve.png index cbb3d0753b154bac0cc160d140ab5c27e59dbddb..af99cbc493115d0de96f50ce8391f5f6aae85028 100644 GIT binary patch literal 16975 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 FKLA35BUk_c literal 15288 zcmeHOYfuwc6y6O88B8z^js}!REJC&87$JZKffz7?%0r~;pshg=BZ$=&5kVfYAru<~ zw8a6cg>L25DS|?4aZm(`)LLPMDx!!?6_5^(B9X^{>D>eiiCHMqA9n2hvy(|6d+v9> z^L^*uJxTQTTu0Y4(nAo0?(XL5gCJUF2!d8pb-+6d0=}z75QkWI*EPNo9|Qyn1VeRf zJ-&;8qpkT8r_ZY37~Q~FY$J;13->&O*&Qd%Da9E~x=6zXmEiid!o`|DB>o|s#kSY7 z%E((s7DnfM3TB*wSKE@sz-~qjJ+w5(2Li8Jq0QgJ`o*+yokn>)$ z#vFh})-PA!oESQ?<-!OxOuQ|%1#gKl zYm@4D%i^~9Lj7p-w3JYnB~G8p7L>)-(&zXzyi*uqHt)*k&DPs~$xS`m`m;<oWjORZHLiB+ky1)41HvpmEb-3Ttwi$t6pJR%;r7L>z(W^JxRROGiUGx~lJN=0{s$POl@ zoQyo)z)kn+%`y*nP4_*F+mA}N=eU@*<=)8;sLpT+J~~$~*6)cOul;0(Tz9?Wxu=H# z^Gcf45;q}9M0o<{SbVP%kA%hTx``BrH2JStTM+3tYvu2q^k<(elid!s2)q=y$?w;u zO-4=w;dcq(OQ!^$C|%XMp}EA}E`3&H#tPG$8(B}kGxs6x>eNjNW|@Gq)NEy;*Miv$u^?JQJlQ;t>On+i}qPtYIU1@G}x5#$Nn87Z_{k{39|YCCCU`pj+xSXRgj{iT@s|Q+<^Tj z-jK=P{D4q7q#P`9Iv2I0O2qU+?nlEkD{4 zW?@Gv0)$yaO{KJi*b_SRFGN6u8>ZmCj#HJIdfP#*HX#xnN49fn%u3wU9x%^xW!EMyi?2*D^TWYx&?KJ)X~)P1*GT zjsu`o-yD&DD>`iIoFPpJqnfkXZ2J>6ZQlAKISorcke4gqOX9(c$qtY=pCaX+dXX&Y z06ut!F?2N+cy;6Ej#$YUO-jScYjK~T$6_SgaZYFdH$AClcaQQ`BANNjPRE5<6raE0 zGl0np7P|}x{}*aHJK?v4_YA(G04R&?ZI_UIODGLeNFh3)v|$5M4fxS~(lZk;igu z=ua3CY@_I^#o9gA(xB?>MXASWQtaJ>YWvcvD_R#2rf(8sBO$i-w{<3PjN$2GRDYi7YR#G7!=H^;T`H#S3 z(^=f>mM4NLvyI~WX>vmoD``!ukj44?9^7(t0uJOLeGRjg_rGQ6E1_Ck(te07wn zkHLKZm`w(A@{Uwx;Az?^EMmgsH6QxH5Qxk}6d(#Oy%%x;ashH-;uIFDBhiCG6d(#O zJ8{Sb$OXs+LK7hhub?0>?C~E@Q$r9;5&O