From f680776941823a56142f61ec93bb062cc792fbde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Almeida?= <60551627+luis605@users.noreply.github.com> Date: Wed, 1 Oct 2025 10:43:38 +0100 Subject: [PATCH] feat:Added DrawLineDashed() and a new example explaining how to use this new function. (#5222) --- examples/Makefile | 5 +- examples/Makefile.Web | 5 +- examples/README.md | 1 + examples/examples_list.txt | 1 + examples/shapes/shapes_dashed_line.c | 103 +++++++++++++++++++++++++ examples/shapes/shapes_dashed_line.png | Bin 0 -> 16908 bytes src/raylib.h | 1 + src/rshapes.c | 49 ++++++++++++ 8 files changed, 161 insertions(+), 4 deletions(-) create mode 100644 examples/shapes/shapes_dashed_line.c create mode 100644 examples/shapes/shapes_dashed_line.png diff --git a/examples/Makefile b/examples/Makefile index de02ae085..9a3f640b7 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -355,7 +355,7 @@ ifeq ($(TARGET_PLATFORM),$(filter $(TARGET_PLATFORM),PLATFORM_WEB PLATFORM_WEB_R ifeq ($(BUILD_WEB_WEBGL2),TRUE) LDFLAGS += -sMIN_WEBGL_VERSION=2 -sMAX_WEBGL_VERSION=2 endif - + # Add resources building if required ifeq ($(BUILD_WEB_RESOURCES),TRUE) LDFLAGS += --preload-file $(BUILD_WEB_RESOURCES_PATH) @@ -559,7 +559,8 @@ SHAPES = \ shapes/shapes_ring_drawing \ shapes/shapes_rounded_rectangle_drawing \ shapes/shapes_splines_drawing \ - shapes/shapes_top_down_lights + shapes/shapes_top_down_lights \ + shapes/shapes_dashed_line TEXTURES = \ textures/textures_background_scrolling \ diff --git a/examples/Makefile.Web b/examples/Makefile.Web index 8c9707274..20d737c38 100644 --- a/examples/Makefile.Web +++ b/examples/Makefile.Web @@ -355,7 +355,7 @@ ifeq ($(TARGET_PLATFORM),$(filter $(TARGET_PLATFORM),PLATFORM_WEB PLATFORM_WEB_R ifeq ($(BUILD_WEB_WEBGL2),TRUE) LDFLAGS += -sMIN_WEBGL_VERSION=2 -sMAX_WEBGL_VERSION=2 endif - + # Add resources building if required ifeq ($(BUILD_WEB_RESOURCES),TRUE) LDFLAGS += --preload-file $(BUILD_WEB_RESOURCES_PATH) @@ -559,7 +559,8 @@ SHAPES = \ shapes/shapes_ring_drawing \ shapes/shapes_rounded_rectangle_drawing \ shapes/shapes_splines_drawing \ - shapes/shapes_top_down_lights + shapes/shapes_top_down_lights \ + shapes/shapes_dashed_line TEXTURES = \ textures/textures_background_scrolling \ diff --git a/examples/README.md b/examples/README.md index 92ea9aa07..a5ee53afd 100644 --- a/examples/README.md +++ b/examples/README.md @@ -91,6 +91,7 @@ Examples using raylib shapes drawing functionality, provided by raylib [shapes]( | [shapes_splines_drawing](shapes/shapes_splines_drawing.c) | shapes_splines_drawing | ⭐⭐⭐☆ | 5.0 | 5.0 | [Ramon Santamaria](https://github.com/raysan5) | | [shapes_digital_clock](shapes/shapes_digital_clock.c) | shapes_digital_clock | ⭐⭐⭐⭐️ | 5.5 | 5.6 | [Hamza RAHAL](https://github.com/hmz-rhl) | | [shapes_double_pendulum](shapes/shapes_double_pendulum.c) | shapes_double_pendulum | ⭐⭐☆☆ | 5.5 | 5.5 | [JoeCheong](https://github.com/Joecheong2006) | +| [shapes_dashed_line](shapes/shapes_dashed_line.c) | shapes_dashed_line | ⭐☆☆☆ | 5.5 | 5.5 | [Luís Almeida](https://github.com/luis605) | ### category: textures [26] diff --git a/examples/examples_list.txt b/examples/examples_list.txt index 6af9bb6eb..10bf09ceb 100644 --- a/examples/examples_list.txt +++ b/examples/examples_list.txt @@ -66,6 +66,7 @@ shapes;shapes_rectangle_advanced;★★★★;5.5;5.5;2024;2025;"Everton Jr.";@e shapes;shapes_splines_drawing;★★★☆;5.0;5.0;2023;2025;"Ramon Santamaria";@raysan5 shapes;shapes_digital_clock;★★★★;5.5;5.6;2025;2025;"Hamza RAHAL";@hmz-rhl shapes;shapes_double_pendulum;★★☆☆;5.5;5.5;2025;2025;"JoeCheong";@Joecheong2006 +shapes;shapes_dashed_line;★☆☆☆;5.5;5.5;2025;2025;"Luís Almeida";@luis605 textures;textures_logo_raylib;★☆☆☆;1.0;1.0;2014;2025;"Ramon Santamaria";@raysan5 textures;textures_srcrec_dstrec;★★★☆;1.3;1.3;2015;2025;"Ramon Santamaria";@raysan5 textures;textures_image_drawing;★★☆☆;1.4;1.4;2016;2025;"Ramon Santamaria";@raysan5 diff --git a/examples/shapes/shapes_dashed_line.c b/examples/shapes/shapes_dashed_line.c new file mode 100644 index 000000000..fd017562f --- /dev/null +++ b/examples/shapes/shapes_dashed_line.c @@ -0,0 +1,103 @@ +/******************************************************************************************* +* +* raylib [shapes] example - dashed line drawing +* +* Example complexity rating: [★☆☆☆] 1/4 +* +* Example originally created with raylib 2.5, last time updated with raylib 2.5 +* +* Example contributed by Luís Almeida (@luis605) +* +* 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) 2025 Luís Almeida (@luis605) +* +********************************************************************************************/ + +#include "raylib.h" +#define RAYGUI_IMPLEMENTATION +#include "raygui.h" // Required for GUI controls + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [shapes] example - interactive dashed line"); + + // Line Properties + Vector2 lineStartPosition = { 20.0f, 50.0f }; + Vector2 lineEndPosition = { 780.0f, 400.0f }; + float dashLength = 25.0f; + float blankLength = 15.0f; + + // Color selection + Color lineColors[] = { RED, ORANGE, GOLD, GREEN, BLUE, VIOLET, PINK, BLACK }; + int colorIndex = 0; + + 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 + //---------------------------------------------------------------------------------- + lineEndPosition = GetMousePosition(); // Line endpoint follows the mouse + + // --- Keyboard Controls --- + + // Change Dash Length (UP/DOWN arrows) + if (IsKeyDown(KEY_UP)) dashLength += 1.0f; + if (IsKeyDown(KEY_DOWN) && dashLength > 1.0f) dashLength -= 1.0f; + + // Change Space Length (LEFT/RIGHT arrows) + if (IsKeyDown(KEY_RIGHT)) blankLength += 1.0f; + if (IsKeyDown(KEY_LEFT) && blankLength > 1.0f) blankLength -= 1.0f; + + // Cycle through colors ('C' key) + if (IsKeyPressed(KEY_C)) + { + colorIndex = (colorIndex + 1) % (sizeof(lineColors)/sizeof(Color)); + } + + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + // Draw the dashed line with the current properties + DrawLineDashed(lineStartPosition, lineEndPosition, dashLength, blankLength, lineColors[colorIndex]); + + // Draw UI and Instructions + DrawRectangle(5, 5, 265, 95, Fade(SKYBLUE, 0.5f)); + DrawRectangleLines(5, 5, 265, 95, BLUE); + + DrawText("CONTROLS:", 15, 15, 10, BLACK); + DrawText("UP/DOWN: Change Dash Length", 15, 35, 10, BLACK); + DrawText("LEFT/RIGHT: Change Space Length", 15, 55, 10, BLACK); + DrawText("C: Cycle Color", 15, 75, 10, BLACK); + + DrawText(TextFormat("Dash: %.0f | Space: %.0f", dashLength, blankLength), 15, 115, 10, DARKGRAY); + + DrawFPS(screenWidth - 80, 10); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} \ No newline at end of file diff --git a/examples/shapes/shapes_dashed_line.png b/examples/shapes/shapes_dashed_line.png new file mode 100644 index 0000000000000000000000000000000000000000..5c3ce3ef3fc5ae84996f01b90b56b235fcd42308 GIT binary patch literal 16908 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 M>FVdQ&MBb@0JjS^0RR91 literal 0 HcmV?d00001 diff --git a/src/raylib.h b/src/raylib.h index 642f9318c..b7ccaae22 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1258,6 +1258,7 @@ RLAPI Rectangle GetShapesTextureRectangle(void); // Get texture source re RLAPI void DrawPixel(int posX, int posY, Color color); // Draw a pixel using geometry [Can be slow, use with care] RLAPI void DrawPixelV(Vector2 position, Color color); // Draw a pixel using geometry (Vector version) [Can be slow, use with care] RLAPI void DrawLine(int startPosX, int startPosY, int endPosX, int endPosY, Color color); // Draw a line +RLAPI void DrawLineDashed(Vector2 startPos, Vector2 endPos, int dashSize, int whiteSpaceSize, Color color); // Draw a dashed line RLAPI void DrawLineV(Vector2 startPos, Vector2 endPos, Color color); // Draw a line (using gl lines) RLAPI void DrawLineEx(Vector2 startPos, Vector2 endPos, float thick, Color color); // Draw a line (using triangles/quads) RLAPI void DrawLineStrip(const Vector2 *points, int pointCount, Color color); // Draw lines sequence (using gl lines) diff --git a/src/rshapes.c b/src/rshapes.c index 14e3f856a..a62b1c5f8 100644 --- a/src/rshapes.c +++ b/src/rshapes.c @@ -182,6 +182,55 @@ void DrawLine(int startPosX, int startPosY, int endPosX, int endPosY, Color colo rlEnd(); } +void DrawLineDashed(Vector2 startPos, Vector2 endPos, int dashSize, int whiteSpaceSize, Color color) +{ + // Calculate the vector and length of the line + float dx = endPos.x - startPos.x; + float dy = endPos.y - startPos.y; + float lineLength = sqrtf(dx*dx + dy*dy); + + // If the line is too short for dashing or dash size is invalid, draw a solid thick line + if (lineLength < (dashSize + whiteSpaceSize) || dashSize <= 0) + { + DrawLineV(startPos, endPos, color); + return; + } + + // Calculate the normalized direction vector of the line + float invLineLength = 1 / lineLength; + float dirX = dx * invLineLength; + float dirY = dy * invLineLength; + + Vector2 currentPos = startPos; + float distanceTraveled = 0; + + rlBegin(RL_LINES); + rlColor4ub(color.r, color.g, color.b, color.a); + + while (distanceTraveled < lineLength) + { + // Calculate the end of the current dash + float dashEndDist = distanceTraveled + dashSize; + if (dashEndDist > lineLength) + { + dashEndDist = lineLength; + } + + Vector2 dashEndPos = { startPos.x + dashEndDist * dirX, startPos.y + dashEndDist * dirY }; + + // Draw the dash segment + rlVertex2f(currentPos.x, currentPos.y); + rlVertex2f(dashEndPos.x, dashEndPos.y); + + // Update the distance traveled and move the current position for the next dash + distanceTraveled = dashEndDist + whiteSpaceSize; + currentPos.x = startPos.x + distanceTraveled * dirX; + currentPos.y = startPos.y + distanceTraveled * dirY; + } + + rlEnd(); +} + // Draw a line (using gl lines) void DrawLineV(Vector2 startPos, Vector2 endPos, Color color) {