3 Commits

Author SHA1 Message Date
Ray
3d671a6dd4 Merge branch 'master' of https://github.com/raysan5/raylib 2026-08-04 21:16:17 +02:00
Ray
7711de62fb Code gardening 2026-08-04 21:16:08 +02:00
37712a8fbe [rshapes] Fix Draw*LinesEx() functions' inconsistent handling of thick parameter. (#6035)
* [rshapes] Update `DrawRectangleLinesEx()`

Add support for negative `thick` values. When `thick` is negative, lines are drawn growing outside of the rectangle.

* [rshapes] Update `DrawPolyLinesEx()`

Add support for negative `thick` values. When `thick` is negative, lines are drawn growing outside of the polygon. Also refactored to explicitly use an `outerRadius` variable instead of using `radius` as the outer radius.

* [rshapes] Update `DrawRectangleRoundedLinesEx()`

Make the outline vertices easier to work with.

* [rshapes] Updated `DrawRectangleRoundedLinesEx()`.

Lines used to draw outside when `thick` was positive. Added support for negative `thick` values. When `thick` is negative, lines are drawn growing outside of the rectangle.

* [rshapes] Update `DrawRectangleRoundedLines()`.

Make the formatting of the points' x and y coordinates in DrawRectangleRoundedLines() match DrawRectangleRoundedLinesEx().
2026-08-04 18:04:56 +02:00
15 changed files with 224 additions and 110 deletions

2
src/external/rlsw.h vendored
View File

@ -774,7 +774,7 @@ SWAPI void swGetFramebufferAttachmentParameteriv(SWattachment attachment, SWatta
// Simple log system to avoid printf() calls if required
// NOTE: Avoiding those calls, also avoids const strings memory usage
#define RLSW_SUPPORT_LOG_INFO
#if defined(RLSW_SUPPORT_LOG_INFO) //&& defined(_DEBUG) // WARNING: LOG() output required for this tool
#if defined(RLSW_SUPPORT_LOG_INFO)
#include <stdio.h>
#define SW_LOG(...) printf(__VA_ARGS__)
#else

View File

@ -1613,11 +1613,11 @@ void PollInputEvents(void)
}
//-----------------------------------------------------------------------------
// using RGFW callbacks instead of polling
// Using RGFW callbacks instead of polling
RGFW_pollEvents();
//-----------------------------------------------------------------------------
mg_event gamepad_event;
mg_event gamepad_event = { 0 };
while (mg_gamepads_check_event(&platform.minigamepad, &gamepad_event))
{
int gamepadIndex = gamepad_event.gamepad->index;

View File

@ -1652,7 +1652,7 @@ void PollInputEvents(void)
} break;
#endif
// Keyboard events
// Check keyboard events
case SDL_KEYDOWN:
{
#if defined(USING_VERSION_SDL3)
@ -1680,10 +1680,8 @@ void PollInputEvents(void)
if (CORE.Input.Keyboard.currentKeyState[CORE.Input.Keyboard.exitKey]) CORE.Window.shouldClose = true;
} break;
case SDL_KEYUP:
{
#if defined(USING_VERSION_SDL3)
KeyboardKey key = ConvertScancodeToKey(event.key.scancode);
#else
@ -1691,7 +1689,6 @@ void PollInputEvents(void)
#endif
if (key != KEY_NULL) CORE.Input.Keyboard.currentKeyState[key] = 0;
} break;
case SDL_TEXTINPUT:
{
// NOTE: event.text.text data comes an UTF-8 text sequence but register codepoints (int)
@ -1700,7 +1697,6 @@ void PollInputEvents(void)
if (CORE.Input.Keyboard.charPressedQueueCount < MAX_CHAR_PRESSED_QUEUE)
{
// Add character (codepoint) to the queue
#if defined(USING_VERSION_SDL3)
size_t textLen = strlen(event.text.text);
unsigned int codepoint = (unsigned int)SDL_StepUTF8(&event.text.text, &textLen);
@ -1769,6 +1765,7 @@ void PollInputEvents(void)
touchAction = 2;
} break;
// Check Touch events
case SDL_FINGERDOWN:
{
UpdateTouchPointsSDL(event.tfinger);
@ -1788,24 +1785,21 @@ void PollInputEvents(void)
realTouch = true;
} break;
// Check gamepad events
// Check Gamepad events
case SDL_JOYDEVICEADDED:
{
int jid = event.jdevice.which; // Joystick device index
// check if already added at InitPlatform
// Check if already added at InitPlatform
for (int i = 0; i < MAX_GAMEPADS; i++)
{
if (jid == platform.gamepadId[i])
{
return;
}
if (jid == platform.gamepadId[i]) return;
}
int nextAvailableSlot = 0;
while (nextAvailableSlot < MAX_GAMEPADS && CORE.Input.Gamepad.ready[nextAvailableSlot])
{
++nextAvailableSlot;
nextAvailableSlot++;
}
if ((nextAvailableSlot < MAX_GAMEPADS) && !CORE.Input.Gamepad.ready[nextAvailableSlot])

View File

@ -1118,7 +1118,7 @@ void PollInputEvents(void)
// NOTE: For DRM touchscreen devices, this mapping is disabled to avoid false touch detection
// CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition;
// Handle the mouse/touch/gestures events:
// Handle the mouse/touch/gestures events
PollMouseEvents();
}
@ -1938,6 +1938,7 @@ static void InitEvdevInput(void)
(strncmp("mouse", entity->d_name, strlen("mouse")) == 0)) // Search for devices named "mouse*"
{
snprintf(path, MAX_FILEPATH_LENGTH, "%s%s", DEFAULT_EVDEV_PATH, entity->d_name);
ConfigureEvdevDevice(path); // Configure the device if appropriate
}
}

View File

@ -477,7 +477,7 @@ void PollInputEvents(void)
if (kbhit())
{
int key = getch();
if (key == 27) CORE.Window.shouldClose = true; // KEY_SCAPE
if (key == 27) CORE.Window.shouldClose = true; // KEY_ESCAPE
}
}

View File

@ -1128,7 +1128,7 @@ void PollInputEvents(void)
// Register previous gamepad button states
for (int k = 0; k < MAX_GAMEPAD_BUTTONS; k++) CORE.Input.Gamepad.previousButtonState[i][k] = CORE.Input.Gamepad.currentButtonState[i][k];
EmscriptenGamepadEvent gamepadState;
EmscriptenGamepadEvent gamepadState = { 0 };
int result = emscripten_get_gamepad_status(i, &gamepadState);

View File

@ -353,7 +353,7 @@ void ProcessGestureEvent(GestureEvent event)
GESTURES.Drag.vector.y = GESTURES.Touch.moveDownPositionA.y - GESTURES.Touch.downDragPosition.y;
}
}
else if (GESTURES.Touch.pointCount == 2) // Two touch points
else if (GESTURES.Touch.pointCount == 2)
{
if (event.touchAction == TOUCH_ACTION_DOWN)
{

View File

@ -637,6 +637,8 @@ void DrawRectangleLinesEx(Rectangle rec, float thick, Color color)
else if (rec.width <= rec.height) thick = rec.width/2;
}
if (thick > 0.0f)
{
// When rec = { x, y, 8.0f, 6.0f } and thick = 2, the following
// four rectangles are drawn ([T]op, [B]ottom, [L]eft, [R]ight):
//
@ -648,13 +650,40 @@ void DrawRectangleLinesEx(Rectangle rec, float thick, Color color)
// BBBBBBBB
//
if (thick > 0.0f)
{
Rectangle top = { rec.x, rec.y, rec.width, thick };
Rectangle bottom = { rec.x, rec.y - thick + rec.height, rec.width, thick };
Rectangle left = { rec.x, rec.y + thick, thick, rec.height - thick*2.0f };
Rectangle right = { rec.x - thick + rec.width, rec.y + thick, thick, rec.height - thick*2.0f };
DrawRectangleRec(top, color);
DrawRectangleRec(bottom, color);
DrawRectangleRec(left, color);
DrawRectangleRec(right, color);
}
else
{
// When rec = { x, y, 8.0f, 6.0f } and thick = -2, the following
// four rectangles are drawn ([T]op, [B]ottom, [L]eft, [R]ight):
//
// TTTTTTTTTTTT
// TTTTTTTTTTTT
// LL RR
// LL RR
// LL RR
// LL RR
// LL RR
// LL RR
// BBBBBBBBBBBB
// BBBBBBBBBBBB
//
thick *= -1.0f;
Rectangle top = { rec.x - thick, rec.y - thick, rec.width + thick*2.0f, thick };
Rectangle bottom = { rec.x - thick, rec.y + rec.height, rec.width + thick*2.0f, thick};
Rectangle left = { rec.x - thick, rec.y, thick, rec.height };
Rectangle right = { rec.x + rec.width, rec.y, thick, rec.height };
DrawRectangleRec(top, color);
DrawRectangleRec(bottom, color);
DrawRectangleRec(left, color);
@ -931,22 +960,35 @@ void DrawRectangleRoundedLines(Rectangle rec, float roundness, int segments, Col
\ /
P5 ------------------ P4
*/
// The x-coordinates used for the outline
const float x0 = rec.x + radius + 0.5f;
const float x1 = (rec.x + rec.width) - radius - 0.5f;
const float x2 = rec.x + rec.width - 0.5f;
const float x3 = rec.x + 0.5f;
// The y-coordinates used for the outline
const float y0 = rec.y + 0.5f;
const float y1 = rec.y + radius + 0.5f;
const float y2 = (rec.y + rec.height) - radius - 0.5f;
const float y3 = rec.y + rec.height - 0.5f;
const Vector2 point[8] = {
{(float)rec.x + radius + 0.5f, rec.y + 0.5f},
{(float)(rec.x + rec.width) - radius - 0.5f, rec.y + 0.5f},
{rec.x + rec.width - 0.5f, (float)rec.y + radius + 0.5f}, // PO, P1, P2
{rec.x + rec.width - 0.5f, (float)(rec.y + rec.height) - radius - 0.5f},
{(float)(rec.x + rec.width) - radius - 0.5f, rec.y + rec.height - 0.5f}, // P3, P4
{(float)rec.x + radius + 0.5f, rec.y + rec.height - 0.5f},
{rec.x + 0.5f, (float)(rec.y + rec.height) - radius - 0.5f},
{rec.x + 0.5f, (float)rec.y + radius + 0.5f}, // P5, P6, P7
{x0, y0}, // P0
{x1, y0}, // P1
{x2, y1}, // P2
{x2, y2}, // P3
{x1, y3}, // P4
{x0, y3}, // P5
{x3, y2}, // P6
{x3, y1}, // P7
};
const Vector2 centers[4] = {
{(float)rec.x + radius + 0.5f, (float)rec.y + radius + 0.5f},
{(float)(rec.x + rec.width) - radius - 0.5f, (float)rec.y + radius + 0.5f}, // P16, P17
{(float)(rec.x + rec.width) - radius - 0.5f, (float)(rec.y + rec.height) - radius - 0.5f},
{(float)rec.x + radius + 0.5f, (float)(rec.y + rec.height) - radius - 0.5f} // P18, P19
{x0, y1}, // P16
{x1, y1}, // P17
{x1, y2}, // P18
{x0, y2} // P19
};
const float angles[4] = { 180.0f, 270.0f, 0.0f, 90.0f };
@ -980,32 +1022,81 @@ void DrawRectangleRoundedLines(Rectangle rec, float roundness, int segments, Col
// Draw rectangle with rounded edges outline with line thickness
void DrawRectangleRoundedLinesEx(Rectangle rec, float roundness, int segments, float thick, Color color)
{
if (thick <= 0) return;
// Not a rounded rectangle
if (roundness <= 0.0f)
{
DrawRectangleLinesEx((Rectangle){rec.x - thick, rec.y - thick, rec.width + 2*thick, rec.height + 2*thick}, thick, color);
DrawRectangleLinesEx(rec, thick, color);
return;
}
if (roundness >= 1.0f) roundness = 1.0f;
float radius = 0.0f;
float roundedOutlineThick = 0.0f;
float outerRadius = 0.0f;
float innerRadius = 0.0f;
if (thick >= 0.0f)
{
// Calculate corner radius
float radius = (rec.width > rec.height)? (rec.height*roundness)/2 : (rec.width*roundness)/2;
radius = (rec.width > rec.height)? (rec.height*roundness)/2 : (rec.width*roundness)/2;
if (radius <= 0.0f) return;
outerRadius = radius;
innerRadius = outerRadius - thick;
// The maximum thickness the outline can have and still be rounded on the interior edge is equal to the corner radius
// Put another way, when `innerRadius <= 0`, the interior of the outline is just a normal rectangle with no rounding
if (innerRadius <= 0.0f)
{
innerRadius = 0.0f;
roundedOutlineThick = outerRadius;
// Draw the not-rounded portion of the outline
DrawRectangleLinesEx((Rectangle){ rec.x + outerRadius, rec.y + outerRadius, rec.width - outerRadius*2.0f, rec.height - outerRadius*2.0f }, thick - outerRadius, color);
}
else
{
roundedOutlineThick = thick;
}
// Calculate number of segments to use for the corners
if (segments < 4)
{
// Calculate the maximum angle between segments based on the error rate (usually 0.5f)
float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/radius, 2) - 1);
float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/outerRadius, 2) - 1);
segments = (int)ceilf((2*PI/th)/4.0f);
if (segments <= 0) segments = 4;
}
}
else
{
thick *= -1.0f;
// Calculate corner radius
radius = (rec.width > rec.height)? (rec.height*roundness)/2 : (rec.width*roundness)/2;
if (radius <= 0.0f) return; // Only possible if the rectangle has 0 width or height
// Expand the rectangle
rec.x -= thick;
rec.y -= thick;
rec.width += thick*2.0f;
rec.height += thick*2.0f;
innerRadius = radius;
outerRadius = innerRadius + thick;
roundedOutlineThick = thick;
// Calculate number of segments to use for the corners
if (segments < 4)
{
// Calculate the maximum angle between segments based on the error rate (usually 0.5f)
float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/innerRadius, 2) - 1);
segments = (int)ceilf((2*PI/th)/4.0f);
if (segments <= 0) segments = 4;
}
}
float stepLength = 90.0f/(float)segments;
const float outerRadius = radius + thick, innerRadius = radius;
/*
Quick sketch to make sense of all of this,
@ -1023,30 +1114,47 @@ void DrawRectangleRoundedLinesEx(Rectangle rec, float roundness, int segments, f
\\ P13 P12 //
P5 ================== P4
*/
// The x-coordinates used for the outline
const float x0 = rec.x + outerRadius;
const float x1 = (rec.x + rec.width) - outerRadius;
const float x2 = rec.x + rec.width;
const float x3 = rec.x;
const float x4 = rec.x + rec.width - roundedOutlineThick;
const float x5 = rec.x + roundedOutlineThick;
// The y-coordinates used for the outline
const float y0 = rec.y;
const float y1 = rec.y + outerRadius;
const float y2 = (rec.y + rec.height) - outerRadius;
const float y3 = rec.y + rec.height;
const float y4 = rec.y + roundedOutlineThick;
const float y5 = rec.y + rec.height - roundedOutlineThick;
const Vector2 point[16] = {
{(float)rec.x + innerRadius + 0.5f, rec.y - thick + 0.5f},
{(float)(rec.x + rec.width) - innerRadius - 0.5f, rec.y - thick + 0.5f},
{rec.x + rec.width + thick - 0.5f, (float)rec.y + innerRadius + 0.5f}, // PO, P1, P2
{rec.x + rec.width + thick - 0.5f, (float)(rec.y + rec.height) - innerRadius - 0.5f},
{(float)(rec.x + rec.width) - innerRadius - 0.5f, rec.y + rec.height + thick - 0.5f}, // P3, P4
{(float)rec.x + innerRadius + 0.5f, rec.y + rec.height + thick - 0.5f},
{rec.x - thick + 0.5f, (float)(rec.y + rec.height) - innerRadius - 0.5f},
{rec.x - thick + 0.5f, (float)rec.y + innerRadius + 0.5f}, // P5, P6, P7
{(float)rec.x + innerRadius + 0.5f, rec.y + 0.5f},
{(float)(rec.x + rec.width) - innerRadius - 0.5f, rec.y + 0.5f}, // P8, P9
{rec.x + rec.width - 0.5f, (float)rec.y + innerRadius + 0.5f},
{rec.x + rec.width - 0.5f, (float)(rec.y + rec.height) - innerRadius - 0.5f}, // P10, P11
{(float)(rec.x + rec.width) - innerRadius - 0.5f, rec.y + rec.height - 0.5f},
{(float)rec.x + innerRadius + 0.5f, rec.y + rec.height - 0.5f}, // P12, P13
{rec.x + 0.5f, (float)(rec.y + rec.height) - innerRadius - 0.5f},
{rec.x + 0.5f, (float)rec.y + innerRadius + 0.5f} // P14, P15
{x0, y0}, // P0
{x1, y0}, // P1
{x2, y1}, // P2
{x2, y2}, // P3
{x1, y3}, // P4
{x0, y3}, // P5
{x3, y2}, // P6
{x3, y1}, // P7
{x0, y4}, // P8
{x1, y4}, // P9
{x4, y1}, // P10
{x4, y2}, // P11
{x1, y5}, // P12
{x0, y5}, // P13
{x5, y2}, // P14
{x5, y1} // P15
};
const Vector2 centers[4] = {
{(float)rec.x + innerRadius + 0.5f, (float)rec.y + innerRadius + 0.5f},
{(float)(rec.x + rec.width) - innerRadius - 0.5f, (float)rec.y + innerRadius + 0.5f}, // P16, P17
{(float)(rec.x + rec.width) - innerRadius - 0.5f, (float)(rec.y + rec.height) - innerRadius - 0.5f},
{(float)rec.x + innerRadius + 0.5f, (float)(rec.y + rec.height) - innerRadius - 0.5f} // P18, P19
{x0, y1}, // P16
{x1, y1}, // P17
{x1, y2}, // P18
{x0, y2} // P19
};
const float angles[4] = { 180.0f, 270.0f, 0.0f, 90.0f };
@ -1263,13 +1371,24 @@ void DrawPolyLines(Vector2 center, int sides, float radius, float rotation, Colo
void DrawPolyLinesEx(Vector2 center, int sides, float radius, float rotation, float thick, Color color)
{
if (thick <= 0.0f) return;
if (sides < 3) sides = 3;
float centralAngle = rotation*DEG2RAD;
float exteriorAngle = 360.0f/(float)sides*DEG2RAD;
float apothem = radius*cosf(DEG2RAD*180.0f/(float)sides);
float innerRadius = fmaxf(0.0f, radius - thick*(radius/apothem));
float outerRadius = 0.0f;
float innerRadius = 0.0f;
if (thick >= 0.0f)
{
outerRadius = radius;
innerRadius = fmaxf(0.0f, radius - thick*(radius/apothem));
}
else
{
thick *= -1.0f;
outerRadius = radius + thick*(radius/apothem);
innerRadius = radius;
}
#if SUPPORT_QUADS_DRAW_MODE
rlSetTexture(GetShapesTexture().id);
@ -1282,7 +1401,7 @@ void DrawPolyLinesEx(Vector2 center, int sides, float radius, float rotation, fl
float nextAngle = centralAngle + exteriorAngle;
rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
rlVertex2f(center.x + cosf(centralAngle)*radius, center.y + sinf(centralAngle)*radius);
rlVertex2f(center.x + cosf(centralAngle)*outerRadius, center.y + sinf(centralAngle)*outerRadius);
rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
rlVertex2f(center.x + cosf(centralAngle)*innerRadius, center.y + sinf(centralAngle)*innerRadius);
@ -1291,7 +1410,7 @@ void DrawPolyLinesEx(Vector2 center, int sides, float radius, float rotation, fl
rlVertex2f(center.x + cosf(nextAngle)*innerRadius, center.y + sinf(nextAngle)*innerRadius);
rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
rlVertex2f(center.x + cosf(nextAngle)*radius, center.y + sinf(nextAngle)*radius);
rlVertex2f(center.x + cosf(nextAngle)*outerRadius, center.y + sinf(nextAngle)*outerRadius);
centralAngle = nextAngle;
}
@ -1304,13 +1423,13 @@ void DrawPolyLinesEx(Vector2 center, int sides, float radius, float rotation, fl
rlColor4ub(color.r, color.g, color.b, color.a);
float nextAngle = centralAngle + exteriorAngle;
rlVertex2f(center.x + cosf(nextAngle)*radius, center.y + sinf(nextAngle)*radius);
rlVertex2f(center.x + cosf(centralAngle)*radius, center.y + sinf(centralAngle)*radius);
rlVertex2f(center.x + cosf(nextAngle)*outerRadius, center.y + sinf(nextAngle)*outerRadius);
rlVertex2f(center.x + cosf(centralAngle)*outerRadius, center.y + sinf(centralAngle)*outerRadius);
rlVertex2f(center.x + cosf(centralAngle)*innerRadius, center.y + sinf(centralAngle)*innerRadius);
rlVertex2f(center.x + cosf(centralAngle)*innerRadius, center.y + sinf(centralAngle)*innerRadius);
rlVertex2f(center.x + cosf(nextAngle)*innerRadius, center.y + sinf(nextAngle)*innerRadius);
rlVertex2f(center.x + cosf(nextAngle)*radius, center.y + sinf(nextAngle)*radius);
rlVertex2f(center.x + cosf(nextAngle)*outerRadius, center.y + sinf(nextAngle)*outerRadius);
centralAngle = nextAngle;
}