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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 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) {