diff options
| author | Uneven Prankster <unevenprankster@protonmail.com> | 2023-10-15 21:28:29 -0300 |
|---|---|---|
| committer | Uneven Prankster <unevenprankster@protonmail.com> | 2023-10-15 21:28:29 -0300 |
| commit | 1c0cc775732201f4c4d3ee0d6772be786b3b4aa1 (patch) | |
| tree | f5d692d046868261275c7430a624c3ea9ed75d3d /raylib/examples/textures/textures_textured_curve.c | |
| parent | a89f892640cf12f75c7ce18e6e88c70a8d3965ed (diff) | |
A lot has certainly happened!
Diffstat (limited to 'raylib/examples/textures/textures_textured_curve.c')
| -rw-r--r-- | raylib/examples/textures/textures_textured_curve.c | 259 |
1 files changed, 259 insertions, 0 deletions
diff --git a/raylib/examples/textures/textures_textured_curve.c b/raylib/examples/textures/textures_textured_curve.c new file mode 100644 index 0000000..3c2f060 --- /dev/null +++ b/raylib/examples/textures/textures_textured_curve.c @@ -0,0 +1,259 @@ +/******************************************************************************************* +* +* raylib [textures] example - Draw a texture along a segmented curve +* +* Example originally created with raylib 4.5, last time updated with raylib 4.5 +* +* 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) 2022-2023 Jeffery Myers and Ramon Santamaria (@raysan5) +* +********************************************************************************************/ + + +#include "raylib.h" + +#include "raymath.h" +#include "rlgl.h" + +#include <math.h> // Required for: powf() +#include <stdlib.h> // Required for: NULL + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +static Texture texRoad = { 0 }; + +static bool showCurve = false; + +static float curveWidth = 50; +static int curveSegments = 24; + +static Vector2 curveStartPosition = { 0 }; +static Vector2 curveStartPositionTangent = { 0 }; + +static Vector2 curveEndPosition = { 0 }; +static Vector2 curveEndPositionTangent = { 0 }; + +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() +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + 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"); + SetTextureFilter(texRoad, TEXTURE_FILTER_BILINEAR); + + // Setup the curve + curveStartPosition = (Vector2){ 80, 100 }; + curveStartPositionTangent = (Vector2){ 100, 300 }; + + curveEndPosition = (Vector2){ 700, 350 }; + curveEndPositionTangent = (Vector2){ 600, 100 }; + + 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; +} + +//---------------------------------------------------------------------------------- +// Module Functions Definition +//---------------------------------------------------------------------------------- +static void DrawCurve(void) +{ + 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)) + { + 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) +{ + const float step = 1.0f/curveSegments; + + 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; + + 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); + + // 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 }; + + // 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); + + // 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)); + + 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); + + rlColor4ub(255,255,255,255); + rlNormal3f(0.0f, 0.0f, 1.0f); + + rlTexCoord2f(0, previousV); + rlVertex2f(prevNegNormal.x, prevNegNormal.y); + + rlTexCoord2f(1, previousV); + rlVertex2f(prevPosNormal.x, prevPosNormal.y); + + rlTexCoord2f(1, v); + rlVertex2f(currentPosNormal.x, currentPosNormal.y); + + rlTexCoord2f(0, v); + rlVertex2f(currentNegNormal.x, currentNegNormal.y); + + rlEnd(); + + // The current step is the start of the next step + previous = current; + previousTangent = normal; + previousV = v; + } +} + +static void UpdateOptions(void) +{ + if (IsKeyPressed(KEY_SPACE)) showCurve = !showCurve; + + // Update with + if (IsKeyPressed(KEY_EQUAL)) curveWidth += 2; + if (IsKeyPressed(KEY_MINUS)) curveWidth -= 2; + + if (curveWidth < 2) curveWidth = 2; + + // Update segments + if (IsKeyPressed(KEY_LEFT)) curveSegments -= 2; + if (IsKeyPressed(KEY_RIGHT)) curveSegments += 2; + + if (curveSegments < 2) curveSegments = 2; +} |
