diff --git a/examples/textures/resources/roadTexture_01.png b/examples/textures/resources/road.png similarity index 100% rename from examples/textures/resources/roadTexture_01.png rename to examples/textures/resources/road.png diff --git a/examples/textures/textures_textured_curve.c b/examples/textures/textures_textured_curve.c index 1407f738..27667097 100644 --- a/examples/textures/textures_textured_curve.c +++ b/examples/textures/textures_textured_curve.c @@ -2,145 +2,219 @@ * * raylib [textures] example - Draw a texture along a segmented curve * -* Example originally created with raylib 4.5 +* Example originally created with raylib 4.5-dev * * Example contributed by Jeffery Myers 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 * -* Copyright (c) 2019-2022 Jeffery Myers and Ramon Santamaria (@raysan5) +* Copyright (c) 2022 Jeffery Myers and Ramon Santamaria (@raysan5) * ********************************************************************************************/ #include "raylib.h" + #include "raymath.h" #include "rlgl.h" -Texture RoadTexture = { 0 }; +#include // Required for: powf() +#include // Required for: NULL -bool ShowCurve = false; +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +static Texture texRoad = { 0 }; -float Width = 50; -int Segments = 24; +static bool showCurve = false; -Vector2 SP = { 0 }; -Vector2 SPTangent = { 0 }; +static float curveWidth = 50; +static int curveSegments = 24; -Vector2 EP = { 0 }; -Vector2 EPTangent = { 0 }; +static Vector2 curveStartPosition = { 0 }; +static Vector2 curveStartPositionTangent = { 0 }; -Vector2* Selected = NULL; +static Vector2 curveEndPosition = { 0 }; +static Vector2 curveEndPositionTangent = { 0 }; -void DrawCurve() +static Vector2 *curveSelectedPoint = NULL; + +//---------------------------------------------------------------------------------- +// Module Functions Declaration +//---------------------------------------------------------------------------------- +static void UpdateOptions(void); +static void UpdateCurve(void); +static void DrawCurve(void); +static void DrawTexturedCurve(void); + + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main() { - if (ShowCurve) - DrawLineBezierCubic(SP, EP, SPTangent, EPTangent, 2, BLUE); + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; - // draw the various control points and highlight where the mouse is - DrawLineV(SP, SPTangent, SKYBLUE); - DrawLineV(EP, EPTangent, PURPLE); - Vector2 mouse = GetMousePosition(); + SetConfigFlags(FLAG_VSYNC_HINT | FLAG_MSAA_4X_HINT); + InitWindow(screenWidth, screenHeight, "raylib [textures] examples - textured curve"); - if (CheckCollisionPointCircle(mouse, SP, 6)) - DrawCircleV(SP, 7, YELLOW); - DrawCircleV(SP, 5, RED); + // Load the road texture + texRoad = LoadTexture("resources/road.png"); + SetTextureFilter(texRoad, TEXTURE_FILTER_BILINEAR); - if (CheckCollisionPointCircle(mouse, SPTangent, 6)) - DrawCircleV(SPTangent, 7, YELLOW); - DrawCircleV(SPTangent, 5, MAROON); + // Setup the curve + curveStartPosition = (Vector2){ 80, 100 }; + curveStartPositionTangent = (Vector2){ 100, 300 }; - if (CheckCollisionPointCircle(mouse, EP, 6)) - DrawCircleV(EP, 7, YELLOW); - DrawCircleV(EP, 5, GREEN); + curveEndPosition = (Vector2){ 700, 350 }; + curveEndPositionTangent = (Vector2){ 600, 100 }; - if (CheckCollisionPointCircle(mouse, EPTangent, 6)) - DrawCircleV(EPTangent, 7, YELLOW); - DrawCircleV(EPTangent, 5, DARKGREEN); + SetTargetFPS(60); // Set our game to run at 60 frames-per-second + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + UpdateCurve(); + UpdateOptions(); + + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + DrawTexturedCurve(); + DrawCurve(); + + DrawText("Drag points to move curve, press SPACE to show/hide base curve", 10, 10, 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); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + UnloadTexture(texRoad); + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; } -void EditCurve() +//---------------------------------------------------------------------------------- +// Module Functions Definition +//---------------------------------------------------------------------------------- +static void DrawCurve(void) { - // if the mouse is not down, we are not editing the curve so clear the selection + 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(); + + 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, curveEndPosition, 6)) DrawCircleV(curveEndPosition, 7, YELLOW); + DrawCircleV(curveEndPosition, 5, GREEN); + + if (CheckCollisionPointCircle(mouse, curveEndPositionTangent, 6)) DrawCircleV(curveEndPositionTangent, 7, YELLOW); + DrawCircleV(curveEndPositionTangent, 5, DARKGREEN); +} + +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)) { - Selected = NULL; + curveSelectedPoint = NULL; return; } - // if a point was selected, move it - if (Selected) + // If a point was selected, move it + if (curveSelectedPoint) { - *Selected = Vector2Add(*Selected, GetMouseDelta()); + *curveSelectedPoint = Vector2Add(*curveSelectedPoint, GetMouseDelta()); return; } - // the mouse is down, and nothing was selected, so see if anything was picked + // The mouse is down, and nothing was selected, so see if anything was picked Vector2 mouse = GetMousePosition(); - if (CheckCollisionPointCircle(mouse, SP, 6)) - Selected = &SP; - else if (CheckCollisionPointCircle(mouse, SPTangent, 6)) - Selected = &SPTangent; - else if (CheckCollisionPointCircle(mouse, EP, 6)) - Selected = &EP; - else if (CheckCollisionPointCircle(mouse, EPTangent, 6)) - Selected = &EPTangent; + 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; } -void DrawTexturedCurve() +static void DrawTexturedCurve(void) { - const float step = 1.0f / Segments; + const float step = 1.0f/curveSegments; - Vector2 previous = SP; + 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 + // 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; - for (int i = 1; i <= Segments; i++) + for (int i = 1; i <= curveSegments; i++) { - // segment the curve - t = step * 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 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 * SP.y + b * SPTangent.y + c * EPTangent.y + d * EP.y; - current.x = a * SP.x + b * SPTangent.x + c * EPTangent.x + d * EP.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 + // Vector from previous to current Vector2 delta = { current.x - previous.x, current.y - previous.y }; - // the right hand normal to the delta vector + // 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) + // 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 + // 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, Width)); - Vector2 prevNegNormal = Vector2Add(previous, Vector2Scale(previousTangent, -Width)); + // 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, Width)); - Vector2 currentNegNormal = Vector2Add(current, Vector2Scale(normal, -Width)); + Vector2 currentPosNormal = Vector2Add(current, Vector2Scale(normal, curveWidth)); + Vector2 currentNegNormal = Vector2Add(current, Vector2Scale(normal, -curveWidth)); - // draw the segment as a quad - rlSetTexture(RoadTexture.id); + // Draw the segment as a quad + rlSetTexture(texRoad.id); rlBegin(RL_QUADS); rlColor4ub(255,255,255,255); @@ -160,82 +234,26 @@ void DrawTexturedCurve() rlEnd(); - // the current step is the start of the next step + // The current step is the start of the next step previous = current; previousTangent = normal; previousV = v; } } -void UpdateOptions() +static void UpdateOptions(void) { - if (IsKeyPressed(KEY_SPACE)) - ShowCurve = !ShowCurve; + if (IsKeyPressed(KEY_SPACE)) showCurve = !showCurve; - // width - if (IsKeyPressed(KEY_EQUAL)) - Width += 2; + // Update with + if (IsKeyPressed(KEY_EQUAL)) curveWidth += 2; + if (IsKeyPressed(KEY_MINUS)) curveWidth -= 2; - if (IsKeyPressed(KEY_MINUS)) - Width -= 2; + if (curveWidth < 2) curveWidth = 2; - if (Width < 2) - Width = 2; + // Update segments + if (IsKeyPressed(KEY_LEFT)) curveSegments -= 2; + if (IsKeyPressed(KEY_RIGHT)) curveSegments += 2; - // segments - - if (IsKeyPressed(KEY_LEFT_BRACKET)) - Segments -= 2; - - if (IsKeyPressed(KEY_RIGHT_BRACKET)) - Segments += 2; - - if (Segments < 2) - Segments = 2; + if (curveSegments < 2) curveSegments = 2; } - -int main () -{ - // set up the window - SetConfigFlags(FLAG_VSYNC_HINT); - InitWindow(1280, 800, "raylib [textures] examples - textured curve"); - SetTargetFPS(144); - - // load the road texture - RoadTexture = LoadTexture("resources/roadTexture_01.png"); - - // setup the curve - SP = (Vector2){ 80, 400 }; - SPTangent = (Vector2){ 600, 100 }; - - EP = (Vector2){ 1200, 400 }; - EPTangent = (Vector2){ 600, 700 }; - - // game loop - while (!WindowShouldClose()) - { - EditCurve(); - UpdateOptions(); - - BeginDrawing(); - - ClearBackground(BLACK); - - DrawTexturedCurve(); - DrawCurve(); - - DrawText("Drag points to move curve, press space to show/hide base curve", 10, 0, 20, WHITE); - DrawText(TextFormat("Width %2.0f + and - to adjust", Width), 10, 20, 20, WHITE); - DrawText(TextFormat("Segments %d [ and ] to adjust", Segments), 10, 40, 20, WHITE); - DrawFPS(10, 60); - - EndDrawing(); - } - - // cleanup - UnloadTexture(RoadTexture); - CloseWindow(); - return 0; -} - - \ No newline at end of file diff --git a/examples/textures/textures_textured_curve.png b/examples/textures/textures_textured_curve.png index 1f45e8d2..6d5efacb 100644 Binary files a/examples/textures/textures_textured_curve.png and b/examples/textures/textures_textured_curve.png differ