|
@ -59,19 +59,19 @@ int main() |
|
|
const int screenWidth = 800; |
|
|
const int screenWidth = 800; |
|
|
const int screenHeight = 450; |
|
|
const int screenHeight = 450; |
|
|
|
|
|
|
|
|
SetConfigFlags(FLAG_VSYNC_HINT | FLAG_MSAA_4X_HINT); |
|
|
|
|
|
InitWindow(screenWidth, screenHeight, "raylib [textures] examples - textured curve"); |
|
|
|
|
|
|
|
|
SetConfigFlags(FLAG_VSYNC_HINT | FLAG_MSAA_4X_HINT); |
|
|
|
|
|
InitWindow(screenWidth, screenHeight, "raylib [textures] examples - textured curve"); |
|
|
|
|
|
|
|
|
// Load the road texture |
|
|
|
|
|
texRoad = LoadTexture("resources/road.png"); |
|
|
|
|
|
|
|
|
// Load the road texture |
|
|
|
|
|
texRoad = LoadTexture("resources/road.png"); |
|
|
SetTextureFilter(texRoad, TEXTURE_FILTER_BILINEAR); |
|
|
SetTextureFilter(texRoad, TEXTURE_FILTER_BILINEAR); |
|
|
|
|
|
|
|
|
// Setup the curve |
|
|
|
|
|
curveStartPosition = (Vector2){ 80, 100 }; |
|
|
|
|
|
curveStartPositionTangent = (Vector2){ 100, 300 }; |
|
|
|
|
|
|
|
|
// Setup the curve |
|
|
|
|
|
curveStartPosition = (Vector2){ 80, 100 }; |
|
|
|
|
|
curveStartPositionTangent = (Vector2){ 100, 300 }; |
|
|
|
|
|
|
|
|
curveEndPosition = (Vector2){ 700, 350 }; |
|
|
|
|
|
curveEndPositionTangent = (Vector2){ 600, 100 }; |
|
|
|
|
|
|
|
|
curveEndPosition = (Vector2){ 700, 350 }; |
|
|
|
|
|
curveEndPositionTangent = (Vector2){ 600, 100 }; |
|
|
|
|
|
|
|
|
SetTargetFPS(60); // Set our game to run at 60 frames-per-second |
|
|
SetTargetFPS(60); // Set our game to run at 60 frames-per-second |
|
|
//-------------------------------------------------------------------------------------- |
|
|
//-------------------------------------------------------------------------------------- |
|
@ -81,8 +81,8 @@ int main() |
|
|
{ |
|
|
{ |
|
|
// Update |
|
|
// Update |
|
|
//---------------------------------------------------------------------------------- |
|
|
//---------------------------------------------------------------------------------- |
|
|
UpdateCurve(); |
|
|
|
|
|
UpdateOptions(); |
|
|
|
|
|
|
|
|
UpdateCurve(); |
|
|
|
|
|
UpdateOptions(); |
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------- |
|
|
//---------------------------------------------------------------------------------- |
|
|
|
|
|
|
|
@ -99,13 +99,13 @@ int main() |
|
|
DrawText(TextFormat("Curve width: %2.0f (Use + and - to adjust)", curveWidth), 10, 30, 10, DARKGRAY); |
|
|
DrawText(TextFormat("Curve width: %2.0f (Use + and - to adjust)", curveWidth), 10, 30, 10, DARKGRAY); |
|
|
DrawText(TextFormat("Curve segments: %d (Use LEFT and RIGHT to adjust)", curveSegments), 10, 50, 10, DARKGRAY); |
|
|
DrawText(TextFormat("Curve segments: %d (Use LEFT and RIGHT to adjust)", curveSegments), 10, 50, 10, DARKGRAY); |
|
|
|
|
|
|
|
|
EndDrawing(); |
|
|
|
|
|
|
|
|
EndDrawing(); |
|
|
//---------------------------------------------------------------------------------- |
|
|
//---------------------------------------------------------------------------------- |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// De-Initialization |
|
|
// De-Initialization |
|
|
//-------------------------------------------------------------------------------------- |
|
|
//-------------------------------------------------------------------------------------- |
|
|
UnloadTexture(texRoad); |
|
|
|
|
|
|
|
|
UnloadTexture(texRoad); |
|
|
|
|
|
|
|
|
CloseWindow(); // Close window and OpenGL context |
|
|
CloseWindow(); // Close window and OpenGL context |
|
|
//-------------------------------------------------------------------------------------- |
|
|
//-------------------------------------------------------------------------------------- |
|
@ -118,142 +118,142 @@ int main() |
|
|
//---------------------------------------------------------------------------------- |
|
|
//---------------------------------------------------------------------------------- |
|
|
static void DrawCurve(void) |
|
|
static void DrawCurve(void) |
|
|
{ |
|
|
{ |
|
|
if (showCurve) DrawLineBezierCubic(curveStartPosition, curveEndPosition, curveStartPositionTangent, curveEndPositionTangent, 2, BLUE); |
|
|
|
|
|
|
|
|
if (showCurve) DrawLineBezierCubic(curveStartPosition, curveEndPosition, curveStartPositionTangent, curveEndPositionTangent, 2, BLUE); |
|
|
|
|
|
|
|
|
// Draw the various control points and highlight where the mouse is |
|
|
|
|
|
DrawLineV(curveStartPosition, curveStartPositionTangent, SKYBLUE); |
|
|
|
|
|
DrawLineV(curveEndPosition, curveEndPositionTangent, PURPLE); |
|
|
|
|
|
Vector2 mouse = GetMousePosition(); |
|
|
|
|
|
|
|
|
// Draw the various control points and highlight where the mouse is |
|
|
|
|
|
DrawLineV(curveStartPosition, curveStartPositionTangent, SKYBLUE); |
|
|
|
|
|
DrawLineV(curveEndPosition, curveEndPositionTangent, PURPLE); |
|
|
|
|
|
Vector2 mouse = GetMousePosition(); |
|
|
|
|
|
|
|
|
if (CheckCollisionPointCircle(mouse, curveStartPosition, 6)) DrawCircleV(curveStartPosition, 7, YELLOW); |
|
|
|
|
|
DrawCircleV(curveStartPosition, 5, RED); |
|
|
|
|
|
|
|
|
if (CheckCollisionPointCircle(mouse, curveStartPosition, 6)) DrawCircleV(curveStartPosition, 7, YELLOW); |
|
|
|
|
|
DrawCircleV(curveStartPosition, 5, RED); |
|
|
|
|
|
|
|
|
if (CheckCollisionPointCircle(mouse, curveStartPositionTangent, 6)) DrawCircleV(curveStartPositionTangent, 7, YELLOW); |
|
|
|
|
|
DrawCircleV(curveStartPositionTangent, 5, MAROON); |
|
|
|
|
|
|
|
|
if (CheckCollisionPointCircle(mouse, curveStartPositionTangent, 6)) DrawCircleV(curveStartPositionTangent, 7, YELLOW); |
|
|
|
|
|
DrawCircleV(curveStartPositionTangent, 5, MAROON); |
|
|
|
|
|
|
|
|
if (CheckCollisionPointCircle(mouse, curveEndPosition, 6)) DrawCircleV(curveEndPosition, 7, YELLOW); |
|
|
|
|
|
DrawCircleV(curveEndPosition, 5, GREEN); |
|
|
|
|
|
|
|
|
if (CheckCollisionPointCircle(mouse, curveEndPosition, 6)) DrawCircleV(curveEndPosition, 7, YELLOW); |
|
|
|
|
|
DrawCircleV(curveEndPosition, 5, GREEN); |
|
|
|
|
|
|
|
|
if (CheckCollisionPointCircle(mouse, curveEndPositionTangent, 6)) DrawCircleV(curveEndPositionTangent, 7, YELLOW); |
|
|
|
|
|
DrawCircleV(curveEndPositionTangent, 5, DARKGREEN); |
|
|
|
|
|
|
|
|
if (CheckCollisionPointCircle(mouse, curveEndPositionTangent, 6)) DrawCircleV(curveEndPositionTangent, 7, YELLOW); |
|
|
|
|
|
DrawCircleV(curveEndPositionTangent, 5, DARKGREEN); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static void UpdateCurve(void) |
|
|
static void UpdateCurve(void) |
|
|
{ |
|
|
{ |
|
|
// If the mouse is not down, we are not editing the curve so clear the selection |
|
|
|
|
|
if (!IsMouseButtonDown(MOUSE_LEFT_BUTTON)) |
|
|
|
|
|
{ |
|
|
|
|
|
curveSelectedPoint = NULL; |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// If a point was selected, move it |
|
|
|
|
|
if (curveSelectedPoint) |
|
|
|
|
|
{ |
|
|
|
|
|
*curveSelectedPoint = Vector2Add(*curveSelectedPoint, GetMouseDelta()); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// The mouse is down, and nothing was selected, so see if anything was picked |
|
|
|
|
|
Vector2 mouse = GetMousePosition(); |
|
|
|
|
|
|
|
|
|
|
|
if (CheckCollisionPointCircle(mouse, curveStartPosition, 6)) curveSelectedPoint = &curveStartPosition; |
|
|
|
|
|
else if (CheckCollisionPointCircle(mouse, curveStartPositionTangent, 6)) curveSelectedPoint = &curveStartPositionTangent; |
|
|
|
|
|
else if (CheckCollisionPointCircle(mouse, curveEndPosition, 6)) curveSelectedPoint = &curveEndPosition; |
|
|
|
|
|
else if (CheckCollisionPointCircle(mouse, curveEndPositionTangent, 6)) curveSelectedPoint = &curveEndPositionTangent; |
|
|
|
|
|
|
|
|
// If the mouse is not down, we are not editing the curve so clear the selection |
|
|
|
|
|
if (!IsMouseButtonDown(MOUSE_LEFT_BUTTON)) |
|
|
|
|
|
{ |
|
|
|
|
|
curveSelectedPoint = NULL; |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// If a point was selected, move it |
|
|
|
|
|
if (curveSelectedPoint) |
|
|
|
|
|
{ |
|
|
|
|
|
*curveSelectedPoint = Vector2Add(*curveSelectedPoint, GetMouseDelta()); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// The mouse is down, and nothing was selected, so see if anything was picked |
|
|
|
|
|
Vector2 mouse = GetMousePosition(); |
|
|
|
|
|
|
|
|
|
|
|
if (CheckCollisionPointCircle(mouse, curveStartPosition, 6)) curveSelectedPoint = &curveStartPosition; |
|
|
|
|
|
else if (CheckCollisionPointCircle(mouse, curveStartPositionTangent, 6)) curveSelectedPoint = &curveStartPositionTangent; |
|
|
|
|
|
else if (CheckCollisionPointCircle(mouse, curveEndPosition, 6)) curveSelectedPoint = &curveEndPosition; |
|
|
|
|
|
else if (CheckCollisionPointCircle(mouse, curveEndPositionTangent, 6)) curveSelectedPoint = &curveEndPositionTangent; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static void DrawTexturedCurve(void) |
|
|
static void DrawTexturedCurve(void) |
|
|
{ |
|
|
{ |
|
|
const float step = 1.0f/curveSegments; |
|
|
|
|
|
|
|
|
const float step = 1.0f/curveSegments; |
|
|
|
|
|
|
|
|
Vector2 previous = curveStartPosition; |
|
|
|
|
|
Vector2 previousTangent = { 0 }; |
|
|
|
|
|
float previousV = 0; |
|
|
|
|
|
|
|
|
Vector2 previous = curveStartPosition; |
|
|
|
|
|
Vector2 previousTangent = { 0 }; |
|
|
|
|
|
float previousV = 0; |
|
|
|
|
|
|
|
|
// We can't compute a tangent for the first point, so we need to reuse the tangent from the first segment |
|
|
|
|
|
bool tangentSet = false; |
|
|
|
|
|
|
|
|
// We can't compute a tangent for the first point, so we need to reuse the tangent from the first segment |
|
|
|
|
|
bool tangentSet = false; |
|
|
|
|
|
|
|
|
Vector2 current = { 0 }; |
|
|
|
|
|
float t = 0.0f; |
|
|
|
|
|
|
|
|
Vector2 current = { 0 }; |
|
|
|
|
|
float t = 0.0f; |
|
|
|
|
|
|
|
|
for (int i = 1; i <= curveSegments; i++) |
|
|
|
|
|
{ |
|
|
|
|
|
// Segment the curve |
|
|
|
|
|
t = step*i; |
|
|
|
|
|
float a = powf(1 - t, 3); |
|
|
|
|
|
float b = 3*powf(1 - t, 2)*t; |
|
|
|
|
|
float c = 3*(1 - t)*powf(t, 2); |
|
|
|
|
|
float d = powf(t, 3); |
|
|
|
|
|
|
|
|
for (int i = 1; i <= curveSegments; i++) |
|
|
|
|
|
{ |
|
|
|
|
|
// Segment the curve |
|
|
|
|
|
t = step*i; |
|
|
|
|
|
float a = powf(1 - t, 3); |
|
|
|
|
|
float b = 3*powf(1 - t, 2)*t; |
|
|
|
|
|
float c = 3*(1 - t)*powf(t, 2); |
|
|
|
|
|
float d = powf(t, 3); |
|
|
|
|
|
|
|
|
// Compute the endpoint for this segment |
|
|
|
|
|
current.y = a*curveStartPosition.y + b*curveStartPositionTangent.y + c*curveEndPositionTangent.y + d*curveEndPosition.y; |
|
|
|
|
|
current.x = a*curveStartPosition.x + b*curveStartPositionTangent.x + c*curveEndPositionTangent.x + d*curveEndPosition.x; |
|
|
|
|
|
|
|
|
// Compute the endpoint for this segment |
|
|
|
|
|
current.y = a*curveStartPosition.y + b*curveStartPositionTangent.y + c*curveEndPositionTangent.y + d*curveEndPosition.y; |
|
|
|
|
|
current.x = a*curveStartPosition.x + b*curveStartPositionTangent.x + c*curveEndPositionTangent.x + d*curveEndPosition.x; |
|
|
|
|
|
|
|
|
// Vector from previous to current |
|
|
|
|
|
Vector2 delta = { current.x - previous.x, current.y - previous.y }; |
|
|
|
|
|
|
|
|
// Vector from previous to current |
|
|
|
|
|
Vector2 delta = { current.x - previous.x, current.y - previous.y }; |
|
|
|
|
|
|
|
|
// The right hand normal to the delta vector |
|
|
|
|
|
Vector2 normal = Vector2Normalize((Vector2){ -delta.y, delta.x }); |
|
|
|
|
|
|
|
|
// The right hand normal to the delta vector |
|
|
|
|
|
Vector2 normal = Vector2Normalize((Vector2){ -delta.y, delta.x }); |
|
|
|
|
|
|
|
|
// The v texture coordinate of the segment (add up the length of all the segments so far) |
|
|
|
|
|
float v = previousV + Vector2Length(delta); |
|
|
|
|
|
|
|
|
// The v texture coordinate of the segment (add up the length of all the segments so far) |
|
|
|
|
|
float v = previousV + Vector2Length(delta); |
|
|
|
|
|
|
|
|
// Make sure the start point has a normal |
|
|
|
|
|
if (!tangentSet) |
|
|
|
|
|
{ |
|
|
|
|
|
previousTangent = normal; |
|
|
|
|
|
tangentSet = true; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// Make sure the start point has a normal |
|
|
|
|
|
if (!tangentSet) |
|
|
|
|
|
{ |
|
|
|
|
|
previousTangent = normal; |
|
|
|
|
|
tangentSet = true; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// Extend out the normals from the previous and current points to get the quad for this segment |
|
|
|
|
|
Vector2 prevPosNormal = Vector2Add(previous, Vector2Scale(previousTangent, curveWidth)); |
|
|
|
|
|
Vector2 prevNegNormal = Vector2Add(previous, Vector2Scale(previousTangent, -curveWidth)); |
|
|
|
|
|
|
|
|
// Extend out the normals from the previous and current points to get the quad for this segment |
|
|
|
|
|
Vector2 prevPosNormal = Vector2Add(previous, Vector2Scale(previousTangent, curveWidth)); |
|
|
|
|
|
Vector2 prevNegNormal = Vector2Add(previous, Vector2Scale(previousTangent, -curveWidth)); |
|
|
|
|
|
|
|
|
Vector2 currentPosNormal = Vector2Add(current, Vector2Scale(normal, curveWidth)); |
|
|
|
|
|
Vector2 currentNegNormal = Vector2Add(current, Vector2Scale(normal, -curveWidth)); |
|
|
|
|
|
|
|
|
Vector2 currentPosNormal = Vector2Add(current, Vector2Scale(normal, curveWidth)); |
|
|
|
|
|
Vector2 currentNegNormal = Vector2Add(current, Vector2Scale(normal, -curveWidth)); |
|
|
|
|
|
|
|
|
// Draw the segment as a quad |
|
|
|
|
|
rlSetTexture(texRoad.id); |
|
|
|
|
|
rlBegin(RL_QUADS); |
|
|
|
|
|
|
|
|
// Draw the segment as a quad |
|
|
|
|
|
rlSetTexture(texRoad.id); |
|
|
|
|
|
rlBegin(RL_QUADS); |
|
|
|
|
|
|
|
|
rlColor4ub(255,255,255,255); |
|
|
|
|
|
rlNormal3f(0.0f, 0.0f, 1.0f); |
|
|
|
|
|
|
|
|
rlColor4ub(255,255,255,255); |
|
|
|
|
|
rlNormal3f(0.0f, 0.0f, 1.0f); |
|
|
|
|
|
|
|
|
rlTexCoord2f(0, previousV); |
|
|
|
|
|
rlVertex2f(prevNegNormal.x, prevNegNormal.y); |
|
|
|
|
|
|
|
|
rlTexCoord2f(0, previousV); |
|
|
|
|
|
rlVertex2f(prevNegNormal.x, prevNegNormal.y); |
|
|
|
|
|
|
|
|
rlTexCoord2f(1, previousV); |
|
|
|
|
|
rlVertex2f(prevPosNormal.x, prevPosNormal.y); |
|
|
|
|
|
|
|
|
rlTexCoord2f(1, previousV); |
|
|
|
|
|
rlVertex2f(prevPosNormal.x, prevPosNormal.y); |
|
|
|
|
|
|
|
|
rlTexCoord2f(1, v); |
|
|
|
|
|
rlVertex2f(currentPosNormal.x, currentPosNormal.y); |
|
|
|
|
|
|
|
|
rlTexCoord2f(1, v); |
|
|
|
|
|
rlVertex2f(currentPosNormal.x, currentPosNormal.y); |
|
|
|
|
|
|
|
|
rlTexCoord2f(0, v); |
|
|
|
|
|
rlVertex2f(currentNegNormal.x, currentNegNormal.y); |
|
|
|
|
|
|
|
|
rlTexCoord2f(0, v); |
|
|
|
|
|
rlVertex2f(currentNegNormal.x, currentNegNormal.y); |
|
|
|
|
|
|
|
|
rlEnd(); |
|
|
|
|
|
|
|
|
rlEnd(); |
|
|
|
|
|
|
|
|
// The current step is the start of the next step |
|
|
|
|
|
previous = current; |
|
|
|
|
|
previousTangent = normal; |
|
|
|
|
|
previousV = v; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// The current step is the start of the next step |
|
|
|
|
|
previous = current; |
|
|
|
|
|
previousTangent = normal; |
|
|
|
|
|
previousV = v; |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static void UpdateOptions(void) |
|
|
static void UpdateOptions(void) |
|
|
{ |
|
|
{ |
|
|
if (IsKeyPressed(KEY_SPACE)) showCurve = !showCurve; |
|
|
|
|
|
|
|
|
if (IsKeyPressed(KEY_SPACE)) showCurve = !showCurve; |
|
|
|
|
|
|
|
|
// Update with |
|
|
|
|
|
if (IsKeyPressed(KEY_EQUAL)) curveWidth += 2; |
|
|
|
|
|
if (IsKeyPressed(KEY_MINUS)) curveWidth -= 2; |
|
|
|
|
|
|
|
|
// Update with |
|
|
|
|
|
if (IsKeyPressed(KEY_EQUAL)) curveWidth += 2; |
|
|
|
|
|
if (IsKeyPressed(KEY_MINUS)) curveWidth -= 2; |
|
|
|
|
|
|
|
|
if (curveWidth < 2) curveWidth = 2; |
|
|
|
|
|
|
|
|
if (curveWidth < 2) curveWidth = 2; |
|
|
|
|
|
|
|
|
// Update segments |
|
|
|
|
|
if (IsKeyPressed(KEY_LEFT)) curveSegments -= 2; |
|
|
|
|
|
if (IsKeyPressed(KEY_RIGHT)) curveSegments += 2; |
|
|
|
|
|
|
|
|
// Update segments |
|
|
|
|
|
if (IsKeyPressed(KEY_LEFT)) curveSegments -= 2; |
|
|
|
|
|
if (IsKeyPressed(KEY_RIGHT)) curveSegments += 2; |
|
|
|
|
|
|
|
|
if (curveSegments < 2) curveSegments = 2; |
|
|
|
|
|
|
|
|
if (curveSegments < 2) curveSegments = 2; |
|
|
} |
|
|
} |