3 Commits

Author SHA1 Message Date
Ray
5f886e208a ADDED: ImageDrawRectangleGradientEx(), implemented function 2026-09-21 22:26:03 +02:00
Ray
d33888dd28 Update rtextures.c 2026-09-21 18:43:44 +02:00
Ray
5f83146cac Some code claaning 2026-09-21 18:18:42 +02:00
11 changed files with 71 additions and 73 deletions

35
src/external/rlsw.h vendored
View File

@ -1402,12 +1402,10 @@ static SW_INLINE void sw_color8_to_color(float *SW_RESTRICT dst, const uint8_t *
uint32x4_t dwords = vmovl_u16(vget_low_u16(words));
float32x4_t fvals = vmulq_f32(vcvtq_f32_u32(dwords), vdupq_n_f32(SW_INV_255));
vst1q_f32(dst, fvals);
#elif defined(SW_HAS_SSE41)
__m128i bytes = _mm_loadu_si32(src);
__m128 fvals = _mm_mul_ps(_mm_cvtepi32_ps(_mm_cvtepu8_epi32(bytes)), _mm_set1_ps(SW_INV_255));
_mm_storeu_ps(dst, fvals);
#elif defined(SW_HAS_SSE2)
__m128i zero = _mm_setzero_si128();
__m128i bytes = _mm_loadu_si32(src);
@ -1415,22 +1413,13 @@ static SW_INLINE void sw_color8_to_color(float *SW_RESTRICT dst, const uint8_t *
__m128i dwords = _mm_unpacklo_epi16(words, zero);
__m128 fvals = _mm_mul_ps(_mm_cvtepi32_ps(dwords), _mm_set1_ps(SW_INV_255));
_mm_storeu_ps(dst, fvals);
#elif defined(SW_HAS_RVV)
// TODO: WARNING: Sample code generated by AI, needs testing and review
size_t vl = __riscv_vsetvl_e8m1(4); // Set vector length for 8-bit input elements
vuint8m1_t vsrc_u8 = __riscv_vle8_v_u8m1(src, vl); // Load 4 unsigned 8-bit integers
vuint32m1_t vsrc_u32 = __riscv_vwcvt_xu_u_v_u32m1(vsrc_u8, vl); // Widen to 32-bit unsigned integers
vfloat32m1_t vsrc_f32 = __riscv_vfcvt_f_xu_v_f32m1(vsrc_u32, vl); // Convert to float32
vfloat32m1_t vnorm = __riscv_vfmul_vf_f32m1(vsrc_f32, SW_INV_255, vl); // Multiply by 1/255.0 to normalize
__riscv_vse32_v_f32m1(dst, vnorm, vl); // Store result
// TODO: Implement RVV intrinsics
#elif RLSW_USE_COLOR_LUT
dst[0] = SW_LUT_UINT8_TO_FLOAT[src[0]];
dst[1] = SW_LUT_UINT8_TO_FLOAT[src[1]];
dst[2] = SW_LUT_UINT8_TO_FLOAT[src[2]];
dst[3] = SW_LUT_UINT8_TO_FLOAT[src[3]];
#else
dst[0] = (float)src[0]*SW_INV_255;
dst[1] = (float)src[1]*SW_INV_255;
@ -1447,39 +1436,21 @@ static SW_INLINE void sw_color_to_color8(uint8_t *SW_RESTRICT dst, const float *
uint16x4_t i16 = vmovn_u32(i32);
uint8x8_t i8 = vmovn_u16(vcombine_u16(i16, i16));
vst1_lane_u32((uint32_t *)dst, vreinterpret_u32_u8(i8), 0);
#elif defined(SW_HAS_SSE41)
__m128 fvals = _mm_mul_ps(_mm_loadu_ps(src), _mm_set1_ps(255.0f));
__m128i i32 = _mm_cvttps_epi32(fvals);
__m128i i16 = _mm_packus_epi32(i32, i32);
__m128i i8 = _mm_packus_epi16(i16, i16);
_mm_storeu_si32(dst, i8);
#elif defined(SW_HAS_SSE2)
__m128 fvals = _mm_mul_ps(_mm_loadu_ps(src), _mm_set1_ps(255.0f));
__m128i i32 = _mm_cvttps_epi32(fvals);
__m128i i16 = _mm_packs_epi32(i32, i32);
__m128i i8 = _mm_packus_epi16(i16, i16);
_mm_storeu_si32(dst, i8);
#elif defined(SW_HAS_RVV)
// TODO: WARNING: Sample code generated by AI, needs testing and review
// REVIEW: It shouldn't perform so many operations; take inspiration from other versions
// TODO: Implement RVV intrinsics
// NOTE: RVV 1.0 specs define the use of __riscv_ prefix for instrinsic functions
size_t vl = __riscv_vsetvl_e32m1(4); // Load up to 4 floats into a vector register
vfloat32m1_t vsrc = __riscv_vle32_v_f32m1(src, vl); // Load float32 values
// Multiply by 255.0f and add 0.5f for rounding
vfloat32m1_t vscaled = __riscv_vfmul_vf_f32m1(vsrc, 255.0f, vl);
vscaled = __riscv_vfadd_vf_f32m1(vscaled, 0.5f, vl);
// Convert to unsigned integer (truncate toward zero)
vuint32m1_t vu32 = __riscv_vfcvt_xu_f_v_u32m1(vscaled, vl);
// Narrow from u32 -> u8
vuint8m1_t vu8 = __riscv_vnclipu_wx_u8m1(vu32, 0, vl); // Round toward zero
__riscv_vse8_v_u8m1(dst, vu8, vl); // Store result
#else
dst[0] = (uint8_t)(src[0]*255.0f);
dst[1] = (uint8_t)(src[1]*255.0f);
@ -4062,7 +4033,6 @@ void *swGetColorBuffer(int *width, int *height)
return RLSW.framebuffer.color.pixels;
}
void swSwapColorBuffers(void)
{
#if RLSW_DOUBLE_BUFFERING
@ -4077,7 +4047,6 @@ void swSwapColorBuffers(void)
#endif
}
void swEnable(SWstate state)
{
switch (state)

View File

@ -1222,7 +1222,6 @@ void OpenURL(const char *url)
#if defined(__APPLE__)
sprintf(cmd, "open '%s'", url);
#endif
// TODO: Replace system() call by custom process
int result = system(cmd);
if (result == -1) TRACELOG(LOG_WARNING, "OpenURL() child process could not be created");

View File

@ -2236,7 +2236,7 @@ static void PollKeyboardEvents(void)
if (CORE.Input.Keyboard.charPressedQueueCount < MAX_CHAR_PRESSED_QUEUE)
{
// TODO/FIXME: This is not actually converting to unicode properly because it's not taking things like shift into account
// TODO: WARNING: This is not actually converting to unicode properly because it's not taking things like shift into account
CORE.Input.Keyboard.charPressedQueue[CORE.Input.Keyboard.charPressedQueueCount] = evkeyToUnicodeLUT[event.code];
CORE.Input.Keyboard.charPressedQueueCount++;
}

View File

@ -54,8 +54,8 @@
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
// TODO: HACK: Added flag if not provided by GLFW when using external library
// Latest GLFW release (GLFW 3.3.8) does not implement this flag, it was added for 3.4.0-dev
// NOTE: Added flag if not provided by GLFW when using external library
// WARNING: Latest GLFW release (GLFW 3.3.8) does not implement this flag, it was added for 3.4.0-dev
#if !defined(GLFW_MOUSE_PASSTHROUGH)
#define GLFW_MOUSE_PASSTHROUGH 0x0002000D
#endif
@ -1313,9 +1313,8 @@ int InitPlatform(void)
}, platform.canvasId);
// Load memory framebuffer with desired screen size
// NOTE: Despite using a software framebuffer for blitting, GLFW still creates a WebGL canvas,
// WARNING: Despite using a software framebuffer for blitting, GLFW still creates a WebGL canvas,
// but it is not being used, on SwapScreenBuffer() the pure software renderer is used
// TODO: Consider requesting another type of canvas, not a WebGL one --> Replace GLFW-web by Emscripten?
platform.pixels = (unsigned int *)RL_CALLOC(CORE.Window.screen.width*CORE.Window.screen.height, sizeof(unsigned int));
#else
if (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE))
@ -1406,7 +1405,9 @@ int InitPlatform(void)
glfwSetCursorEnterCallback(platform.handle, MouseEnterCallback);
glfwMakeContextCurrent(platform.handle);
result = true; // TODO: WARNING: glfwGetError(NULL); symbol can not be found in Web
// WARNING: result = glfwGetError(NULL), symbol can not be found in GLFW Web
result = true;
// Check context activation
if (result == true) //(result != GLFW_NO_WINDOW_CONTEXT) && (result != GLFW_PLATFORM_ERROR))

View File

@ -389,7 +389,6 @@ RMAPI float Vector2LineAngle(Vector2 start, Vector2 end)
{
float result = 0.0f;
// TODO(10/9/2023): Currently angles move clockwise, determine if this is wanted behavior
result = -atan2f(end.y - start.y, end.x - start.x);
return result;
@ -2703,7 +2702,7 @@ RMAPI Matrix MatrixCompose(Vector3 translation, Quaternion rotation, Vector3 sca
}
// Decompose a transformation matrix into its rotational, translational and scaling components and remove shear
// TODO: This function is not following raymath conventions defined in header: NOT self-contained
// TODO: WARNING: Following raymath convention and make the function self-contained
RMAPI void MatrixDecompose(Matrix mat, Vector3 *translation, Quaternion *rotation, Vector3 *scale)
{
float eps = (float)1e-9;

View File

@ -478,7 +478,7 @@ static const char *autoEventTypeName[] = {
static AutomationEventList *currentEventList = NULL; // Current automation events list, set by user, keep internal pointer
static bool automationEventRecording = false; // Recording automation events flag
//static short automationEventEnabled = 0b0000001111111111; // TODO: Automation events enabled for recording/playing
//static short automationEventEnabled = 0b0000001111111111; // Automation events enabled for recording/playing
#endif
//-----------------------------------------------------------------------------------
@ -535,8 +535,6 @@ const char *TextFormat(const char *text, ...); // Formatting of text with variab
#elif defined(PLATFORM_MEMORY)
#include "platforms/rcore_memory.c"
#else
// TODO: Include your custom platform backend!
// i.e software rendering backend or console backend!
#pragma message ("WARNING: No [rcore] platform defined")
#endif
@ -611,8 +609,6 @@ void InitWindow(int width, int height, const char *title)
#elif defined(PLATFORM_MEMORY)
TRACELOG(LOG_INFO, "Platform backend: MEMORY (No OS)");
#else
// TODO: Include your custom platform backend!
// i.e software rendering backend or console backend!
TRACELOG(LOG_INFO, "Platform backend: CUSTOM");
#endif
@ -4570,7 +4566,7 @@ static void RecordAutomationEvent(void)
if ((CORE.Input.Gamepad.currentState[gamepad] != CORE.Input.Gamepad.previousState[gamepad]) &&
(CORE.Input.Gamepad.currentState[gamepad])) // Check if changed to ready
{
// TODO: Save gamepad connect event
// TODO: Automation event: Save gamepad connect event
}
*/
@ -4579,7 +4575,7 @@ static void RecordAutomationEvent(void)
if ((CORE.Input.Gamepad.currentState[gamepad] != CORE.Input.Gamepad.previousState[gamepad]) &&
(!CORE.Input.Gamepad.currentState[gamepad])) // Check if changed to not-ready
{
// TODO: Save gamepad disconnect event
// TODO: Automation event: Save gamepad disconnect event
}
*/

View File

@ -886,7 +886,7 @@ RLAPI void rlLoadDrawQuad(void); // Load and draw a quad
#elif defined(GRAPHICS_API_OPENGL_ES2)
// NOTE: OpenGL ES 2.0 can be enabled on Desktop platforms,
// in that case, functions are loaded from a custom glad for OpenGL ES 2.0
// TODO: OpenGL ES 2.0 support shouldn't be platform-dependent, neither require GLAD
// TODO: rlgl OpenGL ES 2.0 selection shouldn't depend on raylib platform macros, a specific GLAD shouldn't be neither required
#if defined(PLATFORM_DESKTOP_GLFW) || defined(PLATFORM_DESKTOP_SDL)
#define GLAD_GLES2_IMPLEMENTATION
#include "external/glad_gles2.h"
@ -2966,8 +2966,9 @@ void rlDrawRenderBatch(rlRenderBatch *batch)
// Activate elements VAO
if (RLGL.ExtSupported.vao) glBindVertexArray(batch->vertexBuffer[batch->currentBuffer].vaoId);
// TODO: If no data changed on the CPU arrays there is no need to re-upload data to GPU,
// a flag can be used to detect changes but it would imply keeping a copy buffer and memcmp() both, does it worth it?
// NOTE: If no data changed on the CPU arrays there is no need to re-upload data to GPU,
// a flag can be used to detect changes but it would imply keeping a copy buffer and memcmp() both
// It was tested and the gain seemed to be minimal or nothing at all, probably driver already takes care of that
// Vertex positions buffer
glBindBuffer(GL_ARRAY_BUFFER, batch->vertexBuffer[batch->currentBuffer].vboId[0]);
@ -3240,7 +3241,6 @@ unsigned int rlLoadTexture(const void *data, int width, int height, int format,
#if defined(GRAPHICS_API_OPENGL_11)
if (format >= RL_PIXELFORMAT_COMPRESSED_DXT1_RGB)
{
// TODO: Support texture data decompression
TRACELOG(RL_LOG_WARNING, "GL: OpenGL 1.1 does not support GPU compressed texture formats");
return id;
}

View File

@ -2041,12 +2041,12 @@ bool ExportMesh(Mesh mesh, const char *fileName)
{
// TODO: Implement gltf/glb support
/*
cgltf_size expected = cgltf_write(options, NULL, 0, data);
char *buffer = (char *)RL_CALLOC(expected, 0);
cgltf_size actual = cgltf_write(options, buffer, expected, data);
cgltf_size expectedSize = cgltf_write(options, NULL, 0, data);
char *buffer = (char *)RL_CALLOC(expectedSize, 0);
cgltf_size actualSize = cgltf_write(options, buffer, expectedSize, data);
// NOTE: cgltf_write() includes a NULL terminator that should be ommited in case of a .glb
if (options->type == cgltf_file_type_glb) cgltf_write_glb(file, buffer, actual - 1, data->bin, data->bin_size);
if (options->type == cgltf_file_type_glb) cgltf_write_glb(fileName, buffer, actual - 1, data->bin, data->bin_size);
else SaveFileText(fileName, buffer); // Write a plain JSON file
*/
}
@ -2197,8 +2197,6 @@ Material *LoadMaterials(const char *fileName, int *materialCount)
Material *materials = NULL;
unsigned int count = 0;
// TODO: Support IQM and GLTF for materials parsing
#if SUPPORT_FILEFORMAT_MTL
if (IsFileExtension(fileName, ".mtl"))
{
@ -5142,7 +5140,7 @@ static ModelAnimation *LoadModelAnimationsIQM(const char *fileName, int *animCou
animations[a].keyframeCount = anim[a].num_frames;
animations[a].keyframePoses = (Transform **)RL_CALLOC(anim[a].num_frames, sizeof(Transform *));
memcpy(animations[a].name, fileDataPtr + iqmHeader->ofs_text + anim[a].name, 32);
// TODO: Use animation framerate data?
// TODO: Store animation framerate data?
//animations[a].framerate = anim.framerate;
TRACELOG(LOG_INFO, "MODEL: [%s] Loaded animation: %s | Frames: %d | Framerate: %f", fileName, animations[a].name, animations[a].keyframeCount, anim[a].framerate);

View File

@ -3773,10 +3773,7 @@ void DrawSplineLinear(const Vector2 *points, int pointCount, float thick, Color
normal.y = 0.0f;
}
}
else
{
normal = prevNormal;
}
else normal = prevNormal;
Vector2 radius = { prevNormal.x + normal.x, prevNormal.y + normal.y };
float radiusLength = sqrtf(radius.x*radius.x + radius.y*radius.y);

View File

@ -638,7 +638,6 @@ GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSiz
{
bool genFontChars = false;
stbtt_fontinfo fontInfo = { 0 };
// TODO: Should a shallow copy be created to avoid "dealing" with a const user array?
int *requiredCodepoints = (int *)codepoints;
if (stbtt_InitFont(&fontInfo, (unsigned char *)fileData, 0)) // Initialize font for data reading
@ -1797,8 +1796,6 @@ char *TextReplace(const char *text, const char *search, const char *replacement)
if ((textLen + count*(replaceLen - searchLen)) < (MAX_TEXT_BUFFER_LENGTH - 1))
{
// TODO: Allow copying data replaced up to maximum buffer size and stop
tempPtr = buffer; // Point to result start
// First time through the loop, all the variable are set correctly from here on,
@ -1988,8 +1985,6 @@ char *TextInsert(const char *text, const char *insert, int position)
if ((textLen + insertLen) < (MAX_TEXT_BUFFER_LENGTH - 1))
{
// TODO: Allow copying data inserted up to maximum buffer size and stop
for (int i = 0; i < position; i++) buffer[i] = text[i];
for (int i = 0; i < insertLen; i++) buffer[i+position] = insert[i];
for (int i = position; i < textLen; i++) buffer[i+insertLen] = text[i];
@ -2131,7 +2126,7 @@ int TextFindIndex(const char *text, const char *search)
// Get upper case version of provided string
// WARNING: Limited functionality, only basic characters set
// TODO: Support UTF-8 diacritics to upper-case, check codepoints
// TODO: Support UTF-8 diacritics (á, ñ, ü...) to upper-case, check codepoints
char *TextToUpper(const char *text)
{
static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };

View File

@ -1592,7 +1592,7 @@ Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Co
TRACELOG(LOG_INFO, "IMAGE: Text scaled by factor: %f", scaleFactor);
// Using nearest-neighbor scaling algorithm for default font
// TODO: Allow defining the preferred scaling mechanism externally
// TODO: Support selection of preferred scaling mechanism, use flag?
if (font.texture.id == GetFontDefault().texture.id) ImageResizeNN(&imText, (int)(imSize.x*scaleFactor), (int)(imSize.y*scaleFactor));
else ImageResize(&imText, (int)(imSize.x*scaleFactor), (int)(imSize.y*scaleFactor));
}
@ -1654,7 +1654,7 @@ Image ImageFromChannel(Image image, int selectedChannel)
selectedChannel = 3;
}
// TODO: Consider other one-channel formats: R16, R32
// TODO: Support R16 and R32 channel sizes, not only 8-bit
result.format = PIXELFORMAT_UNCOMPRESSED_GRAYSCALE;
result.height = image.height;
result.width = image.width;
@ -3965,7 +3965,51 @@ void ImageDrawRectangleLinesEx(Image *dst, Rectangle rec, int thick, Color color
// Draw rectangle with gradient colors within an image, counter-clockwise color order
void ImageDrawRectangleGradientEx(Image *dst, Rectangle rec, Color col1, Color col2, Color col3, Color col4)
{
// TODO: NEW: Implement ImageDrawRectangleGradientEx()
if ((dst == NULL) || (rec.width <= 0) || (rec.height <= 0)) return;
int x0 = (int)floorf(rec.x);
int y0 = (int)floorf(rec.y);
int x1 = (int)ceilf(rec.x + rec.width);
int y1 = (int)ceilf(rec.y + rec.height);
// Limit draw to image bounds
if (x0 < 0) x0 = 0;
if (y0 < 0) y0 = 0;
if (x1 > dst->width) x1 = dst->width;
if (y1 > dst->height) y1 = dst->height;
// Safety check
if ((x0 >= x1) || (y0 >= y1)) return;
for (int y = y0; y < y1; y++)
{
float ty = (y - rec.y)/rec.height;
if (ty < 0.0f) ty = 0.0f;
if (ty > 1.0f) ty = 1.0f;
for (int x = x0; x < x1; x++)
{
float tx = (x - rec.x)/rec.width;
if (tx < 0.0f) tx = 0.0f;
if (tx > 1.0f) tx = 1.0f;
// Bilinear interpolation weights
float w1 = (1.0f - tx)*(1.0f - ty);
float w2 = (1.0f - tx)*ty;
float w3 = tx*ty;
float w4 = tx*(1.0f - ty);
Color color = {
(unsigned char)(col1.r*w1 + col2.r*w2 + col3.r*w3 + col4.r*w4),
(unsigned char)(col1.g*w1 + col2.g*w2 + col3.g*w3 + col4.g*w4),
(unsigned char)(col1.b*w1 + col2.b*w2 + col3.b*w3 + col4.b*w4),
(unsigned char)(col1.a*w1 + col2.a*w2 + col3.a*w3 + col4.a*w4)
};
// Using ImageDrawPixel() to let it manage color format conversion
ImageDrawPixel(dst, x, y, color);
}
}
}
// Draw circle within an image