4 Commits

Author SHA1 Message Date
aa4cf20eae [rlsw] Variant dispatch refactor + bunch of improvements (#5996)
* rlsw config section

* use raster flags to define rasterizer variants

* simplifies the generation of dispatch tables

* single dispatch table for the lines
same logic as for the points

* internal color interp state

* check whether vertex colors should be interpolated

* vector op helper macro + pick sampler once before primitive drawing

* op order tweaks

* refactoring without gotos for triangle and quad rasterizers

* same cleaning for the lines
2026-07-21 18:22:58 +02:00
78535d2343 [rlsw] First batch of embedded optimizations and compiler requirements Pico 2 (#5994)
* pico doesn't implement time.h

* add option for RLSW to hold a back buffer, and give it a sw method to swap

* Remove unused pointer and give swSwapColorBuffers a default nop-behaviour

* Fix compilation by removing old colorBackBuffer setters

* use the correct logger

* return line

* rename RLSW_BACKBUFFER to SW_DOUBLE_BUFFERING
2026-07-21 18:20:58 +02:00
e809face7b [rmodels] DrawSphereWires(), code optimization (#6000)
* Fix DrawSphereWires (Less aggressively) 

Summary:
- Eliminated some redundancies
- Fixed a bug(?) where the sphere would have 1 more "ring" (latitude division) than expected
- Fixed a bug where the top ring was double-covered
- Added comments denoting which code draws which lines

* DrawSphereWires + DrawSphereEx parity

Summary:
- Replaced DrawSphereWires algorithm with one based on the much faster algorithm from DrawSphereEx
- Fixed +1 ring quirk on DrawSphereEx to match the change made to DrawSphereWires
2026-07-21 17:48:07 +02:00
9fd4726c31 [rshapes] Fix DrawRectangleRoundedLines() (#5992)
In #5980 a bug was introduced for `DrawRectangleRoundedLines()`. `DrawRectangleRoundedLines()` previously assumed that `DrawRectangleRoundedLinesEx()` uses `RL_LINES` when line thickness is 1 (which is no longer true, it now uses `RL_QUADS` or `RL_TRIANGLES`.)

I copy/pasted the previous `DrawRectangleRoundedLinesEx()` implementation and trimmed it down (since now the line thickness is always 1), so now `DrawRectangleRoundedLines()` uses `RL_LINES`. This makes it consistent with all other `Draw*Lines()` functions, which use `RL_LINES`.
2026-07-21 17:46:22 +02:00
4 changed files with 843 additions and 822 deletions

1430
src/external/rlsw.h vendored

File diff suppressed because it is too large Load Diff

View File

@ -110,7 +110,12 @@
#include <stdio.h> // Required for: FILE, fopen(), fseek(), ftell(), fread(), fwrite(), fprintf(), vprintf(), fclose(), sprintf() [Used in OpenURL()] #include <stdio.h> // Required for: FILE, fopen(), fseek(), ftell(), fread(), fwrite(), fprintf(), vprintf(), fclose(), sprintf() [Used in OpenURL()]
#include <string.h> // Required for: strlen(), strcmp(), strrchr(), memset(), memcpy(), strcat() #include <string.h> // Required for: strlen(), strcmp(), strrchr(), memset(), memcpy(), strcat()
#include <stdarg.h> // Required for: va_list, va_start(), va_end() [Used in TraceLog()] #include <stdarg.h> // Required for: va_list, va_start(), va_end() [Used in TraceLog()]
#ifndef PICO_RP2350
#include <time.h> // Required for: time() [Used in InitTimer()] #include <time.h> // Required for: time() [Used in InitTimer()]
#else
#include "pico/rand.h" // Pico doesn't implement time, and will implement its own hardware timer elsewhere. However, we need something to get a random seed from...
#endif
#include <math.h> // Required for: tan() [Used in BeginMode3D()], atan2f() [Used in LoadVrStereoConfig()] #include <math.h> // Required for: tan() [Used in BeginMode3D()], atan2f() [Used in LoadVrStereoConfig()]
#if defined(PLATFORM_MEMORY) || defined(PLATFORM_WEB) #if defined(PLATFORM_MEMORY) || defined(PLATFORM_WEB)
@ -713,8 +718,12 @@ void InitWindow(int width, int height, const char *title)
CORE.Time.frameCounter = 0; CORE.Time.frameCounter = 0;
CORE.Window.shouldClose = false; CORE.Window.shouldClose = false;
// Initialize random seed // Initialize random seed using available timer source instead of standard time() on embedded platforms
#ifndef PICO_RP2350
SetRandomSeed((unsigned int)time(NULL)); SetRandomSeed((unsigned int)time(NULL));
#else
SetRandomSeed(get_rand_32());
#endif
TRACELOG(LOG_INFO, "SYSTEM: Working Directory: %s", GetWorkingDirectory()); TRACELOG(LOG_INFO, "SYSTEM: Working Directory: %s", GetWorkingDirectory());
} }

View File

@ -488,7 +488,7 @@ void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color
rlBegin(RL_TRIANGLES); rlBegin(RL_TRIANGLES);
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);
float ringangle = DEG2RAD*(180.0f/(rings + 1)); // Angle between latitudinal parallels float ringangle = DEG2RAD*(180.0f/rings); // Angle between latitudinal parallels
float sliceangle = DEG2RAD*(360.0f/slices); // Angle between longitudinal meridians float sliceangle = DEG2RAD*(360.0f/slices); // Angle between longitudinal meridians
float cosring = cosf(ringangle); float cosring = cosf(ringangle);
@ -500,7 +500,7 @@ void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color
vertices[2] = (Vector3){ 0, 1, 0 }; vertices[2] = (Vector3){ 0, 1, 0 };
vertices[3] = (Vector3){ sinring, cosring, 0 }; vertices[3] = (Vector3){ sinring, cosring, 0 };
for (int i = 0; i < rings + 1; i++) for (int i = 0; i < rings; i++)
{ {
for (int j = 0; j < slices; j++) for (int j = 0; j < slices; j++)
{ {
@ -542,31 +542,42 @@ void DrawSphereWires(Vector3 centerPos, float radius, int rings, int slices, Col
rlBegin(RL_LINES); rlBegin(RL_LINES);
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);
for (int i = 0; i < (rings + 2); i++) float ringangle = DEG2RAD*(180.0f/rings); // Angle between latitudinal parallels
float sliceangle = DEG2RAD*(360.0f/slices); // Angle between longitudinal meridians
float cosring = cosf(ringangle);
float sinring = sinf(ringangle);
float cosslice = cosf(sliceangle);
float sinslice = sinf(sliceangle);
Vector3 vertices[4] = { 0 }; // Required to store face vertices
vertices[2] = (Vector3){ 0, 1, 0 };
vertices[3] = (Vector3){ sinring, cosring, 0 };
for (int i = 0; i < rings; i++)
{ {
for (int j = 0; j < slices; j++) for (int j = 0; j < slices; j++)
{ {
rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*i))*sinf(DEG2RAD*(360.0f*j/slices)), vertices[0] = vertices[2]; // Rotate around y axis to set up vertices for next face
sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*i)), vertices[1] = vertices[3];
cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*i))*cosf(DEG2RAD*(360.0f*j/slices))); vertices[2] = (Vector3){ cosslice*vertices[2].x - sinslice*vertices[2].z, vertices[2].y, sinslice*vertices[2].x + cosslice*vertices[2].z }; // Rotation matrix around y axis
rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*sinf(DEG2RAD*(360.0f*(j + 1)/slices)), vertices[3] = (Vector3){ cosslice*vertices[3].x - sinslice*vertices[3].z, vertices[3].y, sinslice*vertices[3].x + cosslice*vertices[3].z };
sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1))),
cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*cosf(DEG2RAD*(360.0f*(j + 1)/slices)));
rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*sinf(DEG2RAD*(360.0f*(j + 1)/slices)), // Longitude Lines
sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1))), rlVertex3f(vertices[0].x, vertices[0].y, vertices[0].z);
cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*cosf(DEG2RAD*(360.0f*(j + 1)/slices))); rlVertex3f(vertices[1].x, vertices[1].y, vertices[1].z);
rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*sinf(DEG2RAD*(360.0f*j/slices)),
sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1))),
cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*cosf(DEG2RAD*(360.0f*j/slices)));
rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*sinf(DEG2RAD*(360.0f*j/slices)), // Latitude Lines
sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1))), rlVertex3f(vertices[0].x, vertices[0].y, vertices[0].z);
cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*cosf(DEG2RAD*(360.0f*j/slices))); rlVertex3f(vertices[2].x, vertices[2].y, vertices[2].z);
rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*i))*sinf(DEG2RAD*(360.0f*j/slices)),
sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*i)), // Diagonal Lines
cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*i))*cosf(DEG2RAD*(360.0f*j/slices))); rlVertex3f(vertices[0].x, vertices[0].y, vertices[0].z);
rlVertex3f(vertices[3].x, vertices[3].y, vertices[3].z);
} }
vertices[2] = vertices[3]; // Rotate around z axis to set up starting vertices for next ring
vertices[3] = (Vector3){ cosring*vertices[3].x + sinring*vertices[3].y, -sinring*vertices[3].x + cosring*vertices[3].y, vertices[3].z }; // Rotation matrix around z axis
} }
rlEnd(); rlEnd();
rlPopMatrix(); rlPopMatrix();

View File

@ -888,7 +888,90 @@ void DrawRectangleRounded(Rectangle rec, float roundness, int segments, Color co
// Draw rectangle with rounded edges // Draw rectangle with rounded edges
void DrawRectangleRoundedLines(Rectangle rec, float roundness, int segments, Color color) void DrawRectangleRoundedLines(Rectangle rec, float roundness, int segments, Color color)
{ {
DrawRectangleRoundedLinesEx(rec, roundness, segments, 1.0f, color); // Not a rounded rectangle
if (roundness <= 0.0f)
{
DrawRectangleLines((int)rec.x, (int)rec.y, (int)rec.width, (int)rec.height, color);
return;
}
if (roundness >= 1.0f) roundness = 1.0f;
// Calculate corner radius
float radius = (rec.width > rec.height)? (rec.height*roundness)/2 : (rec.width*roundness)/2;
if (radius <= 0.0f) return;
// 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);
segments = (int)ceilf((2*PI/th)/4.0f);
if (segments <= 0) segments = 4;
}
float stepLength = 90.0f/(float)segments;
/*
Quick sketch to make sense of all of this,
marks the 8 + 4 (corner centers P8-11) points used
P0 ------------------ P1
/ \
/ \
P7 / \ P2
| *P8 P9* |
| |
| |
P6 \ *P11 P10* / P3
\ /
\ /
P5 ------------------ P4
*/
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
};
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
};
const float angles[4] = { 180.0f, 270.0f, 0.0f, 90.0f };
rlBegin(RL_LINES);
// Draw all the 4 corners first: Upper Left Corner, Upper Right Corner, Lower Right Corner, Lower Left Corner
for (int k = 0; k < 4; ++k) // Hope the compiler is smart enough to unroll this loop
{
float angle = angles[k];
const Vector2 center = centers[k];
for (int i = 0; i < segments; i++)
{
rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2f(center.x + cosf(DEG2RAD*angle)*radius, center.y + sinf(DEG2RAD*angle)*radius);
rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*radius, center.y + sinf(DEG2RAD*(angle + stepLength))*radius);
angle += stepLength;
}
}
// And now the remaining 4 lines
for (int i = 0; i < 8; i += 2)
{
rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2f(point[i].x, point[i].y);
rlVertex2f(point[i + 1].x, point[i + 1].y);
}
rlEnd();
} }
// Draw rectangle with rounded edges outline with line thickness // Draw rectangle with rounded edges outline with line thickness