Skip to content

Commit 6dfaf9f

Browse files
committed
REVIEWED: example shapes_hilbert_curve #5454
Make it more didactic and dynamic, avoid global variables
1 parent 7523738 commit 6dfaf9f

File tree

2 files changed

+109
-100
lines changed

2 files changed

+109
-100
lines changed

examples/shapes/shapes_hilbert_curve.c

Lines changed: 109 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
*
77
* Example originally created with raylib 5.6, last time updated with raylib 5.6
88
*
9-
* Example contributed by Hamza RAHAL (@hmz-rhl)
9+
* Example contributed by Hamza RAHAL (@hmz-rhl) and reviewed by Ramon Santamaria (@raysan5)
1010
*
1111
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
1212
* BSD-like license that allows static linking with closed source software
@@ -17,48 +17,18 @@
1717

1818

1919
#include "raylib.h"
20-
#include "raymath.h"
21-
#include <stdlib.h>
22-
#include <stdio.h>
2320

24-
const int screenWidth = 800;
21+
#define RAYGUI_IMPLEMENTATION
22+
#include "raygui.h"
2523

26-
const int screenHeight = 450;
27-
28-
int order = 2;
29-
30-
int total;
31-
32-
int counter = 0;
33-
34-
Vector2 *hilbertPath = 0;
35-
36-
const Vector2 hilbertPoints[4] =
37-
{
38-
[0] = {
39-
.x = 0,
40-
.y = 0
41-
},
42-
[1] = {
43-
.x = 0,
44-
.y = 1
45-
},
46-
[2] = {
47-
.x = 1,
48-
.y = 1
49-
},
50-
[3] = {
51-
.x = 1,
52-
.y = 0
53-
},
54-
};
24+
#include <stdlib.h> // Required for: calloc(), free()
5525

5626
//------------------------------------------------------------------------------------
5727
// Module Functions Declaration
5828
//------------------------------------------------------------------------------------
59-
Vector2 Hilbert(int index);
60-
61-
void InitHilbertPath(void);
29+
static Vector2 *LoadHilbertPath(int order, float size, int *strokeCount);
30+
static void UnloadHilbertPath(Vector2 *hilbertPath);
31+
static Vector2 ComputeHilbertStep(int order, int index);
6232

6333
//------------------------------------------------------------------------------------
6434
// Program main entry point
@@ -67,13 +37,23 @@ int main(void)
6737
{
6838
// Initialization
6939
//--------------------------------------------------------------------------------------
40+
const int screenWidth = 800;
41+
const int screenHeight = 450;
7042

71-
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - hilbert curve example");
72-
73-
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
43+
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - hilbert curve");
7444

75-
InitHilbertPath();
45+
int order = 2;
46+
float size = GetScreenHeight();
47+
int strokeCount = 0;
48+
Vector2 *hilbertPath = LoadHilbertPath(order, size, &strokeCount);
7649

50+
int prevOrder = order;
51+
int prevSize = (int)size; // NOTE: Size from slider is float but for comparison we use int
52+
int counter = 0;
53+
float thick = 2.0f;
54+
bool animate = true;
55+
56+
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
7757
//--------------------------------------------------------------------------------------
7858

7959
// Main game loop
@@ -82,106 +62,135 @@ int main(void)
8262
{
8363
// Update
8464
//----------------------------------------------------------------------------------
85-
if ((IsKeyPressed(KEY_UP)) && (order < 8))
65+
// Check if order or size have changed to regenerate
66+
// NOTE: Size from slider is float but for comparison we use int
67+
if ((prevOrder != order) || (prevSize != (int)size))
8668
{
87-
counter = 0;
88-
++order;
89-
InitHilbertPath();
90-
}
91-
else if((IsKeyPressed(KEY_DOWN)) && (order > 1))
92-
{
93-
counter = 0;
94-
--order;
95-
InitHilbertPath();
69+
UnloadHilbertPath(hilbertPath);
70+
hilbertPath = LoadHilbertPath(order, size, &strokeCount);
71+
72+
if (animate) counter = 0;
73+
else counter = strokeCount;
74+
75+
prevOrder = order;
76+
prevSize = size;
9677
}
9778
//----------------------------------------------------------------------------------
9879

9980
// Draw
10081
//--------------------------------------------------------------------------
10182
BeginDrawing();
102-
DrawText(TextFormat("(press UP or DOWN to change)\norder : %d", order), screenWidth/2 + 70, 25, 20, WHITE);
10383

104-
if(counter < total)
105-
{
106-
ClearBackground(BLACK);
107-
for (int i = 1; i <= counter; i++)
84+
ClearBackground(RAYWHITE);
85+
86+
if (counter < strokeCount)
10887
{
109-
DrawLineV(hilbertPath[i], hilbertPath[i-1], ColorFromHSV(((float)i / total) * 360.0f, 1.0f, 1.0f));
88+
// Draw Hilbert path animation, one stroke every frame
89+
for (int i = 1; i <= counter; i++)
90+
{
91+
DrawLineEx(hilbertPath[i], hilbertPath[i - 1], thick, ColorFromHSV(((float)i/strokeCount)*360.0f, 1.0f, 1.0f));
92+
}
93+
94+
counter += 1;
11095
}
111-
counter += 1;
112-
}
96+
else
97+
{
98+
// Draw full Hilbert path
99+
for (int i = 1; i < strokeCount; i++)
100+
{
101+
DrawLineEx(hilbertPath[i], hilbertPath[i - 1], thick, ColorFromHSV(((float)i/strokeCount)*360.0f, 1.0f, 1.0f));
102+
}
103+
}
104+
105+
// Draw UI using raygui
106+
GuiCheckBox((Rectangle){ 450, 50, 20, 20 }, "ANIMATE GENERATION ON CHANGE", &animate);
107+
GuiSpinner((Rectangle){ 585, 100, 180, 30 }, "HILBERT CURVE ORDER: ", &order, 2, 8, false);
108+
GuiSlider((Rectangle){ 524, 150, 240, 24 }, "THICKNESS: ", NULL, &thick, 1.0f, 10.0f);
109+
GuiSlider((Rectangle){ 524, 190, 240, 24 }, "TOTAL SIZE: ", NULL, &size, 10.0f, GetScreenHeight()*1.5f);
110+
113111
EndDrawing();
114112
//--------------------------------------------------------------------------
115113
}
116114
//--------------------------------------------------------------------------------------
117115

118116
// De-Initialization
119117
//--------------------------------------------------------------------------------------
118+
UnloadHilbertPath(hilbertPath);
119+
120120
CloseWindow(); // Close window and OpenGL context
121-
MemFree(hilbertPath);
122121
//--------------------------------------------------------------------------------------
123122
return 0;
124123
}
125124

126125
//------------------------------------------------------------------------------------
127126
// Module Functions Definition
128127
//------------------------------------------------------------------------------------
128+
// Load the whole Hilbert Path (including each U and their link)
129+
static Vector2 *LoadHilbertPath(int order, float size, int *strokeCount)
130+
{
131+
int N = 1 << order;
132+
float len = size/N;
133+
*strokeCount = N*N;
129134

130-
// calculate U positions
131-
Vector2 Hilbert(int index)
135+
Vector2 *hilbertPath = (Vector2 *)RL_CALLOC(*strokeCount, sizeof(Vector2));
136+
137+
for (int i = 0; i < *strokeCount; i++)
138+
{
139+
hilbertPath[i] = ComputeHilbertStep(order, i);
140+
hilbertPath[i].x = hilbertPath[i].x*len + len/2.0f;
141+
hilbertPath[i].y = hilbertPath[i].y*len + len/2.0f;
142+
}
143+
144+
return hilbertPath;
145+
}
146+
147+
// Unload Hilbert path data
148+
static void UnloadHilbertPath(Vector2 *hilbertPath)
132149
{
150+
RL_FREE(hilbertPath);
151+
}
133152

134-
int hiblertIndex = index&3;
135-
Vector2 vect = hilbertPoints[hiblertIndex];
136-
float temp;
137-
int len;
153+
// Compute Hilbert path U positions
154+
static Vector2 ComputeHilbertStep(int order, int index)
155+
{
156+
// Hilbert points base pattern
157+
static const Vector2 hilbertPoints[4] = {
158+
[0] = { .x = 0, .y = 0 },
159+
[1] = { .x = 0, .y = 1 },
160+
[2] = { .x = 1, .y = 1 },
161+
[3] = { .x = 1, .y = 0 },
162+
};
163+
164+
int hilbertIndex = index&3;
165+
Vector2 vect = hilbertPoints[hilbertIndex];
166+
float temp = 0.0f;
167+
int len = 0;
138168

139169
for (int j = 1; j < order; j++)
140170
{
141-
index = index>>2;
142-
hiblertIndex = index&3;
143-
len = 1<<j;
144-
switch (hiblertIndex)
171+
index = index >> 2;
172+
hilbertIndex = index&3;
173+
len = 1 << j;
174+
175+
switch (hilbertIndex)
145176
{
146177
case 0:
178+
{
147179
temp = vect.x;
148180
vect.x = vect.y;
149181
vect.y = temp;
150-
break;
151-
case 2:
152-
vect.x += len;
153-
case 1:
154-
vect.y += len;
155-
break;
182+
} break;
183+
case 2: vect.x += len;
184+
case 1: vect.y += len; break;
156185
case 3:
186+
{
157187
temp = len - 1 - vect.x;
158188
vect.x = 2*len - 1 - vect.y;
159189
vect.y = temp;
160-
break;
190+
} break;
191+
default: break;
161192
}
162193
}
194+
163195
return vect;
164196
}
165-
166-
// Calculate the whole Hilbert Path (including each U and their link)
167-
void InitHilbertPath(void)
168-
{
169-
int N;
170-
float len;
171-
N = 1<<order;
172-
total = N*N;
173-
MemFree(hilbertPath);
174-
hilbertPath = NULL;
175-
hilbertPath = (Vector2*)MemAlloc(sizeof(Vector2)*total);
176-
if(hilbertPath == NULL)
177-
{
178-
printf("%s: malloc failed\n", __func__);
179-
}
180-
len = (float)screenHeight/N;
181-
for (int i = 0; i < total; i++)
182-
{
183-
hilbertPath[i] = Hilbert(i);
184-
hilbertPath[i].x = hilbertPath[i].x*len + len/2.0f;
185-
hilbertPath[i].y = hilbertPath[i].y*len + len/2.0f;
186-
}
187-
}
1.65 KB
Loading

0 commit comments

Comments
 (0)