2
2
*
3
3
* raylib [textures] example - Draw a texture along a segmented curve
4
4
*
5
- * Example originally created with raylib 4.5
5
+ * Example originally created with raylib 4.5-dev
6
6
*
7
7
* Example contributed by Jeffery Myers and reviewed by Ramon Santamaria (@raysan5)
8
8
*
9
9
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
10
10
* BSD-like license that allows static linking with closed source software
11
11
*
12
- * Copyright (c) 2019- 2022 Jeffery Myers and Ramon Santamaria (@raysan5)
12
+ * Copyright (c) 2022 Jeffery Myers and Ramon Santamaria (@raysan5)
13
13
*
14
14
********************************************************************************************/
15
15
16
16
17
17
#include "raylib.h"
18
+
18
19
#include "raymath.h"
19
20
#include "rlgl.h"
20
21
21
- Texture RoadTexture = { 0 };
22
+ #include <math.h> // Required for: powf()
23
+ #include <stdlib.h> // Required for: NULL
24
+
25
+ //----------------------------------------------------------------------------------
26
+ // Global Variables Definition
27
+ //----------------------------------------------------------------------------------
28
+ static Texture texRoad = { 0 };
29
+
30
+ static bool showCurve = false;
31
+
32
+ static float curveWidth = 50 ;
33
+ static int curveSegments = 24 ;
34
+
35
+ static Vector2 curveStartPosition = { 0 };
36
+ static Vector2 curveStartPositionTangent = { 0 };
37
+
38
+ static Vector2 curveEndPosition = { 0 };
39
+ static Vector2 curveEndPositionTangent = { 0 };
40
+
41
+ static Vector2 * curveSelectedPoint = NULL ;
42
+
43
+ //----------------------------------------------------------------------------------
44
+ // Module Functions Declaration
45
+ //----------------------------------------------------------------------------------
46
+ static void UpdateOptions (void );
47
+ static void UpdateCurve (void );
48
+ static void DrawCurve (void );
49
+ static void DrawTexturedCurve (void );
50
+
22
51
23
- bool ShowCurve = false;
52
+ //------------------------------------------------------------------------------------
53
+ // Program main entry point
54
+ //------------------------------------------------------------------------------------
55
+ int main ()
56
+ {
57
+ // Initialization
58
+ //--------------------------------------------------------------------------------------
59
+ const int screenWidth = 800 ;
60
+ const int screenHeight = 450 ;
61
+
62
+ SetConfigFlags (FLAG_VSYNC_HINT | FLAG_MSAA_4X_HINT );
63
+ InitWindow (screenWidth , screenHeight , "raylib [textures] examples - textured curve" );
64
+
65
+ // Load the road texture
66
+ texRoad = LoadTexture ("resources/road.png" );
67
+ SetTextureFilter (texRoad , TEXTURE_FILTER_BILINEAR );
68
+
69
+ // Setup the curve
70
+ curveStartPosition = (Vector2 ){ 80 , 100 };
71
+ curveStartPositionTangent = (Vector2 ){ 100 , 300 };
72
+
73
+ curveEndPosition = (Vector2 ){ 700 , 350 };
74
+ curveEndPositionTangent = (Vector2 ){ 600 , 100 };
75
+
76
+ SetTargetFPS (60 ); // Set our game to run at 60 frames-per-second
77
+ //--------------------------------------------------------------------------------------
78
+
79
+ // Main game loop
80
+ while (!WindowShouldClose ()) // Detect window close button or ESC key
81
+ {
82
+ // Update
83
+ //----------------------------------------------------------------------------------
84
+ UpdateCurve ();
85
+ UpdateOptions ();
24
86
25
- float Width = 50 ;
26
- int Segments = 24 ;
87
+ //----------------------------------------------------------------------------------
27
88
28
- Vector2 SP = { 0 };
29
- Vector2 SPTangent = { 0 };
89
+ // Draw
90
+ //----------------------------------------------------------------------------------
91
+ BeginDrawing ();
30
92
31
- Vector2 EP = { 0 };
32
- Vector2 EPTangent = { 0 };
93
+ ClearBackground (RAYWHITE );
33
94
34
- Vector2 * Selected = NULL ;
95
+ DrawTexturedCurve ();
96
+ DrawCurve ();
97
+
98
+ DrawText ("Drag points to move curve, press SPACE to show/hide base curve" , 10 , 10 , 10 , DARKGRAY );
99
+ DrawText (TextFormat ("Curve width: %2.0f (Use + and - to adjust)" , curveWidth ), 10 , 30 , 10 , DARKGRAY );
100
+ DrawText (TextFormat ("Curve segments: %d (Use LEFT and RIGHT to adjust)" , curveSegments ), 10 , 50 , 10 , DARKGRAY );
101
+
102
+ EndDrawing ();
103
+ //----------------------------------------------------------------------------------
104
+ }
35
105
36
- void DrawCurve ()
106
+ // De-Initialization
107
+ //--------------------------------------------------------------------------------------
108
+ UnloadTexture (texRoad );
109
+
110
+ CloseWindow (); // Close window and OpenGL context
111
+ //--------------------------------------------------------------------------------------
112
+
113
+ return 0 ;
114
+ }
115
+
116
+ //----------------------------------------------------------------------------------
117
+ // Module Functions Definition
118
+ //----------------------------------------------------------------------------------
119
+ static void DrawCurve (void )
37
120
{
38
- if (ShowCurve )
39
- DrawLineBezierCubic (SP , EP , SPTangent , EPTangent , 2 , BLUE );
121
+ if (showCurve ) DrawLineBezierCubic (curveStartPosition , curveEndPosition , curveStartPositionTangent , curveEndPositionTangent , 2 , BLUE );
40
122
41
- // draw the various control points and highlight where the mouse is
42
- DrawLineV (SP , SPTangent , SKYBLUE );
43
- DrawLineV (EP , EPTangent , PURPLE );
123
+ // Draw the various control points and highlight where the mouse is
124
+ DrawLineV (curveStartPosition , curveStartPositionTangent , SKYBLUE );
125
+ DrawLineV (curveEndPosition , curveEndPositionTangent , PURPLE );
44
126
Vector2 mouse = GetMousePosition ();
45
127
46
- if (CheckCollisionPointCircle (mouse , SP , 6 ))
47
- DrawCircleV (SP , 7 , YELLOW );
48
- DrawCircleV (SP , 5 , RED );
128
+ if (CheckCollisionPointCircle (mouse , curveStartPosition , 6 )) DrawCircleV (curveStartPosition , 7 , YELLOW );
129
+ DrawCircleV (curveStartPosition , 5 , RED );
49
130
50
- if (CheckCollisionPointCircle (mouse , SPTangent , 6 ))
51
- DrawCircleV (SPTangent , 7 , YELLOW );
52
- DrawCircleV (SPTangent , 5 , MAROON );
131
+ if (CheckCollisionPointCircle (mouse , curveStartPositionTangent , 6 )) DrawCircleV (curveStartPositionTangent , 7 , YELLOW );
132
+ DrawCircleV (curveStartPositionTangent , 5 , MAROON );
53
133
54
- if (CheckCollisionPointCircle (mouse , EP , 6 ))
55
- DrawCircleV (EP , 7 , YELLOW );
56
- DrawCircleV (EP , 5 , GREEN );
134
+ if (CheckCollisionPointCircle (mouse , curveEndPosition , 6 )) DrawCircleV (curveEndPosition , 7 , YELLOW );
135
+ DrawCircleV (curveEndPosition , 5 , GREEN );
57
136
58
- if (CheckCollisionPointCircle (mouse , EPTangent , 6 ))
59
- DrawCircleV (EPTangent , 7 , YELLOW );
60
- DrawCircleV (EPTangent , 5 , DARKGREEN );
137
+ if (CheckCollisionPointCircle (mouse , curveEndPositionTangent , 6 )) DrawCircleV (curveEndPositionTangent , 7 , YELLOW );
138
+ DrawCircleV (curveEndPositionTangent , 5 , DARKGREEN );
61
139
}
62
140
63
- void EditCurve ( )
141
+ static void UpdateCurve ( void )
64
142
{
65
- // if the mouse is not down, we are not editing the curve so clear the selection
143
+ // If the mouse is not down, we are not editing the curve so clear the selection
66
144
if (!IsMouseButtonDown (MOUSE_LEFT_BUTTON ))
67
145
{
68
- Selected = NULL ;
146
+ curveSelectedPoint = NULL ;
69
147
return ;
70
148
}
71
149
72
- // if a point was selected, move it
73
- if (Selected )
150
+ // If a point was selected, move it
151
+ if (curveSelectedPoint )
74
152
{
75
- * Selected = Vector2Add (* Selected , GetMouseDelta ());
153
+ * curveSelectedPoint = Vector2Add (* curveSelectedPoint , GetMouseDelta ());
76
154
return ;
77
155
}
78
156
79
- // the mouse is down, and nothing was selected, so see if anything was picked
157
+ // The mouse is down, and nothing was selected, so see if anything was picked
80
158
Vector2 mouse = GetMousePosition ();
81
159
82
- if (CheckCollisionPointCircle (mouse , SP , 6 ))
83
- Selected = & SP ;
84
- else if (CheckCollisionPointCircle (mouse , SPTangent , 6 ))
85
- Selected = & SPTangent ;
86
- else if (CheckCollisionPointCircle (mouse , EP , 6 ))
87
- Selected = & EP ;
88
- else if (CheckCollisionPointCircle (mouse , EPTangent , 6 ))
89
- Selected = & EPTangent ;
160
+ if (CheckCollisionPointCircle (mouse , curveStartPosition , 6 )) curveSelectedPoint = & curveStartPosition ;
161
+ else if (CheckCollisionPointCircle (mouse , curveStartPositionTangent , 6 )) curveSelectedPoint = & curveStartPositionTangent ;
162
+ else if (CheckCollisionPointCircle (mouse , curveEndPosition , 6 )) curveSelectedPoint = & curveEndPosition ;
163
+ else if (CheckCollisionPointCircle (mouse , curveEndPositionTangent , 6 )) curveSelectedPoint = & curveEndPositionTangent ;
90
164
}
91
165
92
- void DrawTexturedCurve ()
166
+ static void DrawTexturedCurve (void )
93
167
{
94
- const float step = 1.0f / Segments ;
168
+ const float step = 1.0f / curveSegments ;
95
169
96
- Vector2 previous = SP ;
170
+ Vector2 previous = curveStartPosition ;
97
171
Vector2 previousTangent = { 0 };
98
172
float previousV = 0 ;
99
173
100
- // we can't compute a tangent for the first point, so we need to reuse the tangent from the first segment
174
+ // We can't compute a tangent for the first point, so we need to reuse the tangent from the first segment
101
175
bool tangentSet = false;
102
176
103
177
Vector2 current = { 0 };
104
178
float t = 0.0f ;
105
179
106
- for (int i = 1 ; i <= Segments ; i ++ )
180
+ for (int i = 1 ; i <= curveSegments ; i ++ )
107
181
{
108
- // segment the curve
109
- t = step * i ;
182
+ // Segment the curve
183
+ t = step * i ;
110
184
float a = powf (1 - t , 3 );
111
- float b = 3 * powf (1 - t , 2 ) * t ;
112
- float c = 3 * (1 - t ) * powf (t , 2 );
185
+ float b = 3 * powf (1 - t , 2 )* t ;
186
+ float c = 3 * (1 - t )* powf (t , 2 );
113
187
float d = powf (t , 3 );
114
188
115
- // compute the endpoint for this segment
116
- current .y = a * SP .y + b * SPTangent .y + c * EPTangent .y + d * EP .y ;
117
- current .x = a * SP .x + b * SPTangent .x + c * EPTangent .x + d * EP .x ;
189
+ // Compute the endpoint for this segment
190
+ current .y = a * curveStartPosition .y + b * curveStartPositionTangent .y + c * curveEndPositionTangent .y + d * curveEndPosition .y ;
191
+ current .x = a * curveStartPosition .x + b * curveStartPositionTangent .x + c * curveEndPositionTangent .x + d * curveEndPosition .x ;
118
192
119
- // vector from previous to current
193
+ // Vector from previous to current
120
194
Vector2 delta = { current .x - previous .x , current .y - previous .y };
121
195
122
- // the right hand normal to the delta vector
196
+ // The right hand normal to the delta vector
123
197
Vector2 normal = Vector2Normalize ((Vector2 ){ - delta .y , delta .x });
124
198
125
- // the v texture coordinate of the segment (add up the length of all the segments so far)
199
+ // The v texture coordinate of the segment (add up the length of all the segments so far)
126
200
float v = previousV + Vector2Length (delta );
127
201
128
- // make sure the start point has a normal
202
+ // Make sure the start point has a normal
129
203
if (!tangentSet )
130
204
{
131
205
previousTangent = normal ;
132
206
tangentSet = true;
133
207
}
134
208
135
- // extend out the normals from the previous and current points to get the quad for this segment
136
- Vector2 prevPosNormal = Vector2Add (previous , Vector2Scale (previousTangent , Width ));
137
- Vector2 prevNegNormal = Vector2Add (previous , Vector2Scale (previousTangent , - Width ));
209
+ // Extend out the normals from the previous and current points to get the quad for this segment
210
+ Vector2 prevPosNormal = Vector2Add (previous , Vector2Scale (previousTangent , curveWidth ));
211
+ Vector2 prevNegNormal = Vector2Add (previous , Vector2Scale (previousTangent , - curveWidth ));
138
212
139
- Vector2 currentPosNormal = Vector2Add (current , Vector2Scale (normal , Width ));
140
- Vector2 currentNegNormal = Vector2Add (current , Vector2Scale (normal , - Width ));
213
+ Vector2 currentPosNormal = Vector2Add (current , Vector2Scale (normal , curveWidth ));
214
+ Vector2 currentNegNormal = Vector2Add (current , Vector2Scale (normal , - curveWidth ));
141
215
142
- // draw the segment as a quad
143
- rlSetTexture (RoadTexture .id );
216
+ // Draw the segment as a quad
217
+ rlSetTexture (texRoad .id );
144
218
rlBegin (RL_QUADS );
145
219
146
220
rlColor4ub (255 ,255 ,255 ,255 );
@@ -160,82 +234,26 @@ void DrawTexturedCurve()
160
234
161
235
rlEnd ();
162
236
163
- // the current step is the start of the next step
237
+ // The current step is the start of the next step
164
238
previous = current ;
165
239
previousTangent = normal ;
166
240
previousV = v ;
167
241
}
168
242
}
169
243
170
- void UpdateOptions ()
244
+ static void UpdateOptions (void )
171
245
{
172
- if (IsKeyPressed (KEY_SPACE ))
173
- ShowCurve = !ShowCurve ;
174
-
175
- // width
176
- if (IsKeyPressed (KEY_EQUAL ))
177
- Width += 2 ;
178
-
179
- if (IsKeyPressed (KEY_MINUS ))
180
- Width -= 2 ;
181
-
182
- if (Width < 2 )
183
- Width = 2 ;
246
+ if (IsKeyPressed (KEY_SPACE )) showCurve = !showCurve ;
184
247
185
- // segments
248
+ // Update with
249
+ if (IsKeyPressed (KEY_EQUAL )) curveWidth += 2 ;
250
+ if (IsKeyPressed (KEY_MINUS )) curveWidth -= 2 ;
186
251
187
- if (IsKeyPressed (KEY_LEFT_BRACKET ))
188
- Segments -= 2 ;
252
+ if (curveWidth < 2 ) curveWidth = 2 ;
189
253
190
- if (IsKeyPressed (KEY_RIGHT_BRACKET ))
191
- Segments += 2 ;
254
+ // Update segments
255
+ if (IsKeyPressed (KEY_LEFT )) curveSegments -= 2 ;
256
+ if (IsKeyPressed (KEY_RIGHT )) curveSegments += 2 ;
192
257
193
- if (Segments < 2 )
194
- Segments = 2 ;
258
+ if (curveSegments < 2 ) curveSegments = 2 ;
195
259
}
196
-
197
- int main ()
198
- {
199
- // set up the window
200
- SetConfigFlags (FLAG_VSYNC_HINT );
201
- InitWindow (1280 , 800 , "raylib [textures] examples - textured curve" );
202
- SetTargetFPS (144 );
203
-
204
- // load the road texture
205
- RoadTexture = LoadTexture ("resources/roadTexture_01.png" );
206
-
207
- // setup the curve
208
- SP = (Vector2 ){ 80 , 400 };
209
- SPTangent = (Vector2 ){ 600 , 100 };
210
-
211
- EP = (Vector2 ){ 1200 , 400 };
212
- EPTangent = (Vector2 ){ 600 , 700 };
213
-
214
- // game loop
215
- while (!WindowShouldClose ())
216
- {
217
- EditCurve ();
218
- UpdateOptions ();
219
-
220
- BeginDrawing ();
221
-
222
- ClearBackground (BLACK );
223
-
224
- DrawTexturedCurve ();
225
- DrawCurve ();
226
-
227
- DrawText ("Drag points to move curve, press space to show/hide base curve" , 10 , 0 , 20 , WHITE );
228
- DrawText (TextFormat ("Width %2.0f + and - to adjust" , Width ), 10 , 20 , 20 , WHITE );
229
- DrawText (TextFormat ("Segments %d [ and ] to adjust" , Segments ), 10 , 40 , 20 , WHITE );
230
- DrawFPS (10 , 60 );
231
-
232
- EndDrawing ();
233
- }
234
-
235
- // cleanup
236
- UnloadTexture (RoadTexture );
237
- CloseWindow ();
238
- return 0 ;
239
- }
240
-
241
-
0 commit comments