Skip to content

Commit 8969884

Browse files
committed
REVIEWED: Example: textures_textured_curve
1 parent 57dd345 commit 8969884

File tree

3 files changed

+152
-134
lines changed

3 files changed

+152
-134
lines changed
File renamed without changes.

examples/textures/textures_textured_curve.c

Lines changed: 152 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -2,145 +2,219 @@
22
*
33
* raylib [textures] example - Draw a texture along a segmented curve
44
*
5-
* Example originally created with raylib 4.5
5+
* Example originally created with raylib 4.5-dev
66
*
77
* Example contributed by Jeffery Myers and reviewed by Ramon Santamaria (@raysan5)
88
*
99
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
1010
* BSD-like license that allows static linking with closed source software
1111
*
12-
* Copyright (c) 2019-2022 Jeffery Myers and Ramon Santamaria (@raysan5)
12+
* Copyright (c) 2022 Jeffery Myers and Ramon Santamaria (@raysan5)
1313
*
1414
********************************************************************************************/
1515

1616

1717
#include "raylib.h"
18+
1819
#include "raymath.h"
1920
#include "rlgl.h"
2021

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+
2251

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();
2486

25-
float Width = 50;
26-
int Segments = 24;
87+
//----------------------------------------------------------------------------------
2788

28-
Vector2 SP = { 0 };
29-
Vector2 SPTangent = { 0 };
89+
// Draw
90+
//----------------------------------------------------------------------------------
91+
BeginDrawing();
3092

31-
Vector2 EP = { 0 };
32-
Vector2 EPTangent = { 0 };
93+
ClearBackground(RAYWHITE);
3394

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+
}
35105

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)
37120
{
38-
if (ShowCurve)
39-
DrawLineBezierCubic(SP, EP, SPTangent, EPTangent, 2, BLUE);
121+
if (showCurve) DrawLineBezierCubic(curveStartPosition, curveEndPosition, curveStartPositionTangent, curveEndPositionTangent, 2, BLUE);
40122

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);
44126
Vector2 mouse = GetMousePosition();
45127

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);
49130

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);
53133

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);
57136

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);
61139
}
62140

63-
void EditCurve()
141+
static void UpdateCurve(void)
64142
{
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
66144
if (!IsMouseButtonDown(MOUSE_LEFT_BUTTON))
67145
{
68-
Selected = NULL;
146+
curveSelectedPoint = NULL;
69147
return;
70148
}
71149

72-
// if a point was selected, move it
73-
if (Selected)
150+
// If a point was selected, move it
151+
if (curveSelectedPoint)
74152
{
75-
*Selected = Vector2Add(*Selected, GetMouseDelta());
153+
*curveSelectedPoint = Vector2Add(*curveSelectedPoint, GetMouseDelta());
76154
return;
77155
}
78156

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
80158
Vector2 mouse = GetMousePosition();
81159

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;
90164
}
91165

92-
void DrawTexturedCurve()
166+
static void DrawTexturedCurve(void)
93167
{
94-
const float step = 1.0f / Segments;
168+
const float step = 1.0f/curveSegments;
95169

96-
Vector2 previous = SP;
170+
Vector2 previous = curveStartPosition;
97171
Vector2 previousTangent = { 0 };
98172
float previousV = 0;
99173

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
101175
bool tangentSet = false;
102176

103177
Vector2 current = { 0 };
104178
float t = 0.0f;
105179

106-
for (int i = 1; i <= Segments; i++)
180+
for (int i = 1; i <= curveSegments; i++)
107181
{
108-
// segment the curve
109-
t = step * i;
182+
// Segment the curve
183+
t = step*i;
110184
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);
113187
float d = powf(t, 3);
114188

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;
118192

119-
// vector from previous to current
193+
// Vector from previous to current
120194
Vector2 delta = { current.x - previous.x, current.y - previous.y };
121195

122-
// the right hand normal to the delta vector
196+
// The right hand normal to the delta vector
123197
Vector2 normal = Vector2Normalize((Vector2){ -delta.y, delta.x });
124198

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)
126200
float v = previousV + Vector2Length(delta);
127201

128-
// make sure the start point has a normal
202+
// Make sure the start point has a normal
129203
if (!tangentSet)
130204
{
131205
previousTangent = normal;
132206
tangentSet = true;
133207
}
134208

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));
138212

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));
141215

142-
// draw the segment as a quad
143-
rlSetTexture(RoadTexture.id);
216+
// Draw the segment as a quad
217+
rlSetTexture(texRoad.id);
144218
rlBegin(RL_QUADS);
145219

146220
rlColor4ub(255,255,255,255);
@@ -160,82 +234,26 @@ void DrawTexturedCurve()
160234

161235
rlEnd();
162236

163-
// the current step is the start of the next step
237+
// The current step is the start of the next step
164238
previous = current;
165239
previousTangent = normal;
166240
previousV = v;
167241
}
168242
}
169243

170-
void UpdateOptions()
244+
static void UpdateOptions(void)
171245
{
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;
184247

185-
// segments
248+
// Update with
249+
if (IsKeyPressed(KEY_EQUAL)) curveWidth += 2;
250+
if (IsKeyPressed(KEY_MINUS)) curveWidth -= 2;
186251

187-
if (IsKeyPressed(KEY_LEFT_BRACKET))
188-
Segments -= 2;
252+
if (curveWidth < 2) curveWidth = 2;
189253

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;
192257

193-
if (Segments < 2)
194-
Segments = 2;
258+
if (curveSegments < 2) curveSegments = 2;
195259
}
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-
26.3 KB
Loading

0 commit comments

Comments
 (0)