4 Commits

Author SHA1 Message Date
8d246fdaff Fix EXTERNAL_CONFIG_FLAGS being defined even when no custom config is used when building with zig (#5410) 2025-12-15 00:03:31 +01:00
Ray
a0fd5ab1d9 Update rmodels.c 2025-12-14 19:59:12 +01:00
Ray
9a337f3b3b ADDED: Support software renderer on Web, blitting framebuffer data directly to a 2d canvas
This improvement is just a prove of concept, at this moment `PLATFORM_WEB` is limited in terms of software rendering by `GLFW` that only allows creating a WebGL canvas context with `glfwCreateWindow()`.

We can skip that call but then some GLFW functionality is not available (windowing, inputs). The best solution is replacing GLFW completely by a pure Emscripten implementation for `PLATFORM_WEB`.
2025-12-14 19:52:18 +01:00
Ray
5025009860 REVIEWED: Make sure all variables are initialized on definition, prioritize one line per variable definitions 2025-12-14 19:45:28 +01:00
9 changed files with 110 additions and 33 deletions

View File

@ -155,9 +155,9 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.
);
}
// Sets a flag indicating the use of a custom `config.h`
try raylib_flags_arr.append(b.allocator, "-DEXTERNAL_CONFIG_FLAGS");
if (options.config.len > 0) {
// Sets a flag indicating the use of a custom `config.h`
try raylib_flags_arr.append(b.allocator, "-DEXTERNAL_CONFIG_FLAGS");
// Splits a space-separated list of config flags into multiple flags
//
// Note: This means certain flags like `-x c++` won't be processed properly.

8
src/external/rlsw.h vendored
View File

@ -2217,7 +2217,7 @@ static inline bool sw_triangle_face_culling(void)
const float *h2 = RLSW.vertexBuffer[2].homogeneous;
// Compute a value proportional to the signed area in the projected 2D plane,
// calculated directly using homogeneous coordinates BEFORE division by w.
// calculated directly using homogeneous coordinates BEFORE division by w
// This is the determinant of the matrix formed by the (x, y, w) components
// of the vertices, which correctly captures the winding order in homogeneous
// space and its relationship to the projected 2D winding order, even with
@ -2235,13 +2235,13 @@ static inline bool sw_triangle_face_culling(void)
// Discard the triangle if its winding order (determined by the sign
// of the homogeneous area/determinant) matches the culled direction
// A positive hSgnArea typically corresponds to a counter-clockwise
// winding in the projected space when all w > 0.
// winding in the projected space when all w > 0
// This test is robust for points with w > 0 or w < 0, correctly
// capturing the change in orientation when crossing the w=0 plane
// The culling logic remains the same based on the signed area/determinant
// A value of 0 for hSgnArea means the points are collinear in (x, y, w)
// space, which corresponds to a degenerate triangle projection.
// space, which corresponds to a degenerate triangle projection
// Such triangles are typically not culled by this test (0 < 0 is false, 0 > 0 is false)
// and should be handled by the clipper if necessary
return (RLSW.cullFace == SW_FRONT)? (hSgnArea < 0) : (hSgnArea > 0); // Cull if winding is "clockwise" : "counter-clockwise"
@ -2602,7 +2602,7 @@ static inline bool sw_quad_face_culling(void)
// space, which corresponds to a degenerate triangle projection
// Such quads might also be degenerate or non-planar. They are typically
// not culled by this test (0 < 0 is false, 0 > 0 is false)
// and should be handled by the clipper if necessary.
// and should be handled by the clipper if necessary
return (RLSW.cullFace == SW_FRONT)? (hSgnArea < 0.0f) : (hSgnArea > 0.0f); // Cull if winding is "clockwise" : "counter-clockwise"
}

View File

@ -894,7 +894,8 @@ Vector2 GetMonitorPosition(int monitor)
if ((monitor >= 0) && (monitor < monitorCount))
{
int x, y;
int x = 0;
int y = 0;
glfwGetMonitorPos(monitors[monitor], &x, &y);
return (Vector2){ (float)x, (float)y };

View File

@ -428,7 +428,7 @@ void SetMouseCursor(int cursor)
TRACELOG(LOG_WARNING, "SetMouseCursor() not implemented on target platform");
}
// Get physical key name.
// Get physical key name
const char *GetKeyName(int key)
{
TRACELOG(LOG_WARNING, "GetKeyName() not implemented on target platform");

View File

@ -78,6 +78,11 @@ typedef struct {
int unmaximizedHeight; // Internal var to store the unmaximized window (canvas) height
char canvasId[64]; // Keep current canvas id where wasm app is running
// NOTE: Useful when trying to run multiple wasms in different canvases in same webpage
#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
unsigned int *pixels; // Pointer to pixel data buffer (RGBA 32bit format)
#endif
} PlatformData;
//----------------------------------------------------------------------------------
@ -264,7 +269,8 @@ void ToggleFullscreen(void)
};
emscripten_enter_soft_fullscreen(platform.canvasId, &strategy);
int width, height;
int width = 0;
int height = 0;
emscripten_get_canvas_element_size(platform.canvasId, &width, &height);
TRACELOG(LOG_WARNING, "Emscripten: Enter fullscreen: Canvas size: %i x %i", width, height);
@ -883,7 +889,32 @@ void DisableCursor(void)
// Swap back buffer with front buffer (screen drawing)
void SwapScreenBuffer(void)
{
#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
// Update framebuffer
rlCopyFramebuffer(0, 0, CORE.Window.render.width, CORE.Window.render.height, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, platform.pixels);
// Copy framebuffer data into canvas
EM_ASM({
const width = $0;
const height = $1;
const ptr = $2;
// Get canvas and 2d context created
const canvas = Module.canvas;
const ctx = canvas.getContext('2d');
if (!Module.__img || (Module.__img.width !== width) || (Module.__img.height !== height)) {
Module.__img = ctx.createImageData(width, height);
}
const src = HEAPU8.subarray(ptr, ptr + width*height*4); // RGBA (4 bytes)
Module.__img.data.set(src);
ctx.putImageData(Module.__img, 0, 0);
}, CORE.Window.screen.width, CORE.Window.screen.height, platform.pixels);
#else
glfwSwapBuffers(platform.handle);
#endif
}
//----------------------------------------------------------------------------------
@ -974,7 +1005,7 @@ void SetMouseCursor(int cursor)
}
}
// Get physical key name.
// Get physical key name
const char *GetKeyName(int key)
{
TRACELOG(LOG_WARNING, "GetKeyName() not implemented on target platform");
@ -1214,7 +1245,21 @@ int InitPlatform(void)
// Init fullscreen toggle required var:
platform.ourFullscreen = false;
#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
// Avoid creating a WebGL canvas, avoid calling glfwCreateWindow()
emscripten_set_canvas_element_size(platform.canvasId, CORE.Window.screen.width, CORE.Window.screen.height);
EM_ASM({
const canvas = document.getElementById("canvas");
Module.canvas = canvas;
});
// Load memory framebuffer with desired screen size
// NOTE: 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 (CORE.Window.fullscreen)
{
// remember center for switchinging from fullscreen to window
@ -1289,6 +1334,7 @@ int InitPlatform(void)
TRACELOG(LOG_WARNING, "GLFW: Failed to initialize Window");
return -1;
}
#endif
// WARNING: glfwCreateWindow() title doesn't work with emscripten
emscripten_set_window_title((CORE.Window.title != 0)? CORE.Window.title : " ");

View File

@ -117,7 +117,7 @@
#include <time.h> // Required for: time() [Used in InitTimer()]
#include <math.h> // Required for: tan() [Used in BeginMode3D()], atan2f() [Used in LoadVrStereoConfig()]
#if defined(PLATFORM_MEMORY)
#if defined(PLATFORM_MEMORY) || defined(PLATFORM_WEB)
#define SW_GL_FRAMEBUFFER_COPY_BGRA false
#endif
#define RLGL_IMPLEMENTATION

View File

@ -3655,7 +3655,7 @@ void GenMeshTangents(Mesh *mesh)
for (int t = 0; t < mesh->triangleCount; t++)
{
// Get triangle vertex indices
int i0, i1, i2;
int i0 = 0, i1 = 0, i2 = 0;
if (mesh->indices != NULL)
{
@ -4150,7 +4150,9 @@ RayCollision GetRayCollisionMesh(Ray ray, Mesh mesh, Matrix transform)
// Test against all triangles in mesh
for (int i = 0; i < triangleCount; i++)
{
Vector3 a, b, c;
Vector3 a = { 0 };
Vector3 b = { 0 };
Vector3 c = { 0 };
Vector3 *vertdata = (Vector3 *)mesh.vertices;
if (mesh.indices)
@ -4193,8 +4195,10 @@ RayCollision GetRayCollisionTriangle(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3
RayCollision collision = { 0 };
Vector3 edge1 = { 0 };
Vector3 edge2 = { 0 };
Vector3 p, q, tv;
float det, invDet, u, v, t;
Vector3 p = { 0 };
Vector3 q = { 0 };
Vector3 tv = { 0 };
float det = 0.0f, invDet = 0.0f, u = 0.0f, v = 0.0f, t = 0.0f;
// Find vectors for two edges sharing V1
edge1 = Vector3Subtract(p2, p1);

View File

@ -649,7 +649,9 @@ GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSiz
// Calculate font basic metrics
// NOTE: ascent is equivalent to font baseline
int ascent, descent, lineGap;
int ascent = 0;
int descent = 0;
int lineGap = 0;
stbtt_GetFontVMetrics(&fontInfo, &ascent, &descent, &lineGap);
// In case no chars count provided, default to 95
@ -2483,7 +2485,15 @@ static Font LoadBMFont(const char *fileName)
font.glyphs = (GlyphInfo *)RL_MALLOC(glyphCount*sizeof(GlyphInfo));
font.recs = (Rectangle *)RL_MALLOC(glyphCount*sizeof(Rectangle));
int charId, charX, charY, charWidth, charHeight, charOffsetX, charOffsetY, charAdvanceX, pageID;
int charId = 0;
int charX = 0;
int charY = 0;
int charWidth = 0;
int charHeight = 0;
int charOffsetX = 0;
int charOffsetY = 0;
int charAdvanceX = 0;
int pageID = 0;
for (int i = 0; i < glyphCount; i++)
{

View File

@ -1727,7 +1727,8 @@ void ImageResizeNN(Image *image, int newWidth, int newHeight)
int xRatio = (int)((image->width << 16)/newWidth) + 1;
int yRatio = (int)((image->height << 16)/newHeight) + 1;
int x2, y2;
int x2 = 0;
int y2 = 0;
for (int y = 0; y < newHeight; y++)
{
for (int x = 0; x < newWidth; x++)
@ -2488,8 +2489,13 @@ void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp)
Color oldPixel = WHITE;
Color newPixel = WHITE;
int rError, gError, bError;
unsigned short rPixel, gPixel, bPixel, aPixel; // Used for 16bit pixel composition
int rError = 0;
int gError = 0;
int bError = 0;
unsigned short rPixel = 0; // Used for 16bit pixel composition
unsigned short gPixel = 0;
unsigned short bPixel = 0;
unsigned short aPixel = 0;
#define MIN(a,b) (((a)<(b))?(a):(b))
@ -4006,7 +4012,9 @@ void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Color
// [-] GetPixelColor(): Get Vector4 instead of Color, easier for ColorAlphaBlend()
// [ ] TODO: Support 16bit and 32bit (float) channels drawing
Color colSrc, colDst, blend;
Color colSrc = { 0 };
Color colDst = { 0 };
Color blend = { 0 };
bool blendRequired = true;
// Fast path: Avoid blend if source has no alpha to blend
@ -4681,17 +4689,23 @@ void DrawTextureNPatch(Texture2D texture, NPatchInfo nPatchInfo, Rectangle dest,
bottomBorder = patchHeight - topBorder;
}
Vector2 vertA, vertB, vertC, vertD;
vertA.x = 0.0f; // outer left
vertA.y = 0.0f; // outer top
vertB.x = leftBorder; // inner left
vertB.y = topBorder; // inner top
vertC.x = patchWidth - rightBorder; // inner right
vertC.y = patchHeight - bottomBorder; // inner bottom
vertD.x = patchWidth; // outer right
vertD.y = patchHeight; // outer bottom
Vector2 vertA = { 0 };
Vector2 vertB = { 0 };
Vector2 vertC = { 0 };
Vector2 vertD = { 0 };
vertA.x = 0.0f; // Outer left
vertA.y = 0.0f; // Outer top
vertB.x = leftBorder; // Inner left
vertB.y = topBorder; // Inner top
vertC.x = patchWidth - rightBorder; // Inner right
vertC.y = patchHeight - bottomBorder; // Inner bottom
vertD.x = patchWidth; // Outer right
vertD.y = patchHeight; // Outer bottom
Vector2 coordA, coordB, coordC, coordD;
Vector2 coordA = { 0 };
Vector2 coordB = { 0 };
Vector2 coordC = { 0 };
Vector2 coordD = { 0 };
coordA.x = nPatchInfo.source.x/width;
coordA.y = nPatchInfo.source.y/height;
coordB.x = (nPatchInfo.source.x + leftBorder)/width;
@ -4907,7 +4921,9 @@ Vector3 ColorToHSV(Color color)
{
Vector3 hsv = { 0 };
Vector3 rgb = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f };
float min, max, delta;
float min = 0.0f;
float max = 0.0f;
float delta = 0.0f;
min = rgb.x < rgb.y? rgb.x : rgb.y;
min = min < rgb.z? min : rgb.z;