From 087aa1bc3f5333537dfe28d0d6fa4c114e17be4c Mon Sep 17 00:00:00 2001 From: Jopestpe <47086979+Jopestpe@users.noreply.github.com> Date: Fri, 17 Oct 2025 03:53:02 -0300 Subject: [PATCH 01/30] Fix triangle strip array size and simplify loop (#5280) --- examples/shapes/shapes_triangle_strip.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/examples/shapes/shapes_triangle_strip.c b/examples/shapes/shapes_triangle_strip.c index d8b5faeea..3172e1f7f 100644 --- a/examples/shapes/shapes_triangle_strip.c +++ b/examples/shapes/shapes_triangle_strip.c @@ -33,7 +33,7 @@ int main(void) InitWindow(screenWidth, screenHeight, "raylib [shapes] example - triangle strip"); - Vector2 points[120] = { 0 }; + Vector2 points[122] = { 0 }; Vector2 center = { (screenWidth/2.0f) - 125.f, screenHeight/2.0f }; float segments = 6.0f; float insideRadius = 100.0f; @@ -69,17 +69,22 @@ int main(void) ClearBackground(RAYWHITE); - for (int i = 0, i2 = 0; i < pointCount; i++, i2 += 2) + for (int i = 0; i < pointCount; i++) { - float angle1 = i*angleStep; - Color color = ColorFromHSV(angle1*RAD2DEG, 1.0f, 1.0f); - DrawTriangle(points[i2 + 2], points[i2 + 1], points[i2], color); - if (outline) DrawTriangleLines(points[i2], points[i2 + 1], points[i2 + 2], BLACK); + Vector2 a = points[i*2]; + Vector2 b = points[i*2 + 1]; + Vector2 c = points[i*2 + 2]; + Vector2 d = points[i*2 + 3]; - float angle2 = angle1 + angleStep/2.0f; - color = ColorFromHSV(angle2*RAD2DEG, 1.0f, 1.0f); - DrawTriangle(points[i2 + 3], points[i2 + 1], points[i2 + 2], color); - if (outline) DrawTriangleLines(points[i2 + 2], points[i2 + 1], points[i2 + 3], BLACK); + float angle1 = i*angleStep; + DrawTriangle(c, b, a, ColorFromHSV(angle1*RAD2DEG, 1.0f, 1.0f)); + DrawTriangle(d, b, c, ColorFromHSV((angle1 + angleStep/2)*RAD2DEG, 1.0f, 1.0f)); + + if (outline) + { + DrawTriangleLines(a, b, c, BLACK); + DrawTriangleLines(c, b, d, BLACK); + } } DrawLine(580, 0, 580, GetScreenHeight(), (Color){ 218, 218, 218, 255 }); From 4256be560819e36c6d9b509802f5c0d2ba377edc Mon Sep 17 00:00:00 2001 From: Jopestpe <47086979+Jopestpe@users.noreply.github.com> Date: Fri, 17 Oct 2025 03:53:48 -0300 Subject: [PATCH 02/30] Fix branch array size and remove extra function (#5281) * Fix branch array size and remove extra function * Fix branch array size and remove extra function --- examples/shapes/shapes_recursive_tree.c | 33 +++++++++---------------- 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/examples/shapes/shapes_recursive_tree.c b/examples/shapes/shapes_recursive_tree.c index 4d0042419..e9cadd8ec 100644 --- a/examples/shapes/shapes_recursive_tree.c +++ b/examples/shapes/shapes_recursive_tree.c @@ -31,11 +31,6 @@ typedef struct { float length; } Branch; -//---------------------------------------------------------------------------------- -// Module Functions Declaration -//---------------------------------------------------------------------------------- -static Vector2 CalculateBranchEnd(Vector2 start, float angle, float length); - //------------------------------------------------------------------------------------ // Program main entry point //------------------------------------------------------------------------------------ @@ -64,13 +59,12 @@ int main(void) { // Update //---------------------------------------------------------------------------------- - float theta = angle*DEG2RAD; int maxBranches = (int)(powf(2, floorf(treeDepth))); - Branch branches[1024] = { 0 }; + Branch branches[1030] = { 0 }; int count = 0; - Vector2 initialEnd = CalculateBranchEnd(start, 0.0f, length); + Vector2 initialEnd = { start.x + length*sinf(0.0f), start.y - length*cosf(0.0f) }; branches[count++] = (Branch){start, initialEnd, 0.0f, length}; for (int i = 0; i < count; i++) @@ -84,14 +78,16 @@ int main(void) { Vector2 branchStart = branch.end; - Vector2 branchEnd1 = CalculateBranchEnd(branchStart, branch.angle + theta, nextLength); - Vector2 branchEnd2 = CalculateBranchEnd(branchStart, branch.angle - theta, nextLength); - - branches[count++] = (Branch){branchStart, branchEnd1, branch.angle + theta, nextLength}; - branches[count++] = (Branch){branchStart, branchEnd2, branch.angle - theta, nextLength}; + float angle1 = branch.angle + theta; + Vector2 branchEnd1 = { branchStart.x + nextLength*sinf(angle1), branchStart.y - nextLength*cosf(angle1) }; + branches[count++] = (Branch){branchStart, branchEnd1, angle1, nextLength}; + + float angle2 = branch.angle - theta; + Vector2 branchEnd2 = { branchStart.x + nextLength*sinf(angle2), branchStart.y - nextLength*cosf(angle2) }; + branches[count++] = (Branch){branchStart, branchEnd2, angle2, nextLength}; } } - + //---------------------------------------------------------------------------------- // Draw //---------------------------------------------------------------------------------- BeginDrawing(); @@ -103,8 +99,8 @@ int main(void) Branch branch = branches[i]; if (branch.length >= 2) { - if (!bezier) DrawLineEx(branch.start, branch.end, thick, RED); - else DrawLineBezier(branch.start, branch.end, thick, RED); + if (bezier) DrawLineBezier(branch.start, branch.end, thick, RED); + else DrawLineEx(branch.start, branch.end, thick, RED); } } @@ -133,9 +129,4 @@ int main(void) //-------------------------------------------------------------------------------------- return 0; -} - -static Vector2 CalculateBranchEnd(Vector2 start, float angle, float length) -{ - return (Vector2){ start.x + length*sinf(angle), start.y - length*cosf(angle) }; } \ No newline at end of file From 601ff4f02e51e545098ab7e57245fe8fb54ac8aa Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 17 Oct 2025 09:54:49 +0200 Subject: [PATCH 03/30] REVIEW: Naming tweaks and comments added #5271 --- src/rlgl.h | 114 +++++++++++++++++++++++++++-------------------------- 1 file changed, 58 insertions(+), 56 deletions(-) diff --git a/src/rlgl.h b/src/rlgl.h index 9cf8ebefb..dfdb26d32 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -785,8 +785,8 @@ RLAPI unsigned int rlLoadShaderCode(const char *vsCode, const char *fsCode); RLAPI unsigned int rlCompileShader(const char *shaderCode, int type); // Compile custom shader and return shader id (type: RL_VERTEX_SHADER, RL_FRAGMENT_SHADER, RL_COMPUTE_SHADER) RLAPI unsigned int rlLoadShaderProgram(unsigned int vShaderId, unsigned int fShaderId); // Load custom shader program RLAPI void rlUnloadShaderProgram(unsigned int id); // Unload shader program -RLAPI int rlGetLocationUniform(unsigned int shaderId, const char *uniformName); // Get shader location uniform -RLAPI int rlGetLocationAttrib(unsigned int shaderId, const char *attribName); // Get shader location attribute +RLAPI int rlGetLocationUniform(unsigned int shaderId, const char *uniformName); // Get shader location uniform, requires shader program id +RLAPI int rlGetLocationAttrib(unsigned int shaderId, const char *attribName); // Get shader location attribute, requires shader program id RLAPI void rlSetUniform(int locIndex, const void *value, int uniformType, int count); // Set shader value uniform RLAPI void rlSetUniformMatrix(int locIndex, Matrix mat); // Set shader value matrix RLAPI void rlSetUniformMatrices(int locIndex, const Matrix *mat, int count); // Set shader value matrices @@ -4238,121 +4238,121 @@ unsigned int rlLoadShaderCode(const char *vsCode, const char *fsCode) // Compile custom shader and return shader id unsigned int rlCompileShader(const char *shaderCode, int type) { - unsigned int shader = 0; + unsigned int shaderId = 0; #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - shader = glCreateShader(type); - glShaderSource(shader, 1, &shaderCode, NULL); + shaderId = glCreateShader(type); + glShaderSource(shaderId, 1, &shaderCode, NULL); GLint success = 0; - glCompileShader(shader); - glGetShaderiv(shader, GL_COMPILE_STATUS, &success); + glCompileShader(shaderId); + glGetShaderiv(shaderId, GL_COMPILE_STATUS, &success); if (success == GL_FALSE) { switch (type) { - case GL_VERTEX_SHADER: TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to compile vertex shader code", shader); break; - case GL_FRAGMENT_SHADER: TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to compile fragment shader code", shader); break; + case GL_VERTEX_SHADER: TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to compile vertex shader code", shaderId); break; + case GL_FRAGMENT_SHADER: TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to compile fragment shader code", shaderId); break; //case GL_GEOMETRY_SHADER: #if defined(GRAPHICS_API_OPENGL_43) - case GL_COMPUTE_SHADER: TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to compile compute shader code", shader); break; + case GL_COMPUTE_SHADER: TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to compile compute shader code", shaderId); break; #elif defined(GRAPHICS_API_OPENGL_33) - case GL_COMPUTE_SHADER: TRACELOG(RL_LOG_WARNING, "SHADER: Compute shaders not enabled. Define GRAPHICS_API_OPENGL_43", shader); break; + case GL_COMPUTE_SHADER: TRACELOG(RL_LOG_WARNING, "SHADER: Compute shaders not enabled. Define GRAPHICS_API_OPENGL_43", shaderId); break; #endif default: break; } int maxLength = 0; - glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength); + glGetShaderiv(shaderId, GL_INFO_LOG_LENGTH, &maxLength); if (maxLength > 0) { int length = 0; char *log = (char *)RL_CALLOC(maxLength, sizeof(char)); - glGetShaderInfoLog(shader, maxLength, &length, log); - TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Compile error: %s", shader, log); + glGetShaderInfoLog(shaderId, maxLength, &length, log); + TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Compile error: %s", shaderId, log); RL_FREE(log); } // Unload object allocated by glCreateShader(), // despite failing in the compilation process - glDeleteShader(shader); + glDeleteShader(shaderId); shader = 0; } else { switch (type) { - case GL_VERTEX_SHADER: TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Vertex shader compiled successfully", shader); break; - case GL_FRAGMENT_SHADER: TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Fragment shader compiled successfully", shader); break; + case GL_VERTEX_SHADER: TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Vertex shader compiled successfully", shaderId); break; + case GL_FRAGMENT_SHADER: TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Fragment shader compiled successfully", shaderId); break; //case GL_GEOMETRY_SHADER: #if defined(GRAPHICS_API_OPENGL_43) - case GL_COMPUTE_SHADER: TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Compute shader compiled successfully", shader); break; + case GL_COMPUTE_SHADER: TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Compute shader compiled successfully", shaderId); break; #elif defined(GRAPHICS_API_OPENGL_33) - case GL_COMPUTE_SHADER: TRACELOG(RL_LOG_WARNING, "SHADER: Compute shaders not enabled. Define GRAPHICS_API_OPENGL_43", shader); break; + case GL_COMPUTE_SHADER: TRACELOG(RL_LOG_WARNING, "SHADER: Compute shaders not enabled. Define GRAPHICS_API_OPENGL_43", shaderId); break; #endif default: break; } } #endif - return shader; + return shaderId; } // Load custom shader strings and return program id unsigned int rlLoadShaderProgram(unsigned int vShaderId, unsigned int fShaderId) { - unsigned int program = 0; + unsigned int programId = 0; #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) GLint success = 0; - program = glCreateProgram(); + programId = glCreateProgram(); - glAttachShader(program, vShaderId); - glAttachShader(program, fShaderId); + glAttachShader(programId, vShaderId); + glAttachShader(programId, fShaderId); // NOTE: Default attribute shader locations must be Bound before linking - glBindAttribLocation(program, RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION, RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION); - glBindAttribLocation(program, RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD, RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD); - glBindAttribLocation(program, RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL, RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL); - glBindAttribLocation(program, RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR, RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR); - glBindAttribLocation(program, RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT, RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT); - glBindAttribLocation(program, RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2, RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2); - glBindAttribLocation(program, RL_DEFAULT_SHADER_ATTRIB_LOCATION_INSTANCE_TX, RL_DEFAULT_SHADER_ATTRIB_NAME_INSTANCE_TX); + glBindAttribLocation(programId, RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION, RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION); + glBindAttribLocation(programId, RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD, RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD); + glBindAttribLocation(programId, RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL, RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL); + glBindAttribLocation(programId, RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR, RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR); + glBindAttribLocation(programId, RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT, RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT); + glBindAttribLocation(programId, RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2, RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2); + glBindAttribLocation(programId, RL_DEFAULT_SHADER_ATTRIB_LOCATION_INSTANCE_TX, RL_DEFAULT_SHADER_ATTRIB_NAME_INSTANCE_TX); #ifdef RL_SUPPORT_MESH_GPU_SKINNING - glBindAttribLocation(program, RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS, RL_DEFAULT_SHADER_ATTRIB_NAME_BONEIDS); - glBindAttribLocation(program, RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS, RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS); + glBindAttribLocation(programId, RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS, RL_DEFAULT_SHADER_ATTRIB_NAME_BONEIDS); + glBindAttribLocation(programId, RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS, RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS); #endif // NOTE: If some attrib name is no found on the shader, it locations becomes -1 - glLinkProgram(program); + glLinkProgram(programId); // NOTE: All uniform variables are intitialised to 0 when a program links - glGetProgramiv(program, GL_LINK_STATUS, &success); + glGetProgramiv(programId, GL_LINK_STATUS, &success); if (success == GL_FALSE) { - TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to link shader program", program); + TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to link shader program", programId); int maxLength = 0; - glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength); + glGetProgramiv(programId, GL_INFO_LOG_LENGTH, &maxLength); if (maxLength > 0) { int length = 0; char *log = (char *)RL_CALLOC(maxLength, sizeof(char)); - glGetProgramInfoLog(program, maxLength, &length, log); - TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Link error: %s", program, log); + glGetProgramInfoLog(programId, maxLength, &length, log); + TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Link error: %s", programId, log); RL_FREE(log); } - glDeleteProgram(program); + glDeleteProgram(programId); - program = 0; + programId = 0; } else { @@ -4361,10 +4361,10 @@ unsigned int rlLoadShaderProgram(unsigned int vShaderId, unsigned int fShaderId) //GLint binarySize = 0; //glGetProgramiv(id, GL_PROGRAM_BINARY_LENGTH, &binarySize); - TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Program shader loaded successfully", program); + TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Program shader loaded successfully", programId); } #endif - return program; + return programId; } // Unload shader program @@ -4378,6 +4378,7 @@ void rlUnloadShaderProgram(unsigned int id) } // Get shader location uniform +// NOTE: First parameter refers to shader program id int rlGetLocationUniform(unsigned int shaderId, const char *uniformName) { int location = -1; @@ -4391,6 +4392,7 @@ int rlGetLocationUniform(unsigned int shaderId, const char *uniformName) } // Get shader location attribute +// NOTE: First parameter refers to shader program id int rlGetLocationAttrib(unsigned int shaderId, const char *attribName) { int location = -1; @@ -4516,37 +4518,37 @@ void rlSetShader(unsigned int id, int *locs) // Load compute shader program unsigned int rlLoadComputeShaderProgram(unsigned int shaderId) { - unsigned int program = 0; + unsigned int programId = 0; #if defined(GRAPHICS_API_OPENGL_43) GLint success = 0; - program = glCreateProgram(); - glAttachShader(program, shaderId); - glLinkProgram(program); + programId = glCreateProgram(); + glAttachShader(programId, shaderId); + glLinkProgram(programId); // NOTE: All uniform variables are intitialised to 0 when a program links - glGetProgramiv(program, GL_LINK_STATUS, &success); + glGetProgramiv(programId, GL_LINK_STATUS, &success); if (success == GL_FALSE) { - TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to link compute shader program", program); + TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to link compute shader program", programId); int maxLength = 0; - glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength); + glGetProgramiv(programId, GL_INFO_LOG_LENGTH, &maxLength); if (maxLength > 0) { int length = 0; char *log = (char *)RL_CALLOC(maxLength, sizeof(char)); - glGetProgramInfoLog(program, maxLength, &length, log); - TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Link error: %s", program, log); + glGetProgramInfoLog(programId, maxLength, &length, log); + TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Link error: %s", programId, log); RL_FREE(log); } - glDeleteProgram(program); + glDeleteProgram(programId); - program = 0; + programId = 0; } else { @@ -4555,13 +4557,13 @@ unsigned int rlLoadComputeShaderProgram(unsigned int shaderId) //GLint binarySize = 0; //glGetProgramiv(id, GL_PROGRAM_BINARY_LENGTH, &binarySize); - TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Compute shader program loaded successfully", program); + TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Compute shader program loaded successfully", programId); } #else TRACELOG(RL_LOG_WARNING, "SHADER: Compute shaders not enabled. Define GRAPHICS_API_OPENGL_43"); #endif - return program; + return programId; } // Dispatch compute shader (equivalent to *draw* for graphics pilepine) From 311f6243e3dd242d03a114385253a2409be291bc Mon Sep 17 00:00:00 2001 From: MULTi <78434796+MULTidll@users.noreply.github.com> Date: Fri, 17 Oct 2025 13:31:24 +0530 Subject: [PATCH 04/30] Disable touch position simulation from mouse movement for DRM touchscreen devices (#5279) --- src/platforms/rcore_drm.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/platforms/rcore_drm.c b/src/platforms/rcore_drm.c index e067fd82a..58e820af1 100644 --- a/src/platforms/rcore_drm.c +++ b/src/platforms/rcore_drm.c @@ -1130,11 +1130,12 @@ void PollInputEvents(void) // Register previous touch states for (int i = 0; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.previousTouchState[i] = CORE.Input.Touch.currentTouchState[i]; - // Reset touch positions - //for (int i = 0; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.position[i] = (Vector2){ 0, 0 }; + // Reset touch positions to invalid state + for (int i = 0; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.position[i] = (Vector2){ -1, -1 }; // Map touch position to mouse position for convenience - CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition; + // 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: PollMouseEvents(); @@ -2262,7 +2263,8 @@ static void PollMouseEvents(void) } else CORE.Input.Mouse.currentPosition.x += event.value; - CORE.Input.Touch.position[0].x = CORE.Input.Mouse.currentPosition.x; + // NOTE: For DRM touchscreen, do not simulate touch from mouse movement + // CORE.Input.Touch.position[0].x = CORE.Input.Mouse.currentPosition.x; touchAction = 2; // TOUCH_ACTION_MOVE } @@ -2275,7 +2277,8 @@ static void PollMouseEvents(void) } else CORE.Input.Mouse.currentPosition.y += event.value; - CORE.Input.Touch.position[0].y = CORE.Input.Mouse.currentPosition.y; + // NOTE: For DRM touchscreen, do not simulate touch from mouse movement + // CORE.Input.Touch.position[0].y = CORE.Input.Mouse.currentPosition.y; touchAction = 2; // TOUCH_ACTION_MOVE } From 9ed785c2e1de44ca4f4b0130ac7538bbb8f596d2 Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 17 Oct 2025 10:04:21 +0200 Subject: [PATCH 05/30] Update rlgl.h --- src/rlgl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rlgl.h b/src/rlgl.h index dfdb26d32..f587d81a2 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -4278,7 +4278,7 @@ unsigned int rlCompileShader(const char *shaderCode, int type) // Unload object allocated by glCreateShader(), // despite failing in the compilation process glDeleteShader(shaderId); - shader = 0; + shaderId = 0; } else { From bb910bb0b8624a8e58fa3adce2e2ce5cadeb0ab2 Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 17 Oct 2025 12:33:41 +0200 Subject: [PATCH 06/30] REXM: RENAME: example: `models_geometry_textures_cube` --> `models_rotating_cube` --- examples/Makefile | 2 +- examples/Makefile.Web | 4 ++-- examples/README.md | 2 +- examples/examples_list.txt | 2 +- ...try_textures_cube.c => models_rotating_cube.c} | 14 ++++++++++---- ...textures_cube.png => models_rotating_cube.png} | Bin ..._cube.vcxproj => models_rotating_cube.vcxproj} | 6 +++--- projects/VS2022/raylib.sln | 2 +- 8 files changed, 19 insertions(+), 13 deletions(-) rename examples/models/{models_geometry_textures_cube.c => models_rotating_cube.c} (84%) rename examples/models/{models_geometry_textures_cube.png => models_rotating_cube.png} (100%) rename projects/VS2022/examples/{models_geometry_textures_cube.vcxproj => models_rotating_cube.vcxproj} (99%) diff --git a/examples/Makefile b/examples/Makefile index eb6725756..332e6c9d5 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -630,7 +630,7 @@ MODELS = \ models/models_cubicmap_rendering \ models/models_first_person_maze \ models/models_geometric_shapes \ - models/models_geometry_textures_cube \ + models/models_rotating_cube \ models/models_heightmap_rendering \ models/models_loading \ models/models_loading_gltf \ diff --git a/examples/Makefile.Web b/examples/Makefile.Web index e365a5fee..5b34c34c7 100644 --- a/examples/Makefile.Web +++ b/examples/Makefile.Web @@ -630,7 +630,7 @@ MODELS = \ models/models_cubicmap_rendering \ models/models_first_person_maze \ models/models_geometric_shapes \ - models/models_geometry_textures_cube \ + models/models_rotating_cube \ models/models_heightmap_rendering \ models/models_loading \ models/models_loading_gltf \ @@ -1146,7 +1146,7 @@ models/models_first_person_maze: models/models_first_person_maze.c models/models_geometric_shapes: models/models_geometric_shapes.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) -models/models_geometry_textures_cube: models/models_geometry_textures_cube.c +models/models_rotating_cube: models/models_rotating_cube.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \ --preload-file models/resources/cubicmap_atlas.png@resources/cubicmap_atlas.png diff --git a/examples/README.md b/examples/README.md index e8b6ba4bf..13f39c503 100644 --- a/examples/README.md +++ b/examples/README.md @@ -191,7 +191,7 @@ Examples using raylib models functionality, including models loading/generation | [models_bone_socket](models/models_bone_socket.c) | models_bone_socket | ⭐⭐⭐⭐️ | 4.5 | 4.5 | [iP](https://github.com/ipzaur) | | [models_tesseract_view](models/models_tesseract_view.c) | models_tesseract_view | ⭐⭐☆☆ | 5.6-dev | 5.6-dev | [Timothy van der Valk](https://github.com/arceryz) | | [models_basic_voxel](models/models_basic_voxel.c) | models_basic_voxel | ⭐⭐☆☆ | 5.5 | 5.5 | [Tim Little](https://github.com/timlittle) | -| [models_geometry_textures_cube](models/models_geometry_textures_cube.c) | models_geometry_textures_cube | ⭐☆☆☆ | 5.6-dev | 5.6-dev | [Jopestpe](https://github.com/jopestpe) | +| [models_rotating_cube](models/models_rotating_cube.c) | models_rotating_cube | ⭐☆☆☆ | 5.6-dev | 5.6-dev | [Jopestpe](https://github.com/jopestpe) | ### category: shaders [30] diff --git a/examples/examples_list.txt b/examples/examples_list.txt index b86a4bc02..7d55d09cf 100644 --- a/examples/examples_list.txt +++ b/examples/examples_list.txt @@ -139,7 +139,7 @@ models;models_animation_gpu_skinning;★★★☆;4.5;4.5;2024;2025;"Daniel Hold models;models_bone_socket;★★★★;4.5;4.5;2024;2025;"iP";@ipzaur models;models_tesseract_view;★★☆☆;5.6-dev;5.6-dev;2024;2025;"Timothy van der Valk";@arceryz models;models_basic_voxel;★★☆☆;5.5;5.5;2025;2025;"Tim Little";@timlittle -models;models_geometry_textures_cube;★☆☆☆;5.6-dev;5.6-dev;2025;2025;"Jopestpe";@jopestpe +models;models_rotating_cube;★☆☆☆;5.6-dev;5.6-dev;2025;2025;"Jopestpe";@jopestpe shaders;shaders_ascii_rendering;★★☆☆;5.5;5.6;2025;2025;"Maicon Santana";@maiconpintoabreu shaders;shaders_basic_lighting;★★★★;3.0;4.2;2019;2025;"Chris Camacho";@chriscamacho shaders;shaders_model_shader;★★☆☆;1.3;3.7;2014;2025;"Ramon Santamaria";@raysan5 diff --git a/examples/models/models_geometry_textures_cube.c b/examples/models/models_rotating_cube.c similarity index 84% rename from examples/models/models_geometry_textures_cube.c rename to examples/models/models_rotating_cube.c index 9441c7fd4..930dae516 100644 --- a/examples/models/models_geometry_textures_cube.c +++ b/examples/models/models_rotating_cube.c @@ -1,6 +1,6 @@ /******************************************************************************************* * -* raylib [models] example - geometry textures cube +* raylib [models] example - rotating cube * * Example complexity rating: [★☆☆☆] 1/4 * @@ -27,11 +27,11 @@ int main(void) const int screenWidth = 800; const int screenHeight = 450; - InitWindow(screenWidth, screenHeight, "raylib [models] example - geometry textures cube"); + InitWindow(screenWidth, screenHeight, "raylib [models] example - rotating cube"); // Define the camera to look into our 3d world Camera camera = { 0 }; - camera.position = (Vector3){ 0.0f, 0.0f, 4.0f }; + camera.position = (Vector3){ 0.0f, 3.0f, 3.0f }; camera.target = (Vector3){ 0.0f, 0.0f, 0.0f }; camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; camera.fovy = 45.0f; @@ -58,6 +58,7 @@ int main(void) // Update //---------------------------------------------------------------------------------- rotation += 1.0f; + //---------------------------------------------------------------------------------- // Draw //---------------------------------------------------------------------------------- @@ -67,7 +68,11 @@ int main(void) BeginMode3D(camera); - DrawModelEx(model, (Vector3){0,0,0}, (Vector3){0.5f,1,0}, rotation, (Vector3){1,1,1}, WHITE); + // Draw model defining: position, size, rotation-axis, rotation (degrees), size, and tint-color + DrawModelEx(model, (Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.5f, 1.0f, 0.0f }, + rotation, (Vector3){ 1.0f, 1.0f, 1.0f }, WHITE); + + DrawGrid(10, 1.0f); EndMode3D(); @@ -81,6 +86,7 @@ int main(void) //-------------------------------------------------------------------------------------- UnloadTexture(texture); // Unload texture UnloadModel(model); // Unload model + CloseWindow(); // Close window and OpenGL context //-------------------------------------------------------------------------------------- diff --git a/examples/models/models_geometry_textures_cube.png b/examples/models/models_rotating_cube.png similarity index 100% rename from examples/models/models_geometry_textures_cube.png rename to examples/models/models_rotating_cube.png diff --git a/projects/VS2022/examples/models_geometry_textures_cube.vcxproj b/projects/VS2022/examples/models_rotating_cube.vcxproj similarity index 99% rename from projects/VS2022/examples/models_geometry_textures_cube.vcxproj rename to projects/VS2022/examples/models_rotating_cube.vcxproj index 77fcd94d4..ebf5f10f7 100644 --- a/projects/VS2022/examples/models_geometry_textures_cube.vcxproj +++ b/projects/VS2022/examples/models_rotating_cube.vcxproj @@ -53,9 +53,9 @@ {A4662163-83E7-4309-8CAA-B0BF13655FE6} Win32Proj - models_geometry_textures_cube + models_rotating_cube 10.0 - models_geometry_textures_cube + models_rotating_cube @@ -553,7 +553,7 @@ - + diff --git a/projects/VS2022/raylib.sln b/projects/VS2022/raylib.sln index 5a784adbe..601b3d409 100644 --- a/projects/VS2022/raylib.sln +++ b/projects/VS2022/raylib.sln @@ -357,7 +357,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "models_basic_voxel", "examp EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_dashed_line", "examples\shapes_dashed_line.vcxproj", "{8E132D5A-2C00-48D0-8747-97E41356F26F}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "models_geometry_textures_cube", "examples\models_geometry_textures_cube.vcxproj", "{A4662163-83E7-4309-8CAA-B0BF13655FE6}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "models_rotating_cube", "examples\models_rotating_cube.vcxproj", "{A4662163-83E7-4309-8CAA-B0BF13655FE6}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shaders_ascii_rendering", "examples\shaders_ascii_rendering.vcxproj", "{5F4B766F-DD52-4B53-B6C3-BC7611E17F20}" EndProject From 0c97c95f6c462582a2404f9de2401b189c3e11bc Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 17 Oct 2025 12:33:50 +0200 Subject: [PATCH 07/30] Update rexm.c --- tools/rexm/rexm.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/tools/rexm/rexm.c b/tools/rexm/rexm.c index 2dc295f37..c615e810f 100644 --- a/tools/rexm/rexm.c +++ b/tools/rexm/rexm.c @@ -224,6 +224,7 @@ int main(int argc, char *argv[]) char exRebuildRequested[16] = { 0 }; // Example category/full rebuild request int opCode = OP_NONE; // Operation code: 0-None(Help), 1-Create, 2-Add, 3-Rename, 4-Remove + bool showUsage = false; // Flag to show usage help bool verbose = false; // Flag for verbose log info // Command-line usage mode: command args processing @@ -231,12 +232,14 @@ int main(int argc, char *argv[]) if (argc > 1) { // Supported commands: - // help : Provides command-line usage information (default) // create : Creates an empty example, from internal template // add : Add existing example, category extracted from name // rename : Rename an existing example // remove : Remove an existing example - // validate : Validate examples collection + // build : Build example for Desktop and Web platforms + // validate : Validate examples collection, generates report + // update : Validate and update examples collection, generates report + if (strcmp(argv[1], "create") == 0) { // Check for valid upcoming argument @@ -410,11 +413,18 @@ int main(int argc, char *argv[]) } } } - - // Check for verbose log mode request + + // Process command line options arguments for (int i = 1; i < argc; i++) { - if ((strcmp(argv[i], "-v") == 0) || (strcmp(argv[i], "--verbose") == 0)) verbose = true; + if ((strcmp(argv[i], "-h") == 0) || (strcmp(argv[i], "--help") == 0)) + { + showUsage = true; + } + else if ((strcmp(argv[i], "-v") == 0) || (strcmp(argv[i], "--verbose") == 0)) + { + verbose = true; + } } } @@ -1372,7 +1382,6 @@ int main(int argc, char *argv[]) default: // Help { // Supported commands: - // help : Provides command-line usage information // create : Creates an empty example, from internal template // add : Add existing example, category extracted from name // rename : Rename an existing example @@ -1394,7 +1403,6 @@ int main(int argc, char *argv[]) printf(" > rexm []\n\n"); printf("COMMANDS:\n\n"); - printf(" help : Provides command-line usage information\n"); printf(" create : Creates an empty example, from internal template\n"); printf(" add : Add existing example, category extracted from name\n"); printf(" Supported categories: core, shapes, textures, text, models\n"); @@ -1403,6 +1411,9 @@ int main(int argc, char *argv[]) printf(" build : Build example for Desktop and Web platforms\n"); printf(" validate : Validate examples collection, generates report\n"); printf(" update : Validate and update examples collection, generates report\n\n"); + printf("OPTIONS:\n\n"); + printf(" -h, --help : Show tool version and command line usage help\n"); + printf(" -v, --verbose : Verbose mode, show additional logs on processes\n"); printf("\nEXAMPLES:\n\n"); printf(" > rexm add shapes_custom_stars\n"); printf(" Add and updates new example provided \n\n"); From 9c1216699d84b2d5e18e766b77d3f32fe51a89e7 Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 17 Oct 2025 12:35:12 +0200 Subject: [PATCH 08/30] ADDED: example: `core_highdpi_testbed` -WIP- ADDED: example: `core_screen_recording` -WIP- --- examples/Makefile | 2 + examples/Makefile.Web | 8 + examples/README.md | 6 +- examples/core/core_highdpi_testbed.c | 70 +++ examples/core/core_highdpi_testbed.png | Bin 0 -> 17323 bytes examples/core/core_screen_recording.c | 70 +++ examples/core/core_screen_recording.png | Bin 0 -> 17323 bytes examples/examples_list.txt | 2 + .../examples/core_highdpi_testbed.vcxproj | 569 ++++++++++++++++++ .../examples/core_screen_recording.vcxproj | 569 ++++++++++++++++++ projects/VS2022/raylib.sln | 54 ++ 11 files changed, 1348 insertions(+), 2 deletions(-) create mode 100644 examples/core/core_highdpi_testbed.c create mode 100644 examples/core/core_highdpi_testbed.png create mode 100644 examples/core/core_screen_recording.c create mode 100644 examples/core/core_screen_recording.png create mode 100644 projects/VS2022/examples/core_highdpi_testbed.vcxproj create mode 100644 projects/VS2022/examples/core_screen_recording.vcxproj diff --git a/examples/Makefile b/examples/Makefile index 332e6c9d5..498a36f47 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -519,6 +519,7 @@ CORE = \ core/core_directory_files \ core/core_drop_files \ core/core_high_dpi \ + core/core_highdpi_testbed \ core/core_input_actions \ core/core_input_gamepad \ core/core_input_gestures \ @@ -533,6 +534,7 @@ CORE = \ core/core_random_values \ core/core_render_texture \ core/core_scissor_test \ + core/core_screen_recording \ core/core_smooth_pixelperfect \ core/core_storage_values \ core/core_undo_redo \ diff --git a/examples/Makefile.Web b/examples/Makefile.Web index 5b34c34c7..1b32ebddf 100644 --- a/examples/Makefile.Web +++ b/examples/Makefile.Web @@ -519,6 +519,7 @@ CORE = \ core/core_directory_files \ core/core_drop_files \ core/core_high_dpi \ + core/core_highdpi_testbed \ core/core_input_actions \ core/core_input_gamepad \ core/core_input_gestures \ @@ -533,6 +534,7 @@ CORE = \ core/core_random_values \ core/core_render_texture \ core/core_scissor_test \ + core/core_screen_recording \ core/core_smooth_pixelperfect \ core/core_storage_values \ core/core_undo_redo \ @@ -761,6 +763,9 @@ core/core_drop_files: core/core_drop_files.c core/core_high_dpi: core/core_high_dpi.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) +core/core_highdpi_testbed: core/core_highdpi_testbed.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) + core/core_input_actions: core/core_input_actions.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) @@ -805,6 +810,9 @@ core/core_render_texture: core/core_render_texture.c core/core_scissor_test: core/core_scissor_test.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) +core/core_screen_recording: core/core_screen_recording.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) + core/core_smooth_pixelperfect: core/core_smooth_pixelperfect.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) diff --git a/examples/README.md b/examples/README.md index 13f39c503..dbc36fe22 100644 --- a/examples/README.md +++ b/examples/README.md @@ -17,9 +17,9 @@ You may find it easier to use than other toolchains, especially when it comes to - `zig build [module]` to compile all examples for a module (e.g. `zig build core`) - `zig build [example]` to compile _and run_ a particular example (e.g. `zig build core_basic_window`) -## EXAMPLES COLLECTION [TOTAL: 183] +## EXAMPLES COLLECTION [TOTAL: 185] -### category: core [42] +### category: core [44] Examples using raylib[core](../src/rcore.c) platform functionality like window creation, inputs, drawing modes and system functionality. @@ -66,6 +66,8 @@ Examples using raylib[core](../src/rcore.c) platform functionality like window c | [core_undo_redo](core/core_undo_redo.c) | core_undo_redo | ⭐⭐⭐☆ | 5.5 | 5.6 | [Ramon Santamaria](https://github.com/raysan5) | | [core_input_actions](core/core_input_actions.c) | core_input_actions | ⭐⭐☆☆ | 5.5 | 5.6 | [Jett](https://github.com/JettMonstersGoBoom) | | [core_directory_files](core/core_directory_files.c) | core_directory_files | ⭐☆☆☆ | 5.5 | 5.6 | [Hugo ARNAL](https://github.com/hugoarnal) | +| [core_highdpi_testbed](core/core_highdpi_testbed.c) | core_highdpi_testbed | ⭐☆☆☆ | 5.5 | 5.6 | [](https://github.com/) | +| [core_screen_recording](core/core_screen_recording.c) | core_screen_recording | ⭐☆☆☆ | 5.5 | 5.6 | [](https://github.com/) | | [core_clipboard_text](core/core_clipboard_text.c) | core_clipboard_text | ⭐☆☆☆ | 5.6-dev | 5.6-dev | [Robin](https://github.com/RobinsAviary) | ### category: shapes [31] diff --git a/examples/core/core_highdpi_testbed.c b/examples/core/core_highdpi_testbed.c new file mode 100644 index 000000000..b22aa507a --- /dev/null +++ b/examples/core/core_highdpi_testbed.c @@ -0,0 +1,70 @@ +/******************************************************************************************* +* +* raylib [core] example - highdpi testbed +* +* Example complexity rating: [★☆☆☆] 1/4 +* +* Example originally created with raylib 5.5, last time updated with raylib 5.6 +* +* Example contributed by (@) and reviewed by Ramon Santamaria (@raysan5) +* +* 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) 0 (@) +* +********************************************************************************************/ + +#include "raylib.h" + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [core] example - highdpi testbed"); + + // TODO: Load resources / Initialize variables at this point + + SetTargetFPS(60); + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + // TODO: Update variables / Implement example logic at this point + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + // TODO: Draw everything that requires to be drawn at this point + + DrawLineEx((Vector2){ 0, 0 }, (Vector2){ screenWidth, screenHeight }, 2.0f, RED); + DrawLineEx((Vector2){ 0, screenHeight }, (Vector2){ screenWidth, 0 }, 2.0f, RED); + DrawText("example base code template", 260, 400, 20, LIGHTGRAY); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + + // TODO: Unload all loaded resources at this point + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} diff --git a/examples/core/core_highdpi_testbed.png b/examples/core/core_highdpi_testbed.png new file mode 100644 index 0000000000000000000000000000000000000000..da99bbb0d97118eef3ca41c16b62182acced63f9 GIT binary patch literal 17323 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 aXx{Fh`%kLYY!czW3FF=h-xU_U{Qm(sHl%3) literal 0 HcmV?d00001 diff --git a/examples/core/core_screen_recording.c b/examples/core/core_screen_recording.c new file mode 100644 index 000000000..9d0611bde --- /dev/null +++ b/examples/core/core_screen_recording.c @@ -0,0 +1,70 @@ +/******************************************************************************************* +* +* raylib [core] example - screen recording +* +* Example complexity rating: [★☆☆☆] 1/4 +* +* Example originally created with raylib 5.5, last time updated with raylib 5.6 +* +* Example contributed by (@) and reviewed by Ramon Santamaria (@raysan5) +* +* 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) 0 (@) +* +********************************************************************************************/ + +#include "raylib.h" + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [core] example - screen recording"); + + // TODO: Load resources / Initialize variables at this point + + SetTargetFPS(60); + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + // TODO: Update variables / Implement example logic at this point + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + // TODO: Draw everything that requires to be drawn at this point + + DrawLineEx((Vector2){ 0, 0 }, (Vector2){ screenWidth, screenHeight }, 2.0f, RED); + DrawLineEx((Vector2){ 0, screenHeight }, (Vector2){ screenWidth, 0 }, 2.0f, RED); + DrawText("example base code template", 260, 400, 20, LIGHTGRAY); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + + // TODO: Unload all loaded resources at this point + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} diff --git a/examples/core/core_screen_recording.png b/examples/core/core_screen_recording.png new file mode 100644 index 0000000000000000000000000000000000000000..da99bbb0d97118eef3ca41c16b62182acced63f9 GIT binary patch literal 17323 zcmai6c|cUv{+|KF5eFH=bl5?R=aPwVMFqrx!5QtnDH2=cmpxR%i`&Bh{P7(^qao3Oe9i%G9f&4Qqo7$7w5-4+ak7WJM-ss zc{ih%ud|iqABu8W8(V8LGV|`OUw1#x>89{Ay5(>-BVRf`P7-}?H_S6 zxqXV|AD*w-#A`m$&QN6AJ8!mk(tKbU0Fc$`M0w9_RNZZ2IaVFRa2dK{R-(7?L*`<2 zwACX%QK1UzZ(KEpu~8|bE&R|%NU{Uxh3>Jo+83Xoiec`)bi#;>W25^ANVvCucK*E} z#L#AWzUUa8=(V+u;b*j--5cv?m$C1;Sl)C_KdY+x?%C(WDcxGgPA>T=zud^W<+@{&!| z>qI**-JjH?Enc2n=M$GIna5sn zJiL5bg7MKyw@}jC%KC>X%jf!gmW7TvI5vj4Wm#^br^;yG!qV6Y<5B z#nCetII!Jg$VPv+yiskUm#@70lh19HX<4@&oXQg|+o$4pnf%*tGHj1YC7(oOy>ZI9 zJozO9mrA6qtRr`q=MZ;ytcb$~o0bD;Ds!eqpW!Gl%K> zDx(W_$)`CF&KZ61oh2``H_-qa-Mz#WUjEk0zxYk{V5L6xu%$(Fl3D3c8{I9> z$9p!4L*JTh+~;LnamJD>MD$9jx$>o3qMPi4X)X|1-(X9VDF@l8-h4d&H%boOPFtKw zl9Ce;AMz)57(O!4+b>FF$r$qMCn};rSmKv}Zf~}F*8Jrb^eCRW zvY7qDdQp1jX>IO`Q*4;i(8ZP%Ij~0x*E--?g-fHhTC#;p^N+e?Y1Qmktc;E7+OS!L z)?uDss2tC-CH@wIgLasW>e8oMw`Fm?Bsn!B40}{PzqACdP9~q@v1Wt2YGj_H(_Ev= zId#u3ERFj>qE8Gdd%LI6-!mrdcXqjprA@>jMg(QwOY&&cM#yx=9`S|sZZ8;PPH$`= zQAq{xZ;;yz86m$mmbQzEzS$um8$7Z_+A zc0JxrQ(!#S^n#&D8?nbTT);C`kSAkzl}ihXYR-HinpN0A{4PssiCnM6yKBmf<19>d z8&mD(MlQuv33g3f+89eyRgn~2o*jW<*?6tP zATo7cJZM&eLz!p#TJEWraop_}#1%0XX6=#c|8B-s#+W1(h8nU^IA=k(W zoSM&fsR3v5q0HDS&W`OePXXv*QEbxJHIR{S##K%q6!ox+<4gBLLO<#COb{e=<8H7a zM?GXqm!(SFp^)`C>s9I?PwxRgs{LEp>s^WAH<-y1KflVldY|UruQU;Fe*tny9|AdN zlRF@*qAzE~w!H{B7xTFJ8Cs!x?@{*pz9M6{E*YZeFtNzthV#*|IkA(br_|W(2;09) za+>=t#O$xC?3*mn-^M6MDUqUMNoSiB4aHpdhZ}b7Sy5asEn^QVz?93UF`-?g6anXH zT*WbIpg!b54c4;;Q5;fYvOVO-VO_}-G}&p$S9-yB7S`_DdPD#noBX{t6% zHD;{g;C44F<06Hsvd=LuUy{uA?i6G1NK?4e$Jvwl<0SgiT7CYI9Yh)<47r`=s>cFL zLJX_poTx0ut(D1#7O5Q1chr>huuQ)5Cw1h|F;uXpS!|-)1=gxlrd;A-Wo&6-2XC7J z`U5PNDHt8?qG3BF5pDQ#sk>&qHT-!~g}TxWqe#jc)_Ja1iLG*dMn`!0211ps^>Bi2 zSJ?&CFk&2Ua3NZOq1;#8l^ZH0cPy0{H&AnH2o*Ui|?6Hv3hFP<{e4 zIb`NP&x5>)nFhz;A(6Z0kXeb|$p3B~=9)u3q}K4+%Ed6{GUKWw^J1f5R%1pQeq8x~ z)c-4$AvPqB@~Jg%t_C}Rjtj@QDx(u@W0)xp-@x_?)Q-(&+l$9O9?fRl9R85W8)3vv zQ(>pw9^E&a0!8HDC8^Za6tak*kg$q zvM+S>lrg-ao+i=H4fD`E@P?$3mHITBA(tRF0x~mtB8A+TRRqX))Q(ThkQKx`8N)Lb zs1I&%zc?LG?V_2xS@;7jwk!MrXEWCv;B1vm_m$Qg&hzRK*2m1FxgWzK{f!N?7#k=K zft_6~ze{b>(aet(gL(3a!zh#}M2zq1b)tz9{d;|kC#JUVPU{RIZPDi&Iax7S1DdTG z?rik|q){u^^fe2r4q5cm;fA>?r8b_2A9;e6RD+dQ$1n@ctICkOv>amto$ST65H=h% z3QwfNpg&Np#S^BHq67HGLsfZyT=z9|VXOE48mNGU40EvyRW1Ow} zK=dmZLz+N+NifgRV+}{tO6@_2w0jIQE<-0;L8aS6pwT-}92oSbyS@14NVpxN@Q0J16I0dj$vGXF;+H)pZNXua-U{EAw74QU*!uHvW4GVXD z^#Xg(*<{Rlkj(WK_Dwf?@gp!9VC@GiH)v^^izZgk(kMuLvAgDTtn!>jrkfCcFMvm3 z`ndqU8r%r*J3ve+(4P|of!;v^WN7yv=7cb+7@HX#Y_I|`MN>tRU$t1#%2gwj--@dM zzd#*%nUzR0sl6VBPgG-zGWFVO!KedlRHrU*ePGn7L*VT2)-pQkcMm^&k)8~xIZ9U%ru2bAPKW8iDKd9)ziaG`C=3C>51e1&GfkiwVW$=Sm>k$Fq z^plYEDm^I$RGQ{0rZIH~yfhC)L<|)+B+f^I7o~ThafmaG z7lH1-)NdZ(4?of5;~XTWhw#2~*PP}JrWED#seN2wu(MU^NV@$+fIJnDFB?xJ^NyDXpkJmeA(`t?fo zB1{hbIo{m~FKPi9Ex%uQ$RuzQSHF%w{6Zl=1kNLXe8fX@kB4jxhPqzCI+J-QS-GNj z=?$nZBIAT*1hV!D7QU^||A8zlj^L@Pl4O^6kOIo|v3#dg97R;&Z}^#a)oeh1^WIM_LI{7R55mYo1rs+Mbf z`IU^j zc=d2GL+pf=L?E6KfB%}twHj`XHYz^~>LY1f2oaM4)jG+KBY7Z`09bdDokr#YQ9oSB zjNs?u1DdCi1T?7mCa}jlX(r*31oQ}=XXf)A1zxidSO(8y6|ciG{EVychz<$#jbFJc zK08wEriQwohh=~EkfyCko8IGvf#nYs!1N2t?(5T zRVbDQ(b8?8j@ErN0i8$;)mgL0=v7?oYj99S(sB`9Ns=EwqJ!38kjO<-M*0UYDKDTU73rOL2R=>`p2Z*L zQZ486uyq=VKA=kFct0L?-yCfCl74HFWh*bsJw%q5*st7A!fTeQD`{tmObW=RNe=*A zwu|O6X`EKxVw34c22sejC^#eqE{Vofi+y3Gk6bld_;0<3Qh$HQL!JstL*C^0Fd9%1 z+6m9%535Xu$%9j&lnrQ8IX;O-;+!zb(2IWi3041d9&$SP#kQI~;(>fkv%uIObiC2& zBzXxv=LrXn)Og0a!W)<`uz{w!ON_jk)bsWf9|TRB+#*7>e@r*IBfQ8|V5IZ7IhhtD zp`6DIB0N!9$tIif9r2%31Wx>9unlC__Q$yap%Wzf{4HFw(Bx=?C4z&(cvDs>MQZGE zfO@ShBxv|ZRe6fv74k~N9Fp%L(DM`8fV$9y48Ma^>XBUIVOm8IMf3aN!e>*A@BJar zATx0hzDH6@Jj-C(gePhUmoJPbx}lBI5Y4#pc84lTvwz1%sn3G_mh-{>$=WjzZecpl+K6^Hsne_$ z<{FIsDd#7>wvB6Z9qMcn65kSpq9zM-Ux%X>^=ce2!g-l-+!2$=Dv+~5=Yx=o^3So@ zoBf5n^@XZyvkC_a3qGPAzs;01iZY;&sX;|+e`BBM`-+7HkR%e1uN46N%!j8tKHm{r zZKdvoyw;RR3-%NU(@0$qKj3>VNnYM+n#(ty%5;hFS%l9b_l+?loo^d22sN9nDUpsh zfw%RAf{r%#c*4cIm){T`O+qw6?KG1*i+ze1*8kM2(BTPz)z<_or37J?WOJVgbHM}y z)@^s`ZLAq>*iW5E868i<^v5)bL)J>1-~Z#@e$GpclW8i&*w`-Moh`E7BxC7WNPhg< zzQc_*BMj?>saTUt+oyto=tew~INNXGUPrFR!&f4YCh`6^lL^Y}h)mrU*kmAu+9x!z zNq2_C)&0Vj(_maB_N%_-;^pNBgf9_3i4(Oqk0rX|@pH6UiNUIUw*;h5X}oN&(T{lf zPIRs_x@B>*g?2+JQVYVOHv~u+^GfSVlGE*L-!bAY0mKPw|0^uIXhfAd$lW;kza|0e zXp<3kO7t=zDFsS7G4`}cvX;Nj7g4s?f{qc zbx0|>vd5z_NgrDxK%5Mzq0&Fram=B2mXM_HsmWTS>u3jZhhPxB`&gxJD;az7uH1ZF z`3V)_BVlbDU9n=m2q#6x3ms0#iIi=HX>C@D4hP!s5=32Ol7|RpGX^P6dwCu&shEz8 z2@LwFP?)h2PwFWoUo~w+v{JM`$c{{wHllqpEn);*xIthV@Z)PX0~<%_p;^Z&lV(9v zKT_Rh2|}?Kf9s`~sh&opnJvI&Y|>FHl4g|osIl0^DlM=tS=9!Wv}p?pw9!eEWSF30 zXR9Qo=qk=b;8nHehe^gtGSOemKsYb$l^Shac+*zBZA1Il$Rf$%3d&TPQ$yY6sf9(q zr*<{l{1+Rg=+}wgaIbyPv5`vpz{LLi&Eo*>-~UK;@8^`MI%8h*4qdU&nD)iAz?)U$ zrjeT;Eu`(agC@F#G88?;Z*F)u11Hp)2=h47*o5js%(5&-%9~kAt|v@2tCb|`5HL;D zpiFI=jpnHQ#LEWK3zQt%V~g z(q9ND`c8e8Ez-wc6`U>^OoZI|oUptnSYH)zTjES=`XvIdkOl-!Lv{!NLSde64rlwv zGKWlALgF|)m78n*{*#m^uXUPEW9FafAMz3q?93n{vuTB6EjU8sjd9;zFbYGkB?JnwjIl^2dbl;W#P3W#i zBh0?KBa7gEYcQf<~>qz#h`aJ~x5ST}Cs~`KARG*AQ;&dR-Y1 zKgt;;>*R|n=YtFNaGx`eGwiH{aObdm%;f4V*D-+i^XZ*zV7wDRG zpX`H-Esb7_(+ZNk!X87 zjnYvxTOn;{)R$FCAV2|XDwJ>ITR^_XPg?2&$a9UW7LI~XCA(|R&~Fj#U<+|*2tu%B zDB_fJnBL^9MRV2IK))>l8KE1>&=|QDkmm&$v@4+iQqh}cM-D>5Ya>BRmiXRJ-`6iJy^n6QxltHgt^@+B&53WJg2pY-*K0 z6c=gLxf^>R($*7Pb4@%Z)lpofWM=U}%!PJS2`H`@i-)*sR`6Q3hVT%-n)$1PiVbjs zJ9-~Naf_j!Vd_ZIibW=yMop8BLU^B3r}x>5Q3wvi;c3w$Mg32T;{Wk08emMvr!(`g zVg)SnNuVK$$6Igej`A+1Xu(`%dY>J51Vm<7rjFz*7tv0dPSfse0jd2ra7V#jq{O&? zpPk8D3b{x?I#=fjND&UYFGe_N!m+Q#=v*z!%D>G6!9^_INO{j!yaO%1rE;u*sWib< z(0j%~584_9s3%b5#mywFcU&+*`P+cI`J&1i>qS5?xU@oNAA=c2R~4l$%o zXYzPk$%W{D@HP1GOjQP{Ak%M%bnFNSbYjFfZj1NK^%@}N^S8smOy%T%b4wa43|P+ zLpP{+zxjm{z&#AN0nffRw!`59A<_-lg&z(0*YPkp$N(YTqtr7PCkG#8M<_VSRu(N{fH!UZFNQ=0N;9LMX%(~~LT8UPNG3qN$#^u{9$ zA{-_}EzQg)=L%0K^lex?9nfoCHJLngQ1WI7>TPx8SqSP1rL@y{ zzy{C0lj*~=8_KR+v|~TpZ5)I)zwN(ieY74EAX$wXo#`V~`{W`A5onhKMiHf|2Hse~ zBugNP%Wj%^m|zqQ0k5FZJ(V1LQXjw{$YlXnKZg!&EugQH|bby|AFY z7`In<_Tx)iawCA0o;c+tHwV`L!upx}3kn+Y zW@sLFCa+|{S?{8C}`rbKEwbp#c zjlbTu)JgL`O<+jzbd2PxC#N!9ZgAk5N&Ze8p}={tg-OGw!8);lHdr1{Hi-KO;w`7y zWEc&6n&|vUIyP(<&2T)|@KjHZpUx|d4gc9n!8_<-k>q;HW1eOCAJO3UmtnTV-4&Y@64hE$J18 zt0Hg2Lq3{%V?#1YRcnF`=^f@l4o%$tQmH9@Zpk)f&L&nPt_rA8O&R$QYD_o5g6m)? zxZG4Im@q;da_CznT=Uo}V25~gEB}R?LPf?^0)_I3a2OahEHhu1hi#G@c(=3RxM7J* zo>15mQIk^;5{-J3a6;1K+qpClS#^M9FGd43>ff39Yx2;0Cuv&XK&ooq=Zm&HzUY4i-yq?jt0;G_A> zyY?teNKAU8JHmR;<6L;BQH2P;Xg3X-g?mx_-Ava#)CPVu+W-g%M11~##_eFN7Y19i)sj{APAg{B{RZ91b=(cSm_eTFhe( z;tQ{lhKf$3;;C(#Zw8XPh@?3w)N{PpQW3Uq-Qp&_d4{ey(tx=_18`Zs-J|du8ZGS8 zF@~89;1!5IL3Iv7#pOqH+mw_W=!)+=qmCRtlv>1(1+boO=h!fFLl6{SL$>&s-9c_! zlFr@x^U4BD7Nc_H6Uz3< zbfn`*jMV{&BvJRp64K>>ScTIxlQk-k!d>cVj7wWb1>5gim~Xb;N8iyZP>g^%3ZMEK zV$-n~Quc-7|I4TU{mot^8QqStVKiv+k(2z$#bwz8$b$QjteKdsT-6g7E(H4$utBOM z+c#Y&mb}%E>>y0&+n7|Z{Rqx+TdtW!>{+WXF7%BOk&Diz-j~TqtWm-=q8U9Bu_81s znkgmMrA@Ki1dH4!ZCsPHsjnK=nqA~kUT1t2L8_Dd3EMvP@*X(`uZT$R7m;&`_X4^s zl}hdz5Ahz7k%=qmaf`EJ>$sDA!O(#O3t*{_KaSaY0mAhC^bc~C{6eRNV5g+cIwNgj zf&tm*Zjj*}^^i?nAlIPEYTQ)wdA@pNoHCJ-zncA6i15Phhy}PY&C{2HM$>BJnbM3Gc5d_%!7LKF3QZ5tsBS!N z_3!0s=`|`-+~bu7x<&F-pRYr740T^XwEESHqwc_$7R9mKvLPeSjNRmwgsP5w%p1E1 zx%9=Q&d!5k0jsPwj=84q+kS9n(mm*QGVJYZ+XZ&cjauoNHu9##xW+E3MaqTl-KFzChp0 zrEML|GH<%8-lxryAZ*ctJ8;VO4R_FJ#UQ+Y@{pY;^r;2y;F2CW$y+J?@Iw^z6{G$n zr*jteDDCiG3`5?F3AO;fxZ^7}*YS!?k;SPxysa~dysZ<+PgT(~<Gh%7@ec(5c3lZ1P>PoWM((Ke zd26!Dzvn~93Aw3oC@+k`?hh$N=X<2=e;myu{}IEu$w+fw<~Q*aq2UgvZ-R4`!GSX+ zEwzjA@=(|Zndl9EdJ$Li_Uyls_N2!p|4??$sDr^j+*o_lecHKe6V*F{R%!aB{W8ws z{iuhVE?eXOK!XW1N?OKhh?e^gdHe{i2&y(2#KcdNf43!G#3tHf`YQ@^mA+_lW#de7V# zGOaY_HzsUmQLW#GNz1PJt^DYj@w2B}4=%`kqTUs>YV+`|RsUXhLmAev`C?5-R8LeN z(Fh(FWcQ}cD70SgeVMc$aM`{ym64C4;RLqV(9Os|D~`;faC9PT>mU5PZRm0No6sFU zSiAMJzW&iCjjwHWSQ3+5aIE|GhN%U|JPw}?+FAN>(bwN_fymX#l?-)SQS&86lGLH0k;gwFj9Wy*5W2 zbeX+KrHcx2Drj@5Pf*Sd<_3H8di8l0ZUcKMvSgz9;n|ly_iU|y>LrzWAGG#^eOP+a zjj>^oYVY&fm>1L^!537s9BbZLDf(_vkNEP0VwGav35NqC>gx`!z5IFqX_X$|)r8MY zdd1~T)hENYEs7Z5@{hw$)H{9}xY^5dq$~UCv*y<4>_g)_TQ-sJ)ad9Zk6La$&&igmaaU>u;=c5`%(L)83}X+wB=@13$KbLNIu9#wh`*)R zV-yXTa-PL0<;v)-r*+axh{BL_t|d9k?Yw-?2KF!AMWxdD#T63~>u@c8U1r&y3x72x zQX>7eb!cUL`c`rdJhf{`;C=RTnCR)*u;zfKh?b`8FY#(_lD;p~NeCv_M%AE;{NIA{ zD0YZFcFulKw-WQj9r2oqUhWgAOhYX$=ximGDu0*~9Mg&yt#M7^q6NdoY>KexflUrh z&FBz9>9aeflV*5Dcn^60hVFCl_9zOp@{Yc04%fnq$G`Hsi*0WLwC6LtiQ^>3cG05b ziUfXt7tH6n=85oIK|ib1{Y%CS49Ls+3-AaN)-k0kaIz{2*x?^i$vk)1Cz-;reJn3aleTSM+Ta?o aXx{Fh`%kLYY!czW3FF=h-xU_U{Qm(sHl%3) literal 0 HcmV?d00001 diff --git a/examples/examples_list.txt b/examples/examples_list.txt index 7d55d09cf..7abfdd453 100644 --- a/examples/examples_list.txt +++ b/examples/examples_list.txt @@ -48,6 +48,8 @@ core;core_render_texture;★☆☆☆;5.6-dev;5.6-dev;2025;2025;"Ramon Santamari core;core_undo_redo;★★★☆;5.5;5.6;2025;2025;"Ramon Santamaria";@raysan5 core;core_input_actions;★★☆☆;5.5;5.6;2025;2025;"Jett";@JettMonstersGoBoom core;core_directory_files;★☆☆☆;5.5;5.6;2025;2025;"Hugo ARNAL";@hugoarnal +core;core_highdpi_testbed;★☆☆☆;5.5;5.6;0;0;"";@ +core;core_screen_recording;★☆☆☆;5.5;5.6;0;0;"";@ shapes;shapes_basic_shapes;★☆☆☆;1.0;4.2;2014;2025;"Ramon Santamaria";@raysan5 shapes;shapes_bouncing_ball;★☆☆☆;2.5;2.5;2013;2025;"Ramon Santamaria";@raysan5 shapes;shapes_bullet_hell;★☆☆☆;5.6;5.6;2025;2025;"Zero";@zerohorsepower diff --git a/projects/VS2022/examples/core_highdpi_testbed.vcxproj b/projects/VS2022/examples/core_highdpi_testbed.vcxproj new file mode 100644 index 000000000..89675f5ed --- /dev/null +++ b/projects/VS2022/examples/core_highdpi_testbed.vcxproj @@ -0,0 +1,569 @@ + + + + + Debug.DLL + ARM64 + + + Debug.DLL + Win32 + + + Debug.DLL + x64 + + + Debug + ARM64 + + + Debug + Win32 + + + Debug + x64 + + + Release.DLL + ARM64 + + + Release.DLL + Win32 + + + Release.DLL + x64 + + + Release + ARM64 + + + Release + Win32 + + + Release + x64 + + + + {6B1A933E-71B8-4C1F-9E79-02D98830E671} + Win32Proj + core_highdpi_testbed + 10.0 + core_highdpi_testbed + + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + $(SolutionDir)..\..\examples\core + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\core + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\core + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\core + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\core + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\core + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\core + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\core + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\core + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\core + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\core + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\core + WindowsLocalDebugger + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + /FS %(AdditionalOptions) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;shcore.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + /FS %(AdditionalOptions) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + Copy Debug DLL to output directory + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + Copy Debug DLL to output directory + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + Copy Debug DLL to output directory + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + + + Copy Release DLL to output directory + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + + + Copy Release DLL to output directory + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + + + Copy Release DLL to output directory + + + + + + + + + + + {e89d61ac-55de-4482-afd4-df7242ebc859} + + + + + + \ No newline at end of file diff --git a/projects/VS2022/examples/core_screen_recording.vcxproj b/projects/VS2022/examples/core_screen_recording.vcxproj new file mode 100644 index 000000000..1669c6ac7 --- /dev/null +++ b/projects/VS2022/examples/core_screen_recording.vcxproj @@ -0,0 +1,569 @@ + + + + + Debug.DLL + ARM64 + + + Debug.DLL + Win32 + + + Debug.DLL + x64 + + + Debug + ARM64 + + + Debug + Win32 + + + Debug + x64 + + + Release.DLL + ARM64 + + + Release.DLL + Win32 + + + Release.DLL + x64 + + + Release + ARM64 + + + Release + Win32 + + + Release + x64 + + + + {6B1A933E-71B8-4C1F-9E79-02D98830E671} + Win32Proj + core_screen_recording + 10.0 + core_screen_recording + + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + $(SolutionDir)..\..\examples\core + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\core + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\core + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\core + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\core + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\core + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\core + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\core + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\core + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\core + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\core + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\core + WindowsLocalDebugger + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + /FS %(AdditionalOptions) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;shcore.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + /FS %(AdditionalOptions) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + Copy Debug DLL to output directory + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + Copy Debug DLL to output directory + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + Copy Debug DLL to output directory + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + + + Copy Release DLL to output directory + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + + + Copy Release DLL to output directory + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + + + Copy Release DLL to output directory + + + + + + + + + + + {e89d61ac-55de-4482-afd4-df7242ebc859} + + + + + + \ No newline at end of file diff --git a/projects/VS2022/raylib.sln b/projects/VS2022/raylib.sln index 601b3d409..20b7ad9bb 100644 --- a/projects/VS2022/raylib.sln +++ b/projects/VS2022/raylib.sln @@ -387,6 +387,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_mouse_trail", "examp EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_starfield", "examples\shapes_starfield.vcxproj", "{EA4AD5A7-DB95-43C0-9A67-2D94146BCF91}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_highdpi_testbed", "examples\core_highdpi_testbed.vcxproj", "{6B1A933E-71B8-4C1F-9E79-02D98830E671}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_screen_recording", "examples\core_screen_recording.vcxproj", "{6B1A933E-71B8-4C1F-9E79-02D98830E671}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug.DLL|ARM64 = Debug.DLL|ARM64 @@ -4793,6 +4797,54 @@ Global {EA4AD5A7-DB95-43C0-9A67-2D94146BCF91}.Release|x64.Build.0 = Release|x64 {EA4AD5A7-DB95-43C0-9A67-2D94146BCF91}.Release|x86.ActiveCfg = Release|Win32 {EA4AD5A7-DB95-43C0-9A67-2D94146BCF91}.Release|x86.Build.0 = Release|Win32 + {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 + {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 + {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug|ARM64.Build.0 = Debug|ARM64 + {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug|x64.ActiveCfg = Debug|x64 + {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug|x64.Build.0 = Debug|x64 + {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug|x86.ActiveCfg = Debug|Win32 + {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug|x86.Build.0 = Debug|Win32 + {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 + {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 + {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release|ARM64.ActiveCfg = Release|ARM64 + {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release|ARM64.Build.0 = Release|ARM64 + {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release|x64.ActiveCfg = Release|x64 + {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release|x64.Build.0 = Release|x64 + {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release|x86.ActiveCfg = Release|Win32 + {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release|x86.Build.0 = Release|Win32 + {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 + {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 + {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug|ARM64.Build.0 = Debug|ARM64 + {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug|x64.ActiveCfg = Debug|x64 + {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug|x64.Build.0 = Debug|x64 + {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug|x86.ActiveCfg = Debug|Win32 + {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug|x86.Build.0 = Debug|Win32 + {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 + {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 + {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release|ARM64.ActiveCfg = Release|ARM64 + {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release|ARM64.Build.0 = Release|ARM64 + {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release|x64.ActiveCfg = Release|x64 + {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release|x64.Build.0 = Release|x64 + {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release|x86.ActiveCfg = Release|Win32 + {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -4988,6 +5040,8 @@ Global {AC215730-2B5F-4498-B7F5-5DB80AEFCA5F} = {278D8859-20B1-428F-8448-064F46E1F021} {0835E6BF-0170-4E99-A55C-E06E1EF4C3B2} = {278D8859-20B1-428F-8448-064F46E1F021} {EA4AD5A7-DB95-43C0-9A67-2D94146BCF91} = {278D8859-20B1-428F-8448-064F46E1F021} + {6B1A933E-71B8-4C1F-9E79-02D98830E671} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} + {6B1A933E-71B8-4C1F-9E79-02D98830E671} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {E926C768-6307-4423-A1EC-57E95B1FAB29} From ffc405325f51a39d1ed3770c797f11bac8e3c089 Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 17 Oct 2025 12:54:46 +0200 Subject: [PATCH 09/30] Update shapes_pie_chart.c --- examples/shapes/shapes_pie_chart.c | 242 ++++++++++++++--------------- 1 file changed, 113 insertions(+), 129 deletions(-) diff --git a/examples/shapes/shapes_pie_chart.c b/examples/shapes/shapes_pie_chart.c index 1fa938905..e2f6900eb 100644 --- a/examples/shapes/shapes_pie_chart.c +++ b/examples/shapes/shapes_pie_chart.c @@ -22,6 +22,8 @@ #define RAYGUI_IMPLEMENTATION #include "raygui.h" +#define MAX_PIE_SLICES 10 // Max pie slices + //------------------------------------------------------------------------------------ // Program main entry point //------------------------------------------------------------------------------------ @@ -34,15 +36,14 @@ int main(void) InitWindow(screenWidth, screenHeight, "raylib [shapes] example - pie chart"); - #define MAX_SLICES 10 int sliceCount = 7; float donutInnerRadius = 25.0f; - float values[MAX_SLICES] = {300.0f, 100.0f, 450.0f, 350.0f, 600.0f, 380.0f, 750.0f}; //initial slice values - char labels[MAX_SLICES][32]; - bool editingLabel[MAX_SLICES] = {false}; + float values[MAX_PIE_SLICES] = { 300.0f, 100.0f, 450.0f, 350.0f, 600.0f, 380.0f, 750.0f }; // Initial slice values + char labels[MAX_PIE_SLICES][32] = { 0 }; + bool editingLabel[MAX_PIE_SLICES] = { 0 }; - for (int i = 0; i < MAX_SLICES; i++) - snprintf(labels[i], 32, "Slice %i", i + 1); + for (int i = 0; i < MAX_PIE_SLICES; i++) + snprintf(labels[i], 32, "Slice %02i", i + 1); bool showValues = true; bool showPercentages = false; @@ -50,7 +51,32 @@ int main(void) int hoveredSlice = -1; Rectangle scrollPanelBounds = {0}; Vector2 scrollContentOffset = {0}; - Rectangle view = {0}; + Rectangle view = { 0 }; + + // UI layout parameters + const int panelWidth = 270; + const int panelMargin = 5; + + // UI Panel top-left anchor + const Vector2 panelPos = { + (float)screenWidth - panelMargin - panelWidth, + (float)panelMargin + }; + + // UI Panel rectangle + const Rectangle panelRect = { + panelPos.x, panelPos.y, + (float)panelWidth, + (float)screenHeight - 2.0f*panelMargin + }; + + // Pie chart geometry + const Rectangle canvas = { 0, 0, panelPos.x, (float)screenHeight }; + const Vector2 center = { canvas.width/2.0f, canvas.height/2.0f}; + const float radius = 205.0f; + + // Total value for percentage calculations + float totalValue = 0.0f; SetTargetFPS(60); //-------------------------------------------------------------------------------------- @@ -60,32 +86,9 @@ int main(void) { // Update //---------------------------------------------------------------------------------- - //UI layout parameters - const int panelWidth = 270; - const int panelMargin = 5; - - // UI Panel top-left anchor - const Vector2 panelPos = { - (float)screenWidth - panelMargin - panelWidth, - (float)panelMargin - }; - - // UI Panel rectangle - const Rectangle panelRect = { - panelPos.x, panelPos.y, - (float)panelWidth, - (float)screenHeight - 2.0f*panelMargin - }; - - // Pie chart geometry - const Rectangle canvas = { 0, 0, panelPos.x, (float)screenHeight }; - const Vector2 center = {canvas.width / 2.0f, canvas.height / 2.0f}; - const float radius = 205.0f; - // Calculate total value for percentage calculations - float totalValue = 0.0f; - for (int i = 0; i < sliceCount; i++) - totalValue += values[i]; + totalValue = 0.0f; + for (int i = 0; i < sliceCount; i++) totalValue += values[i]; // Check for mouse hover over slices hoveredSlice = -1; // Reset hovered slice @@ -94,23 +97,24 @@ int main(void) { float dx = mousePos.x - center.x; float dy = mousePos.y - center.y; - float distance = sqrtf(dx * dx + dy * dy); + float distance = sqrtf(dx*dx + dy*dy); if (distance <= radius) // Inside the pie radius { - float angle = atan2f(dy, dx) * RAD2DEG; - if (angle < 0) - angle += 360; + float angle = atan2f(dy, dx)*RAD2DEG; + if (angle < 0) angle += 360; float currentAngle = 0.0f; for (int i = 0; i < sliceCount; i++) { - float sweep = (totalValue > 0) ? (values[i] / totalValue) * 360.0f : 0.0f; - if (angle >= currentAngle && angle < (currentAngle + sweep)) + float sweep = (totalValue > 0)? (values[i]/totalValue)*360.0f : 0.0f; + + if ((angle >= currentAngle) && (angle < (currentAngle + sweep))) { hoveredSlice = i; break; } + currentAngle += sweep; } } @@ -120,116 +124,96 @@ int main(void) // Draw //---------------------------------------------------------------------------------- BeginDrawing(); - ClearBackground(RAYWHITE); + ClearBackground(RAYWHITE); - // Draw the pie chart on the canvas - //------------------------------------------------------------------------------ - float startAngle = 0.0f; - for (int i = 0; i < sliceCount; i++) - { - float sweepAngle = (totalValue > 0) ? (values[i] / totalValue) * 360.0f : 0.0f; - float midAngle = startAngle + sweepAngle / 2.0f; // Middle angle for label positioning - - Color color = ColorFromHSV((float)i / sliceCount * 360.0f, 0.75f, 0.9f); - float currentRadius = radius; - - // Make the hovered slice pop out by adding 5 pixels to its radius - if (i == hoveredSlice) - currentRadius += 5.0f; - - // Draw the pie slice using raylib's DrawCircleSector function - DrawCircleSector(center, currentRadius, startAngle, startAngle + sweepAngle, 120, color); - - // Draw the label for the current slice - if (values[i] > 0) + // Draw the pie chart on the canvas + float startAngle = 0.0f; + for (int i = 0; i < sliceCount; i++) { - char labelText[64]; - if (showValues && showPercentages) - snprintf(labelText, 64, "%.1f (%.0f%%)", values[i], (values[i] / totalValue) * 100.0f); - else if (showValues) - snprintf(labelText, 64, "%.1f", values[i]); - else if (showPercentages) - snprintf(labelText, 64, "%.0f%%", (values[i] / totalValue) * 100.0f); - else - labelText[0] = '\0'; + float sweepAngle = (totalValue > 0)? (values[i]/totalValue)*360.0f : 0.0f; + float midAngle = startAngle + sweepAngle/2.0f; // Middle angle for label positioning - Vector2 textSize = MeasureTextEx(GetFontDefault(), labelText, 18, 1); - float labelRadius = radius * 0.7f; - Vector2 labelPos = { - center.x + cosf(midAngle * DEG2RAD) * labelRadius - textSize.x / 2, - center.y + sinf(midAngle * DEG2RAD) * labelRadius - textSize.y / 2}; - DrawText(labelText, (int)labelPos.x, (int)labelPos.y, 18, WHITE); - } + Color color = ColorFromHSV((float)i/sliceCount*360.0f, 0.75f, 0.9f); + float currentRadius = radius; + + // Make the hovered slice pop out by adding 5 pixels to its radius + if (i == hoveredSlice) currentRadius += 20.0f; + + // Draw the pie slice using raylib's DrawCircleSector function + DrawCircleSector(center, currentRadius, startAngle, startAngle + sweepAngle, 120, color); + + // Draw the label for the current slice + if (values[i] > 0) + { + char labelText[64] = { 0 }; + if (showValues && showPercentages) snprintf(labelText, 64, "%.1f (%.0f%%)", values[i], (values[i]/totalValue)*100.0f); + else if (showValues) snprintf(labelText, 64, "%.1f", values[i]); + else if (showPercentages) snprintf(labelText, 64, "%.0f%%", (values[i]/totalValue)*100.0f); + else labelText[0] = '\0'; + + Vector2 textSize = MeasureTextEx(GetFontDefault(), labelText, 20, 1); + float labelRadius = radius*0.7f; + Vector2 labelPos = { center.x + cosf(midAngle*DEG2RAD)*labelRadius - textSize.x/2.0f, + center.y + sinf(midAngle*DEG2RAD)*labelRadius - textSize.y/2.0f }; + DrawText(labelText, (int)labelPos.x, (int)labelPos.y, 20, WHITE); + } - if(showDonut) - { // Draw inner circle to create donut effect - DrawCircle(center.x, center.y, donutInnerRadius, RAYWHITE); + // TODO: This is a hacky solution, better use DrawRing() + if (showDonut) DrawCircle(center.x, center.y, donutInnerRadius, RAYWHITE); + + startAngle += sweepAngle; } - startAngle += sweepAngle; - } - //------------------------------------------------------------------------------ + // UI control panel + DrawRectangleRec(panelRect, Fade(LIGHTGRAY, 0.5f)); + DrawRectangleLinesEx(panelRect, 1.0f, GRAY); - // UI control panel - //------------------------------------------------------------------------------ - DrawRectangleRec(panelRect, Fade(LIGHTGRAY, 0.5f)); - DrawRectangleLinesEx(panelRect, 1.0f, GRAY); + GuiSpinner((Rectangle){ panelPos.x + 95, (float)panelPos.y + 12, 125, 25 }, "Slices ", &sliceCount, 1, MAX_PIE_SLICES, false); + GuiCheckBox((Rectangle){ panelPos.x + 20, (float)panelPos.y + 12 + 40, 20, 20 }, "Show Values", &showValues); + GuiCheckBox((Rectangle){ panelPos.x + 20, (float)panelPos.y + 12 + 70, 20, 20 }, "Show Percentages", &showPercentages); + GuiCheckBox((Rectangle){ panelPos.x + 20, (float)panelPos.y + 12 + 100, 20, 20 }, "Make Donut", &showDonut); - int currentY = (int)panelPos.y + 12; // Start a bit lower for margin + if (showDonut) GuiDisable(); + GuiSliderBar((Rectangle){ panelPos.x + 80, (float)panelPos.y + 12 + 130, panelRect.width - 100, 30 }, + "Inner Radius", NULL, &donutInnerRadius, 5.0f, radius - 10.0f); + GuiEnable(); - GuiSpinner((Rectangle){ panelPos.x + 95, (float)currentY, 125, 25 }, "Slices ", &sliceCount, 1, MAX_SLICES, false); - currentY += 40; + GuiLine((Rectangle){ panelPos.x + 10, (float)panelPos.y + 12 + 170, panelRect.width - 20, 1 }, NULL); - GuiCheckBox((Rectangle){ panelPos.x + 20, (float)currentY, 20, 20 }, "Show Values", &showValues); - currentY += 30; + // Scrollable area for slice editors + scrollPanelBounds = (Rectangle){ + panelPos.x + panelMargin, + (float)panelPos.y + 12 + 190, + panelRect.width - panelMargin*2, + panelRect.y + panelRect.height - panelPos.y + 12 + 190 - panelMargin + }; + int contentHeight = sliceCount*35; - GuiCheckBox((Rectangle){ panelPos.x + 20, (float)currentY, 20, 20 }, "Show Percentages", &showPercentages); - currentY += 30; + GuiScrollPanel(scrollPanelBounds, NULL, + (Rectangle){ 0, 0, panelRect.width - 25, (float)contentHeight }, + &scrollContentOffset, &view); - GuiCheckBox((Rectangle){ panelPos.x + 20, (float)currentY, 20, 20 }, "Make Donut", &showDonut); - currentY += 30; + const float contentX = view.x + scrollContentOffset.x; // Left of content + const float contentY = view.y + scrollContentOffset.y; // Top of content - if(showDonut) - { - GuiSliderBar((Rectangle){ panelPos.x + 80, (float)currentY, panelRect.width - 100, 30 }, - "Inner Radius", NULL, &donutInnerRadius, 5.0f, radius - 10.0f); - currentY += 40; - } + BeginScissorMode((int)view.x, (int)view.y, (int)view.width, (int)view.height); - GuiLine((Rectangle){ panelPos.x + 10, (float)currentY, panelRect.width - 20, 1 }, NULL); - currentY += 20; + for (int i = 0; i < sliceCount; i++) + { + const int rowY = (int)(contentY + 5 + i*35); - + // Color indicator + Color color = ColorFromHSV((float)i/sliceCount*360.0f, 0.75f, 0.9f); + DrawRectangle((int)(contentX + 15), rowY + 5, 20, 20, color); - // Scrollable area for slice editors - scrollPanelBounds = (Rectangle){ panelPos.x+panelMargin, (float)currentY, panelRect.width-panelMargin*2, panelRect.y + panelRect.height - currentY - panelMargin }; - int contentHeight = sliceCount * 35; + // Label textbox + if (GuiTextBox((Rectangle){ contentX + 45, (float)rowY, 75, 30 }, labels[i], 32, editingLabel[i])) editingLabel[i] = !editingLabel[i]; - GuiScrollPanel(scrollPanelBounds, NULL, - (Rectangle){ 0, 0, panelRect.width - 25, (float)contentHeight }, - &scrollContentOffset, &view); + GuiSliderBar((Rectangle){ contentX + 130, (float)rowY, 110, 30 }, NULL, NULL, &values[i], 0.0f, 1000.0f); + } - const float contentX = view.x + scrollContentOffset.x; // left of content - const float contentY = view.y + scrollContentOffset.y; // top of content - - BeginScissorMode((int)view.x, (int)view.y, (int)view.width, (int)view.height); - for (int i = 0; i < sliceCount; i++) - { - const int rowY = (int)(contentY + 5 + i * 35); - - // Color indicator - Color color = ColorFromHSV((float)i / sliceCount * 360.0f, 0.75f, 0.9f); - DrawRectangle((int)(contentX + 15), rowY + 5, 20, 20, color); - - // Label textbox - if (GuiTextBox((Rectangle){contentX + 45, (float)rowY, 75, 30}, labels[i], 32, editingLabel[i])) - editingLabel[i] = !editingLabel[i]; - - GuiSliderBar((Rectangle){contentX + 130, (float)rowY, 110, 30}, - NULL, NULL, &values[i], 0.0f, 1000.0f); - } - EndScissorMode(); + EndScissorMode(); EndDrawing(); //---------------------------------------------------------------------------------- From 4099218f1a5f1aaf96e6e5c646585a50d053c688 Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 17 Oct 2025 12:55:13 +0200 Subject: [PATCH 10/30] Update new examples UUID --- .../examples/core_highdpi_testbed.vcxproj | 2 +- .../examples/core_screen_recording.vcxproj | 2 +- projects/VS2022/raylib.sln | 106 +++++++++--------- 3 files changed, 55 insertions(+), 55 deletions(-) diff --git a/projects/VS2022/examples/core_highdpi_testbed.vcxproj b/projects/VS2022/examples/core_highdpi_testbed.vcxproj index 89675f5ed..d50de0d6e 100644 --- a/projects/VS2022/examples/core_highdpi_testbed.vcxproj +++ b/projects/VS2022/examples/core_highdpi_testbed.vcxproj @@ -51,7 +51,7 @@ - {6B1A933E-71B8-4C1F-9E79-02D98830E671} + {1ACC8236-EF4E-44B0-BD0C-AB1D95D5890F} Win32Proj core_highdpi_testbed 10.0 diff --git a/projects/VS2022/examples/core_screen_recording.vcxproj b/projects/VS2022/examples/core_screen_recording.vcxproj index 1669c6ac7..7b5856dbd 100644 --- a/projects/VS2022/examples/core_screen_recording.vcxproj +++ b/projects/VS2022/examples/core_screen_recording.vcxproj @@ -51,7 +51,7 @@ - {6B1A933E-71B8-4C1F-9E79-02D98830E671} + {9DE2FC01-A839-4F89-8319-9071D4C54821} Win32Proj core_screen_recording 10.0 diff --git a/projects/VS2022/raylib.sln b/projects/VS2022/raylib.sln index 20b7ad9bb..be06d43a2 100644 --- a/projects/VS2022/raylib.sln +++ b/projects/VS2022/raylib.sln @@ -387,9 +387,9 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_mouse_trail", "examp EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_starfield", "examples\shapes_starfield.vcxproj", "{EA4AD5A7-DB95-43C0-9A67-2D94146BCF91}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_highdpi_testbed", "examples\core_highdpi_testbed.vcxproj", "{6B1A933E-71B8-4C1F-9E79-02D98830E671}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_highdpi_testbed", "examples\core_highdpi_testbed.vcxproj", "{1ACC8236-EF4E-44B0-BD0C-AB1D95D5890F}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_screen_recording", "examples\core_screen_recording.vcxproj", "{6B1A933E-71B8-4C1F-9E79-02D98830E671}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_screen_recording", "examples\core_screen_recording.vcxproj", "{9DE2FC01-A839-4F89-8319-9071D4C54821}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -4797,54 +4797,54 @@ Global {EA4AD5A7-DB95-43C0-9A67-2D94146BCF91}.Release|x64.Build.0 = Release|x64 {EA4AD5A7-DB95-43C0-9A67-2D94146BCF91}.Release|x86.ActiveCfg = Release|Win32 {EA4AD5A7-DB95-43C0-9A67-2D94146BCF91}.Release|x86.Build.0 = Release|Win32 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug|ARM64.Build.0 = Debug|ARM64 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug|x64.ActiveCfg = Debug|x64 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug|x64.Build.0 = Debug|x64 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug|x86.ActiveCfg = Debug|Win32 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug|x86.Build.0 = Debug|Win32 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release.DLL|x64.Build.0 = Release.DLL|x64 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release.DLL|x86.Build.0 = Release.DLL|Win32 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release|ARM64.ActiveCfg = Release|ARM64 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release|ARM64.Build.0 = Release|ARM64 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release|x64.ActiveCfg = Release|x64 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release|x64.Build.0 = Release|x64 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release|x86.ActiveCfg = Release|Win32 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release|x86.Build.0 = Release|Win32 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug|ARM64.Build.0 = Debug|ARM64 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug|x64.ActiveCfg = Debug|x64 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug|x64.Build.0 = Debug|x64 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug|x86.ActiveCfg = Debug|Win32 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug|x86.Build.0 = Debug|Win32 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release.DLL|x64.Build.0 = Release.DLL|x64 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release.DLL|x86.Build.0 = Release.DLL|Win32 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release|ARM64.ActiveCfg = Release|ARM64 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release|ARM64.Build.0 = Release|ARM64 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release|x64.ActiveCfg = Release|x64 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release|x64.Build.0 = Release|x64 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release|x86.ActiveCfg = Release|Win32 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release|x86.Build.0 = Release|Win32 + {1ACC8236-EF4E-44B0-BD0C-AB1D95D5890F}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 + {1ACC8236-EF4E-44B0-BD0C-AB1D95D5890F}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 + {1ACC8236-EF4E-44B0-BD0C-AB1D95D5890F}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {1ACC8236-EF4E-44B0-BD0C-AB1D95D5890F}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {1ACC8236-EF4E-44B0-BD0C-AB1D95D5890F}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {1ACC8236-EF4E-44B0-BD0C-AB1D95D5890F}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {1ACC8236-EF4E-44B0-BD0C-AB1D95D5890F}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {1ACC8236-EF4E-44B0-BD0C-AB1D95D5890F}.Debug|ARM64.Build.0 = Debug|ARM64 + {1ACC8236-EF4E-44B0-BD0C-AB1D95D5890F}.Debug|x64.ActiveCfg = Debug|x64 + {1ACC8236-EF4E-44B0-BD0C-AB1D95D5890F}.Debug|x64.Build.0 = Debug|x64 + {1ACC8236-EF4E-44B0-BD0C-AB1D95D5890F}.Debug|x86.ActiveCfg = Debug|Win32 + {1ACC8236-EF4E-44B0-BD0C-AB1D95D5890F}.Debug|x86.Build.0 = Debug|Win32 + {1ACC8236-EF4E-44B0-BD0C-AB1D95D5890F}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 + {1ACC8236-EF4E-44B0-BD0C-AB1D95D5890F}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 + {1ACC8236-EF4E-44B0-BD0C-AB1D95D5890F}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {1ACC8236-EF4E-44B0-BD0C-AB1D95D5890F}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {1ACC8236-EF4E-44B0-BD0C-AB1D95D5890F}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {1ACC8236-EF4E-44B0-BD0C-AB1D95D5890F}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {1ACC8236-EF4E-44B0-BD0C-AB1D95D5890F}.Release|ARM64.ActiveCfg = Release|ARM64 + {1ACC8236-EF4E-44B0-BD0C-AB1D95D5890F}.Release|ARM64.Build.0 = Release|ARM64 + {1ACC8236-EF4E-44B0-BD0C-AB1D95D5890F}.Release|x64.ActiveCfg = Release|x64 + {1ACC8236-EF4E-44B0-BD0C-AB1D95D5890F}.Release|x64.Build.0 = Release|x64 + {1ACC8236-EF4E-44B0-BD0C-AB1D95D5890F}.Release|x86.ActiveCfg = Release|Win32 + {1ACC8236-EF4E-44B0-BD0C-AB1D95D5890F}.Release|x86.Build.0 = Release|Win32 + {9DE2FC01-A839-4F89-8319-9071D4C54821}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 + {9DE2FC01-A839-4F89-8319-9071D4C54821}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 + {9DE2FC01-A839-4F89-8319-9071D4C54821}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {9DE2FC01-A839-4F89-8319-9071D4C54821}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {9DE2FC01-A839-4F89-8319-9071D4C54821}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {9DE2FC01-A839-4F89-8319-9071D4C54821}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {9DE2FC01-A839-4F89-8319-9071D4C54821}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {9DE2FC01-A839-4F89-8319-9071D4C54821}.Debug|ARM64.Build.0 = Debug|ARM64 + {9DE2FC01-A839-4F89-8319-9071D4C54821}.Debug|x64.ActiveCfg = Debug|x64 + {9DE2FC01-A839-4F89-8319-9071D4C54821}.Debug|x64.Build.0 = Debug|x64 + {9DE2FC01-A839-4F89-8319-9071D4C54821}.Debug|x86.ActiveCfg = Debug|Win32 + {9DE2FC01-A839-4F89-8319-9071D4C54821}.Debug|x86.Build.0 = Debug|Win32 + {9DE2FC01-A839-4F89-8319-9071D4C54821}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 + {9DE2FC01-A839-4F89-8319-9071D4C54821}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 + {9DE2FC01-A839-4F89-8319-9071D4C54821}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {9DE2FC01-A839-4F89-8319-9071D4C54821}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {9DE2FC01-A839-4F89-8319-9071D4C54821}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {9DE2FC01-A839-4F89-8319-9071D4C54821}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {9DE2FC01-A839-4F89-8319-9071D4C54821}.Release|ARM64.ActiveCfg = Release|ARM64 + {9DE2FC01-A839-4F89-8319-9071D4C54821}.Release|ARM64.Build.0 = Release|ARM64 + {9DE2FC01-A839-4F89-8319-9071D4C54821}.Release|x64.ActiveCfg = Release|x64 + {9DE2FC01-A839-4F89-8319-9071D4C54821}.Release|x64.Build.0 = Release|x64 + {9DE2FC01-A839-4F89-8319-9071D4C54821}.Release|x86.ActiveCfg = Release|Win32 + {9DE2FC01-A839-4F89-8319-9071D4C54821}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -5012,7 +5012,7 @@ Global {C54703BF-D68A-480D-BE27-49B62E45D582} = {5317807F-61D4-4E0F-B6DC-2D9F12621ED9} {9CD8BCAD-F212-4BCC-BA98-899743CE3279} = {CC132A4D-D081-4C26-BFB9-AB11984054F8} {0981CA28-E4A5-4DF1-987F-A41D09131EFC} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} - {6B1A933E-71B8-4C1F-9E79-02D98830E671} = {8D3C83B7-F1E0-4C2E-9E34-EE5F6AB2502A} + {6B1A933E-71B8-4C1F-9E79-02D98830E671} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} {6BFF72EA-7362-4A3B-B6E5-9A3655BBBDA3} = {5317807F-61D4-4E0F-B6DC-2D9F12621ED9} {6777EC3C-077C-42FC-B4AD-B799CE55CCE4} = {8D3C83B7-F1E0-4C2E-9E34-EE5F6AB2502A} {A61DAD9C-271C-4E95-81AA-DB4CD58564D4} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} @@ -5040,8 +5040,8 @@ Global {AC215730-2B5F-4498-B7F5-5DB80AEFCA5F} = {278D8859-20B1-428F-8448-064F46E1F021} {0835E6BF-0170-4E99-A55C-E06E1EF4C3B2} = {278D8859-20B1-428F-8448-064F46E1F021} {EA4AD5A7-DB95-43C0-9A67-2D94146BCF91} = {278D8859-20B1-428F-8448-064F46E1F021} - {6B1A933E-71B8-4C1F-9E79-02D98830E671} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} - {6B1A933E-71B8-4C1F-9E79-02D98830E671} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} + {1ACC8236-EF4E-44B0-BD0C-AB1D95D5890F} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} + {9DE2FC01-A839-4F89-8319-9071D4C54821} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {E926C768-6307-4423-A1EC-57E95B1FAB29} From ed8c4c1b9b0154a84746c9316a58023d7d351ff2 Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 17 Oct 2025 17:01:38 +0200 Subject: [PATCH 11/30] REXM: Update examples collection, some renames --- examples/Makefile | 6 +- examples/Makefile.Web | 18 ++-- examples/README.md | 12 +-- examples/core/core_highdpi_testbed.c | 6 +- ...nitor_change.c => core_monitor_detector.c} | 14 +-- ...r_change.png => core_monitor_detector.png} | Bin examples/core/core_screen_recording.c | 6 +- examples/examples_list.txt | 20 ++--- examples/shapes/shapes_pie_chart.c | 2 +- examples/shapes/shapes_simple_particles.c | 34 ++++--- ..._starfield.c => shapes_starfield_effect.c} | 83 +++++++++--------- ...rfield.png => shapes_starfield_effect.png} | Bin ....vcxproj => core_monitor_detector.vcxproj} | 6 +- ...cxproj => shapes_starfield_effect.vcxproj} | 6 +- projects/VS2022/raylib.sln | 4 +- tools/rexm/examples_report.md | 18 ++-- tools/rexm/examples_report_issues.md | 2 + 17 files changed, 126 insertions(+), 111 deletions(-) rename examples/core/{core_monitor_change.c => core_monitor_detector.c} (96%) rename examples/core/{core_monitor_change.png => core_monitor_detector.png} (100%) rename examples/shapes/{shapes_starfield.c => shapes_starfield_effect.c} (66%) rename examples/shapes/{shapes_starfield.png => shapes_starfield_effect.png} (100%) rename projects/VS2022/examples/{core_monitor_change.vcxproj => core_monitor_detector.vcxproj} (99%) rename projects/VS2022/examples/{shapes_starfield.vcxproj => shapes_starfield_effect.vcxproj} (99%) diff --git a/examples/Makefile b/examples/Makefile index 498a36f47..30d619e94 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -529,7 +529,7 @@ CORE = \ core/core_input_mouse_wheel \ core/core_input_multitouch \ core/core_input_virtual_controls \ - core/core_monitor_change \ + core/core_monitor_detector \ core/core_random_sequence \ core/core_random_values \ core/core_render_texture \ @@ -572,7 +572,7 @@ SHAPES = \ shapes/shapes_rounded_rectangle_drawing \ shapes/shapes_simple_particles \ shapes/shapes_splines_drawing \ - shapes/shapes_starfield \ + shapes/shapes_starfield_effect \ shapes/shapes_top_down_lights \ shapes/shapes_triangle_strip \ shapes/shapes_vector_angle @@ -632,7 +632,6 @@ MODELS = \ models/models_cubicmap_rendering \ models/models_first_person_maze \ models/models_geometric_shapes \ - models/models_rotating_cube \ models/models_heightmap_rendering \ models/models_loading \ models/models_loading_gltf \ @@ -643,6 +642,7 @@ MODELS = \ models/models_orthographic_projection \ models/models_point_rendering \ models/models_rlgl_solar_system \ + models/models_rotating_cube \ models/models_skybox_rendering \ models/models_tesseract_view \ models/models_textured_cube \ diff --git a/examples/Makefile.Web b/examples/Makefile.Web index 1b32ebddf..222c56e11 100644 --- a/examples/Makefile.Web +++ b/examples/Makefile.Web @@ -529,7 +529,7 @@ CORE = \ core/core_input_mouse_wheel \ core/core_input_multitouch \ core/core_input_virtual_controls \ - core/core_monitor_change \ + core/core_monitor_detector \ core/core_random_sequence \ core/core_random_values \ core/core_render_texture \ @@ -572,7 +572,7 @@ SHAPES = \ shapes/shapes_rounded_rectangle_drawing \ shapes/shapes_simple_particles \ shapes/shapes_splines_drawing \ - shapes/shapes_starfield \ + shapes/shapes_starfield_effect \ shapes/shapes_top_down_lights \ shapes/shapes_triangle_strip \ shapes/shapes_vector_angle @@ -632,7 +632,6 @@ MODELS = \ models/models_cubicmap_rendering \ models/models_first_person_maze \ models/models_geometric_shapes \ - models/models_rotating_cube \ models/models_heightmap_rendering \ models/models_loading \ models/models_loading_gltf \ @@ -643,6 +642,7 @@ MODELS = \ models/models_orthographic_projection \ models/models_point_rendering \ models/models_rlgl_solar_system \ + models/models_rotating_cube \ models/models_skybox_rendering \ models/models_tesseract_view \ models/models_textured_cube \ @@ -795,7 +795,7 @@ core/core_input_multitouch: core/core_input_multitouch.c core/core_input_virtual_controls: core/core_input_virtual_controls.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) -core/core_monitor_change: core/core_monitor_change.c +core/core_monitor_detector: core/core_monitor_detector.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) core/core_random_sequence: core/core_random_sequence.c @@ -920,7 +920,7 @@ shapes/shapes_simple_particles: shapes/shapes_simple_particles.c shapes/shapes_splines_drawing: shapes/shapes_splines_drawing.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) -shapes/shapes_starfield: shapes/shapes_starfield.c +shapes/shapes_starfield_effect: shapes/shapes_starfield_effect.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) shapes/shapes_top_down_lights: shapes/shapes_top_down_lights.c @@ -1154,10 +1154,6 @@ models/models_first_person_maze: models/models_first_person_maze.c models/models_geometric_shapes: models/models_geometric_shapes.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) -models/models_rotating_cube: models/models_rotating_cube.c - $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \ - --preload-file models/resources/cubicmap_atlas.png@resources/cubicmap_atlas.png - models/models_heightmap_rendering: models/models_heightmap_rendering.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \ --preload-file models/resources/heightmap.png@resources/heightmap.png @@ -1201,6 +1197,10 @@ models/models_point_rendering: models/models_point_rendering.c models/models_rlgl_solar_system: models/models_rlgl_solar_system.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) +models/models_rotating_cube: models/models_rotating_cube.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \ + --preload-file models/resources/cubicmap_atlas.png@resources/cubicmap_atlas.png + models/models_skybox_rendering: models/models_skybox_rendering.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \ --preload-file models/resources/shaders/glsl100/skybox.vs@resources/shaders/glsl100/skybox.vs \ diff --git a/examples/README.md b/examples/README.md index dbc36fe22..b40966a5a 100644 --- a/examples/README.md +++ b/examples/README.md @@ -49,7 +49,7 @@ Examples using raylib[core](../src/rcore.c) platform functionality like window c | [core_window_flags](core/core_window_flags.c) | core_window_flags | ⭐⭐⭐☆ | 3.5 | 3.5 | [Ramon Santamaria](https://github.com/raysan5) | | [core_window_letterbox](core/core_window_letterbox.c) | core_window_letterbox | ⭐⭐☆☆ | 2.5 | 4.0 | [Anata](https://github.com/anatagawa) | | [core_window_should_close](core/core_window_should_close.c) | core_window_should_close | ⭐☆☆☆ | 4.2 | 4.2 | [Ramon Santamaria](https://github.com/raysan5) | -| [core_monitor_change](core/core_monitor_change.c) | core_monitor_change | ⭐☆☆☆ | 5.5 | 5.6 | [Maicon Santana](https://github.com/maiconpintoabreu) | +| [core_monitor_detector](core/core_monitor_detector.c) | core_monitor_detector | ⭐☆☆☆ | 5.5 | 5.6 | [Maicon Santana](https://github.com/maiconpintoabreu) | | [core_custom_logging](core/core_custom_logging.c) | core_custom_logging | ⭐⭐⭐☆ | 2.5 | 2.5 | [Pablo Marcos Oltra](https://github.com/pamarcos) | | [core_drop_files](core/core_drop_files.c) | core_drop_files | ⭐⭐☆☆ | 1.3 | 4.2 | [Ramon Santamaria](https://github.com/raysan5) | | [core_random_values](core/core_random_values.c) | core_random_values | ⭐☆☆☆ | 1.1 | 1.1 | [Ramon Santamaria](https://github.com/raysan5) | @@ -66,8 +66,8 @@ Examples using raylib[core](../src/rcore.c) platform functionality like window c | [core_undo_redo](core/core_undo_redo.c) | core_undo_redo | ⭐⭐⭐☆ | 5.5 | 5.6 | [Ramon Santamaria](https://github.com/raysan5) | | [core_input_actions](core/core_input_actions.c) | core_input_actions | ⭐⭐☆☆ | 5.5 | 5.6 | [Jett](https://github.com/JettMonstersGoBoom) | | [core_directory_files](core/core_directory_files.c) | core_directory_files | ⭐☆☆☆ | 5.5 | 5.6 | [Hugo ARNAL](https://github.com/hugoarnal) | -| [core_highdpi_testbed](core/core_highdpi_testbed.c) | core_highdpi_testbed | ⭐☆☆☆ | 5.5 | 5.6 | [](https://github.com/) | -| [core_screen_recording](core/core_screen_recording.c) | core_screen_recording | ⭐☆☆☆ | 5.5 | 5.6 | [](https://github.com/) | +| [core_highdpi_testbed](core/core_highdpi_testbed.c) | core_highdpi_testbed | ⭐☆☆☆ | 5.6-dev | 5.6-dev | [Ramon Santamaria](https://github.com/raysan5) | +| [core_screen_recording](core/core_screen_recording.c) | core_screen_recording | ⭐☆☆☆ | 5.6-dev | 5.6-dev | [Ramon Santamaria](https://github.com/raysan5) | | [core_clipboard_text](core/core_clipboard_text.c) | core_clipboard_text | ⭐☆☆☆ | 5.6-dev | 5.6-dev | [Robin](https://github.com/RobinsAviary) | ### category: shapes [31] @@ -101,12 +101,12 @@ Examples using raylib shapes drawing functionality, provided by raylib [shapes]( | [shapes_dashed_line](shapes/shapes_dashed_line.c) | shapes_dashed_line | ⭐☆☆☆ | 5.5 | 5.5 | [Luís Almeida](https://github.com/luis605) | | [shapes_triangle_strip](shapes/shapes_triangle_strip.c) | shapes_triangle_strip | ⭐⭐☆☆ | 5.6-dev | 5.6-dev | [Jopestpe](https://github.com/jopestpe) | | [shapes_vector_angle](shapes/shapes_vector_angle.c) | shapes_vector_angle | ⭐⭐☆☆ | 1.0 | 5.0 | [Ramon Santamaria](https://github.com/raysan5) | -| [shapes_pie_chart](shapes/shapes_pie_chart.c) | shapes_pie_chart | ⭐☆☆☆ | 5.5 | 5.6 | [Gideon Serfontein](https://github.com/GideonSerf) | +| [shapes_pie_chart](shapes/shapes_pie_chart.c) | shapes_pie_chart | ⭐⭐⭐☆ | 5.5 | 5.6 | [Gideon Serfontein](https://github.com/GideonSerf) | | [shapes_kaleidoscope](shapes/shapes_kaleidoscope.c) | shapes_kaleidoscope | ⭐⭐☆☆ | 5.5 | 5.6 | [Hugo ARNAL](https://github.com/hugoarnal) | | [shapes_clock_of_clocks](shapes/shapes_clock_of_clocks.c) | shapes_clock_of_clocks | ⭐⭐☆☆ | 5.5 | 5.6-dev | [JP Mortiboys](https://github.com/themushroompirates) | | [shapes_mouse_trail](shapes/shapes_mouse_trail.c) | shapes_mouse_trail | ⭐☆☆☆ | 5.6 | 5.6-dev | [[Balamurugan R]](https://github.com/[Bala050814]) | -| [shapes_simple_particles](shapes/shapes_simple_particles.c) | shapes_simple_particles | ⭐☆☆☆ | 5.6 | 5.6 | [Jordi Santonja](https://github.com/JordSant) | -| [shapes_starfield](shapes/shapes_starfield.c) | shapes_starfield | ⭐☆☆☆ | 5.5 | 5.6-dev | [JP Mortiboys](https://github.com/themushroompirates) | +| [shapes_simple_particles](shapes/shapes_simple_particles.c) | shapes_simple_particles | ⭐⭐☆☆ | 5.6 | 5.6 | [Jordi Santonja](https://github.com/JordSant) | +| [shapes_starfield_effect](shapes/shapes_starfield_effect.c) | shapes_starfield_effect | ⭐⭐☆☆ | 5.5 | 5.6-dev | [JP Mortiboys](https://github.com/themushroompirates) | ### category: textures [26] diff --git a/examples/core/core_highdpi_testbed.c b/examples/core/core_highdpi_testbed.c index b22aa507a..5cd2a7dc7 100644 --- a/examples/core/core_highdpi_testbed.c +++ b/examples/core/core_highdpi_testbed.c @@ -4,14 +4,14 @@ * * Example complexity rating: [★☆☆☆] 1/4 * -* Example originally created with raylib 5.5, last time updated with raylib 5.6 +* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev * -* Example contributed by (@) and reviewed by Ramon Santamaria (@raysan5) +* Example contributed by Ramon Santamaria (@raysan5) and reviewed by Ramon Santamaria (@raysan5) * * 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) 0 (@) +* Copyright (c) 2025 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/core/core_monitor_change.c b/examples/core/core_monitor_detector.c similarity index 96% rename from examples/core/core_monitor_change.c rename to examples/core/core_monitor_detector.c index 3286ba22d..0e94f6895 100644 --- a/examples/core/core_monitor_change.c +++ b/examples/core/core_monitor_detector.c @@ -1,6 +1,6 @@ /******************************************************************************************* * -* raylib [core] example - monitor change +* raylib [core] example - monitor detector * * Example complexity rating: [★☆☆☆] 1/4 * @@ -19,8 +19,8 @@ #define MAX_MONITORS 10 -// Monitor Details -typedef struct Monitor { +// Monitor info +typedef struct MonitorInfo { Vector2 position; const char *name; int width; @@ -28,7 +28,7 @@ typedef struct Monitor { int physicalWidth; int physicalHeight; int refreshRate; -} Monitor; +} MonitorInfo; //------------------------------------------------------------------------------------ // Program main entry point @@ -40,9 +40,9 @@ int main(void) const int screenWidth = 800; const int screenHeight = 450; - Monitor monitors[MAX_MONITORS] = { 0 }; + MonitorInfo monitors[MAX_MONITORS] = { 0 }; - InitWindow(screenWidth, screenHeight, "raylib [core] example - monitor change"); + InitWindow(screenWidth, screenHeight, "raylib [core] example - monitor detector"); int currentMonitorIndex = GetCurrentMonitor(); int monitorCount = 0; @@ -67,7 +67,7 @@ int main(void) monitorCount = GetMonitorCount(); for (int i = 0; i < monitorCount; i++) { - monitors[i] = (Monitor){ + monitors[i] = (MonitorInfo){ GetMonitorPosition(i), GetMonitorName(i), GetMonitorWidth(i), diff --git a/examples/core/core_monitor_change.png b/examples/core/core_monitor_detector.png similarity index 100% rename from examples/core/core_monitor_change.png rename to examples/core/core_monitor_detector.png diff --git a/examples/core/core_screen_recording.c b/examples/core/core_screen_recording.c index 9d0611bde..43c90eec5 100644 --- a/examples/core/core_screen_recording.c +++ b/examples/core/core_screen_recording.c @@ -4,14 +4,14 @@ * * Example complexity rating: [★☆☆☆] 1/4 * -* Example originally created with raylib 5.5, last time updated with raylib 5.6 +* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev * -* Example contributed by (@) and reviewed by Ramon Santamaria (@raysan5) +* Example contributed by Ramon Santamaria (@raysan5) and reviewed by Ramon Santamaria (@raysan5) * * 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) 0 (@) +* Copyright (c) 2025 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/examples_list.txt b/examples/examples_list.txt index 7abfdd453..6c9d0c3bd 100644 --- a/examples/examples_list.txt +++ b/examples/examples_list.txt @@ -31,7 +31,7 @@ core;core_world_screen;★★☆☆;1.3;1.4;2015;2025;"Ramon Santamaria";@raysan core;core_window_flags;★★★☆;3.5;3.5;2020;2025;"Ramon Santamaria";@raysan5 core;core_window_letterbox;★★☆☆;2.5;4.0;2019;2025;"Anata";@anatagawa core;core_window_should_close;★☆☆☆;4.2;4.2;2013;2025;"Ramon Santamaria";@raysan5 -core;core_monitor_change;★☆☆☆;5.5;5.6;2025;2025;"Maicon Santana";@maiconpintoabreu +core;core_monitor_detector;★☆☆☆;5.5;5.6;2025;2025;"Maicon Santana";@maiconpintoabreu core;core_custom_logging;★★★☆;2.5;2.5;2018;2025;"Pablo Marcos Oltra";@pamarcos core;core_drop_files;★★☆☆;1.3;4.2;2015;2025;"Ramon Santamaria";@raysan5 core;core_random_values;★☆☆☆;1.1;1.1;2014;2025;"Ramon Santamaria";@raysan5 @@ -48,8 +48,9 @@ core;core_render_texture;★☆☆☆;5.6-dev;5.6-dev;2025;2025;"Ramon Santamari core;core_undo_redo;★★★☆;5.5;5.6;2025;2025;"Ramon Santamaria";@raysan5 core;core_input_actions;★★☆☆;5.5;5.6;2025;2025;"Jett";@JettMonstersGoBoom core;core_directory_files;★☆☆☆;5.5;5.6;2025;2025;"Hugo ARNAL";@hugoarnal -core;core_highdpi_testbed;★☆☆☆;5.5;5.6;0;0;"";@ -core;core_screen_recording;★☆☆☆;5.5;5.6;0;0;"";@ +core;core_highdpi_testbed;★☆☆☆;5.6-dev;5.6-dev;2025;2025;"Ramon Santamaria";@raysan5 +core;core_screen_recording;★☆☆☆;5.6-dev;5.6-dev;2025;2025;"Ramon Santamaria";@raysan5 +core;core_clipboard_text;★☆☆☆;5.6-dev;5.6-dev;2025;2025;"Robin";@RobinsAviary shapes;shapes_basic_shapes;★☆☆☆;1.0;4.2;2014;2025;"Ramon Santamaria";@raysan5 shapes;shapes_bouncing_ball;★☆☆☆;2.5;2.5;2013;2025;"Ramon Santamaria";@raysan5 shapes;shapes_bullet_hell;★☆☆☆;5.6;5.6;2025;2025;"Zero";@zerohorsepower @@ -75,7 +76,12 @@ shapes;shapes_double_pendulum;★★☆☆;5.5;5.5;2025;2025;"JoeCheong";@Joeche shapes;shapes_dashed_line;★☆☆☆;5.5;5.5;2025;2025;"Luís Almeida";@luis605 shapes;shapes_triangle_strip;★★☆☆;5.6-dev;5.6-dev;2025;2025;"Jopestpe";@jopestpe shapes;shapes_vector_angle;★★☆☆;1.0;5.0;2023;2025;"Ramon Santamaria";@raysan5 -shapes;shapes_pie_chart;★☆☆☆;5.5;5.6;2025;2025;"Gideon Serfontein";@GideonSerf +shapes;shapes_pie_chart;★★★☆;5.5;5.6;2025;2025;"Gideon Serfontein";@GideonSerf +shapes;shapes_kaleidoscope;★★☆☆;5.5;5.6;2025;2025;"Hugo ARNAL";@hugoarnal +shapes;shapes_clock_of_clocks;★★☆☆;5.5;5.6-dev;2025;2025;"JP Mortiboys";@themushroompirates +shapes;shapes_mouse_trail;★☆☆☆;5.6;5.6-dev;2024;2024;"[Balamurugan R]";@[Bala050814] +shapes;shapes_simple_particles;★★☆☆;5.6;5.6;2025;2025;"Jordi Santonja";@JordSant +shapes;shapes_starfield_effect;★★☆☆;5.5;5.6-dev;2025;2025;"JP Mortiboys";@themushroompirates 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 @@ -186,9 +192,3 @@ others;easings_testbed;★★★☆;2.5;3.0;2019;2025;"Juan Miguel López";@flas others;raylib_opengl_interop;★★★★;3.8;4.0;2021;2025;"Stephan Soller";@arkanis others;embedded_files_loading;★★☆☆;3.0;3.5;2020;2025;"Kristian Holmgren";@defutura others;web_basic_window;★☆☆☆;5.6-dev;5.6-dev;2014;2025;"Ramon Santamaria";@raysan5 -shapes;shapes_kaleidoscope;★★☆☆;5.5;5.6;2025;2025;"Hugo ARNAL";@hugoarnal -core;core_clipboard_text;★☆☆☆;5.6-dev;5.6-dev;2025;2025;"Robin";@RobinsAviary -shapes;shapes_clock_of_clocks;★★☆☆;5.5;5.6-dev;2025;2025;"JP Mortiboys";@themushroompirates -shapes;shapes_mouse_trail;★☆☆☆;5.6;5.6-dev;2024;2024;"[Balamurugan R]";@[Bala050814] -shapes;shapes_simple_particles;★☆☆☆;5.6;5.6;2025;2025;"Jordi Santonja";@JordSant -shapes;shapes_starfield;★☆☆☆;5.5;5.6-dev;2025;2025;"JP Mortiboys";@themushroompirates diff --git a/examples/shapes/shapes_pie_chart.c b/examples/shapes/shapes_pie_chart.c index e2f6900eb..566e3a4d1 100644 --- a/examples/shapes/shapes_pie_chart.c +++ b/examples/shapes/shapes_pie_chart.c @@ -2,7 +2,7 @@ * * raylib [shapes] example - pie chart * -* Example complexity rating: [★☆☆☆] 1/4 +* Example complexity rating: [★★★☆] 3/4 * * Example originally created with raylib 5.5, last time updated with raylib 5.6 * diff --git a/examples/shapes/shapes_simple_particles.c b/examples/shapes/shapes_simple_particles.c index 5bef0917a..7c2a598c2 100644 --- a/examples/shapes/shapes_simple_particles.c +++ b/examples/shapes/shapes_simple_particles.c @@ -2,7 +2,7 @@ * * raylib [shapes] example - simple particles * -* Example complexity rating: [★☆☆☆] 1/4 +* Example complexity rating: [★★☆☆] 2/4 * * Example originally created with raylib 5.6, last time updated with raylib 5.6 * @@ -20,7 +20,7 @@ #include // Required for: calloc(), free() #include // Required for: cosf(), sinf() -#define MAX_PARTICLES 3000 // Max number particles +#define MAX_PARTICLES 3000 // Max number of particles //---------------------------------------------------------------------------------- // Types and Structures Definition @@ -100,6 +100,7 @@ int main(void) // Update the parameters of each particle UpdateParticles(&circularBuffer, screenWidth, screenHeight); + // Remove dead particles from the circular buffer UpdateCircularBuffer(&circularBuffer); @@ -217,46 +218,53 @@ static void UpdateParticles(CircularBuffer *circularBuffer, int screenWidth, int switch (circularBuffer->buffer[i].type) { case WATER: + { circularBuffer->buffer[i].position.x += circularBuffer->buffer[i].velocity.x; circularBuffer->buffer[i].velocity.y += 0.2f; // Gravity circularBuffer->buffer[i].position.y += circularBuffer->buffer[i].velocity.y; - break; + } break; case SMOKE: + { circularBuffer->buffer[i].position.x += circularBuffer->buffer[i].velocity.x; circularBuffer->buffer[i].velocity.y -= 0.05f; // Upwards circularBuffer->buffer[i].position.y += circularBuffer->buffer[i].velocity.y; circularBuffer->buffer[i].radius += 0.5f; // Increment radius: smoke expands circularBuffer->buffer[i].color.a -= 4; // Decrement alpha: smoke fades - if (circularBuffer->buffer[i].color.a < 4) // If alpha transparent, particle dies - circularBuffer->buffer[i].alive = false; - break; + + // If alpha transparent, particle dies + if (circularBuffer->buffer[i].color.a < 4) circularBuffer->buffer[i].alive = false; + } break; case FIRE: + { // Add a little horizontal oscillation to fire particles circularBuffer->buffer[i].position.x += circularBuffer->buffer[i].velocity.x + cosf(circularBuffer->buffer[i].lifeTime*215.0f); circularBuffer->buffer[i].velocity.y -= 0.05f; // Upwards circularBuffer->buffer[i].position.y += circularBuffer->buffer[i].velocity.y; circularBuffer->buffer[i].radius -= 0.15f; // Decrement radius: fire shrinks circularBuffer->buffer[i].color.g -= 3; // Decrement green: fire turns reddish starting from yellow - if (circularBuffer->buffer[i].radius <= 0.02f) // If radius too small, particle dies - circularBuffer->buffer[i].alive = false; - break; + + // If radius too small, particle dies + if (circularBuffer->buffer[i].radius <= 0.02f) circularBuffer->buffer[i].alive = false; + } break; default: break; } // Disable particle when out of screen Vector2 center = circularBuffer->buffer[i].position; float radius = circularBuffer->buffer[i].radius; - if ((center.x < -radius) || (center.x > screenWidth + radius) || - (center.y < -radius) || (center.y > screenHeight + radius)) + + if ((center.x < -radius) || (center.x > (screenWidth + radius)) || + (center.y < -radius) || (center.y > (screenHeight + radius))) + { circularBuffer->buffer[i].alive = false; + } } } static void UpdateCircularBuffer(CircularBuffer *circularBuffer) { // Update circular buffer: advance tail over dead particles - while ((circularBuffer->tail != circularBuffer->head) && - !circularBuffer->buffer[circularBuffer->tail].alive) + while ((circularBuffer->tail != circularBuffer->head) && !circularBuffer->buffer[circularBuffer->tail].alive) { circularBuffer->tail = (circularBuffer->tail + 1)%MAX_PARTICLES; } diff --git a/examples/shapes/shapes_starfield.c b/examples/shapes/shapes_starfield_effect.c similarity index 66% rename from examples/shapes/shapes_starfield.c rename to examples/shapes/shapes_starfield_effect.c index df543d066..8dd90fe0b 100644 --- a/examples/shapes/shapes_starfield.c +++ b/examples/shapes/shapes_starfield_effect.c @@ -1,8 +1,8 @@ /******************************************************************************************* * -* raylib [shapes] example - starfield +* raylib [shapes] example - starfield effect * -* Example complexity rating: [★☆☆☆] 1/4 +* Example complexity rating: [★★☆☆] 2/4 * * Example originally created with raylib 5.5, last time updated with raylib 5.6-dev * @@ -31,7 +31,7 @@ int main(void) const int screenWidth = 800; const int screenHeight = 450; - InitWindow(screenWidth, screenHeight, "raylib [shapes] example - starfield"); + InitWindow(screenWidth, screenHeight, "raylib [shapes] example - starfield effect"); Color bgColor = ColorLerp(DARKBLUE, BLACK, 0.69f); @@ -45,9 +45,10 @@ int main(void) Vector2 starsScreenPos[STAR_COUNT] = { 0 }; // Setup the stars with a random position - for (int i = 0; i < STAR_COUNT; i++) { - stars[i].x = GetRandomValue(-screenWidth*.5, screenWidth*.5); - stars[i].y = GetRandomValue(-screenHeight*.5, screenHeight*.5); + for (int i = 0; i < STAR_COUNT; i++) + { + stars[i].x = GetRandomValue(-screenWidth*0.5f, screenWidth*0.5f); + stars[i].y = GetRandomValue(-screenHeight*0.5f, screenHeight*0.5f); stars[i].z = 1.0f; } @@ -59,39 +60,36 @@ int main(void) { // Update //---------------------------------------------------------------------------------- - - // Change speed based on number keys - for (int i = 0; i <= 9; i++) { - if (IsKeyPressed(KEY_ZERO + i)) { - speed = 2.0f * (float)i / 9.0f; - } - } + // Change speed based on mouse + float mouseMove = GetMouseWheelMove(); + if ((int)mouseMove != 0) speed += 2.0f*mouseMove/9.0f; + if (speed < 0.0f) speed = 0.1f; + else if (speed > 2.0f) speed = 2.0f; // Toggle lines / points with space bar - if (IsKeyPressed(KEY_SPACE)) { - drawLines = !drawLines; - } + if (IsKeyPressed(KEY_SPACE)) drawLines = !drawLines; float dt = GetFrameTime(); - for (int i = 0; i < STAR_COUNT; i++) { + for (int i = 0; i < STAR_COUNT; i++) + { // Update star's timer - stars[i].z -= dt * speed; + stars[i].z -= dt*speed; + // Calculate the screen position - starsScreenPos[i] = (Vector2) { - screenWidth*.5f + stars[i].x / stars[i].z, - screenHeight*.5f + stars[i].y / stars[i].z, + starsScreenPos[i] = (Vector2){ + screenWidth*0.5f + stars[i].x/stars[i].z, + screenHeight*0.5f + stars[i].y/stars[i].z, }; + // If the star is too old, or offscreen, it dies and we make a new random one - if (stars[i].z < 0.0f - || starsScreenPos[i].x < 0 || starsScreenPos[i].y < 0.0f - || starsScreenPos[i].x > screenWidth || starsScreenPos[i].y > screenHeight) { - stars[i].x = GetRandomValue(-screenWidth*.5, screenWidth*.5); - stars[i].y = GetRandomValue(-screenHeight*.5, screenHeight*.5); + if ((stars[i].z < 0.0f) || (starsScreenPos[i].x < 0) || (starsScreenPos[i].y < 0.0f) || + (starsScreenPos[i].x > screenWidth) || (starsScreenPos[i].y > screenHeight)) + { + stars[i].x = GetRandomValue(-screenWidth*0.5f, screenWidth*0.5f); + stars[i].y = GetRandomValue(-screenHeight*0.5f, screenHeight*0.5f); stars[i].z = 1.0f; } } - - //---------------------------------------------------------------------------------- // Draw @@ -100,42 +98,47 @@ int main(void) ClearBackground(bgColor); - for (int i = 0; i < STAR_COUNT; i++) { - if (drawLines) { + for (int i = 0; i < STAR_COUNT; i++) + { + if (drawLines) + { // Get the time a little while ago for this star, but clamp it float t = Clamp(stars[i].z + 1.0f/32.0f, 0.0f, 1.0f); + // If it's different enough from the current time, we proceed - if (t - stars[i].z > 1e-3) { + if ((t - stars[i].z) > 1e-3) + { // Calculate the screen position of the old point - Vector2 startPos = (Vector2) { - screenWidth*.5f + stars[i].x / t, - screenHeight*.5f + stars[i].y / t, + Vector2 startPos = (Vector2){ + screenWidth*0.5f + stars[i].x/t, + screenHeight*0.5f + stars[i].y/t, }; + // Draw a line connecting the old point to the current point DrawLineV(startPos, starsScreenPos[i], RAYWHITE); } } - else { + else + { // Make the radius grow as the star ages float radius = Lerp(stars[i].z, 1.0f, 5.0f); + // Draw the circle DrawCircleV(starsScreenPos[i], radius, RAYWHITE); } } + DrawText(TextFormat("[MOUSE WHEEL] Current Speed: %.0f", 9.0f*speed/2.0f), 10, 40, 20, RAYWHITE); + DrawText(TextFormat("[SPACE] Current draw mode: %s", drawLines ? "Lines" : "Circles"), 10, 70, 20, RAYWHITE); + DrawFPS(10, 10); - DrawText(TextFormat("Current Speed: %.0f [Number keys to change]", 9.0f * speed / 2.0f), 10, 30, 20, RAYWHITE); - DrawText(TextFormat("Drawing %s [Space to change]", drawLines ? "Lines" : "Circles"), 10, 50, 20, RAYWHITE); - - EndDrawing(); //---------------------------------------------------------------------------------- } // De-Initialization //-------------------------------------------------------------------------------------- - CloseWindow(); // Close window and OpenGL context //-------------------------------------------------------------------------------------- diff --git a/examples/shapes/shapes_starfield.png b/examples/shapes/shapes_starfield_effect.png similarity index 100% rename from examples/shapes/shapes_starfield.png rename to examples/shapes/shapes_starfield_effect.png diff --git a/projects/VS2022/examples/core_monitor_change.vcxproj b/projects/VS2022/examples/core_monitor_detector.vcxproj similarity index 99% rename from projects/VS2022/examples/core_monitor_change.vcxproj rename to projects/VS2022/examples/core_monitor_detector.vcxproj index 07921bef3..bafb1b15c 100644 --- a/projects/VS2022/examples/core_monitor_change.vcxproj +++ b/projects/VS2022/examples/core_monitor_detector.vcxproj @@ -53,9 +53,9 @@ {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3} Win32Proj - core_monitor_change + core_monitor_detector 10.0 - core_monitor_change + core_monitor_detector @@ -553,7 +553,7 @@ - + diff --git a/projects/VS2022/examples/shapes_starfield.vcxproj b/projects/VS2022/examples/shapes_starfield_effect.vcxproj similarity index 99% rename from projects/VS2022/examples/shapes_starfield.vcxproj rename to projects/VS2022/examples/shapes_starfield_effect.vcxproj index 5cfc0a6d3..794ec633e 100644 --- a/projects/VS2022/examples/shapes_starfield.vcxproj +++ b/projects/VS2022/examples/shapes_starfield_effect.vcxproj @@ -53,9 +53,9 @@ {EA4AD5A7-DB95-43C0-9A67-2D94146BCF91} Win32Proj - shapes_starfield + shapes_starfield_effect 10.0 - shapes_starfield + shapes_starfield_effect @@ -553,7 +553,7 @@ - + diff --git a/projects/VS2022/raylib.sln b/projects/VS2022/raylib.sln index be06d43a2..c4de89730 100644 --- a/projects/VS2022/raylib.sln +++ b/projects/VS2022/raylib.sln @@ -361,7 +361,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "models_rotating_cube", "exa EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shaders_ascii_rendering", "examples\shaders_ascii_rendering.vcxproj", "{5F4B766F-DD52-4B53-B6C3-BC7611E17F20}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_monitor_change", "examples\core_monitor_change.vcxproj", "{FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_monitor_detector", "examples\core_monitor_detector.vcxproj", "{FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "web_basic_window", "examples\web_basic_window.vcxproj", "{A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}" EndProject @@ -385,7 +385,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_clock_of_clocks", "e EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_mouse_trail", "examples\shapes_mouse_trail.vcxproj", "{0835E6BF-0170-4E99-A55C-E06E1EF4C3B2}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_starfield", "examples\shapes_starfield.vcxproj", "{EA4AD5A7-DB95-43C0-9A67-2D94146BCF91}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_starfield_effect", "examples\shapes_starfield_effect.vcxproj", "{EA4AD5A7-DB95-43C0-9A67-2D94146BCF91}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_highdpi_testbed", "examples\core_highdpi_testbed.vcxproj", "{1ACC8236-EF4E-44B0-BD0C-AB1D95D5890F}" EndProject diff --git a/tools/rexm/examples_report.md b/tools/rexm/examples_report.md index e55610a30..e058e09a7 100644 --- a/tools/rexm/examples_report.md +++ b/tools/rexm/examples_report.md @@ -44,7 +44,7 @@ Example elements validated: | core_window_flags | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | core_window_letterbox | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | core_window_should_close | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | -| core_monitor_change | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| core_monitor_detector | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | core_custom_logging | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | core_drop_files | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | core_random_values | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | @@ -61,6 +61,9 @@ Example elements validated: | core_undo_redo | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | core_input_actions | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | core_directory_files | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| core_highdpi_testbed | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| core_screen_recording | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| core_clipboard_text | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shapes_basic_shapes | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shapes_bouncing_ball | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shapes_bullet_hell | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | @@ -87,6 +90,11 @@ Example elements validated: | shapes_triangle_strip | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shapes_vector_angle | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shapes_pie_chart | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| shapes_kaleidoscope | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| shapes_clock_of_clocks | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| shapes_mouse_trail | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| shapes_simple_particles | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| shapes_starfield_effect | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | textures_logo_raylib | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | textures_srcrec_dstrec | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | textures_image_drawing | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | @@ -152,7 +160,7 @@ Example elements validated: | models_bone_socket | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | models_tesseract_view | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | models_basic_voxel | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | -| models_geometry_textures_cube | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| models_rotating_cube | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shaders_ascii_rendering | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shaders_basic_lighting | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shaders_model_shader | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | @@ -197,9 +205,3 @@ Example elements validated: | raylib_opengl_interop | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | | embedded_files_loading | ✔ | ❌ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | web_basic_window | ✔ | ❌ | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | -| shapes_kaleidoscope | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | -| core_clipboard_text | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | -| shapes_clock_of_clocks | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | -| shapes_mouse_trail | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | -| shapes_simple_particles | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | -| shapes_starfield | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | diff --git a/tools/rexm/examples_report_issues.md b/tools/rexm/examples_report_issues.md index 5178dabdd..3136c2709 100644 --- a/tools/rexm/examples_report_issues.md +++ b/tools/rexm/examples_report_issues.md @@ -20,6 +20,8 @@ Example elements validated: ``` | **EXAMPLE NAME** | [C] | [CAT]| [INFO]|[PNG]|[WPNG]| [RES]| [MK] |[MKWEB]| [VCX]| [SOL]|[RDME]|[JS] | [WOUT]|[WMETA]| |:---------------------------------|:---:|:----:|:-----:|:---:|:----:|:----:|:----:|:-----:|:----:|:----:|:----:|:---:|:-----:|:-----:| +| core_highdpi_testbed | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| core_screen_recording | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | rlgl_standalone | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | rlgl_compute_shader | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | easings_testbed | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | From 7995f8d1b3a436d5e000dbda9113b8b8a25a1f21 Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 17 Oct 2025 17:01:58 +0200 Subject: [PATCH 12/30] Avoid auto push on rename --- tools/rexm/rexm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/rexm/rexm.c b/tools/rexm/rexm.c index c615e810f..20fc1d5e5 100644 --- a/tools/rexm/rexm.c +++ b/tools/rexm/rexm.c @@ -69,7 +69,7 @@ #define REXM_MAX_RESOURCE_PATHS 256 // Create local commit with changes on example renaming -#define RENAME_AUTO_COMMIT_CREATION +//#define RENAME_AUTO_COMMIT_CREATION //---------------------------------------------------------------------------------- // Types and Structures Definition From cd0d693a5685aa9a6d5b4c8a910679c09bd4a35a Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 17 Oct 2025 17:09:55 +0200 Subject: [PATCH 13/30] Reviewed example --- examples/examples_list.txt | 2 +- examples/shapes/shapes_mouse_trail.c | 26 +++++++++++--------------- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/examples/examples_list.txt b/examples/examples_list.txt index 6c9d0c3bd..9989f940f 100644 --- a/examples/examples_list.txt +++ b/examples/examples_list.txt @@ -79,7 +79,7 @@ shapes;shapes_vector_angle;★★☆☆;1.0;5.0;2023;2025;"Ramon Santamaria";@ra shapes;shapes_pie_chart;★★★☆;5.5;5.6;2025;2025;"Gideon Serfontein";@GideonSerf shapes;shapes_kaleidoscope;★★☆☆;5.5;5.6;2025;2025;"Hugo ARNAL";@hugoarnal shapes;shapes_clock_of_clocks;★★☆☆;5.5;5.6-dev;2025;2025;"JP Mortiboys";@themushroompirates -shapes;shapes_mouse_trail;★☆☆☆;5.6;5.6-dev;2024;2024;"[Balamurugan R]";@[Bala050814] +shapes;shapes_mouse_trail;★☆☆☆;5.6;5.6-dev;2025;2025;"Balamurugan R";@Bala050814 shapes;shapes_simple_particles;★★☆☆;5.6;5.6;2025;2025;"Jordi Santonja";@JordSant shapes;shapes_starfield_effect;★★☆☆;5.5;5.6-dev;2025;2025;"JP Mortiboys";@themushroompirates textures;textures_logo_raylib;★☆☆☆;1.0;1.0;2014;2025;"Ramon Santamaria";@raysan5 diff --git a/examples/shapes/shapes_mouse_trail.c b/examples/shapes/shapes_mouse_trail.c index ad1166548..e0e5a3c1d 100644 --- a/examples/shapes/shapes_mouse_trail.c +++ b/examples/shapes/shapes_mouse_trail.c @@ -6,16 +6,17 @@ * * Example originally created with raylib 5.6 * -* Example contributed by [Balamurugan R] (@[Bala050814]]) and reviewed by [Ray] (@raysan5) +* Example contributed by Balamurugan R (@Bala050814]) and reviewed by Ramon Santamaria (@raysan5) * * 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) 2024 [Balamurugan R] (@[Bala050814]) +* Copyright (c) 2025 Balamurugan R (@Bala050814) * ********************************************************************************************/ #include "raylib.h" + #include "raymath.h" // Define the maximum number of positions to store in the trail @@ -46,14 +47,14 @@ int main(void) //---------------------------------------------------------------------------------- Vector2 mousePosition = GetMousePosition(); - // 1. Shift all existing positions backward by one slot in the array - // The last element (the oldest position) is dropped. + // Shift all existing positions backward by one slot in the array + // The last element (the oldest position) is dropped for (int i = MAX_TRAIL_LENGTH - 1; i > 0; i--) { trailPositions[i] = trailPositions[i - 1]; } - // 2. Store the new, current mouse position at the start of the array (Index 0) + // Store the new, current mouse position at the start of the array (Index 0) trailPositions[0] = mousePosition; //---------------------------------------------------------------------------------- @@ -61,24 +62,23 @@ int main(void) //---------------------------------------------------------------------------------- BeginDrawing(); - // Use BLACK for a darker background to make the colored trail pop ClearBackground(BLACK); - // 3. Draw the trail by looping through the history array + // Draw the trail by looping through the history array for (int i = 0; i < MAX_TRAIL_LENGTH; i++) { // Ensure we skip drawing if the array hasn't been fully filled on startup - if (trailPositions[i].x != 0.0f || trailPositions[i].y != 0.0f) + if ((trailPositions[i].x != 0.0f) || (trailPositions[i].y != 0.0f)) { // Calculate relative trail strength (ratio is near 1.0 for new, near 0.0 for old) float ratio = (float)(MAX_TRAIL_LENGTH - i) / MAX_TRAIL_LENGTH; // Fade effect: oldest positions are more transparent // Fade (color, alpha) - alpha is 0.5 to 1.0 based on ratio - Color trailColor = Fade(SKYBLUE, ratio * 0.5f + 0.5f); + Color trailColor = Fade(SKYBLUE, ratio*0.5f + 0.5f); // Size effect: oldest positions are smaller - float trailRadius = 15.0f * ratio; + float trailRadius = 15.0f*ratio; DrawCircleV(trailPositions[i], trailRadius, trailColor); } @@ -87,8 +87,7 @@ int main(void) // Draw a distinct white circle for the current mouse position (Index 0) DrawCircleV(mousePosition, 15.0f, WHITE); - DrawText("Move the mouse to see the trail effect!", - 10, screenHeight - 30, 20, LIGHTGRAY); + DrawText("Move the mouse to see the trail effect!", 10, screenHeight - 30, 20, LIGHTGRAY); EndDrawing(); //---------------------------------------------------------------------------------- @@ -96,9 +95,6 @@ int main(void) // De-Initialization //-------------------------------------------------------------------------------------- - - // No resources loaded, nothing to unload. - CloseWindow(); // Close window and OpenGL context //-------------------------------------------------------------------------------------- From ab4831911ab8568cea2ee4d14acfb5ff2847cce8 Mon Sep 17 00:00:00 2001 From: Aanjishnu Bhattacharyya <71861112+NimComPoo-04@users.noreply.github.com> Date: Fri, 17 Oct 2025 20:42:14 +0530 Subject: [PATCH 14/30] [examples] Added: `core_text_file_loading` (#5278) Added and example demonstrating reading the contents of a file and rendering them, utilizing rtext module. The demonstration also handles wrapping of long sentences, and text scrolling. Co-authored-by: Ray --- examples/Makefile | 1 + examples/Makefile.Web | 5 + examples/core/core_text_file_loading.c | 164 +++++ examples/core/core_text_file_loading.png | Bin 0 -> 23575 bytes examples/core/resources/text_file.txt | 18 + .../examples/core_text_file_loading.vcxproj | 569 ++++++++++++++++++ projects/VS2022/raylib.sln | 2 + 7 files changed, 759 insertions(+) create mode 100644 examples/core/core_text_file_loading.c create mode 100644 examples/core/core_text_file_loading.png create mode 100644 examples/core/resources/text_file.txt create mode 100644 projects/VS2022/examples/core_text_file_loading.vcxproj diff --git a/examples/Makefile b/examples/Makefile index 30d619e94..a9732679d 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -537,6 +537,7 @@ CORE = \ core/core_screen_recording \ core/core_smooth_pixelperfect \ core/core_storage_values \ + core/core_text_file_loading \ core/core_undo_redo \ core/core_vr_simulator \ core/core_window_flags \ diff --git a/examples/Makefile.Web b/examples/Makefile.Web index 222c56e11..88843af09 100644 --- a/examples/Makefile.Web +++ b/examples/Makefile.Web @@ -537,6 +537,7 @@ CORE = \ core/core_screen_recording \ core/core_smooth_pixelperfect \ core/core_storage_values \ + core/core_text_file_loading \ core/core_undo_redo \ core/core_vr_simulator \ core/core_window_flags \ @@ -819,6 +820,10 @@ core/core_smooth_pixelperfect: core/core_smooth_pixelperfect.c core/core_storage_values: core/core_storage_values.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) +core/core_text_file_loading: core/core_text_file_loading.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \ + --preload-file core/resources/text_file.txt@resources/text_file.txt + core/core_undo_redo: core/core_undo_redo.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) diff --git a/examples/core/core_text_file_loading.c b/examples/core/core_text_file_loading.c new file mode 100644 index 000000000..0077551fd --- /dev/null +++ b/examples/core/core_text_file_loading.c @@ -0,0 +1,164 @@ +/******************************************************************************************* +* +* raylib [core] example - text file loading +* +* Example complexity rating: [★☆☆☆] 1/4 +* +* Example originally created with raylib 5.5, last time updated with raylib 5.6 +* +* Example contributed by Aanjishnu Bhattacharyya (@NimComPoo-04) and reviewed by Ramon Santamaria (@raysan5) +* +* 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) 0 Aanjishnu Bhattacharyya (@NimComPoo-04) +* +********************************************************************************************/ + +#include "raylib.h" +#include "raymath.h" // For Lerp + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [core] example - text file loading"); + + // Setting up the camera + Camera2D cam = { + .offset = {0, 0}, + .target = {0, 0}, + .rotation = 0, + .zoom = 1 + }; + + // Loading file from resources/text_file.txt + const char *fileName = "resources/text_file.txt"; + char *fileData = LoadFileText(fileName); + + // Loading all the lines + int lineCount = 0; + char **lines = LoadTextLines(fileData, &lineCount); + + // Just sylistic choise + int fontSize = 20; + int textTop = 25 + fontSize; // Top of the screen from where the text is rendered + int wrapWidth = screenWidth - 20; + + // Wrap the lines as needed + for(int i = 0; i < lineCount; i++) + { + int j = 0; + int lastSpace = 0; // Keeping track of last valid space to insert '\n' + int lastWrapStart = 0; // Keeping track of the start of this wrapped line. + + while(lines[i][j] != '\0') + { + if(lines[i][j] == ' ') + { + // Making a C Style string by adding a '\0' at the required location so that we can use the MeasureText function + lines[i][j] = '\0'; + + // Checking if the text has crossed the wrapWidth, then going back and inserting a newline + if(MeasureText(lines[i] + lastWrapStart, fontSize) > wrapWidth) + { + lines[i][lastSpace] = '\n'; + + // Since we added a newline the place of wrap changed so we update our lastWrapStart + lastWrapStart = lastSpace + 1; + } + + lines[i][j] = ' '; // Resetting the space back + lastSpace = j; // Since we encountered a new space we update our last encountered space location + } + + j++; + } + } + + // Calculating the total height so that we can show a scrollbar + int textHeight = 0; + + for(int i = 0; i < lineCount; i++) + { + Vector2 size = MeasureTextEx(GetFontDefault(), lines[i], fontSize, 2); + textHeight += size.y + 10; + } + + // A simple scrollbar on the side to show how far we have red into the file + Rectangle scrollBar = { + .x = screenWidth - 5, + .y = 0, + .width = 5, + .height = screenHeight * 100 / (textHeight - screenHeight) // Scrollbar height is just a percentage + }; + + + SetTargetFPS(60); + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + float scroll = GetMouseWheelMove(); + cam.target.y -= scroll * fontSize * 1.5; // Choosing an arbitrary speed for scroll + + if(cam.target.y < 0) // Snapping to 0 if we go too far back + cam.target.y = 0; + + if(cam.target.y > textHeight - screenHeight + textTop) // Ensuring that the camera does not scroll past all text + cam.target.y = textHeight - screenHeight + textTop; + + // Computing the position of the scrollBar depending on the percentage of text covered. + scrollBar.y = Lerp(textTop, screenHeight - scrollBar.height, (cam.target.y - textTop) / (textHeight - screenHeight)); + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + BeginMode2D(cam); + + Font defaultFont = GetFontDefault(); + + // Going through all the read lines + for(int i = 0, t = textTop; i < lineCount; i++) + { + // Each time we go through and calculate the height of the text to move the cursor appropriately + Vector2 size = MeasureTextEx(defaultFont, lines[i], fontSize, 2); + DrawText(lines[i], 10, t, fontSize, RED); + + // Inserting extra space for real newlines, wrapped lines are rendered closer together + t += size.y + 10; + } + EndMode2D(); + + // Header displaying which file is being read currently + DrawRectangle(0, 0, screenWidth, textTop - 10, BEIGE); + DrawText(TextFormat("File: %s", fileName), 10, 10, fontSize, MAROON); + + DrawRectangleRec(scrollBar, MAROON); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + UnloadTextLines(lines, lineCount); + UnloadFileText(fileData); + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} diff --git a/examples/core/core_text_file_loading.png b/examples/core/core_text_file_loading.png new file mode 100644 index 0000000000000000000000000000000000000000..ac4101210a2229e059f49e71aa3496e3f072a361 GIT binary patch literal 23575 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 ti4F$dhn^ literal 0 HcmV?d00001 diff --git a/examples/core/resources/text_file.txt b/examples/core/resources/text_file.txt new file mode 100644 index 000000000..72b1a8bce --- /dev/null +++ b/examples/core/resources/text_file.txt @@ -0,0 +1,18 @@ +Starting of the Lorem ipsum dolor sit amet file +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque at interdum ex, et iaculis quam. Mauris consectetur, magna vel malesuada aliquam, mauris enim venenatis arcu, nec cursus orci ante a massa. Curabitur libero elit, cursus eu odio eget, suscipit rhoncus nibh. Nam justo elit, ullamcorper eget dolor et, ullamcorper tristique nulla. Nullam sagittis dolor in tristique tincidunt. Duis ac porttitor erat, a molestie sapien. Aliquam finibus in ipsum quis venenatis. +Mauris odio lorem, pharetra ut egestas quis, tristique eu mauris. Cras sed gravida velit. Suspendisse potenti. Suspendisse lobortis eleifend fermentum. Donec eu dolor est. Etiam ac felis eu ligula auctor feugiat eu quis diam. Sed eleifend id nibh porta viverra. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Morbi at tristique dui, nec pretium est. Mauris mollis massa quis massa aliquet efficitur. Phasellus posuere, elit id tempus consequat, massa ante scelerisque odio, finibus gravida elit tellus eget lectus. +Donec rutrum sagittis ligula a auctor. Aliquam aliquet tincidunt pulvinar. Aenean a porta ex. Aenean at sagittis nulla. Morbi congue luctus est nec gravida. In hac habitasse platea dictumst. Praesent commodo efficitur congue. Duis interdum enim in pharetra dapibus. Proin vestibulum finibus mauris vitae mollis. +Sed ultricies sed enim vel interdum. Nullam nec sagittis est, quis lobortis nunc. Donec auctor elementum velit vel pulvinar. Sed quis efficitur felis, at mollis elit. Integer id elit ante. Ut gravida ante vitae erat scelerisque scelerisque vel in massa. Praesent varius massa eu purus feugiat, non venenatis urna rhoncus. Pellentesque vehicula, tellus eu venenatis efficitur, libero eros lobortis justo, at ultricies lacus diam non libero. Sed metus nulla, consectetur in justo vitae, mollis maximus orci. Vestibulum dapibus ultrices leo, et facilisis odio molestie a. Phasellus facilisis vitae lorem quis viverra. Etiam imperdiet urna dolor, quis interdum ligula tristique id. Aliquam id dapibus enim. +Curabitur congue elit in magna tristique, sit amet porta quam viverra. Integer nec placerat libero. Praesent sem dolor, tristique eu augue non, ultricies mollis nibh. Fusce finibus, lorem sollicitudin eleifend gravida, eros quam tempus leo, ut iaculis libero ex vitae libero. Sed placerat fringilla accumsan. Nulla laoreet cursus justo nec elementum. Proin facilisis lobortis velit, a sollicitudin leo mollis eu. Aenean et leo est. +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque at interdum ex, et iaculis quam. Mauris consectetur, magna vel malesuada aliquam, mauris enim venenatis arcu, nec cursus orci ante a massa. Curabitur libero elit, cursus eu odio eget, suscipit rhoncus nibh. Nam justo elit, ullamcorper eget dolor et, ullamcorper tristique nulla. Nullam sagittis dolor in tristique tincidunt. Duis ac porttitor erat, a molestie sapien. Aliquam finibus in ipsum quis venenatis. +Mauris odio lorem, pharetra ut egestas quis, tristique eu mauris. Cras sed gravida velit. Suspendisse potenti. Suspendisse lobortis eleifend fermentum. Donec eu dolor est. Etiam ac felis eu ligula auctor feugiat eu quis diam. Sed eleifend id nibh porta viverra. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Morbi at tristique dui, nec pretium est. Mauris mollis massa quis massa aliquet efficitur. Phasellus posuere, elit id tempus consequat, massa ante scelerisque odio, finibus gravida elit tellus eget lectus. +Donec rutrum sagittis ligula a auctor. Aliquam aliquet tincidunt pulvinar. Aenean a porta ex. Aenean at sagittis nulla. Morbi congue luctus est nec gravida. In hac habitasse platea dictumst. Praesent commodo efficitur congue. Duis interdum enim in pharetra dapibus. Proin vestibulum finibus mauris vitae mollis. +Sed ultricies sed enim vel interdum. Nullam nec sagittis est, quis lobortis nunc. Donec auctor elementum velit vel pulvinar. Sed quis efficitur felis, at mollis elit. Integer id elit ante. Ut gravida ante vitae erat scelerisque scelerisque vel in massa. Praesent varius massa eu purus feugiat, non venenatis urna rhoncus. Pellentesque vehicula, tellus eu venenatis efficitur, libero eros lobortis justo, at ultricies lacus diam non libero. Sed metus nulla, consectetur in justo vitae, mollis maximus orci. Vestibulum dapibus ultrices leo, et facilisis odio molestie a. Phasellus facilisis vitae lorem quis viverra. Etiam imperdiet urna dolor, quis interdum ligula tristique id. Aliquam id dapibus enim. +wrapping text from the last available space wrapping text from the last available space wrapping text from the last available space +Curabitur congue elit in magna tristique, sit amet porta quam viverra. Integer nec placerat libero. Praesent sem dolor, tristique eu augue non, ultricies mollis nibh. Fusce finibus, lorem sollicitudin eleifend gravida, eros quam tempus leo, ut iaculis libero ex vitae libero. Sed placerat fringilla accumsan. Nulla laoreet cursus justo nec elementum. Proin facilisis lobortis velit, a sollicitudin leo mollis eu. Aenean et leo est. +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque at interdum ex, et iaculis quam. Mauris consectetur, magna vel malesuada aliquam, mauris enim venenatis arcu, nec cursus orci ante a massa. Curabitur libero elit, cursus eu odio eget, suscipit rhoncus nibh. Nam justo elit, ullamcorper eget dolor et, ullamcorper tristique nulla. Nullam sagittis dolor in tristique tincidunt. Duis ac porttitor erat, a molestie sapien. Aliquam finibus in ipsum quis venenatis. +Mauris odio lorem, pharetra ut egestas quis, tristique eu mauris. Cras sed gravida velit. Suspendisse potenti. Suspendisse lobortis eleifend fermentum. Donec eu dolor est. Etiam ac felis eu ligula auctor feugiat eu quis diam. Sed eleifend id nibh porta viverra. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Morbi at tristique dui, nec pretium est. Mauris mollis massa quis massa aliquet efficitur. Phasellus posuere, elit id tempus consequat, massa ante scelerisque odio, finibus gravida elit tellus eget lectus. +Donec rutrum sagittis ligula a auctor. Aliquam aliquet tincidunt pulvinar. Aenean a porta ex. Aenean at sagittis nulla. Morbi congue luctus est nec gravida. In hac habitasse platea dictumst. Praesent commodo efficitur congue. Duis interdum enim in pharetra dapibus. Proin vestibulum finibus mauris vitae mollis. +Sed ultricies sed enim vel interdum. Nullam nec sagittis est, quis lobortis nunc. Donec auctor elementum velit vel pulvinar. Sed quis efficitur felis, at mollis elit. Integer id elit ante. Ut gravida ante vitae erat scelerisque scelerisque vel in massa. Praesent varius massa eu purus feugiat, non venenatis urna rhoncus. Pellentesque vehicula, tellus eu venenatis efficitur, libero eros lobortis justo, at ultricies lacus diam non libero. Sed metus nulla, consectetur in justo vitae, mollis maximus orci. Vestibulum dapibus ultrices leo, et facilisis odio molestie a. Phasellus facilisis vitae lorem quis viverra. Etiam imperdiet urna dolor, quis interdum ligula tristique id. Aliquam id dapibus enim. +Curabitur congue elit in magna tristique, sit amet porta quam viverra. Integer nec placerat libero. Praesent sem dolor, tristique eu augue non, ultricies mollis nibh. Fusce finibus, lorem sollicitudin eleifend gravida, eros quam tempus leo, ut iaculis libero ex vitae libero. Sed placerat fringilla accumsan. Nulla laoreet cursus justo nec elementum. Proin facilisis lobortis velit, a sollicitudin leo mollis eu. Aenean et leo est. +Ending of the Lorem ipsum dolor sit amet file diff --git a/projects/VS2022/examples/core_text_file_loading.vcxproj b/projects/VS2022/examples/core_text_file_loading.vcxproj new file mode 100644 index 000000000..c2e25e042 --- /dev/null +++ b/projects/VS2022/examples/core_text_file_loading.vcxproj @@ -0,0 +1,569 @@ + + + + + Debug.DLL + ARM64 + + + Debug.DLL + Win32 + + + Debug.DLL + x64 + + + Debug + ARM64 + + + Debug + Win32 + + + Debug + x64 + + + Release.DLL + ARM64 + + + Release.DLL + Win32 + + + Release.DLL + x64 + + + Release + ARM64 + + + Release + Win32 + + + Release + x64 + + + + {6B1A933E-71B8-4C1F-9E79-02D98830E671} + Win32Proj + core_text_file_loading + 10.0 + core_text_file_loading + + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + $(SolutionDir)..\..\examples\core + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\core + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\core + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\core + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\core + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\core + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\core + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\core + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\core + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\core + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\core + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\core + WindowsLocalDebugger + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + /FS %(AdditionalOptions) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + /FS %(AdditionalOptions) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + Copy Debug DLL to output directory + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + Copy Debug DLL to output directory + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + Copy Debug DLL to output directory + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + + + Copy Release DLL to output directory + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + + + Copy Release DLL to output directory + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + + + Copy Release DLL to output directory + + + + + + + + + + + {e89d61ac-55de-4482-afd4-df7242ebc859} + + + + + + \ No newline at end of file diff --git a/projects/VS2022/raylib.sln b/projects/VS2022/raylib.sln index c4de89730..7a7eca297 100644 --- a/projects/VS2022/raylib.sln +++ b/projects/VS2022/raylib.sln @@ -391,6 +391,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_highdpi_testbed", "exa EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_screen_recording", "examples\core_screen_recording.vcxproj", "{9DE2FC01-A839-4F89-8319-9071D4C54821}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_text_file_loading", "examples\core_text_file_loading.vcxproj", "{6B1A933E-71B8-4C1F-9E79-02D98830E671}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug.DLL|ARM64 = Debug.DLL|ARM64 From 085f933b172f70c54afc401a6fb1401662a8a2ff Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 17 Oct 2025 17:17:54 +0200 Subject: [PATCH 15/30] Review example formating --- examples/core/core_text_file_loading.c | 56 +++++++++++++------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/examples/core/core_text_file_loading.c b/examples/core/core_text_file_loading.c index 0077551fd..4b334e811 100644 --- a/examples/core/core_text_file_loading.c +++ b/examples/core/core_text_file_loading.c @@ -16,7 +16,8 @@ ********************************************************************************************/ #include "raylib.h" -#include "raymath.h" // For Lerp + +#include "raymath.h" // Required for: Lerp() //------------------------------------------------------------------------------------ // Program main entry point @@ -38,35 +39,35 @@ int main(void) .zoom = 1 }; - // Loading file from resources/text_file.txt + // Loading text file from resources/text_file.txt const char *fileName = "resources/text_file.txt"; - char *fileData = LoadFileText(fileName); + char *text = LoadFileText(fileName); - // Loading all the lines + // Loading all the text lines int lineCount = 0; - char **lines = LoadTextLines(fileData, &lineCount); + char **lines = LoadTextLines(text, &lineCount); - // Just sylistic choise + // Stylistic choises int fontSize = 20; - int textTop = 25 + fontSize; // Top of the screen from where the text is rendered + int textTop = 25 + fontSize; // Top of the screen from where the text is rendered int wrapWidth = screenWidth - 20; // Wrap the lines as needed - for(int i = 0; i < lineCount; i++) + for (int i = 0; i < lineCount; i++) { int j = 0; int lastSpace = 0; // Keeping track of last valid space to insert '\n' int lastWrapStart = 0; // Keeping track of the start of this wrapped line. - while(lines[i][j] != '\0') + while (lines[i][j] != '\0') { - if(lines[i][j] == ' ') + if (lines[i][j] == ' ') { // Making a C Style string by adding a '\0' at the required location so that we can use the MeasureText function lines[i][j] = '\0'; // Checking if the text has crossed the wrapWidth, then going back and inserting a newline - if(MeasureText(lines[i] + lastWrapStart, fontSize) > wrapWidth) + if (MeasureText(lines[i] + lastWrapStart, fontSize) > wrapWidth) { lines[i][lastSpace] = '\n'; @@ -85,7 +86,7 @@ int main(void) // Calculating the total height so that we can show a scrollbar int textHeight = 0; - for(int i = 0; i < lineCount; i++) + for (int i = 0; i < lineCount; i++) { Vector2 size = MeasureTextEx(GetFontDefault(), lines[i], fontSize, 2); textHeight += size.y + 10; @@ -96,10 +97,9 @@ int main(void) .x = screenWidth - 5, .y = 0, .width = 5, - .height = screenHeight * 100 / (textHeight - screenHeight) // Scrollbar height is just a percentage + .height = screenHeight*100/(textHeight - screenHeight) // Scrollbar height is just a percentage }; - SetTargetFPS(60); //-------------------------------------------------------------------------------------- @@ -109,16 +109,17 @@ int main(void) // Update //---------------------------------------------------------------------------------- float scroll = GetMouseWheelMove(); - cam.target.y -= scroll * fontSize * 1.5; // Choosing an arbitrary speed for scroll + cam.target.y -= scroll*fontSize*1.5f; // Choosing an arbitrary speed for scroll - if(cam.target.y < 0) // Snapping to 0 if we go too far back - cam.target.y = 0; - - if(cam.target.y > textHeight - screenHeight + textTop) // Ensuring that the camera does not scroll past all text + if (cam.target.y < 0) cam.target.y = 0; // Snapping to 0 if we go too far back + + // Ensuring that the camera does not scroll past all text + if (cam.target.y > textHeight - screenHeight + textTop) cam.target.y = textHeight - screenHeight + textTop; - // Computing the position of the scrollBar depending on the percentage of text covered. - scrollBar.y = Lerp(textTop, screenHeight - scrollBar.height, (cam.target.y - textTop) / (textHeight - screenHeight)); + // Computing the position of the scrollBar depending on the percentage of text covered + scrollBar.y = Lerp(textTop, screenHeight - scrollBar.height, (cam.target.y - textTop)/(textHeight - screenHeight)); + //---------------------------------------------------------------------------------- // Draw //---------------------------------------------------------------------------------- @@ -127,17 +128,16 @@ int main(void) ClearBackground(RAYWHITE); BeginMode2D(cam); - - Font defaultFont = GetFontDefault(); - // Going through all the read lines - for(int i = 0, t = textTop; i < lineCount; i++) + for (int i = 0, t = textTop; i < lineCount; i++) { // Each time we go through and calculate the height of the text to move the cursor appropriately - Vector2 size = MeasureTextEx(defaultFont, lines[i], fontSize, 2); + Vector2 size = MeasureTextEx(GetFontDefault(), lines[i], fontSize, 2); + DrawText(lines[i], 10, t, fontSize, RED); - // Inserting extra space for real newlines, wrapped lines are rendered closer together + // Inserting extra space for real newlines, + // wrapped lines are rendered closer together t += size.y + 10; } EndMode2D(); @@ -155,7 +155,7 @@ int main(void) // De-Initialization //-------------------------------------------------------------------------------------- UnloadTextLines(lines, lineCount); - UnloadFileText(fileData); + UnloadFileText(text); CloseWindow(); // Close window and OpenGL context //-------------------------------------------------------------------------------------- From 9ef3448193c4d823975816472e4e9f198cea21c9 Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 18 Oct 2025 19:47:05 +0200 Subject: [PATCH 16/30] Reviewed UUIDs --- .../examples/core_text_file_loading.vcxproj | 2 +- projects/VS2022/raylib.sln | 26 ++++++++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/projects/VS2022/examples/core_text_file_loading.vcxproj b/projects/VS2022/examples/core_text_file_loading.vcxproj index c2e25e042..15324701d 100644 --- a/projects/VS2022/examples/core_text_file_loading.vcxproj +++ b/projects/VS2022/examples/core_text_file_loading.vcxproj @@ -51,7 +51,7 @@ - {6B1A933E-71B8-4C1F-9E79-02D98830E671} + {2F578155-D51F-4C03-AB7F-5C5122CA46CC} Win32Proj core_text_file_loading 10.0 diff --git a/projects/VS2022/raylib.sln b/projects/VS2022/raylib.sln index 7a7eca297..d0a886a4f 100644 --- a/projects/VS2022/raylib.sln +++ b/projects/VS2022/raylib.sln @@ -391,7 +391,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_highdpi_testbed", "exa EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_screen_recording", "examples\core_screen_recording.vcxproj", "{9DE2FC01-A839-4F89-8319-9071D4C54821}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_text_file_loading", "examples\core_text_file_loading.vcxproj", "{6B1A933E-71B8-4C1F-9E79-02D98830E671}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_text_file_loading", "examples\core_text_file_loading.vcxproj", "{2F578155-D51F-4C03-AB7F-5C5122CA46CC}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -4847,6 +4847,30 @@ Global {9DE2FC01-A839-4F89-8319-9071D4C54821}.Release|x64.Build.0 = Release|x64 {9DE2FC01-A839-4F89-8319-9071D4C54821}.Release|x86.ActiveCfg = Release|Win32 {9DE2FC01-A839-4F89-8319-9071D4C54821}.Release|x86.Build.0 = Release|Win32 + {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 + {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 + {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Debug|ARM64.Build.0 = Debug|ARM64 + {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Debug|x64.ActiveCfg = Debug|x64 + {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Debug|x64.Build.0 = Debug|x64 + {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Debug|x86.ActiveCfg = Debug|Win32 + {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Debug|x86.Build.0 = Debug|Win32 + {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 + {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 + {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Release|ARM64.ActiveCfg = Release|ARM64 + {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Release|ARM64.Build.0 = Release|ARM64 + {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Release|x64.ActiveCfg = Release|x64 + {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Release|x64.Build.0 = Release|x64 + {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Release|x86.ActiveCfg = Release|Win32 + {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From aeafce5db4a8b52371882f33dcd5f4ffacbaecac Mon Sep 17 00:00:00 2001 From: JordSant <77529699+JordSant@users.noreply.github.com> Date: Sat, 18 Oct 2025 19:50:52 +0200 Subject: [PATCH 17/30] [examples] Added: `shaders_mandelbrot_set` (#5282) * [examples] Added: `shaders_mandelbrot_set` * Simplified shader code and added comments * Comments starting with a capital letter, and some minor fixes to adhere to the convention --- .../shaders/glsl100/mandelbrot_set.fs | 61 ++ .../shaders/glsl120/mandelbrot_set.fs | 59 ++ .../shaders/glsl330/mandelbrot_set.fs | 58 ++ examples/shaders/shaders_mandelbrot_set.c | 224 +++++++ examples/shaders/shaders_mandelbrot_set.png | Bin 0 -> 71902 bytes .../examples/shaders_mandelbrot_set.vcxproj | 569 ++++++++++++++++++ projects/VS2022/raylib.sln | 2 + 7 files changed, 973 insertions(+) create mode 100644 examples/shaders/resources/shaders/glsl100/mandelbrot_set.fs create mode 100644 examples/shaders/resources/shaders/glsl120/mandelbrot_set.fs create mode 100644 examples/shaders/resources/shaders/glsl330/mandelbrot_set.fs create mode 100644 examples/shaders/shaders_mandelbrot_set.c create mode 100644 examples/shaders/shaders_mandelbrot_set.png create mode 100644 projects/VS2022/examples/shaders_mandelbrot_set.vcxproj diff --git a/examples/shaders/resources/shaders/glsl100/mandelbrot_set.fs b/examples/shaders/resources/shaders/glsl100/mandelbrot_set.fs new file mode 100644 index 000000000..aab8514e8 --- /dev/null +++ b/examples/shaders/resources/shaders/glsl100/mandelbrot_set.fs @@ -0,0 +1,61 @@ +#version 100 + +#define PI 3.1415926535897932384626433832795 + +precision highp float; + +// Input vertex attributes (from vertex shader) +varying vec2 fragTexCoord; +varying vec4 fragColor; + +uniform vec2 offset; // Offset of the scale +uniform float zoom; // Zoom of the scale +// NOTE: Maximum number of shader for-loop iterations depend on GPU, +// For example, on RasperryPi for this examply only supports up to 60 +uniform int maxIterations; // Max iterations per pixel + +const float max = 4.0; // We consider infinite as 4.0: if a point reaches a distance of 4.0 it will escape to infinity +const float max2 = max*max; // Square of max to avoid computing square root + +void main() +{ + // The pixel coordinates are scaled so they are on the mandelbrot scale + // NOTE: fragTexCoord already comes as normalized screen coordinates but offset must be normalized before scaling and zoom + vec2 c = vec2((fragTexCoord.x - 0.5)*2.5, (fragTexCoord.y - 0.5)*1.5)/zoom; + c.x += offset.x; + c.y += offset.y; + float a = 0.0; + float b = 0.0; + + // The Mandelbrot set is a two-dimensional set defined in the complex plane on which the iteration of the function + // Fc(z) = z^2 + c on the complex numbers c from the plane does not diverge to infinity starting at z = 0 + // Here: z = a + bi. Iterations: z -> z^2 + c = (a + bi)^2 + (c.x + c.yi) = (a^2 - b^2 + c.x) + (2ab + c.y)i + + int iter = 0; + while (iter < maxIterations) + { + float aa = a*a; + float bb = b*b; + if (aa + bb > max2) + break; + + float twoab = 2.0*a*b; + a = aa - bb + c.x; + b = twoab + c.y; + + ++iter; + } + + if (iter >= maxIterations) + { + gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); + } + else + { + float normR = float(iter - (iter/55)*55)/55.0; + float normG = float(iter - (iter/69)*69)/69.0; + float normB = float(iter - (iter/40)*40)/40.0; + + gl_FragColor = vec4(sin(normR*PI), sin(normG*PI), sin(normB*PI), 1.0); + } +} diff --git a/examples/shaders/resources/shaders/glsl120/mandelbrot_set.fs b/examples/shaders/resources/shaders/glsl120/mandelbrot_set.fs new file mode 100644 index 000000000..5da3ef437 --- /dev/null +++ b/examples/shaders/resources/shaders/glsl120/mandelbrot_set.fs @@ -0,0 +1,59 @@ +#version 120 + +#define PI 3.1415926535897932384626433832795 + +// Input vertex attributes (from vertex shader) +varying vec2 fragTexCoord; +varying vec4 fragColor; + +uniform vec2 offset; // Offset of the scale +uniform float zoom; // Zoom of the scale +// NOTE: Maximum number of shader for-loop iterations depend on GPU, +// For example, on RasperryPi for this examply only supports up to 60 +uniform int maxIterations; // Max iterations per pixel + +const float max = 4.0; // We consider infinite as 4.0: if a point reaches a distance of 4.0 it will escape to infinity +const float max2 = max*max; // Square of max to avoid computing square root + +void main() +{ + // The pixel coordinates are scaled so they are on the mandelbrot scale + // NOTE: fragTexCoord already comes as normalized screen coordinates but offset must be normalized before scaling and zoom + vec2 c = vec2((fragTexCoord.x - 0.5)*2.5, (fragTexCoord.y - 0.5)*1.5)/zoom; + c.x += offset.x; + c.y += offset.y; + float a = 0.0; + float b = 0.0; + + // The Mandelbrot set is a two-dimensional set defined in the complex plane on which the iteration of the function + // Fc(z) = z^2 + c on the complex numbers c from the plane does not diverge to infinity starting at z = 0 + // Here: z = a + bi. Iterations: z -> z^2 + c = (a + bi)^2 + (c.x + c.yi) = (a^2 - b^2 + c.x) + (2ab + c.y)i + + int iter = 0; + while (iter < maxIterations) + { + float aa = a*a; + float bb = b*b; + if (aa + bb > max2) + break; + + float twoab = 2.0*a*b; + a = aa - bb + c.x; + b = twoab + c.y; + + ++iter; + } + + if (iter >= maxIterations) + { + gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); + } + else + { + float normR = float(iter - (iter/55)*55)/55.0; + float normG = float(iter - (iter/69)*69)/69.0; + float normB = float(iter - (iter/40)*40)/40.0; + + gl_FragColor = vec4(sin(normR*PI), sin(normG*PI), sin(normB*PI), 1.0); + } +} diff --git a/examples/shaders/resources/shaders/glsl330/mandelbrot_set.fs b/examples/shaders/resources/shaders/glsl330/mandelbrot_set.fs new file mode 100644 index 000000000..bde74565f --- /dev/null +++ b/examples/shaders/resources/shaders/glsl330/mandelbrot_set.fs @@ -0,0 +1,58 @@ +#version 330 + +#define PI 3.1415926535897932384626433832795 + +// Input vertex attributes (from vertex shader) +in vec2 fragTexCoord; +in vec4 fragColor; + +// Output fragment color +out vec4 finalColor; + +uniform vec2 offset; // Offset of the scale +uniform float zoom; // Zoom of the scale +uniform int maxIterations; // Max iterations per pixel + +const float max = 4.0; // We consider infinite as 4.0: if a point reaches a distance of 4.0 it will escape to infinity +const float max2 = max*max; // Square of max to avoid computing square root + +void main() +{ + // The pixel coordinates are scaled so they are on the mandelbrot scale + // NOTE: fragTexCoord already comes as normalized screen coordinates but offset must be normalized before scaling and zoom + vec2 c = vec2((fragTexCoord.x - 0.5)*2.5, (fragTexCoord.y - 0.5)*1.5)/zoom; + c.x += offset.x; + c.y += offset.y; + float a = 0.0; + float b = 0.0; + + // The Mandelbrot set is a two-dimensional set defined in the complex plane on which the iteration of the function + // Fc(z) = z^2 + c on the complex numbers c from the plane does not diverge to infinity starting at z = 0 + // Here: z = a + bi. Iterations: z -> z^2 + c = (a + bi)^2 + (c.x + c.yi) = (a^2 - b^2 + c.x) + (2ab + c.y)i + + int iter = 0; + for (iter = 0; iter < maxIterations; ++iter) + { + float aa = a*a; + float bb = b*b; + if (aa + bb > max2) + break; + + float twoab = 2.0*a*b; + a = aa - bb + c.x; + b = twoab + c.y; + } + + if (iter >= maxIterations) + { + finalColor = vec4(0.0, 0.0, 0.0, 1.0); + } + else + { + float normR = float(iter%55)/55.0; + float normG = float(iter%69)/69.0; + float normB = float(iter%40)/40.0; + + finalColor = vec4(sin(normR*PI), sin(normG*PI), sin(normB*PI), 1.0); + } +} diff --git a/examples/shaders/shaders_mandelbrot_set.c b/examples/shaders/shaders_mandelbrot_set.c new file mode 100644 index 000000000..c8d0ce8d3 --- /dev/null +++ b/examples/shaders/shaders_mandelbrot_set.c @@ -0,0 +1,224 @@ +/******************************************************************************************* +* +* raylib [shaders] example - mandelbrot set +* +* Example complexity rating: [★★★☆] 3/4 +* +* NOTE: This example requires raylib OpenGL 3.3 or ES2 versions for shaders support, +* OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version +* +* NOTE: Shaders used in this example are #version 330 (OpenGL 3.3) +* +* Example originally created with raylib 5.6, last time updated with raylib 5.6 +* +* Example contributed by Jordi Santonja (@JordSant) +* Based on previous work by Josh Colclough (@joshcol9232) +* +* 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 Jordi Santonja (@JordSant) +* +********************************************************************************************/ + +#include "raylib.h" +#include + +#if defined(PLATFORM_DESKTOP) + #define GLSL_VERSION 330 +#else // PLATFORM_ANDROID, PLATFORM_WEB + #define GLSL_VERSION 100 +#endif + +// A few good interesting places +const float pointsOfInterest[6][3] = +{ + { -1.76826775f, -0.00422996283f, 28435.9238f }, + { 0.322004497f, -0.0357099883f, 56499.7266f }, + { -0.748880744f, -0.0562955774f, 9237.59082f }, + { -1.78385007f, -0.0156200649f, 14599.5283f }, + { -0.0985441282f, -0.924688697f, 26259.8535f }, + { 0.317785531f, -0.0322612226f, 29297.9258f }, +}; + +const int screenWidth = 800; +const int screenHeight = 450; +const float zoomSpeed = 1.01f; +const float offsetSpeedMul = 2.0f; + +const float startingZoom = 0.6f; +const float startingOffset[2] = { -0.5f, 0.0f }; + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + InitWindow(screenWidth, screenHeight, "raylib [shaders] example - mandelbrot set"); + + // Load mandelbrot set shader + // NOTE: Defining 0 (NULL) for vertex shader forces usage of internal default vertex shader + Shader shader = LoadShader(0, TextFormat("resources/shaders/glsl%i/mandelbrot_set.fs", GLSL_VERSION)); + + // Create a RenderTexture2D to be used for render to texture + RenderTexture2D target = LoadRenderTexture(GetScreenWidth(), GetScreenHeight()); + + // Offset and zoom to draw the mandelbrot set at. (centered on screen and default size) + float offset[2] = { startingOffset[0], startingOffset[1] }; + float zoom = startingZoom; + // Depending on the zoom the mximum number of iterations must be adapted to get more detail as we zzoom in + // The solution is not perfect, so a control has been added to increase/decrease the number of iterations with UP/DOWN keys + int maxIterations = 333; + float maxIterationsMultiplier = 166.5f; + + // Get variable (uniform) locations on the shader to connect with the program + // NOTE: If uniform variable could not be found in the shader, function returns -1 + int zoomLoc = GetShaderLocation(shader, "zoom"); + int offsetLoc = GetShaderLocation(shader, "offset"); + int maxIterationsLoc = GetShaderLocation(shader, "maxIterations"); + + // Upload the shader uniform values! + SetShaderValue(shader, zoomLoc, &zoom, SHADER_UNIFORM_FLOAT); + SetShaderValue(shader, offsetLoc, offset, SHADER_UNIFORM_VEC2); + SetShaderValue(shader, maxIterationsLoc, &maxIterations, SHADER_UNIFORM_INT); + + bool showControls = true; // Show controls + + 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 + //---------------------------------------------------------------------------------- + bool updateShader = false; + + // Press [1 - 6] to reset c to a point of interest + if (IsKeyPressed(KEY_ONE) || + IsKeyPressed(KEY_TWO) || + IsKeyPressed(KEY_THREE) || + IsKeyPressed(KEY_FOUR) || + IsKeyPressed(KEY_FIVE) || + IsKeyPressed(KEY_SIX)) + { + int interestIndex = 0; + if (IsKeyPressed(KEY_ONE)) interestIndex = 0; + else if (IsKeyPressed(KEY_TWO)) interestIndex = 1; + else if (IsKeyPressed(KEY_THREE)) interestIndex = 2; + else if (IsKeyPressed(KEY_FOUR)) interestIndex = 3; + else if (IsKeyPressed(KEY_FIVE)) interestIndex = 4; + else if (IsKeyPressed(KEY_SIX)) interestIndex = 5; + + offset[0] = pointsOfInterest[interestIndex][0]; + offset[1] = pointsOfInterest[interestIndex][1]; + zoom = pointsOfInterest[interestIndex][2]; + updateShader = true; + } + + // If "R" is pressed, reset zoom and offset + if (IsKeyPressed(KEY_R)) + { + offset[0] = startingOffset[0]; + offset[1] = startingOffset[1]; + zoom = startingZoom; + updateShader = true; + } + + if (IsKeyPressed(KEY_F1)) showControls = !showControls; // Toggle whether or not to show controls + + // Change number of max iterations with UP and DOWN keys + // WARNING: Increasing the number of max iterations greatly impacts performance + if (IsKeyPressed(KEY_UP)) + { + maxIterationsMultiplier *= 1.4f; + updateShader = true; + } + else if (IsKeyPressed(KEY_DOWN)) + { + maxIterationsMultiplier /= 1.4f; + updateShader = true; + } + + // If either left or right button is pressed, zoom in/out + if (IsMouseButtonDown(MOUSE_BUTTON_LEFT) || IsMouseButtonDown(MOUSE_BUTTON_RIGHT)) + { + // Change zoom. If Mouse left -> zoom in. Mouse right -> zoom out + zoom *= IsMouseButtonDown(MOUSE_BUTTON_LEFT)? zoomSpeed : (1.0f/zoomSpeed); + + const Vector2 mousePos = GetMousePosition(); + Vector2 offsetVelocity; + // Find the velocity at which to change the camera. Take the distance of the mouse + // From the center of the screen as the direction, and adjust magnitude based on the current zoom + offsetVelocity.x = (mousePos.x/(float)screenWidth - 0.5f)*offsetSpeedMul/zoom; + offsetVelocity.y = (mousePos.y/(float)screenHeight - 0.5f)*offsetSpeedMul/zoom; + + // Apply move velocity to camera + offset[0] += GetFrameTime()*offsetVelocity.x; + offset[1] += GetFrameTime()*offsetVelocity.y; + + updateShader = true; + } + + // In case a parameter has been changed, update the shader values + if (updateShader) + { + // As we zoom in, increase the number of max iterations to get more detail + // Aproximate formula, but it works-ish + maxIterations = (int)(sqrtf(2.0f*sqrtf(fabsf(1.0f - sqrtf(37.5f*zoom))))*maxIterationsMultiplier); + + // Update the shader uniform values! + SetShaderValue(shader, zoomLoc, &zoom, SHADER_UNIFORM_FLOAT); + SetShaderValue(shader, offsetLoc, offset, SHADER_UNIFORM_VEC2); + SetShaderValue(shader, maxIterationsLoc, &maxIterations, SHADER_UNIFORM_INT); + } + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + // Using a render texture to draw Mandelbrot set + BeginTextureMode(target); // Enable drawing to texture + ClearBackground(BLACK); // Clear the render texture + + // Draw a rectangle in shader mode to be used as shader canvas + // NOTE: Rectangle uses font white character texture coordinates, + // So shader can not be applied here directly because input vertexTexCoord + // Do not represent full screen coordinates (space where want to apply shader) + DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), BLACK); + EndTextureMode(); + + BeginDrawing(); + ClearBackground(BLACK); // Clear screen background + + // Draw the saved texture and rendered mandelbrot set with shader + // NOTE: We do not invert texture on Y, already considered inside shader + BeginShaderMode(shader); + // WARNING: If FLAG_WINDOW_HIGHDPI is enabled, HighDPI monitor scaling should be considered + // When rendering the RenderTexture2D to fit in the HighDPI scaled Window + DrawTextureEx(target.texture, (Vector2){ 0.0f, 0.0f }, 0.0f, 1.0f, WHITE); + EndShaderMode(); + + if (showControls) + { + DrawText("Press Mouse buttons right/left to zoom in/out and move", 10, 15, 10, RAYWHITE); + DrawText("Press F1 to toggle these controls", 10, 30, 10, RAYWHITE); + DrawText("Press [1 - 6] to change point of interest", 10, 45, 10, RAYWHITE); + DrawText("Press UP | DOWN to change number of iterations", 10, 60, 10, RAYWHITE); + DrawText("Press R to recenter the camera", 10, 75, 10, RAYWHITE); + } + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + UnloadShader(shader); // Unload shader + UnloadRenderTexture(target); // Unload render texture + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} diff --git a/examples/shaders/shaders_mandelbrot_set.png b/examples/shaders/shaders_mandelbrot_set.png new file mode 100644 index 0000000000000000000000000000000000000000..6d112931d3a3b23a6cae48f6319b495164280359 GIT binary patch literal 71902 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%0D+lk`?xeW~R>$ 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 + + + + Debug.DLL + ARM64 + + + Debug.DLL + Win32 + + + Debug.DLL + x64 + + + Debug + ARM64 + + + Debug + Win32 + + + Debug + x64 + + + Release.DLL + ARM64 + + + Release.DLL + Win32 + + + Release.DLL + x64 + + + Release + ARM64 + + + Release + Win32 + + + Release + x64 + + + + {1C829D1A-892C-451C-AF0B-AC65C85F5CC6} + Win32Proj + shaders_mandelbrot_set + 10.0 + shaders_mandelbrot_set + + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + $(SolutionDir)..\..\examples\shaders + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shaders + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shaders + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shaders + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shaders + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shaders + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shaders + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shaders + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shaders + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shaders + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shaders + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shaders + WindowsLocalDebugger + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + /FS %(AdditionalOptions) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + /FS %(AdditionalOptions) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + Copy Debug DLL to output directory + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + Copy Debug DLL to output directory + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + Copy Debug DLL to output directory + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + + + Copy Release DLL to output directory + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + + + Copy Release DLL to output directory + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + + + Copy Release DLL to output directory + + + + + + + + + + + {e89d61ac-55de-4482-afd4-df7242ebc859} + + + + + + \ No newline at end of file diff --git a/projects/VS2022/raylib.sln b/projects/VS2022/raylib.sln index d0a886a4f..ef46f8fe1 100644 --- a/projects/VS2022/raylib.sln +++ b/projects/VS2022/raylib.sln @@ -393,6 +393,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_screen_recording", "ex EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_text_file_loading", "examples\core_text_file_loading.vcxproj", "{2F578155-D51F-4C03-AB7F-5C5122CA46CC}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shaders_mandelbrot_set", "examples\shaders_mandelbrot_set.vcxproj", "{1C829D1A-892C-451C-AF0B-AC65C85F5CC6}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug.DLL|ARM64 = Debug.DLL|ARM64 From de8575b16e9042d2a0d7f291bb6e696098f7c54b Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 18 Oct 2025 19:54:35 +0200 Subject: [PATCH 18/30] Update raylib.sln --- projects/VS2022/raylib.sln | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/projects/VS2022/raylib.sln b/projects/VS2022/raylib.sln index ef46f8fe1..ec35ed5e5 100644 --- a/projects/VS2022/raylib.sln +++ b/projects/VS2022/raylib.sln @@ -4873,6 +4873,30 @@ Global {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Release|x64.Build.0 = Release|x64 {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Release|x86.ActiveCfg = Release|Win32 {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Release|x86.Build.0 = Release|Win32 + {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 + {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 + {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Debug|ARM64.Build.0 = Debug|ARM64 + {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Debug|x64.ActiveCfg = Debug|x64 + {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Debug|x64.Build.0 = Debug|x64 + {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Debug|x86.ActiveCfg = Debug|Win32 + {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Debug|x86.Build.0 = Debug|Win32 + {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 + {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 + {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Release|ARM64.ActiveCfg = Release|ARM64 + {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Release|ARM64.Build.0 = Release|ARM64 + {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Release|x64.ActiveCfg = Release|x64 + {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Release|x64.Build.0 = Release|x64 + {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Release|x86.ActiveCfg = Release|Win32 + {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -5070,6 +5094,8 @@ Global {EA4AD5A7-DB95-43C0-9A67-2D94146BCF91} = {278D8859-20B1-428F-8448-064F46E1F021} {1ACC8236-EF4E-44B0-BD0C-AB1D95D5890F} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} {9DE2FC01-A839-4F89-8319-9071D4C54821} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} + {2F578155-D51F-4C03-AB7F-5C5122CA46CC} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} + {1C829D1A-892C-451C-AF0B-AC65C85F5CC6} = {5317807F-61D4-4E0F-B6DC-2D9F12621ED9} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {E926C768-6307-4423-A1EC-57E95B1FAB29} From 7ae3eb5d3a25f865c2947bf4b6a0ed2dc101ab4d Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 20 Oct 2025 11:10:08 +0200 Subject: [PATCH 19/30] Create web_basic_window.png --- examples/others/web_basic_window.png | Bin 0 -> 10297 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 examples/others/web_basic_window.png diff --git a/examples/others/web_basic_window.png b/examples/others/web_basic_window.png new file mode 100644 index 0000000000000000000000000000000000000000..346184417a436343a769ba38a9ad9cfda0195181 GIT binary patch literal 10297 zcmeHNdr(tX8ovPwtb*t`tzf8RsjKd8D-SDCgd{K^I$MIZ(%@J~s0vjWd4vcALV~zH zhS9L&w2Oko9cN)Tx8$nWqC65rEUZd04virSi8M&a4JJUiggozF5Nvk_{@Xuq=FUmZ zx#xV}m*4r$_qzAu0eX`Es*S4v0Px?xFX12nc#;5s(CzDujchpD+=qP;*aws10f{`= zfOWjG^0JDGGYgLc2Qp8bD%ws@JVZLZWBbnS5fMq2crpNN{oDS8xI-lwZ-$;- zCibqQeXd9OpHWA%eJ<;O5AKLh6qcwbVhLwrK7KTENc4x&zr?!{hgpVB)uFY5-~G=; zi>Rb}_VD`!1n)rBQnSia_Wp(f|JtB;BY~_}RMfu8YwfR-0$DdANi^sBPf;)7uZt_6 z3V_N_9)6kngK_Xxco*R5H{Uomt|fUS2;TMm!fS%ol5QOz%nh9#PS{1vez-XCTLK}J z=H>f#)xy%N1cJwrbIszDs@o4Tmjs;MNuqgO0N(WjS)?5#8tcg|b;3mZ#r!DwxkZWo zi_pC&1;&_`MH6&=m)UZ0uz3AQZoU7a zM2EaFw(Cd>lD%z?d3*Wh2K^`&r}uiFU&3KfCBSBRoL%a(1dF(2t-o#F(yiV_T$Jcv zei++O+HX+p!$t-pb5m2>FZ-`q!r>OQ0xtbqzSbt6Z7GOal;{8k>#{(L#iu_c1~1{j zVy=KoU2>1K&No|^yC~887B35QYU-Qls9j4qbV*mhC93WMkGxL)lX`LMX~$Op8Wg|a z+EkMKqJ zpKnFg3|_c|VpjGtc|%)8`)x0@I~B$0t@UsIEJ;-~OEuaZWeA7qa#BS+UMFMFQXhI! zxnSQ%WoYm?BjS#|n)6u4L>}C;cQ8WuNI_G*0yOK=E#)c>GgiT%@?%@=T#uf=4>8a+ zrEYmGmWF7fX^rH%VqO;=0_`@?#79aYiW}C6Z9F?iGta+RWx3{VoK1%uKeNSVP^xL~ zxOd9>+PyyOllk=1_SZ_Y`@y8x!Q^Q`q0D|SrG%{+*(uFwFt?f3>_GWYoZv2V=p-LO zPIFA0ALQEDym@Eccc#)%-K7ZG+(dDM{D(2a=9}o*Utph^bPEb!vcbkV8-=02B1ChBx6snl50FuP*bUaZv?NrY`_or)yLGH!O=6sLq6RYbwsBp^@OVb7!oW$U zisZ%7!gdj=*00qYSeTI{_{u@N1?ul`>0m{S zyWYHg>-B$PJMZ>B_MmGf?zTN~R4GK^)j!Q7Rv=hg4q9#FbrUeBf#;lw-WpcSBh-(f zmQo3(7Ca5oQLK2QW;bLgU`vXn!(O(>b~VGQG&;*ApgCZ`MYkMr*;?3FC9QVnfTg)% z;L{Z9hF}qkCiuAA<~-|(Y=k)2V;JHt@ zJ&wK64pEI?BSRsv`u`|kV{LG={CFD##b>q2XDr$JLaQZ3(aNPW^l*Vn8c;h>Hnthl zN*UqsoNVMeWm{vwHG5S-n`XvhsDPveS|nxwfo+hqVHiVImP8)8a^9f7^3tFmut4%m zWa>(l0pTNhqbj0*3g*$FGDJV%Y*fXj=OH$R$P5p~m|~gr{jP@ltLJM&UVW%v2V7NX z?~)n)c?d#v%o#Y4#@dci4zv=qTPr>UGeZ2E4AMqbgv+M9k;Zev2-G%t zuT1J&rz;!VhLLJrQzN4WHli+Dbr-B-P)p2QH$>US5TRhN?BsT#)C5t+&23skwfrU~ zSoK&7Tb8p)X{?o!KC^z&p2jIe++T*Y+M`Vkx*4trVI$VDbUn4-0vlz~Ny0M4h7)Xl zt_jm*-`>8aU}Z zHz<6`kr(%mD2XQU_fr$b+OgZ*%h2g^WVI7ER;YB4{E2RpqdVtRS${IdAuos|vhOWI zs{5KWB2}l#r{|CQDT9nGa@$i1MkyWChEE~4 zn~sLQzQh-j-2?KG87-0Ui*@X-_OSKgT|hnlq=~stRR~qsW`o5YqL=}e#_T{aecw{Wxhm;pAY Date: Mon, 20 Oct 2025 11:13:45 +0200 Subject: [PATCH 20/30] REXM: Update examples collection --- examples/Makefile | 1 + examples/Makefile.Web | 5 +++++ examples/README.md | 10 ++++++---- examples/examples_list.txt | 2 ++ tools/rexm/examples_report.md | 4 +++- tools/rexm/examples_report_issues.md | 2 +- 6 files changed, 18 insertions(+), 6 deletions(-) diff --git a/examples/Makefile b/examples/Makefile index a9732679d..ef7cb5948 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -664,6 +664,7 @@ SHADERS = \ shaders/shaders_hybrid_rendering \ shaders/shaders_julia_set \ shaders/shaders_lightmap_rendering \ + shaders/shaders_mandelbrot_set \ shaders/shaders_mesh_instancing \ shaders/shaders_model_shader \ shaders/shaders_multi_sample2d \ diff --git a/examples/Makefile.Web b/examples/Makefile.Web index 88843af09..5d4f3ffab 100644 --- a/examples/Makefile.Web +++ b/examples/Makefile.Web @@ -664,6 +664,7 @@ SHADERS = \ shaders/shaders_hybrid_rendering \ shaders/shaders_julia_set \ shaders/shaders_lightmap_rendering \ + shaders/shaders_mandelbrot_set \ shaders/shaders_mesh_instancing \ shaders/shaders_model_shader \ shaders/shaders_multi_sample2d \ @@ -1307,6 +1308,10 @@ shaders/shaders_lightmap_rendering: shaders/shaders_lightmap_rendering.c --preload-file shaders/resources/cubicmap_atlas.png@resources/cubicmap_atlas.png \ --preload-file shaders/resources/spark_flame.png@resources/spark_flame.png +shaders/shaders_mandelbrot_set: shaders/shaders_mandelbrot_set.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \ + --preload-file shaders/resources/shaders/glsl100/mandelbrot_set.fs@resources/shaders/glsl100/mandelbrot_set.fs + shaders/shaders_mesh_instancing: shaders/shaders_mesh_instancing.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \ --preload-file shaders/resources/shaders/glsl100/lighting_instancing.vs@resources/shaders/glsl100/lighting_instancing.vs \ diff --git a/examples/README.md b/examples/README.md index b40966a5a..19d110344 100644 --- a/examples/README.md +++ b/examples/README.md @@ -17,9 +17,9 @@ You may find it easier to use than other toolchains, especially when it comes to - `zig build [module]` to compile all examples for a module (e.g. `zig build core`) - `zig build [example]` to compile _and run_ a particular example (e.g. `zig build core_basic_window`) -## EXAMPLES COLLECTION [TOTAL: 185] +## EXAMPLES COLLECTION [TOTAL: 187] -### category: core [44] +### category: core [45] Examples using raylib[core](../src/rcore.c) platform functionality like window creation, inputs, drawing modes and system functionality. @@ -69,6 +69,7 @@ Examples using raylib[core](../src/rcore.c) platform functionality like window c | [core_highdpi_testbed](core/core_highdpi_testbed.c) | core_highdpi_testbed | ⭐☆☆☆ | 5.6-dev | 5.6-dev | [Ramon Santamaria](https://github.com/raysan5) | | [core_screen_recording](core/core_screen_recording.c) | core_screen_recording | ⭐☆☆☆ | 5.6-dev | 5.6-dev | [Ramon Santamaria](https://github.com/raysan5) | | [core_clipboard_text](core/core_clipboard_text.c) | core_clipboard_text | ⭐☆☆☆ | 5.6-dev | 5.6-dev | [Robin](https://github.com/RobinsAviary) | +| [core_text_file_loading](core/core_text_file_loading.c) | core_text_file_loading | ⭐☆☆☆ | 5.5 | 5.6 | [Aanjishnu Bhattacharyya](https://github.com/NimComPoo-04) | ### category: shapes [31] @@ -104,7 +105,7 @@ Examples using raylib shapes drawing functionality, provided by raylib [shapes]( | [shapes_pie_chart](shapes/shapes_pie_chart.c) | shapes_pie_chart | ⭐⭐⭐☆ | 5.5 | 5.6 | [Gideon Serfontein](https://github.com/GideonSerf) | | [shapes_kaleidoscope](shapes/shapes_kaleidoscope.c) | shapes_kaleidoscope | ⭐⭐☆☆ | 5.5 | 5.6 | [Hugo ARNAL](https://github.com/hugoarnal) | | [shapes_clock_of_clocks](shapes/shapes_clock_of_clocks.c) | shapes_clock_of_clocks | ⭐⭐☆☆ | 5.5 | 5.6-dev | [JP Mortiboys](https://github.com/themushroompirates) | -| [shapes_mouse_trail](shapes/shapes_mouse_trail.c) | shapes_mouse_trail | ⭐☆☆☆ | 5.6 | 5.6-dev | [[Balamurugan R]](https://github.com/[Bala050814]) | +| [shapes_mouse_trail](shapes/shapes_mouse_trail.c) | shapes_mouse_trail | ⭐☆☆☆ | 5.6 | 5.6-dev | [Balamurugan R](https://github.com/Bala050814) | | [shapes_simple_particles](shapes/shapes_simple_particles.c) | shapes_simple_particles | ⭐⭐☆☆ | 5.6 | 5.6 | [Jordi Santonja](https://github.com/JordSant) | | [shapes_starfield_effect](shapes/shapes_starfield_effect.c) | shapes_starfield_effect | ⭐⭐☆☆ | 5.5 | 5.6-dev | [JP Mortiboys](https://github.com/themushroompirates) | @@ -195,7 +196,7 @@ Examples using raylib models functionality, including models loading/generation | [models_basic_voxel](models/models_basic_voxel.c) | models_basic_voxel | ⭐⭐☆☆ | 5.5 | 5.5 | [Tim Little](https://github.com/timlittle) | | [models_rotating_cube](models/models_rotating_cube.c) | models_rotating_cube | ⭐☆☆☆ | 5.6-dev | 5.6-dev | [Jopestpe](https://github.com/jopestpe) | -### category: shaders [30] +### category: shaders [31] Examples using raylib shaders functionality, including shaders loading, parameters configuration and drawing using them (model shaders and postprocessing shaders). This functionality is directly provided by raylib [rlgl](../src/rlgl.c) module. @@ -231,6 +232,7 @@ Examples using raylib shaders functionality, including shaders loading, paramete | [shaders_lightmap_rendering](shaders/shaders_lightmap_rendering.c) | shaders_lightmap_rendering | ⭐⭐⭐☆ | 4.5 | 4.5 | [Jussi Viitala](https://github.com/nullstare) | | [shaders_rounded_rectangle](shaders/shaders_rounded_rectangle.c) | shaders_rounded_rectangle | ⭐⭐⭐☆ | 5.5 | 5.5 | [Anstro Pleuton](https://github.com/anstropleuton) | | [shaders_depth_rendering](shaders/shaders_depth_rendering.c) | shaders_depth_rendering | ⭐⭐⭐☆ | 5.6-dev | 5.6-dev | [Luís Almeida](https://github.com/luis605) | +| [shaders_mandelbrot_set](shaders/shaders_mandelbrot_set.c) | shaders_mandelbrot_set | ⭐⭐⭐☆ | 5.6 | 5.6 | [Jordi Santonja](https://github.com/JordSant) | ### category: audio [8] diff --git a/examples/examples_list.txt b/examples/examples_list.txt index 9989f940f..2a1b9c0b7 100644 --- a/examples/examples_list.txt +++ b/examples/examples_list.txt @@ -192,3 +192,5 @@ others;easings_testbed;★★★☆;2.5;3.0;2019;2025;"Juan Miguel López";@flas others;raylib_opengl_interop;★★★★;3.8;4.0;2021;2025;"Stephan Soller";@arkanis others;embedded_files_loading;★★☆☆;3.0;3.5;2020;2025;"Kristian Holmgren";@defutura others;web_basic_window;★☆☆☆;5.6-dev;5.6-dev;2014;2025;"Ramon Santamaria";@raysan5 +core;core_text_file_loading;★☆☆☆;5.5;5.6;0;0;"Aanjishnu Bhattacharyya";@NimComPoo-04 +shaders;shaders_mandelbrot_set;★★★☆;5.6;5.6;2025;2025;"Jordi Santonja";@JordSant diff --git a/tools/rexm/examples_report.md b/tools/rexm/examples_report.md index e058e09a7..fcc1f8839 100644 --- a/tools/rexm/examples_report.md +++ b/tools/rexm/examples_report.md @@ -204,4 +204,6 @@ Example elements validated: | easings_testbed | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | raylib_opengl_interop | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | | embedded_files_loading | ✔ | ❌ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | -| web_basic_window | ✔ | ❌ | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| web_basic_window | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| core_text_file_loading | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| shaders_mandelbrot_set | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | diff --git a/tools/rexm/examples_report_issues.md b/tools/rexm/examples_report_issues.md index 3136c2709..5de76a17a 100644 --- a/tools/rexm/examples_report_issues.md +++ b/tools/rexm/examples_report_issues.md @@ -27,4 +27,4 @@ Example elements validated: | easings_testbed | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | raylib_opengl_interop | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | | embedded_files_loading | ✔ | ❌ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | -| web_basic_window | ✔ | ❌ | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| web_basic_window | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | From 8604085b6ea6e6fb2345742a8a45c43534333267 Mon Sep 17 00:00:00 2001 From: JordSant <77529699+JordSant@users.noreply.github.com> Date: Mon, 20 Oct 2025 15:18:15 +0200 Subject: [PATCH 21/30] [examples] Fixed `shaders_mandelbrot_set` for WebGL (#5286) --- .../shaders/glsl100/mandelbrot_set.fs | 35 ++++++++++--------- examples/shaders/shaders_mandelbrot_set.c | 5 +++ 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/examples/shaders/resources/shaders/glsl100/mandelbrot_set.fs b/examples/shaders/resources/shaders/glsl100/mandelbrot_set.fs index aab8514e8..fb6dee8b3 100644 --- a/examples/shaders/resources/shaders/glsl100/mandelbrot_set.fs +++ b/examples/shaders/resources/shaders/glsl100/mandelbrot_set.fs @@ -17,6 +17,9 @@ uniform int maxIterations; // Max iterations per pixel const float max = 4.0; // We consider infinite as 4.0: if a point reaches a distance of 4.0 it will escape to infinity const float max2 = max*max; // Square of max to avoid computing square root +// WebGL shaders for loop iteration limit only const +const int maxIterationsLimit = 20000; + void main() { // The pixel coordinates are scaled so they are on the mandelbrot scale @@ -31,31 +34,29 @@ void main() // Fc(z) = z^2 + c on the complex numbers c from the plane does not diverge to infinity starting at z = 0 // Here: z = a + bi. Iterations: z -> z^2 + c = (a + bi)^2 + (c.x + c.yi) = (a^2 - b^2 + c.x) + (2ab + c.y)i - int iter = 0; - while (iter < maxIterations) + for (int iter = 0; iter < maxIterationsLimit; ++iter) { float aa = a*a; float bb = b*b; + if (iter >= maxIterations) + { + gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); + return; + } if (aa + bb > max2) - break; + { + float normR = float(iter - (iter/55)*55)/55.0; + float normG = float(iter - (iter/69)*69)/69.0; + float normB = float(iter - (iter/40)*40)/40.0; + + gl_FragColor = vec4(sin(normR*PI), sin(normG*PI), sin(normB*PI), 1.0); + return; + } float twoab = 2.0*a*b; a = aa - bb + c.x; b = twoab + c.y; - - ++iter; } - if (iter >= maxIterations) - { - gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); - } - else - { - float normR = float(iter - (iter/55)*55)/55.0; - float normG = float(iter - (iter/69)*69)/69.0; - float normB = float(iter - (iter/40)*40)/40.0; - - gl_FragColor = vec4(sin(normR*PI), sin(normG*PI), sin(normB*PI), 1.0); - } + gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); } diff --git a/examples/shaders/shaders_mandelbrot_set.c b/examples/shaders/shaders_mandelbrot_set.c index c8d0ce8d3..a373c518a 100644 --- a/examples/shaders/shaders_mandelbrot_set.c +++ b/examples/shaders/shaders_mandelbrot_set.c @@ -70,8 +70,13 @@ int main(void) float zoom = startingZoom; // Depending on the zoom the mximum number of iterations must be adapted to get more detail as we zzoom in // The solution is not perfect, so a control has been added to increase/decrease the number of iterations with UP/DOWN keys +#if defined(PLATFORM_DESKTOP) int maxIterations = 333; float maxIterationsMultiplier = 166.5f; +#else + int maxIterations = 43; + float maxIterationsMultiplier = 22.0f; +#endif // Get variable (uniform) locations on the shader to connect with the program // NOTE: If uniform variable could not be found in the shader, function returns -1 From 74f2a899d945ec9014851ca75dbf1394687058f8 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 20 Oct 2025 19:09:37 +0200 Subject: [PATCH 22/30] Update rshapes.c --- src/rshapes.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/rshapes.c b/src/rshapes.c index 55f7d7fb9..2b5854f86 100644 --- a/src/rshapes.c +++ b/src/rshapes.c @@ -1432,6 +1432,7 @@ void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color) Rectangle shapeRect = GetShapesTextureRectangle(); rlBegin(RL_QUADS); + rlNormal3f(0.0f, 0.0f, 1.0f); rlColor4ub(color.r, color.g, color.b, color.a); rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height); @@ -1441,7 +1442,7 @@ void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color) rlVertex2f(v2.x, v2.y); rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(v2.x, v2.y); + rlVertex2f(v3.x, v3.y); rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height); rlVertex2f(v3.x, v3.y); From ec3cb7045f710b202eb9ea15f64ca8fa9c779136 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 20 Oct 2025 19:09:56 +0200 Subject: [PATCH 23/30] Update rcore.c --- src/rcore.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/rcore.c b/src/rcore.c index f87b68783..5dea97c22 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -679,12 +679,15 @@ void InitWindow(int width, int height, const char *title) // Initialize window data CORE.Window.screen.width = width; CORE.Window.screen.height = height; + CORE.Window.currentFbo.width = CORE.Window.screen.width; + CORE.Window.currentFbo.height = CORE.Window.screen.height; + CORE.Window.eventWaiting = false; - CORE.Window.screenScale = MatrixIdentity(); // No draw scaling required by default + CORE.Window.screenScale = MatrixIdentity(); // No draw scaling required by default if ((title != NULL) && (title[0] != 0)) CORE.Window.title = title; // Initialize global input state - memset(&CORE.Input, 0, sizeof(CORE.Input)); // Reset CORE.Input structure to 0 + memset(&CORE.Input, 0, sizeof(CORE.Input)); // Reset CORE.Input structure to 0 CORE.Input.Keyboard.exitKey = KEY_ESCAPE; CORE.Input.Mouse.scale = (Vector2){ 1.0f, 1.0f }; CORE.Input.Mouse.cursor = MOUSE_CURSOR_ARROW; @@ -696,7 +699,7 @@ void InitWindow(int width, int height, const char *title) if (result != 0) { - TRACELOG(LOG_WARNING, "SYSTEM: Failed to initialize Platform"); + TRACELOG(LOG_WARNING, "SYSTEM: Failed to initialize platform"); return; } //-------------------------------------------------------------- From 166420429106692f2f66d9bec39121ed9617f00f Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 20 Oct 2025 19:10:41 +0200 Subject: [PATCH 24/30] REVIEWED: New Win32 platform backend to accomodate `rlsw` Software Renderer --- src/platforms/rcore_desktop_win32.c | 695 +++++++++++++++++----------- src/rlgl.h | 33 +- 2 files changed, 432 insertions(+), 296 deletions(-) diff --git a/src/platforms/rcore_desktop_win32.c b/src/platforms/rcore_desktop_win32.c index 3ccd4d3bd..7ac6138bd 100644 --- a/src/platforms/rcore_desktop_win32.c +++ b/src/platforms/rcore_desktop_win32.c @@ -91,22 +91,24 @@ typedef struct { HWND hwnd; // Window handler HDC hdc; // Graphic context handler HGLRC glContext; // OpenGL context handler + // Software renderer variables HDC hdcmem; // Memory graphic context handler HBITMAP hbitmap; // GDI bitmap handler unsigned int *pixels; // Pointer to pixel data buffer (BGRA format) - LARGE_INTEGER timerFrequency; unsigned int appScreenWidth; unsigned int appScreenHeight; unsigned int desiredFlags; - bool cursorEnabled; + + LARGE_INTEGER timerFrequency; } PlatformData; // Define WGL function pointer types (no wglext.h needed) typedef HGLRC (WINAPI *PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC, HGLRC, const int *); typedef BOOL (WINAPI *PFNWGLCHOOSEPIXELFORMATARBPROC)(HDC, const int *, const FLOAT *, UINT, int *, UINT *); typedef BOOL (WINAPI *PFNWGLSWAPINTERVALEXTPROC)(int); +typedef const char *(WINAPI *PFNWGLGETEXTENSIONSSTRINGARBPROC)(HDC hdc); //---------------------------------------------------------------------------------- // Global Variables Definition @@ -119,6 +121,7 @@ static PlatformData platform = { 0 }; // Platform specific data static PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = NULL; static PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = NULL; static PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL; +static PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = NULL; // -------------------------------------------------------------------------------- // This part of the file contains pure functions that never access global state @@ -133,10 +136,10 @@ static PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL; // Defines and Macros //---------------------------------------------------------------------------------- #define A_TO_W_ALLOCA(outWstr, inAnsi) do { \ - size_t len = AToWLen(inAnsi); \ - outWstr = (WCHAR *)alloca(sizeof(WCHAR)*(len + 1)); \ - AToWCopy(outWstr, len, inAnsi); \ - outWstr[len] = 0; \ + size_t outLen = AToWLen(inAnsi); \ + outWstr = (WCHAR *)alloca(sizeof(WCHAR)*(outLen + 1)); \ + AToWCopy(inAnsi, outWstr, outLen); \ + outWstr[outLen] = 0; \ } while (0) #define STYLE_MASK_ALL 0xffffffff @@ -150,7 +153,7 @@ static PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL; #define WINDOW_STYLE_EX 0 -#define CLASS_NAME L"RaylibWindow" +#define CLASS_NAME L"raylibWindow" #define FLAG_MASK_OPTIONAL (FLAG_VSYNC_HINT) #define FLAG_MASK_REQUIRED ~(FLAG_MASK_OPTIONAL) @@ -196,93 +199,86 @@ static PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL; #define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 #define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 #define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 +#define WGL_CONTEXT_ES_PROFILE_BIT_EXT 0x00000004 +#define WGL_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004 //---------------------------------------------------------------------------------- // Types and Structures Definition //---------------------------------------------------------------------------------- -typedef enum { MIZED_NONE, MIZED_MIN, MIZED_MAX } Mized; - -typedef enum { - UPDATE_WINDOW_FIRST, - UPDATE_WINDOW_NORMAL, -} UpdateWindowKind; - -typedef enum { - SANITIZE_FLAGS_FIRST, - SANITIZE_FLAGS_NORMAL, -} SanitizeFlagsKind; - -typedef struct { - HMONITOR needle; - int index; - int matchIndex; - RECT rect; -} FindMonitorContext; +// Maximize-minimize request types +typedef enum { + MIZED_NONE, + MIZED_MIN, + MIZED_MAX +} Mized; +// Flag operations +// NOTE: Some ops need to be deferred typedef struct { DWORD set; DWORD clear; } FlagsOp; +// Monitor info type +typedef struct { + HMONITOR needle; + int index; + int matchIndex; + RECT rect; +} MonitorInfo; + //---------------------------------------------------------------------------------- // Module Internal Functions Declaration //---------------------------------------------------------------------------------- -static size_t AToWLen(const char *a) +// Get ASCII to WCHAR length +static size_t AToWLen(const char *ascii) { - int sizeNeeded = MultiByteToWideChar(CP_UTF8, 0, a, -1, NULL, 0); + int sizeNeeded = MultiByteToWideChar(CP_UTF8, 0, ascii, -1, NULL, 0); - if (sizeNeeded < 0) TRACELOG(LOG_ERROR, "Failed to calculate wide length, result=%d, error=%u", sizeNeeded, GetLastError()); + if (sizeNeeded < 0) TRACELOG(LOG_ERROR, "WIN32: Failed to calculate wide length [ERROR: %u]", GetLastError()); return sizeNeeded; } -static void AToWCopy(wchar_t *outPtr, size_t outLen, const char *a) + +// Copy ASCII to WCHAR string +static void AToWCopy(const char *ascii, wchar_t *outPtr, size_t outLen) { - int size = MultiByteToWideChar(CP_UTF8, 0, a, -1, outPtr, (int)outLen); - if (size != outLen) TRACELOG(LOG_WARNING, "WIN32: Convert %zu UTF-8 chars to WCHAR but converted %zu", outLen, size); + int size = MultiByteToWideChar(CP_UTF8, 0, ascii, -1, outPtr, (int)outLen); + if (size != outLen) TRACELOG(LOG_WARNING, "WIN32: Failed to convert %i UTF-8 chars to WCHAR, converted %i chars", outLen, size); } static bool DecoratedFromStyle(DWORD style) { if (style & STYLE_FLAGS_UNDECORATED_ON) { - if (style & STYLE_FLAGS_UNDECORATED_OFF) TRACELOG(LOG_ERROR, "FLAGS: Style 0x%x has both undecorated on/off flags", style); + if (style & STYLE_FLAGS_UNDECORATED_OFF) TRACELOG(LOG_ERROR, "WIN32: FLAGS: Style 0x%x has both undecorated on/off flags", style); return false; // Not decorated } DWORD masked = (style & STYLE_FLAGS_UNDECORATED_OFF); - if (STYLE_FLAGS_UNDECORATED_OFF != masked) TRACELOG(LOG_ERROR, "FLAGS: Style 0x%x is missing these flags 0x%x", masked, masked ^ STYLE_FLAGS_UNDECORATED_OFF); + if (STYLE_FLAGS_UNDECORATED_OFF != masked) TRACELOG(LOG_ERROR, "WIN32: FLAGS: Style 0x%x is missing flags 0x%x", masked, masked ^ STYLE_FLAGS_UNDECORATED_OFF); return true; // Decorated } -static Mized MizedFromStyle(DWORD style) -{ - // Minimized takes precedence over maximized - if (style & WS_MINIMIZE) return MIZED_MIN; - if (style & WS_MAXIMIZE) return MIZED_MAX; - return MIZED_NONE; -} - -static Mized MizedFromFlags(unsigned flags) -{ - // minimized takes precedence over maximized - if (FLAG_CHECK(flags, FLAG_WINDOW_MINIMIZED)) return MIZED_MIN; - if (flags & FLAG_WINDOW_MAXIMIZED) return MIZED_MAX; - return MIZED_NONE; -} - +// Get window style from required flags static DWORD MakeWindowStyle(unsigned flags) { - // we don't need this since we don't have any child windows, but I guess + // We don't need this since we don't have any child windows, but I guess // it improves efficiency, plus, windows adds this flag automatically anyway // so it keeps our flags in sync with the OS - DWORD style = WS_CLIPSIBLINGS ; + DWORD style = WS_CLIPSIBLINGS; style |= (flags & FLAG_WINDOW_HIDDEN)? 0 : WS_VISIBLE; style |= (flags & FLAG_WINDOW_RESIZABLE)? STYLE_FLAGS_RESIZABLE : 0; style |= (flags & FLAG_WINDOW_UNDECORATED)? STYLE_FLAGS_UNDECORATED_ON : STYLE_FLAGS_UNDECORATED_OFF; - switch (MizedFromFlags(flags)) + // Minimized takes precedence over maximized + int mized = MIZED_NONE; + if (FLAG_CHECK(flags, FLAG_WINDOW_MINIMIZED)) mized = MIZED_MIN; + if (flags & FLAG_WINDOW_MAXIMIZED) mized = MIZED_MAX; + + switch (mized) { case MIZED_NONE: break; case MIZED_MIN: style |= WS_MINIMIZE; break; @@ -293,15 +289,13 @@ static DWORD MakeWindowStyle(unsigned flags) return style; } -// Enforces that the actual window/platform state is in sync with raylib's flags +// Check flags state, enforces that the actual window/platform state is in sync with raylib's flags static void CheckFlags(const char *context, HWND hwnd, DWORD flags, DWORD expectedStyle, DWORD styleCheckMask) { - //TRACELOG(LOG_INFO, "Verifying Flags 0x%x Style 0x%x Mask 0x%x", flags, expectedStyle & styleCheckMask, styleCheckMask); - DWORD styleFromFlags = MakeWindowStyle(flags); if ((styleFromFlags & styleCheckMask) != (expectedStyle & styleCheckMask)) { - TRACELOG(LOG_ERROR, "%s: window flags (0x%x) produced style 0x%x which != expected 0x%x (diff=0x%x, mask=0x%x)", + TRACELOG(LOG_ERROR, "WIN32: FLAGS: %s: window flags (0x%x) produced style 0x%x which != expected 0x%x (diff=0x%x, mask=0x%x)", context, flags, styleFromFlags & styleCheckMask, expectedStyle & styleCheckMask, (styleFromFlags & styleCheckMask) ^ (expectedStyle & styleCheckMask), styleCheckMask); } @@ -310,7 +304,7 @@ static void CheckFlags(const char *context, HWND hwnd, DWORD flags, DWORD expect LONG actualStyle = (LONG)GetWindowLongPtrW(hwnd, GWL_STYLE); if ((actualStyle & styleCheckMask) != (expectedStyle & styleCheckMask)) { - TRACELOG(LOG_ERROR, "%s: expected style 0x%x but got 0x%x (diff=0x%x, mask=0x%x, lasterror=%lu)", + TRACELOG(LOG_ERROR, "WIN32: FLAGS: %s: expected style 0x%x but got 0x%x (diff=0x%x, mask=0x%x, lasterror=%lu)", context, expectedStyle & styleCheckMask, actualStyle & styleCheckMask, (expectedStyle & styleCheckMask) ^ (actualStyle & styleCheckMask), styleCheckMask, GetLastError()); @@ -320,7 +314,7 @@ static void CheckFlags(const char *context, HWND hwnd, DWORD flags, DWORD expect { bool isIconic = IsIconic(hwnd); bool styleMinimized = !!(WS_MINIMIZE & actualStyle); - if (isIconic != styleMinimized) TRACELOG(LOG_ERROR, "IsIconic(%d) != WS_MINIMIZED(%d)", isIconic, styleMinimized); + if (isIconic != styleMinimized) TRACELOG(LOG_ERROR, "WIN32: FLAGS: IsIconic(%d) != WS_MINIMIZED(%d)", isIconic, styleMinimized); } if (styleCheckMask & WS_MAXIMIZE) @@ -329,49 +323,32 @@ static void CheckFlags(const char *context, HWND hwnd, DWORD flags, DWORD expect placement.length = sizeof(placement); if (!GetWindowPlacement(hwnd, &placement)) { - TRACELOG(LOG_ERROR, "%s failed, error=%lu", "GetWindowPlacement", GetLastError()); + TRACELOG(LOG_ERROR, "WIN32: FLAGS: %s failed, error=%lu", "GetWindowPlacement", GetLastError()); } bool placementMaximized = (placement.showCmd == SW_SHOWMAXIMIZED); bool styleMaximized = WS_MAXIMIZE & actualStyle; if (placementMaximized != styleMaximized) { - TRACELOG(LOG_ERROR, "maximized state desync, placement maximized=%d (showCmd=%lu) style maximized=%d", + TRACELOG(LOG_ERROR, "WIN32: FLAGS: Maximized state desync, placement maximized=%d (showCmd=%lu) style maximized=%d", placementMaximized, placement.showCmd, styleMaximized); } } } -static SIZE PxFromPt2(float dpiScale, bool highdpiEnabled, int screenWidth, int screenHeight) -{ - // Get size in pixels from points - return (SIZE){ - highdpiEnabled? (int)((float)screenWidth*dpiScale) : screenWidth, - highdpiEnabled? (int)((float)screenHeight*dpiScale) : screenHeight, - }; -} - -static SIZE GetClientSize(HWND hwnd) -{ - RECT rect = { 0 }; - - if (GetClientRect(hwnd, &rect) == 0) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "GetClientRect", GetLastError()); - - return (SIZE){ rect.right, rect.bottom }; -} - +// Calculate window size (with borders, title-bar...) from desired client size (framebuffer size) static SIZE CalcWindowSize(UINT dpi, SIZE clientSize, DWORD style) { RECT rect = { 0, 0, clientSize.cx, clientSize.cy }; int result = AdjustWindowRectExForDpi(&rect, style, 0, WINDOW_STYLE_EX, dpi); - - if (result == 0) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "AdjustWindowRect", GetLastError()); + if (result == 0) TRACELOG(LOG_ERROR, "WIN32: Failed to adjust window rect [ERROR: %lu]", GetLastError()); return (SIZE){ rect.right - rect.left, rect.bottom - rect.top }; } -// returns true if the window size was updated, false otherwise -static bool UpdateWindowSize(UpdateWindowKind kind, HWND hwnd, int width, int height, unsigned flags) +// Update window size if required +// NOTE: Returns true if the window size was updated, false otherwise +static bool UpdateWindowSize(int mode, HWND hwnd, int width, int height, unsigned flags) { if (flags & FLAG_WINDOW_MINIMIZED) return false; @@ -386,10 +363,10 @@ static bool UpdateWindowSize(UpdateWindowKind kind, HWND hwnd, int width, int he MONITORINFO info = { 0 }; HMONITOR monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY); info.cbSize = sizeof(info); - if (!GetMonitorInfoW(monitor, &info)) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "GetMonitorInfo", GetLastError()); + if (!GetMonitorInfoW(monitor, &info)) TRACELOG(LOG_ERROR, "WIN32: Failed to get monitor info [ERROR: %lu]", GetLastError()); RECT windowRect = { 0 }; - if (!GetWindowRect(hwnd, &windowRect)) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "GetWindowRect", GetLastError()); + if (!GetWindowRect(hwnd, &windowRect)) TRACELOG(LOG_ERROR, "WIN32: Failed to get window rect [ERROR: %lu]", GetLastError()); if ((windowRect.left == info.rcMonitor.left) && (windowRect.top == info.rcMonitor.top) && @@ -402,33 +379,45 @@ static bool UpdateWindowSize(UpdateWindowKind kind, HWND hwnd, int width, int he info.rcMonitor.bottom - info.rcMonitor.top, SWP_NOOWNERZORDER)) { - TRACELOG(LOG_ERROR, "%s failed, error=%lu", "SetWindowPos", GetLastError()); + TRACELOG(LOG_ERROR, "WIN32: Failed to set window position [ERROR: %lu]", GetLastError()); } return true; } + // Get size in pixels from points, considering high-dpi UINT dpi = GetDpiForWindow(hwnd); float dpiScale = ((float)dpi)/96.0f; bool dpiScaling = flags & FLAG_WINDOW_HIGHDPI; - SIZE desired = PxFromPt2(dpiScale, dpiScaling, width, height); - SIZE actual = GetClientSize(hwnd); - if ((actual.cx == desired.cx) || (actual.cy == desired.cy)) return false; + SIZE desiredSize = { + .cx = dpiScaling? (int)((float)width*dpiScale) : width, + .cy = dpiScaling? (int)((float)height*dpiScale) : height + }; - TRACELOG(LOG_INFO, "Restoring client size from [%dx%d] to [%dx%d] (dpi:%lu dpiScaling:%d app:%ix%i)", - actual.cx, actual.cy, desired.cx, desired.cy, dpi, dpiScaling, width, height); + // Get client size (framebuffer inside the window) + RECT rect = { 0 }; + GetClientRect(hwnd, &rect); + SIZE clientSize = { rect.right, rect.bottom }; - SIZE windowSize = CalcWindowSize(dpi, desired, MakeWindowStyle(flags)); - POINT windowPos = (POINT){ 0, 0 }; + // If client size is alread desired size, no need to update + if ((clientSize.cx == desiredSize.cx) || (clientSize.cy == desiredSize.cy)) return false; + + TRACELOG(LOG_INFO, "WIN32: Restoring client size from [%dx%d] to [%dx%d] (dpi:%lu dpiScaling:%d app:%ix%i)", + clientSize.cx, clientSize.cy, desiredSize.cx, desiredSize.cy, dpi, dpiScaling, width, height); + + // Calculate window size from desired framebuffer size and window flags + SIZE windowSize = CalcWindowSize(dpi, desiredSize, MakeWindowStyle(flags)); + POINT windowPos = { 0 }; UINT swpFlags = SWP_NOZORDER | SWP_FRAMECHANGED; - if (kind == UPDATE_WINDOW_FIRST) + + if (mode == 0) // UPDATE_WINDOW_FIRST { HMONITOR monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY); - if (!monitor) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "MonitorFromWindow", GetLastError()); + if (!monitor) TRACELOG(LOG_ERROR, "WIN32: Failed to get monitor from window [ERROR: %lu]", GetLastError()); - MONITORINFO info; + MONITORINFO info = { 0 }; info.cbSize = sizeof(info); - if (!GetMonitorInfoW(monitor, &info)) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "GetMonitorInfo", GetLastError()); + if (!GetMonitorInfoW(monitor, &info)) TRACELOG(LOG_ERROR, "WIN32: Failed to get monitor info [ERROR: %lu]", GetLastError()); #define MAX(a,b) (((a)>(b))? (a):(b)) @@ -446,15 +435,10 @@ static bool UpdateWindowSize(UpdateWindowKind kind, HWND hwnd, int width, int he //AdjustWindowRectEx(&rc, WS_OVERLAPPEDWINDOW, FALSE, 0); //SetWindowPos(hwnd, NULL, windowPos.x, windowPos.y, rc.right - rc.left, rc.bottom - rc.top, SWP_NOMOVE | SWP_NOZORDER); - // Old code - //if (!SetWindowPos(hwnd, NULL, windowPos.x, windowPos.y, windowSize.cx, windowSize.cy, swpFlags)) - //{ - // TRACELOG(LOG_ERROR, "%s failed, error=%lu", "SetWindowPos", GetLastError()); - //} - return true; } +// Verify if we are running in Windows 10 version 1703 (Creators Update) static BOOL IsWindows10Version1703OrGreaterWin32(void) { HMODULE ntdll = LoadLibraryW(L"ntdll.dll"); @@ -463,7 +447,7 @@ static BOOL IsWindows10Version1703OrGreaterWin32(void) (DWORD (*)(RTL_OSVERSIONINFOEXW*, ULONG, ULONGLONG))GetProcAddress(ntdll, "RtlVerifyVersionInfo"); if (!Verify) { - TRACELOG(LOG_ERROR, "%s failed, error=%lu", "GetProcAddress 'RtlVerifyVersionInfo'", GetLastError()); + TRACELOG(LOG_ERROR, "WIN32: Failed to verify Windows version [ERROR: %lu]", GetLastError()); return 0; } @@ -472,6 +456,7 @@ static BOOL IsWindows10Version1703OrGreaterWin32(void) osvi.dwMajorVersion = 10; osvi.dwMinorVersion = 0; osvi.dwBuildNumber = 15063; // Build 15063 corresponds to Windows 10 version 1703 (Creators Update) + DWORDLONG cond = 0; VER_SET_CONDITION(cond, VER_MAJORVERSION, VER_GREATER_EQUAL); VER_SET_CONDITION(cond, VER_MINORVERSION, VER_GREATER_EQUAL); @@ -504,7 +489,8 @@ static void *WglGetProcAddress(const char *procname) return proc; } -static KeyboardKey KeyFromWparam(WPARAM wparam) +// Get key from wparam (mapping) +static KeyboardKey GetKeyFromWparam(WPARAM wparam) { switch (wparam) { @@ -687,6 +673,7 @@ static KeyboardKey KeyFromWparam(WPARAM wparam) } } +// Get cursor name static LPCWSTR GetCursorName(int cursor) { LPCWSTR name = (LPCWSTR)IDC_ARROW; @@ -710,37 +697,46 @@ static LPCWSTR GetCursorName(int cursor) return name; } -static BOOL CALLBACK CountMonitorsProc(HMONITOR handle, HDC _, LPRECT rect, LPARAM lparam) +// Count monitors process +// NOTE: Required by GetMonitorCount() +static BOOL CALLBACK CountMonitorsProc(HMONITOR handle, HDC hdc, LPRECT rect, LPARAM lparam) { int *count = (int *)lparam; *count += 1; + // Always return TRUE to continue the loop, otherwise, the caller // can't distinguish between stopping the loop and an error return TRUE; } -static BOOL CALLBACK FindMonitorProc(HMONITOR handle, HDC _, LPRECT rect, LPARAM lparam) +// Find monitor process +// NOTE: Required by GetCurrentMonitor() +static BOOL CALLBACK FindMonitorProc(HMONITOR handle, HDC hdc, LPRECT rect, LPARAM lparam) { - FindMonitorContext *c = (FindMonitorContext*)lparam; - if (handle == c->needle) + MonitorInfo *monitor = (MonitorInfo *)lparam; + + if (handle == monitor->needle) { - c->matchIndex = c->index; - c->rect = *rect; + monitor->matchIndex = monitor->index; + monitor->rect = *rect; } - c->index += 1; + monitor->index += 1; + // Always return TRUE to continue the loop, otherwise, the caller // can't distinguish between stopping the loop and an error return TRUE; } -static void GetStyleChangeFlagOps(DWORD coreWindowFlags, STYLESTRUCT *ss, FlagsOp *deferredFlags) +// Get style changed required operations flags +// NOTE: Required for deferred operations +static void GetStyleChangeFlagOps(DWORD coreWindowFlags, STYLESTRUCT *style, FlagsOp *deferredFlags) { // Check window resizable flag change bool resizable = (coreWindowFlags & FLAG_WINDOW_RESIZABLE); - bool resizableOld = ((ss->styleOld & STYLE_FLAGS_RESIZABLE) != 0); - bool resizableNew = ((ss->styleNew & STYLE_FLAGS_RESIZABLE) != 0); - if (resizable != resizableOld) TRACELOG(LOG_ERROR, "expected resizable %u but got %u", resizable, resizableOld); + bool resizableOld = ((style->styleOld & STYLE_FLAGS_RESIZABLE) != 0); + bool resizableNew = ((style->styleNew & STYLE_FLAGS_RESIZABLE) != 0); + if (resizable != resizableOld) TRACELOG(LOG_ERROR, "WIN32: Expected resizable %u but got %u", resizable, resizableOld); if (resizableOld != resizableNew) { if (resizableNew) deferredFlags->set |= FLAG_WINDOW_RESIZABLE; @@ -749,9 +745,9 @@ static void GetStyleChangeFlagOps(DWORD coreWindowFlags, STYLESTRUCT *ss, FlagsO // Check window decorated flag change bool decorated = (0 == (coreWindowFlags & FLAG_WINDOW_UNDECORATED)); - bool decoratedOld = DecoratedFromStyle(ss->styleOld); - bool decoratedNew = DecoratedFromStyle(ss->styleNew); - if (decorated != decoratedOld) TRACELOG(LOG_ERROR, "expected decorated %u but got %u", decorated, decoratedOld); + bool decoratedOld = DecoratedFromStyle(style->styleOld); + bool decoratedNew = DecoratedFromStyle(style->styleNew); + if (decorated != decoratedOld) TRACELOG(LOG_ERROR, "WIN32: Expected decorated %u but got %u", decorated, decoratedOld); if (decoratedOld != decoratedNew) { if (decoratedNew) deferredFlags->clear |= FLAG_WINDOW_UNDECORATED; @@ -760,9 +756,9 @@ static void GetStyleChangeFlagOps(DWORD coreWindowFlags, STYLESTRUCT *ss, FlagsO // Check window hidden flag change bool hidden = (coreWindowFlags & FLAG_WINDOW_HIDDEN); - bool hiddenOld = ((ss->styleOld & WS_VISIBLE) == 0); - bool hiddenNew = ((ss->styleNew & WS_VISIBLE) == 0); - if (hidden != hiddenOld) TRACELOG(LOG_ERROR, "expected hidden %u but got %u", hidden, hiddenOld); + bool hiddenOld = ((style->styleOld & WS_VISIBLE) == 0); + bool hiddenNew = ((style->styleNew & WS_VISIBLE) == 0); + if (hidden != hiddenOld) TRACELOG(LOG_ERROR, "WIN32: Expected hidden %u but got %u", hidden, hiddenOld); if (hiddenOld != hiddenNew) { if (hiddenNew) deferredFlags->set |= FLAG_WINDOW_HIDDEN; @@ -770,7 +766,9 @@ static void GetStyleChangeFlagOps(DWORD coreWindowFlags, STYLESTRUCT *ss, FlagsO } } -// Call when the window is rezised, returns true if the new window size should update the desired app size +// Adopt window resize +// NOTE: Call when the window is rezised, returns true +// if the new window size should update the desired app size static bool AdoptWindowResize(unsigned flags) { if (flags & FLAG_WINDOW_MINIMIZED) return false; @@ -805,9 +803,12 @@ static void HandleRawInput(LPARAM lparam); static void HandleWindowResize(HWND hwnd, int *width, int *height); static void UpdateWindowStyle(HWND hwnd, unsigned desiredFlags); -static unsigned SanitizeFlags(SanitizeFlagsKind kind, unsigned flags); +static unsigned SanitizeFlags(int mode, unsigned flags); static void UpdateFlags(HWND hwnd, unsigned desiredFlags, int width, int height); // Update window flags +// Check if OpenGL extension is available +static bool IsWglExtensionAvailable(HDC hdc, const char *extension); + //---------------------------------------------------------------------------------- // Module Functions Declaration //---------------------------------------------------------------------------------- @@ -826,20 +827,14 @@ bool WindowShouldClose(void) // Toggle fullscreen mode void ToggleFullscreen(void) { - TRACELOG(LOG_WARNING, "ToggleFullscreen not implemented"); + TRACELOG(LOG_WARNING, "WIN32: Toggle full screen functionality not implemented"); } // Toggle borderless windowed mode void ToggleBorderlessWindowed(void) { - if (CORE.Window.flags & FLAG_BORDERLESS_WINDOWED_MODE) - { - ClearWindowState(FLAG_BORDERLESS_WINDOWED_MODE); - } - else - { - SetWindowState(FLAG_BORDERLESS_WINDOWED_MODE); - } + if (CORE.Window.flags & FLAG_BORDERLESS_WINDOWED_MODE) ClearWindowState(FLAG_BORDERLESS_WINDOWED_MODE); + else SetWindowState(FLAG_BORDERLESS_WINDOWED_MODE); } // Set window state: maximized, if resizable @@ -858,40 +853,95 @@ void MinimizeWindow(void) void RestoreWindow(void) { if ((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) && - (CORE.Window.flags & FLAG_WINDOW_MINIMIZED) - ) { - ClearWindowState(FLAG_WINDOW_MINIMIZED); - } - else - { - ClearWindowState(FLAG_WINDOW_MINIMIZED|FLAG_WINDOW_MAXIMIZED); - } + (CORE.Window.flags & FLAG_WINDOW_MINIMIZED)) ClearWindowState(FLAG_WINDOW_MINIMIZED); + else ClearWindowState(FLAG_WINDOW_MINIMIZED | FLAG_WINDOW_MAXIMIZED); } // Set window configuration state using flags void SetWindowState(unsigned int flags) { - platform.desiredFlags = SanitizeFlags(SANITIZE_FLAGS_NORMAL, CORE.Window.flags | flags); + platform.desiredFlags = SanitizeFlags(1 /*SANITIZE_FLAGS_NORMAL*/, CORE.Window.flags | flags); UpdateFlags(platform.hwnd, platform.desiredFlags, platform.appScreenWidth, platform.appScreenHeight); } // Clear window configuration state flags void ClearWindowState(unsigned int flags) { - platform.desiredFlags = SanitizeFlags(SANITIZE_FLAGS_NORMAL, CORE.Window.flags & ~flags); + platform.desiredFlags = SanitizeFlags(1 /*SANITIZE_FLAGS_NORMAL*/, CORE.Window.flags & ~flags); UpdateFlags(platform.hwnd, platform.desiredFlags, platform.appScreenWidth, platform.appScreenHeight); } // Set icon for window void SetWindowIcon(Image image) { - TRACELOG(LOG_WARNING, "SetWindowIcon not implemented"); + if (!platform.hwnd || (image.data == NULL) || (image.width <= 0) || (image.height <= 0)) return; + + HDC hdc = GetDC(platform.hwnd); + + // Create 32-bit BGRA DIB for color + BITMAPV5HEADER bi = { 0 }; + ZeroMemory(&bi, sizeof(bi)); + bi.bV5Size = sizeof(bi); + bi.bV5Width = image.width; + bi.bV5Height = -image.height; // Negative = top-down bitmap + bi.bV5Planes = 1; + bi.bV5BitCount = 32; + bi.bV5Compression = BI_BITFIELDS; + bi.bV5RedMask = 0x00FF0000; + bi.bV5GreenMask = 0x0000FF00; + bi.bV5BlueMask = 0x000000FF; + bi.bV5AlphaMask = 0xFF000000; + + unsigned char *targetBits = NULL; + HBITMAP hColorBitmap = CreateDIBSection(hdc, (BITMAPINFO *)&bi, DIB_RGB_COLORS, (void **)&targetBits, NULL, 0); + if (!hColorBitmap) + { + ReleaseDC(platform.hwnd, hdc); + return; + } + + // Copy RGBA > BGRA (Win32 expects BGRA) + for (int y = 0; y < image.height; y++) + { + for (int x = 0; x < image.width; x++) + { + int i = (y*image.width + x)*4; + targetBits[i + 0] = ((unsigned char *)image.data)[i + 2]; // B + targetBits[i + 1] = ((unsigned char *)image.data)[i + 1]; // G + targetBits[i + 2] = ((unsigned char *)image.data)[i + 0]; // R + targetBits[i + 3] = ((unsigned char *)image.data)[i + 3]; // A + } + } + + // Create mask bitmap (1-bit, all opaque) + HBITMAP hMaskBitmap = CreateBitmap(image.width, image.height, 1, 1, NULL); + + // Build icon info + ICONINFO ii = { 0 }; + ZeroMemory(&ii, sizeof(ii)); + ii.fIcon = TRUE; + ii.hbmMask = hMaskBitmap; + ii.hbmColor = hColorBitmap; + + HICON hIcon = CreateIconIndirect(&ii); + + // Clean up GDI bitmaps (icon keeps copies internally) + DeleteObject(hColorBitmap); + DeleteObject(hMaskBitmap); + ReleaseDC(platform.hwnd, hdc); + + if (hIcon) + { + // Set both large and small icons + SendMessage(platform.hwnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon); + SendMessage(platform.hwnd, WM_SETICON, ICON_SMALL, (LPARAM)hIcon); + } } // Set icon for window void SetWindowIcons(Image *images, int count) { - TRACELOG(LOG_WARNING, "SetWindowIcons not implemented"); + // TODO. } void SetWindowTitle(const char *title) @@ -902,13 +952,24 @@ void SetWindowTitle(const char *title) A_TO_W_ALLOCA(titleWide, CORE.Window.title); int result = SetWindowTextW(platform.hwnd, titleWide); - if (result == 0) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "SetWindowText", GetLastError()); + if (result == 0) TRACELOG(LOG_WARNING, "WIN32: Failed to set window title [ERROR: %lu]", GetLastError()); } // Set window position on screen (windowed mode) void SetWindowPosition(int x, int y) { - TRACELOG(LOG_WARNING, "SetWindowPosition not implemented"); + if (platform.hwnd != NULL) + { + RECT rect = { 0 }; + if (GetWindowRect(platform.hwnd, &rect)) + { + int width = rect.right - rect.left; + int height = rect.bottom - rect.top; + + // Move the window to the new position (keeping size and z-order) + SetWindowPos(platform.hwnd, NULL, x, y, width, height, SWP_NOZORDER | SWP_NOACTIVATE); + } + } } // Set monitor for the current window @@ -975,15 +1036,15 @@ int GetCurrentMonitor(void) HMONITOR monitor = MonitorFromWindow(platform.hwnd, MONITOR_DEFAULTTOPRIMARY); if (!monitor) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "MonitorFromWindow", GetLastError()); - FindMonitorContext context; - context.needle = monitor; - context.index = 0; - context.matchIndex = -1; + MonitorInfo info = { 0 }; + info.needle = monitor; + info.index = 0; + info.matchIndex = -1; - int result = EnumDisplayMonitors(NULL, NULL, FindMonitorProc, (LPARAM)&context); + int result = EnumDisplayMonitors(NULL, NULL, FindMonitorProc, (LPARAM)&info); if (result == 0) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "EnumDisplayMonitors", GetLastError()); - return context.matchIndex; + return info.matchIndex; } // Get selected monitor position @@ -1091,10 +1152,9 @@ void HideCursor(void) // Enables cursor (unlock cursor) void EnableCursor(void) { - if (platform.cursorEnabled) TRACELOG(LOG_INFO, "EnableCursor: already enabled"); - else + if (CORE.Input.Mouse.cursorLocked) { - if (!ClipCursor(NULL)) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "ClipCursor", GetLastError()); + if (!ClipCursor(NULL)) TRACELOG(LOG_WARNING, "WIN32: Failed to clip cursor [ERROR: %lu]", GetLastError()); RAWINPUTDEVICE rid = { 0 }; rid.usUsagePage = 0x01; // HID_USAGE_PAGE_GENERIC @@ -1102,18 +1162,17 @@ void EnableCursor(void) rid.dwFlags = RIDEV_REMOVE; // Add to this window even in background rid.hwndTarget = NULL; int result = RegisterRawInputDevices(&rid, 1, sizeof(rid)); - if (result == 0) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "RegisterRawInputDevices", GetLastError()); + if (result == 0) TRACELOG(LOG_WARNING, "WIN32: Failed to register raw input devices [ERROR: %lu]", GetLastError()); ShowCursor(); - platform.cursorEnabled = true; - TRACELOG(LOG_INFO, "EnableCursor: enabled"); + CORE.Input.Mouse.cursorLocked = false; } } // Disables cursor (lock cursor) void DisableCursor(void) { - if (platform.cursorEnabled) + if (!CORE.Input.Mouse.cursorLocked) { RAWINPUTDEVICE rid = { 0 }; rid.usUsagePage = 0x01; // HID_USAGE_PAGE_GENERIC @@ -1121,33 +1180,31 @@ void DisableCursor(void) rid.dwFlags = RIDEV_INPUTSINK; // Add to this window even in background rid.hwndTarget = platform.hwnd; int result = RegisterRawInputDevices(&rid, 1, sizeof(rid)); - if (result == 0) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "RegisterRawInputDevices", GetLastError()); + if (result == 0) TRACELOG(LOG_WARNING, "WIN32: Failed to register raw input devices [ERROR: %lu]", GetLastError()); RECT clientRect = { 0 }; - if (!GetClientRect(platform.hwnd, &clientRect)) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "GetClientRect", GetLastError()); + if (!GetClientRect(platform.hwnd, &clientRect)) TRACELOG(LOG_WARNING, "WIN32: Failed to get client rectangle [ERROR: %lu]", GetLastError()); POINT topleft = { clientRect.left, clientRect.top }; - if (!ClientToScreen(platform.hwnd, &topleft)) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "ClientToScreen", GetLastError()); + if (!ClientToScreen(platform.hwnd, &topleft)) TRACELOG(LOG_WARNING, "WIN32: Failed to get client to screen size [ERROR: %lu]", GetLastError()); LONG width = clientRect.right - clientRect.left; LONG height = clientRect.bottom - clientRect.top; - TRACELOG(LOG_INFO, "ClipCursor client %d,%d %d,%d (topleft %d,%d)", + TRACELOG(LOG_INFO, "WIN32: Clip cursor client rect: [%d,%d %d,%d], top-left: (%d,%d)", clientRect.left, clientRect.top, clientRect.right, clientRect.bottom, topleft.x, topleft.y); LONG centerX = topleft.x + width/2; LONG centerY = topleft.y + height/2; RECT clipRect = { centerX, centerY, centerX + 1, centerY + 1 }; - if (!ClipCursor(&clipRect)) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "ClipCursor", GetLastError()); + if (!ClipCursor(&clipRect)) TRACELOG(LOG_WARNING, "WIN32: Failed to clip cursor [ERROR: %lu]", GetLastError()); CORE.Input.Mouse.previousPosition = (Vector2){ 0, 0 }; CORE.Input.Mouse.currentPosition = (Vector2){ 0, 0 }; HideCursor(); - platform.cursorEnabled = false; - TRACELOG(LOG_INFO, "DisableCursor: disabled"); + CORE.Input.Mouse.cursorLocked = true; } - else TRACELOG(LOG_INFO, "DisableCursor: already disabled"); } // Swap back buffer with front buffer (screen drawing) @@ -1163,8 +1220,8 @@ void SwapScreenBuffer(void) InvalidateRect(platform.hwnd, NULL, FALSE); UpdateWindow(platform.hwnd); #else - if (!SwapBuffers(platform.hdc)) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "SwapBuffers", GetLastError()); - if (!ValidateRect(platform.hwnd, NULL)) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "ValidateRect", GetLastError()); + if (!SwapBuffers(platform.hdc)) TRACELOG(LOG_ERROR, "WIN32: Failed to swap buffers [ERROR: %lu]", GetLastError()); + if (!ValidateRect(platform.hwnd, NULL)) TRACELOG(LOG_ERROR, "WIN32: Failed to validate screen rect [ERROR: %lu]", GetLastError()); #endif } @@ -1216,7 +1273,7 @@ void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float d // Set mouse position XY void SetMousePosition(int x, int y) { - if (platform.cursorEnabled) + if (!CORE.Input.Mouse.cursorLocked) { CORE.Input.Mouse.currentPosition = (Vector2){ (float)x, (float)y }; CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition; @@ -1230,7 +1287,7 @@ void SetMouseCursor(int cursor) { LPCWSTR cursorName = GetCursorName(cursor); HCURSOR hcursor = LoadCursorW(NULL, cursorName); - if (!hcursor) TRACELOG(LOG_ERROR, "LoadCursor %d (win32 %d) failed, error=%lu", cursor, (size_t)cursorName, GetLastError()); + if (!hcursor) TRACELOG(LOG_ERROR, "WIN32: Failed to load requested cursor [ERROR: %lu]", GetLastError()); SetCursor(hcursor); CORE.Input.Mouse.cursorHidden = false; @@ -1319,6 +1376,7 @@ HGLRC InitOpenGL(HWND hwnd, HDC hdc) wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB"); wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB"); wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT"); + wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB"); // Setup modern pixel format if extension is available if (wglChoosePixelFormatARB) @@ -1353,10 +1411,52 @@ HGLRC InitOpenGL(HWND hwnd, HDC hdc) HGLRC realContext = NULL; if (wglCreateContextAttribsARB) { + int glContextVersionMajor = 1; + int glContextVersionMinor = 1; + int glContextProfile = WGL_CONTEXT_CORE_PROFILE_BIT_ARB; + + if (rlGetVersion() == RL_OPENGL_21) // Request OpenGL 2.1 context + { + glContextVersionMajor = 2; + glContextVersionMinor = 1; + } + else if (rlGetVersion() == RL_OPENGL_33) // Request OpenGL 3.3 context + { + glContextVersionMajor = 3; + glContextVersionMinor = 3; + } + else if (rlGetVersion() == RL_OPENGL_43) // Request OpenGL 4.3 context + { + glContextVersionMajor = 4; + glContextVersionMinor = 3; + } + else if (rlGetVersion() == RL_OPENGL_ES_20) // Request OpenGL ES 2.0 context + { + if (IsWglExtensionAvailable(platform.hdc, "WGL_EXT_create_context_es_profile") || + IsWglExtensionAvailable(platform.hdc, "WGL_EXT_create_context_es2_profile")) + { + glContextVersionMajor = 2; + glContextVersionMinor = 0; + glContextProfile = WGL_CONTEXT_ES_PROFILE_BIT_EXT; + } + else TRACELOG(LOG_WARNING, "GL: OpenGL ES context not supported by GPU"); + } + else if (rlGetVersion() == RL_OPENGL_ES_30) // Request OpenGL ES 3.0 context + { + if (IsWglExtensionAvailable(platform.hdc, "WGL_EXT_create_context_es_profile") || + IsWglExtensionAvailable(platform.hdc, "WGL_EXT_create_context_es2_profile")) + { + glContextVersionMajor = 3; + glContextVersionMinor = 0; + glContextProfile = WGL_CONTEXT_ES_PROFILE_BIT_EXT; + } + else TRACELOG(LOG_WARNING, "GL: OpenGL ES context not supported by GPU"); + } + int contextAttribs[] = { - WGL_CONTEXT_MAJOR_VERSION_ARB, 3, - WGL_CONTEXT_MINOR_VERSION_ARB, 3, - WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, // WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, WGL_CONTEXT_ES_PROFILE_BIT_EXT (if supported) + WGL_CONTEXT_MAJOR_VERSION_ARB, glContextVersionMajor, + WGL_CONTEXT_MINOR_VERSION_ARB, glContextVersionMinor, + WGL_CONTEXT_PROFILE_MASK_ARB, glContextProfile, // WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, WGL_CONTEXT_ES_PROFILE_BIT_EXT (if supported) //WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB | WGL_CONTEXT_DEBUG_BIT_ARB [glDebugMessageCallback()] 0 // Terminator }; @@ -1387,9 +1487,11 @@ HGLRC InitOpenGL(HWND hwnd, HDC hdc) // Initialize platform: graphics, inputs and more int InitPlatform(void) { - platform.desiredFlags = SanitizeFlags(SANITIZE_FLAGS_FIRST, CORE.Window.flags); + int result = 0; + platform.appScreenWidth = CORE.Window.screen.width; platform.appScreenHeight = CORE.Window.screen.height; + platform.desiredFlags = SanitizeFlags(0 /*SANITIZE_FLAGS_FIRST*/, CORE.Window.flags); // NOTE: From this point CORE.Window.flags should always reflect the actual state of the window CORE.Window.flags = FLAG_WINDOW_HIDDEN | (platform.desiredFlags & FLAG_MASK_NO_UPDATE); @@ -1411,37 +1513,56 @@ int InitPlatform(void) } */ + HINSTANCE hInstance = GetModuleHandleW(0); + + // Define window class WNDCLASSEXW windowClass = { .cbSize = sizeof(WNDCLASSEXW), .style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC, .lpfnWndProc = WndProc, // Custom procedure assigned .cbWndExtra = sizeof(LONG_PTR), // extra space for the Tuple object ptr - .hInstance = GetModuleHandleW(0), + .hInstance = hInstance, .hCursor = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW), // TODO: Audit if we want to set this since we're implementing WM_SETCURSOR - .lpszClassName = CLASS_NAME //L"GLWindowClass"; + .lpszClassName = CLASS_NAME // Class name: L"raylibWindow" }; - // Register window class - if (RegisterClassExW(&windowClass) == 0) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "RegisterClass", GetLastError()); + // Load user-provided icon if available + // NOTE: raylib resource file defaults to GLFW_ICON id, so looking for same identifier + windowClass.hIcon = LoadImageW(hInstance, L"GLFW_ICON", IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED); + if (!windowClass.hIcon) windowClass.hIcon = LoadImageW(NULL, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED); -/* - // TODO: Remove or move this code that sets the display size; should maybe go somewhere in WndProc? + // Register window class + result = (int)RegisterClassExW(&windowClass); + if (result == 0) TRACELOG(LOG_ERROR, "WIN32: Failed to register window class [ERROR: %lu]", GetLastError()); + + // Get primary monitor info POINT primaryTopLeft = { 0 }; HMONITOR monitor = MonitorFromPoint(primaryTopLeft, MONITOR_DEFAULTTOPRIMARY); if (monitor != NULL) { - MONITORINFO info; + MONITORINFO info = { 0 }; info.cbSize = sizeof(info); - if (!GetMonitorInfoW(monitor, &info)) TRACELOG(LOG_WARNING, "%s failed, error: %u", "GetMonitorInfo", GetLastError()); + result = (int)GetMonitorInfoW(monitor, &info); + + if (result == 0) TRACELOG(LOG_WARNING, "WIN32: DISPLAY: Failed to get monitor info [ERROR: %u]", GetLastError()); else { CORE.Window.display.width = info.rcMonitor.right - info.rcMonitor.left; CORE.Window.display.height = info.rcMonitor.bottom - info.rcMonitor.top; } } - else TRACELOG(LOG_WARNING, "MonitorFromPoint, error: %s", GetLastError()); -*/ - + else TRACELOG(LOG_WARNING, "WIN32: DISPLAY: Failed to get primary monitor from point [ERROR: %u]", GetLastError()); + + // Adjust the window rectangle so the *client area* matches desired size + // NOTE: Window width/height includes borders and title-bar + DWORD style = WS_OVERLAPPEDWINDOW; + RECT rect = { 0, 0, platform.appScreenWidth, platform.appScreenHeight }; + AdjustWindowRect(&rect, style, FALSE); + //AdjustWindowRectEx(&rect, WS_OVERLAPPEDWINDOW, FALSE, WINDOW_STYLE_EX); + //AdjustWindowRectExForDpi(&rect, style, FALSE, WINDOW_STYLE_EX, dpi); + int windowWidth = rect.right - rect.left; + int windowHeight = rect.bottom - rect.top; + // Create window // NOTE: Title string needs to be converted to WCHAR WCHAR *titleWide = NULL; @@ -1454,13 +1575,13 @@ int InitPlatform(void) titleWide, MakeWindowStyle(CORE.Window.flags), // WS_OVERLAPPEDWINDOW | WS_VISIBLE CW_USEDEFAULT, CW_USEDEFAULT, - platform.appScreenWidth, platform.appScreenHeight, // TODO: Window size [width, height], needs to be updated? + windowWidth, windowHeight, // TODO: Window size [width, height], needs to be updated? NULL, NULL, GetModuleHandleW(NULL), NULL); if (!platform.hwnd) { - TRACELOG(LOG_ERROR, "%s failed, error=%lu", "CreateWindow", GetLastError()); + TRACELOG(LOG_ERROR, "WIN32: WINDOW: Failed to create window [ERROR: %lu]", GetLastError()); return -1; } @@ -1475,11 +1596,11 @@ int InitPlatform(void) // Initialize software framebuffer BITMAPINFO bmi = { 0 }; ZeroMemory(&bmi, sizeof(bmi)); - bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bmi.bmiHeader.biWidth = platform.appScreenWidth; - bmi.bmiHeader.biHeight = -(int)(platform.appScreenHeight); // Top-down bitmap - bmi.bmiHeader.biPlanes = 1; - bmi.bmiHeader.biBitCount = 32; // 32-bit BGRA + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = platform.appScreenWidth; + bmi.bmiHeader.biHeight = -(int)(platform.appScreenHeight); // Top-down bitmap + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 32; // 32-bit BGRA bmi.bmiHeader.biCompression = BI_RGB; platform.hdcmem = CreateCompatibleDC(platform.hdc); @@ -1504,6 +1625,8 @@ int InitPlatform(void) //UpdateWindowSize(UPDATE_WINDOW_FIRST, platform.hwnd, platform.appScreenWidth, platform.appScreenHeight, platform.desiredFlags); UpdateFlags(platform.hwnd, platform.desiredFlags, platform.appScreenWidth, platform.appScreenHeight); + CORE.Window.render.width = CORE.Window.screen.width; + CORE.Window.render.height = CORE.Window.screen.height; CORE.Window.currentFbo.width = CORE.Window.render.width; CORE.Window.currentFbo.height = CORE.Window.render.height; TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully"); @@ -1512,17 +1635,29 @@ int InitPlatform(void) TRACELOG(LOG_INFO, " > Render size: %i x %i", CORE.Window.render.width, CORE.Window.render.height); TRACELOG(LOG_INFO, " > Viewport offsets: %i, %i", CORE.Window.renderOffset.x, CORE.Window.renderOffset.y); - CORE.Storage.basePath = GetWorkingDirectory(); + if (rlGetVersion() == RL_OPENGL_11_SOFTWARE) // Using software renderer + { + TRACELOG(LOG_INFO, "GL: OpenGL device information:"); + TRACELOG(LOG_INFO, " > Vendor: %s", "raylib"); + TRACELOG(LOG_INFO, " > Renderer: %s", "rlsw - OpenGL 1.1 Software Renderer"); + TRACELOG(LOG_INFO, " > Version: %s", "1.0"); + TRACELOG(LOG_INFO, " > GLSL: %s", "NOT SUPPORTED"); + } + // Initialize timming system + //---------------------------------------------------------------------------- LARGE_INTEGER time = { 0 }; QueryPerformanceCounter(&time); QueryPerformanceFrequency(&platform.timerFrequency); CORE.Time.base = time.QuadPart; InitTimer(); - - // TODO: Enable cursor? -> Use default value as 0 - platform.cursorEnabled = true; + //---------------------------------------------------------------------------- + + // Initialize storage system + //---------------------------------------------------------------------------- + CORE.Storage.basePath = GetWorkingDirectory(); + //---------------------------------------------------------------------------- TRACELOG(LOG_INFO, "PLATFORM: DESKTOP: WIN32: Initialized successfully"); @@ -1535,7 +1670,7 @@ void ClosePlatform(void) if (platform.hwnd) { int result = DestroyWindow(platform.hwnd); - if (result == 0) TRACELOG(LOG_WARNING, "WIN32: Error on window destroy: %u", GetLastError()); + if (result == 0) TRACELOG(LOG_WARNING, "WIN32: WINDOW: Failed on window destroy [ERROR: %u]", GetLastError()); platform.hwnd = NULL; } } @@ -1617,7 +1752,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara { // TODO: Enforce min/max size } - else TRACELOG(LOG_WARNING, "WINDOW: Trying to resize a non-resizable window"); + else TRACELOG(LOG_WARNING, "WIN32: WINDOW: Trying to resize a non-resizable window"); result = TRUE; } break; @@ -1629,19 +1764,22 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara GetStyleChangeFlagOps(CORE.Window.flags, ss, deferredFlags); UINT dpi = GetDpiForWindow(hwnd); - SIZE clientSize = GetClientSize(hwnd); + // Get client size (framebuffer inside the window) + RECT rect = { 0 }; + GetClientRect(hwnd, &rect); + SIZE clientSize = { rect.right, rect.bottom }; SIZE oldSize = CalcWindowSize(dpi, clientSize, ss->styleOld); SIZE newSize = CalcWindowSize(dpi, clientSize, ss->styleNew); if (oldSize.cx != newSize.cx || oldSize.cy != newSize.cy) { - TRACELOG(LOG_INFO, "resize from style change: %dx%d to %dx%d", oldSize.cx, oldSize.cy, newSize.cx, newSize.cy); + TRACELOG(LOG_INFO, "WIN32: WINDOW: Resize from style change [%dx%d] to [%dx%d]", oldSize.cx, oldSize.cy, newSize.cx, newSize.cy); if (CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) { // looks like windows will automatically "unminimize" a window // if a style changes modifies it's size - TRACELOG(LOG_INFO, "style change modifed window size, removing maximized flag"); + TRACELOG(LOG_INFO, "WIN32: WINDOW: Style change modifed window size, removing maximized flag"); deferredFlags->clear |= FLAG_WINDOW_MAXIMIZED; } } @@ -1650,27 +1788,20 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara case WM_WINDOWPOSCHANGING: { WINDOWPOS *pos = (WINDOWPOS *)lparam; - if (pos->flags & SWP_SHOWWINDOW) - { - //if (pos->flags & SWP_HIDEWINDOW) abort(); - deferredFlags->clear |= FLAG_WINDOW_HIDDEN; - } - else if (pos->flags & SWP_HIDEWINDOW) - { - deferredFlags->set |= FLAG_WINDOW_HIDDEN; - } + if (pos->flags & SWP_SHOWWINDOW) deferredFlags->clear |= FLAG_WINDOW_HIDDEN; + else if (pos->flags & SWP_HIDEWINDOW) deferredFlags->set |= FLAG_WINDOW_HIDDEN; Mized mized = MIZED_NONE; bool isIconic = IsIconic(hwnd); bool styleMinimized = !!(WS_MINIMIZE & GetWindowLongPtrW(hwnd, GWL_STYLE)); - if (isIconic != styleMinimized) TRACELOG(LOG_WARNING, "IsIconic(%d) != WS_MINIMIZED(%d)", isIconic, styleMinimized); + if (isIconic != styleMinimized) TRACELOG(LOG_WARNING, "WIN32: IsIconic state different from WS_MINIMIZED state"); if (isIconic) mized = MIZED_MIN; else { WINDOWPLACEMENT placement; placement.length = sizeof(placement); - if (!GetWindowPlacement(hwnd, &placement)) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "GetWindowPlacement", GetLastError()); + if (!GetWindowPlacement(hwnd, &placement)) TRACELOG(LOG_ERROR, "WIN32: WINDOW: FAiled to get monitor placement [ERROR: %lu]", GetLastError()); if (placement.showCmd == SW_SHOWMAXIMIZED) mized = MIZED_MAX; } @@ -1683,19 +1814,13 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara HMONITOR monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY); MONITORINFO info; info.cbSize = sizeof(info); - if (!GetMonitorInfoW(monitor, &info)) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "GetMonitorInfo", GetLastError()); + if (!GetMonitorInfoW(monitor, &info)) TRACELOG(LOG_ERROR, "WIN32: MONITOR: Failed to get monitor info [ERROR: %lu]", GetLastError()); if ((pos->x == info.rcMonitor.left) && (pos->y == info.rcMonitor.top) && (pos->cx == (info.rcMonitor.right - info.rcMonitor.left)) && - (pos->cy == (info.rcMonitor.bottom - info.rcMonitor.top))) - { - deferredFlags->set |= FLAG_BORDERLESS_WINDOWED_MODE; - } - else - { - deferredFlags->clear |= FLAG_BORDERLESS_WINDOWED_MODE; - } + (pos->cy == (info.rcMonitor.bottom - info.rcMonitor.top))) deferredFlags->set |= FLAG_BORDERLESS_WINDOWED_MODE; + else deferredFlags->clear |= FLAG_BORDERLESS_WINDOWED_MODE; } break; case MIZED_MIN: @@ -1739,7 +1864,11 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara float dpiScale = ((float)newDpi)/96.0f; bool dpiScaling = CORE.Window.flags & FLAG_WINDOW_HIGHDPI; - SIZE desired = PxFromPt2(dpiScale, dpiScaling, platform.appScreenWidth, platform.appScreenHeight); + // Get size in pixels from points + SIZE desired = { + .cx = dpiScaling? (int)((float)platform.appScreenWidth*dpiScale) : platform.appScreenWidth, + .cy = dpiScaling? (int)((float)platform.appScreenHeight*dpiScale) : platform.appScreenHeight + }; inoutSize->cx = desired.cx; inoutSize->cy = desired.cy; @@ -1747,18 +1876,14 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara } break; case WM_DPICHANGED: { - RECT *suggestedRect = (RECT*)lparam; + RECT *suggestedRect = (RECT *)lparam; + // Never set the window size to anything other than the suggested rect here // Doing so can cause a window to stutter between monitors when transitioning between them - if (!SetWindowPos(hwnd, NULL, - suggestedRect->left, - suggestedRect->top, - suggestedRect->right - suggestedRect->left, - suggestedRect->bottom - suggestedRect->top, - SWP_NOZORDER | SWP_NOACTIVATE)) - { - TRACELOG(LOG_ERROR, "%s failed, error=%lu", "SetWindowPos", GetLastError()); - } + int result = (int)SetWindowPos(hwnd, NULL, suggestedRect->left, suggestedRect->top, + suggestedRect->right - suggestedRect->left, suggestedRect->bottom - suggestedRect->top, SWP_NOZORDER | SWP_NOACTIVATE); + if (result == 0) TRACELOG(LOG_ERROR, "Failed to set window position [ERROR: %lu]", GetLastError()); + } break; case WM_SETCURSOR: { @@ -1789,7 +1914,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara } break; case WM_MOUSEMOVE: { - if (platform.cursorEnabled) + if (!CORE.Input.Mouse.cursorLocked) { CORE.Input.Mouse.currentPosition.x = (float)GET_X_LPARAM(lparam); CORE.Input.Mouse.currentPosition.y = (float)GET_Y_LPARAM(lparam); @@ -1833,32 +1958,23 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara } //------------------------------------------------------------------------------------ - // Sanity check - if (platform.hwnd == hwnd) - { - CheckFlags("After WndProc", hwnd, CORE.Window.flags, MakeWindowStyle(CORE.Window.flags), mask); - } + // Sanity check for flags + if (platform.hwnd == hwnd) CheckFlags("After WndProc", hwnd, CORE.Window.flags, MakeWindowStyle(CORE.Window.flags), mask); // Operations to execute after the above check - if (flagsOp.set & flagsOp.clear) - { - TRACELOG(LOG_ERROR, "the flags 0x%x were both set and cleared!", flagsOp.set & flagsOp.clear); - } + if (flagsOp.set & flagsOp.clear) TRACELOG(LOG_WARNING, "WIN32: FLAGS: Flags 0x%x were both set and cleared", flagsOp.set & flagsOp.clear); DWORD save = CORE.Window.flags; CORE.Window.flags |= flagsOp.set; CORE.Window.flags &= ~flagsOp.clear; - if (save != CORE.Window.flags) - { - TRACELOG(LOG_DEBUG, "DeferredFlags: 0x%x > 0x%x (diff 0x%x)", save, CORE.Window.flags, save ^ CORE.Window.flags); - } + if (save != CORE.Window.flags) TRACELOG(LOG_DEBUG, "WIN32: FLAGS: Current deferred flags: 0x%x > 0x%x (diff 0x%x)", save, CORE.Window.flags, save ^ CORE.Window.flags); return result; } static void HandleKey(WPARAM wparam, LPARAM lparam, char state) { - KeyboardKey key = KeyFromWparam(wparam); + KeyboardKey key = GetKeyFromWparam(wparam); // TODO: Use scancode? //BYTE scancode = lparam >> 16; @@ -1888,9 +2004,9 @@ static void HandleRawInput(LPARAM lparam) UINT inputSize = sizeof(input); UINT size = GetRawInputData((HRAWINPUT)lparam, RID_INPUT, &input, &inputSize, sizeof(RAWINPUTHEADER)); - if (size == (UINT)-1) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "GetRawInputData", GetLastError()); + if (size == (UINT)-1) TRACELOG(LOG_ERROR, "WIN32: Failed to get raw input data [ERROR: %lu]", GetLastError()); - if (input.header.dwType != RIM_TYPEMOUSE) TRACELOG(LOG_ERROR, "Unexpected WM_INPUT type %lu", input.header.dwType); + if (input.header.dwType != RIM_TYPEMOUSE) TRACELOG(LOG_ERROR, "WIN32: Unexpected WM_INPUT type %lu", input.header.dwType); if (input.data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) TRACELOG(LOG_ERROR, "TODO: handle absolute mouse inputs!"); @@ -1908,12 +2024,14 @@ static void HandleWindowResize(HWND hwnd, int *width, int *height) { if (CORE.Window.flags & FLAG_WINDOW_MINIMIZED) return; - SIZE clientSize = GetClientSize(hwnd); + // Get client size (framebuffer inside the window) + RECT rect = { 0 }; + GetClientRect(hwnd, &rect); + SIZE clientSize = { rect.right, rect.bottom }; - //TRACELOG(LOG_DEBUG, "WINDOW: New widow client size: [%lux%lu]", clientSize.cx, clientSize.cy); - - //CORE.Window.currentFbo.width = clientSize.cx; - //CORE.Window.currentFbo.height = clientSize.cy; + // TODO: Update framebuffer on resize + CORE.Window.currentFbo.width = (int)clientSize.cx; + CORE.Window.currentFbo.height = (int)clientSize.cy; //glViewport(0, 0, clientSize.cx, clientSize.cy); //SetupFramebuffer(0, 0); @@ -1928,7 +2046,7 @@ static void HandleWindowResize(HWND hwnd, int *width, int *height) if (AdoptWindowResize(CORE.Window.flags)) { - TRACELOG(LOG_DEBUG, "WINDOW: Updating app size to %ix%i from window resize", screenWidth, screenHeight); + TRACELOG(LOG_DEBUG, "WIN32: WINDOW: Updating app size to [%ix%i] from window resize", screenWidth, screenHeight); *width = screenWidth; *height = screenHeight; } @@ -1951,15 +2069,21 @@ static void UpdateWindowStyle(HWND hwnd, unsigned desiredFlags) DWORD previous = STYLE_MASK_WRITABLE & SetWindowLongPtrW(hwnd, GWL_STYLE, desired); if (previous != current) { - TRACELOG(LOG_ERROR, "SetWindowLong returned writable flags 0x%x but expected 0x%x (diff=0x%x, error=%lu)", + TRACELOG(LOG_ERROR, "WIN32: WINDOW: SetWindowLongPtr() returned writable flags 0x%x but expected 0x%x (diff=0x%x, error=%lu)", previous, current, previous ^ current, GetLastError()); } CheckFlags("UpdateWindowStyle", hwnd, desiredFlags, desired, STYLE_MASK_WRITABLE); } - Mized currentMized = MizedFromStyle(MakeWindowStyle(CORE.Window.flags)); - Mized desiredMized = MizedFromStyle(MakeWindowStyle(desiredFlags)); + // Minimized takes precedence over maximized + Mized currentMized = MIZED_NONE; + Mized desiredMized = MIZED_NONE; + if (CORE.Window.flags & WS_MINIMIZE) currentMized = MIZED_MIN; + else if (CORE.Window.flags & WS_MAXIMIZE) currentMized = MIZED_MAX; + if (desiredFlags & WS_MINIMIZE) currentMized = MIZED_MIN; + else if (desiredFlags & WS_MAXIMIZE) currentMized = MIZED_MAX; + if (currentMized != desiredMized) { switch (desiredMized) @@ -1972,24 +2096,21 @@ static void UpdateWindowStyle(HWND hwnd, unsigned desiredFlags) } // Sanitize flags -static unsigned SanitizeFlags(SanitizeFlagsKind kind, unsigned flags) +static unsigned SanitizeFlags(int mode, unsigned flags) { if ((flags & FLAG_WINDOW_MAXIMIZED) && (flags & FLAG_BORDERLESS_WINDOWED_MODE)) { - TRACELOG(LOG_INFO, "borderless windows mode is overriding maximized"); + TRACELOG(LOG_WARNING, "WIN32: WINDOW: Borderless windows mode overriding maximized window flag"); flags &= ~FLAG_WINDOW_MAXIMIZED; } - switch (kind) + if (mode == 1) { - case SANITIZE_FLAGS_FIRST: break; - case SANITIZE_FLAGS_NORMAL: - if ((flags & FLAG_MSAA_4X_HINT) && (!(CORE.Window.flags & FLAG_MSAA_4X_HINT))) - { - TRACELOG(LOG_WARNING, "WINDOW: MSAA can only be configured before window initialization"); - flags &= ~FLAG_MSAA_4X_HINT; - } - break; + if ((flags & FLAG_MSAA_4X_HINT) && (!(CORE.Window.flags & FLAG_MSAA_4X_HINT))) + { + TRACELOG(LOG_WARNING, "WIN32: WINDOW: MSAA can only be configured before window initialization"); + flags &= ~FLAG_MSAA_4X_HINT; + } } return flags; @@ -2018,16 +2139,15 @@ static void UpdateFlags(HWND hwnd, unsigned desiredFlags, int width, int height) CORE.Window.flags |= (desiredFlags & FLAG_MASK_NO_UPDATE); int vsync = (CORE.Window.flags & FLAG_VSYNC_HINT)? 1 : 0; - PFNWGLSWAPINTERVALEXTPROC wglSwapInterval = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT"); - if (wglSwapInterval) + if (wglSwapIntervalEXT) { - (*wglSwapInterval)(vsync); + (*wglSwapIntervalEXT)(vsync); if (vsync) CORE.Window.flags |= FLAG_VSYNC_HINT; else CORE.Window.flags &= ~FLAG_VSYNC_HINT; } // TODO: Review all this code... - DWORD previousStyle; + DWORD previousStyle = 0; for (unsigned attempt = 1; ; attempt++) { CheckFlags("UpdateFlags", hwnd, CORE.Window.flags, MakeWindowStyle(CORE.Window.flags), STYLE_MASK_ALL); @@ -2035,15 +2155,14 @@ static void UpdateFlags(HWND hwnd, unsigned desiredFlags, int width, int height) bool windowSizeUpdated = false; if (MakeWindowStyle(CORE.Window.flags) == MakeWindowStyle(desiredFlags)) { - windowSizeUpdated = UpdateWindowSize(UPDATE_WINDOW_NORMAL, hwnd, width, height, desiredFlags); + windowSizeUpdated = UpdateWindowSize(1, hwnd, width, height, desiredFlags); if ((FLAG_MASK_REQUIRED & desiredFlags) == (FLAG_MASK_REQUIRED & CORE.Window.flags)) break; } - if ((attempt > 1) && - (previousStyle == MakeWindowStyle(CORE.Window.flags)) && - !windowSizeUpdated) + + if ((attempt > 1) && (previousStyle == MakeWindowStyle(CORE.Window.flags)) && !windowSizeUpdated) { - TRACELOG(LOG_ERROR, "WINDOW: UpdateFlags() failed after %u attempt(s) wanted 0x%x but is 0x%x (diff=0x%x)", + TRACELOG(LOG_ERROR, "WIN32: WINDOW: UpdateFlags() failed after %u attempt(s) wanted 0x%x but is 0x%x (diff=0x%x)", attempt, desiredFlags, CORE.Window.flags, desiredFlags ^ CORE.Window.flags); } @@ -2051,3 +2170,21 @@ static void UpdateFlags(HWND hwnd, unsigned desiredFlags, int width, int height) UpdateWindowStyle(hwnd, desiredFlags); } } + +// Check if OpenGL extension is available +static bool IsWglExtensionAvailable(HDC hdc, const char *extension) +{ + bool result = false; + + if (wglGetExtensionsStringARB != NULL) + { + const char *extList = wglGetExtensionsStringARB(hdc); + if (extList != NULL) + { + // Simple substring search (could use strtok or strstr) + if (strstr(extList, extension) != NULL) result = true; + } + } + + return result; +} \ No newline at end of file diff --git a/src/rlgl.h b/src/rlgl.h index f587d81a2..e6a1c9432 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -2329,6 +2329,16 @@ void rlglInit(int width, int height) RLGL.State.currentMatrix = &RLGL.State.modelview; #endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2 +#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE) + // Initialize software renderer backend + int result = swInit(width, height); + if (result == 0) + { + TRACELOG(RL_LOG_ERROR, "RLSW: Software renderer initialization failed!"); + exit(-1); + } +#endif + // Initialize OpenGL default states //---------------------------------------------------------- // Init state: Depth test @@ -2345,39 +2355,28 @@ void rlglInit(int width, int height) glFrontFace(GL_CCW); // Front face are defined counter clockwise (default) glEnable(GL_CULL_FACE); // Enable backface culling - // Init state: Cubemap seamless -#if defined(GRAPHICS_API_OPENGL_33) - glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); // Seamless cubemaps (not supported on OpenGL ES 2.0) -#endif - #if defined(GRAPHICS_API_OPENGL_11) // Init state: Color hints (deprecated in OpenGL 3.0+) glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Improve quality of color and texture coordinate interpolation glShadeModel(GL_SMOOTH); // Smooth shading between vertex (vertex colors interpolation) #endif - -#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE) - int result = swInit(width, height); // Initialize software renderer backend - if (result == 0) - { - TRACELOG(RL_LOG_ERROR, "RLSW: Software renderer initialization failed!"); - exit(-1); - } +#if defined(GRAPHICS_API_OPENGL_33) + // Init state: Cubemap seamless + glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); // Seamless cubemaps (not supported on OpenGL ES 2.0) #endif - #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) // Store screen size into global variables RLGL.State.framebufferWidth = width; RLGL.State.framebufferHeight = height; - - TRACELOG(RL_LOG_INFO, "RLGL: Default OpenGL state initialized successfully"); - //---------------------------------------------------------- #endif // Init state: Color/Depth buffers clear glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Set clear color (black) glClearDepth(1.0f); // Set clear depth value (default) glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear color and depth buffers (depth buffer required for 3D) + + TRACELOG(RL_LOG_INFO, "RLGL: Default OpenGL state initialized successfully"); + //---------------------------------------------------------- } // Vertex Buffer Object deinitialization (memory free) From 79b7cd6b9bfa193aa920cc7dfca64e3822e2884a Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 21 Oct 2025 10:08:36 +0200 Subject: [PATCH 25/30] Format tweaks --- src/external/rlsw.h | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/external/rlsw.h b/src/external/rlsw.h index 49050f848..904bf1210 100644 --- a/src/external/rlsw.h +++ b/src/external/rlsw.h @@ -6,7 +6,7 @@ * rlsw is a custom OpenGL 1.1-style implementation on software, intended to provide all * functionality available on rlgl.h library used by raylib, becoming a direct software * rendering replacement for OpenGL 1.1 backend and allowing to run raylib on GPU-less -* devices when required. +* devices when required * * FEATURES: * - Rendering to custom internal framebuffer with multiple color modes supported: @@ -2892,8 +2892,8 @@ static inline bool sw_quad_is_axis_aligned(void) float dx = v1[0] - v0[0]; float dy = v1[1] - v0[1]; - if (fabsf(dx) > 1e-6f && fabsf(dy) < 1e-6f) horizontal++; - else if (fabsf(dy) > 1e-6f && fabsf(dx) < 1e-6f) vertical++; + if ((fabsf(dx) > 1e-6f) && (fabsf(dy) < 1e-6f)) horizontal++; + else if ((fabsf(dy) > 1e-6f) && (fabsf(dx) < 1e-6f)) vertical++; else return false; // Diagonal edge -> not axis-aligned } @@ -2933,8 +2933,8 @@ static inline void sw_quad_sort_cw(const sw_vertex_t* *output) // Separate vertices based on Y-coordinate for (int i = 0; i < 4; i++) { - if (input[i].screen[1] == minY && topCount < 2) top[topCount++] = &input[i]; - else if (input[i].screen[1] == maxY && bottomCount < 2) bottom[bottomCount++] = &input[i]; + if ((input[i].screen[1] == minY) && (topCount < 2)) top[topCount++] = &input[i]; + else if ((input[i].screen[1] == maxY) && (bottomCount < 2)) bottom[bottomCount++] = &input[i]; } // If we don't have enough top/bottom vertices (e.g., Y values are all different), @@ -2960,7 +2960,7 @@ static inline void sw_quad_sort_cw(const sw_vertex_t* *output) } // Sort bottom vertices by X (left to right) - if (bottomCount == 2 && bottom[0]->screen[0] > bottom[1]->screen[0]) + if ((bottomCount == 2) && (bottom[0]->screen[0] > bottom[1]->screen[0])) { const sw_vertex_t *temp = bottom[0]; bottom[0] = bottom[1]; @@ -2997,7 +2997,7 @@ static inline void FUNC_NAME(void) int width = xMax - xMin; \ int height = yMax - yMin; \ \ - if (width == 0 || height == 0) return; \ + if ((width == 0) || (height == 0)) return; \ \ float wRcp = (width > 0.0f)? 1.0f/width : 0.0f; \ float hRcp = (height > 0.0f)? 1.0f/height : 0.0f; \ @@ -3157,7 +3157,7 @@ static inline void sw_quad_render(void) if (RLSW.vertexCounter < 3) return; - if (RLSW.vertexCounter == 4 && sw_quad_is_axis_aligned()) + if ((RLSW.vertexCounter == 4) && sw_quad_is_axis_aligned()) { if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) sw_quad_raster_axis_aligned_TEX_DEPTH_BLEND(); else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) sw_quad_raster_axis_aligned_DEPTH_BLEND(); @@ -3304,7 +3304,7 @@ static inline void FUNC_NAME(const sw_vertex_t *v0, const sw_vertex_t *v1) \ int dy = y2 - y1; \ \ /* Handling of lines that are more horizontal or vertical */ \ - if (dx == 0 && dy == 0) \ + if ((dx == 0) && (dy == 0)) \ { \ /* TODO: A point should be rendered here */ \ return; \ @@ -3444,7 +3444,7 @@ void FUNC_NAME(const sw_vertex_t *v1, const sw_vertex_t *v2) \ \ RASTER_FUNC(v1, v2); \ \ - if (dx != 0 && abs(dy/dx) < 1) \ + if ((dx != 0) && (abs(dy/dx) < 1)) \ { \ int wy = (int)((RLSW.lineWidth - 1.0f)*abs(dx)/sqrtf(dx*dx + dy*dy)); \ wy >>= 1; \ @@ -3551,13 +3551,13 @@ static inline void FUNC_NAME(int x, int y, float z, const float color[4]) \ { \ if (CHECK_BOUNDS == 1) \ { \ - if (x < RLSW.vpMin[0] || x >= RLSW.vpMax[0]) return; \ - if (y < RLSW.vpMin[1] || y >= RLSW.vpMax[1]) return; \ + if ((x < RLSW.vpMin[0]) || (x >= RLSW.vpMax[0])) return; \ + if ((y < RLSW.vpMin[1]) || (y >= RLSW.vpMax[1])) return; \ } \ else if (CHECK_BOUNDS == SW_SCISSOR_TEST) \ { \ - if (x < RLSW.scMin[0] || x >= RLSW.scMax[0]) return; \ - if (y < RLSW.scMin[1] || y >= RLSW.scMax[1]) return; \ + if ((x < RLSW.scMin[0]) || (x >= RLSW.scMax[0])) return; \ + if ((y < RLSW.scMin[1]) || (y >= RLSW.scMax[1])) return; \ } \ \ int offset = y*RLSW.framebuffer.width + x; \ @@ -3718,12 +3718,12 @@ static inline bool sw_is_texture_valid(uint32_t id) static inline bool sw_is_texture_filter_valid(int filter) { - return (filter == SW_NEAREST || filter == SW_LINEAR); + return ((filter == SW_NEAREST) || (filter == SW_LINEAR)); } static inline bool sw_is_texture_wrap_valid(int wrap) { - return (wrap == SW_REPEAT || wrap == SW_CLAMP); + return ((wrap == SW_REPEAT) || (wrap == SW_CLAMP)); } static inline bool sw_is_draw_mode_valid(int mode) @@ -4392,7 +4392,7 @@ void swRotatef(float angle, float x, float y, float z) float lengthSq = x*x + y*y + z*z; - if (lengthSq != 1.0f && lengthSq != 0.0f) + if ((lengthSq != 1.0f) && (lengthSq != 0.0f)) { float invLength = 1.0f/sqrtf(lengthSq); x *= invLength; From 3c5b3f1c1737cc20940f41ec338669d8b032abdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robin=20=E2=9D=A4=EF=B8=8F?= Date: Tue, 21 Oct 2025 04:11:19 -0400 Subject: [PATCH 26/30] [examples] Added `shapes_lines_drawing` (#5283) * Added shapes_lines_drawing Example * store result of clamp * conventions * fixed more brackets * buffer comments --- examples/shapes/shapes_lines_drawing.c | 146 +++++++++++++++++++++++ examples/shapes/shapes_lines_drawing.png | Bin 0 -> 34456 bytes 2 files changed, 146 insertions(+) create mode 100644 examples/shapes/shapes_lines_drawing.c create mode 100644 examples/shapes/shapes_lines_drawing.png diff --git a/examples/shapes/shapes_lines_drawing.c b/examples/shapes/shapes_lines_drawing.c new file mode 100644 index 000000000..9347acaf3 --- /dev/null +++ b/examples/shapes/shapes_lines_drawing.c @@ -0,0 +1,146 @@ +/******************************************************************************************* +* +* raylib [shapes] example - lines drawing +* +* Example complexity rating: [★☆☆☆] 1/4 +* +* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6 +* +* Example contributed by Robin (@RobinsAviary) and reviewed by Ramon Santamaria (@raysan5) +* +* 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-2025 Robin (@RobinsAviary) +* +********************************************************************************************/ + +#include "raylib.h" +#include "raymath.h" + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [shapes] example - lines drawing"); + + // Hint text that shows before you click the screen + bool startText = true; + + // The mouse's position on the previous frame + Vector2 mousePositionPrevious = GetMousePosition(); + + // The canvas to draw lines on + RenderTexture canvas = LoadRenderTexture(screenWidth, screenHeight); + + // The background color of the canvas + const Color backgroundColor = RAYWHITE; + + // The line's thickness + float lineThickness = 8.0f; + // The lines hue (in HSV, from 0-360) + float lineHue = 0.0f; + + // Clear the canvas to the background color + BeginTextureMode(canvas); + ClearBackground(backgroundColor); + EndTextureMode(); + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + // Disable the hint text once the user clicks + if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT) && startText) + { + startText = false; + } + + // Clear the canvas when the user middle-clicks + if (IsMouseButtonPressed(MOUSE_BUTTON_MIDDLE)) + { + BeginTextureMode(canvas); + ClearBackground(backgroundColor); + EndTextureMode(); + } + + // Store whether the left and right buttons are down + bool leftButtonDown = IsMouseButtonDown(MOUSE_BUTTON_LEFT); + bool rightButtonDown = IsMouseButtonDown(MOUSE_BUTTON_RIGHT); + + if (leftButtonDown || rightButtonDown) + { + // The color for the line + Color drawColor; + + if (leftButtonDown) + { + // Increase the hue value by the distance our cursor has moved since the last frame (divided by 3) + lineHue += Vector2Distance(mousePositionPrevious, GetMousePosition())/3.0f; + + // While the hue is >=360, subtract it to bring it down into the range 0-360 + // This is more visually accurate than resetting to zero + while (lineHue >= 360.0f) + { + lineHue -= 360.0f; + } + + // Create the final color + drawColor = ColorFromHSV(lineHue, 1.0f, 1.0f); + } + else if (rightButtonDown) + { + // Use the background color as an "eraser" + drawColor = backgroundColor; + } + + // Draw the line onto the canvas + BeginTextureMode(canvas); + // Circles act as "caps", smoothing corners + DrawCircleV(mousePositionPrevious, lineThickness/2.0f, drawColor); + DrawCircleV(GetMousePosition(), lineThickness/2.0f, drawColor); + DrawLineEx(mousePositionPrevious, GetMousePosition(), lineThickness, drawColor); + EndTextureMode(); + } + + // Update line thickness based on mousewheel + lineThickness += GetMouseWheelMove(); + lineThickness = Clamp(lineThickness, 1.0, 500.0f); + + // Update mouse's previous position + mousePositionPrevious = GetMousePosition(); + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + // Draw the render texture to the screen, flipped vertically to make it appear top-side up + DrawTextureRec(canvas.texture, (Rectangle){ 0.0f, 0.0f, (float)canvas.texture.width,(float)-canvas.texture.height }, Vector2Zero(), WHITE); + + // Draw the preview circle + if (!leftButtonDown) DrawCircleLinesV(GetMousePosition(), lineThickness/2.0f, (Color){ 127, 127, 127, 127 }); + + // Draw the hint text + if (startText) DrawText("try clicking and dragging!", 275, 215, 20, LIGHTGRAY); + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + // Unload the canvas render texture + UnloadRenderTexture(canvas); + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} \ No newline at end of file diff --git a/examples/shapes/shapes_lines_drawing.png b/examples/shapes/shapes_lines_drawing.png new file mode 100644 index 0000000000000000000000000000000000000000..59ef6593439152c128657ecacb80cc91eb146e07 GIT binary patch literal 34456 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%0Dx%j?@0GXzgbsVf3o;ci0R2uE<-DD}`XSk`QvzIc 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 Date: Tue, 21 Oct 2025 13:51:03 +0200 Subject: [PATCH 27/30] Removed trailing spaces --- .github/workflows/build_windows.yml | 12 +-- examples/core/core_3d_camera_first_person.c | 1 - examples/core/core_render_texture.c | 16 ++-- examples/core/core_text_file_loading.c | 10 +-- examples/shapes/shapes_simple_particles.c | 8 +- src/platforms/rcore_android.c | 2 +- src/platforms/rcore_desktop_glfw.c | 7 +- src/platforms/rcore_desktop_rgfw.c | 12 +-- src/platforms/rcore_desktop_win32.c | 84 ++++++++++----------- src/platforms/rcore_drm.c | 14 ++-- src/rcore.c | 4 +- src/rtext.c | 6 +- tools/rexm/rexm.c | 8 +- 13 files changed, 91 insertions(+), 93 deletions(-) diff --git a/.github/workflows/build_windows.yml b/.github/workflows/build_windows.yml index 9e87b5870..7a92c208a 100644 --- a/.github/workflows/build_windows.yml +++ b/.github/workflows/build_windows.yml @@ -40,10 +40,10 @@ jobs: ziptarget: "win64" - compiler: msvc16 ARCH: "x86" - VSARCHPATH: "Win32" + VSARCHPATH: "Win32" ziptarget: "win32" - compiler: msvc16 - ARCH: "x64" + ARCH: "x64" VSARCHPATH: "x64" ziptarget: "win64" - compiler: msvc16 @@ -61,7 +61,7 @@ jobs: steps: - name: Checkout uses: actions/checkout@master - + - name: Setup Release Version run: | echo "RELEASE_NAME=raylib-${{ github.event.release.tag_name }}_${{ matrix.ziptarget }}_${{ matrix.compiler }}" >> $GITHUB_ENV @@ -69,7 +69,7 @@ jobs: if: github.event_name == 'release' && github.event.action == 'published' - name: Setup Environment - run: | + run: | dir mkdir build cd build @@ -98,7 +98,7 @@ jobs: if: | matrix.compiler == 'mingw-w64' && matrix.arch == 'i686' - + - name: Build Library (MinGW-w64 64bit) run: | cd src @@ -144,7 +144,7 @@ jobs: with: name: ${{ env.RELEASE_NAME }}.zip path: ./build/${{ env.RELEASE_NAME }}.zip - + - name: Upload Artifact to Release uses: softprops/action-gh-release@v1 with: diff --git a/examples/core/core_3d_camera_first_person.c b/examples/core/core_3d_camera_first_person.c index 8f4dc70fb..64368c4aa 100644 --- a/examples/core/core_3d_camera_first_person.c +++ b/examples/core/core_3d_camera_first_person.c @@ -119,7 +119,6 @@ int main(void) // Some default standard keyboard/mouse inputs are hardcoded to simplify use // For advanced camera controls, it's recommended to compute camera movement manually UpdateCamera(&camera, cameraMode); // Update camera - /* // Camera PRO usage example (EXPERIMENTAL) // This new camera function allows custom movement/rotation values to be directly provided diff --git a/examples/core/core_render_texture.c b/examples/core/core_render_texture.c index 47dc66e0f..e30220a73 100644 --- a/examples/core/core_render_texture.c +++ b/examples/core/core_render_texture.c @@ -26,7 +26,7 @@ int main(void) const int screenHeight = 450; InitWindow(screenWidth, screenHeight, "raylib [core] example - render texture"); - + // Define a render texture to render int renderTextureWidth = 300; int renderTextureHeight = 300; @@ -62,14 +62,14 @@ int main(void) //----------------------------------------------------- // Draw our scene to the render texture BeginTextureMode(target); - + ClearBackground(SKYBLUE); - + DrawRectangle(0, 0, 20, 20, RED); DrawCircleV(ballPosition, (float)ballRadius, MAROON); - + EndTextureMode(); - + // Draw render texture to main framebuffer BeginDrawing(); @@ -77,14 +77,14 @@ int main(void) // Draw our render texture with rotation applied // NOTE 1: We set the origin of the texture to the center of the render texture - // NOTE 2: We flip vertically the texture setting negative source rectangle height - DrawTexturePro(target.texture, + // NOTE 2: We flip vertically the texture setting negative source rectangle height + DrawTexturePro(target.texture, (Rectangle){ 0, 0, (float)target.texture.width, (float)-target.texture.height }, (Rectangle){ screenWidth/2.0f, screenHeight/2.0f, (float)target.texture.width, (float)target.texture.height }, (Vector2){ target.texture.width/2.0f, target.texture.height/2.0f }, rotation, WHITE); DrawText("DRAWING BOUNCING BALL INSIDE RENDER TEXTURE!", 10, screenHeight - 40, 20, BLACK); - + DrawFPS(10, 10); diff --git a/examples/core/core_text_file_loading.c b/examples/core/core_text_file_loading.c index 4b334e811..033fd4dc6 100644 --- a/examples/core/core_text_file_loading.c +++ b/examples/core/core_text_file_loading.c @@ -64,7 +64,7 @@ int main(void) if (lines[i][j] == ' ') { // Making a C Style string by adding a '\0' at the required location so that we can use the MeasureText function - lines[i][j] = '\0'; + lines[i][j] = '\0'; // Checking if the text has crossed the wrapWidth, then going back and inserting a newline if (MeasureText(lines[i] + lastWrapStart, fontSize) > wrapWidth) @@ -112,8 +112,8 @@ int main(void) cam.target.y -= scroll*fontSize*1.5f; // Choosing an arbitrary speed for scroll if (cam.target.y < 0) cam.target.y = 0; // Snapping to 0 if we go too far back - - // Ensuring that the camera does not scroll past all text + + // Ensuring that the camera does not scroll past all text if (cam.target.y > textHeight - screenHeight + textTop) cam.target.y = textHeight - screenHeight + textTop; @@ -133,10 +133,10 @@ int main(void) { // Each time we go through and calculate the height of the text to move the cursor appropriately Vector2 size = MeasureTextEx(GetFontDefault(), lines[i], fontSize, 2); - + DrawText(lines[i], 10, t, fontSize, RED); - // Inserting extra space for real newlines, + // Inserting extra space for real newlines, // wrapped lines are rendered closer together t += size.y + 10; } diff --git a/examples/shapes/shapes_simple_particles.c b/examples/shapes/shapes_simple_particles.c index 7c2a598c2..c5d9612c3 100644 --- a/examples/shapes/shapes_simple_particles.c +++ b/examples/shapes/shapes_simple_particles.c @@ -74,7 +74,7 @@ int main(void) // Definition of particles Particle *particles = (Particle*)RL_CALLOC(MAX_PARTICLES, sizeof(Particle)); // Particle array CircularBuffer circularBuffer = { 0, 0, particles }; - + // Particle emitter parameters int emissionRate = -2; // Negative: on average every -X frames. Positive: particles per frame ParticleType currentType = WATER; @@ -100,7 +100,7 @@ int main(void) // Update the parameters of each particle UpdateParticles(&circularBuffer, screenWidth, screenHeight); - + // Remove dead particles from the circular buffer UpdateCircularBuffer(&circularBuffer); @@ -252,10 +252,10 @@ static void UpdateParticles(CircularBuffer *circularBuffer, int screenWidth, int // Disable particle when out of screen Vector2 center = circularBuffer->buffer[i].position; float radius = circularBuffer->buffer[i].radius; - + if ((center.x < -radius) || (center.x > (screenWidth + radius)) || (center.y < -radius) || (center.y > (screenHeight + radius))) - { + { circularBuffer->buffer[i].alive = false; } } diff --git a/src/platforms/rcore_android.c b/src/platforms/rcore_android.c index 6ecc41888..47dcce32b 100644 --- a/src/platforms/rcore_android.c +++ b/src/platforms/rcore_android.c @@ -461,7 +461,7 @@ int GetCurrentMonitor(void) if (display == NULL) { TRACELOG(LOG_ERROR, "GetCurrentMonitor() couldn't get the display object"); - } + } else { jclass displayClass = (*env)->FindClass(env, "android/view/Display"); diff --git a/src/platforms/rcore_desktop_glfw.c b/src/platforms/rcore_desktop_glfw.c index 729ca308c..5dde1df67 100644 --- a/src/platforms/rcore_desktop_glfw.c +++ b/src/platforms/rcore_desktop_glfw.c @@ -1048,6 +1048,7 @@ Image GetClipboardImage(void) void ShowCursor(void) { glfwSetInputMode(platform.handle, GLFW_CURSOR, GLFW_CURSOR_NORMAL); + CORE.Input.Mouse.cursorHidden = false; } @@ -1055,6 +1056,7 @@ void ShowCursor(void) void HideCursor(void) { glfwSetInputMode(platform.handle, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); + CORE.Input.Mouse.cursorHidden = true; } @@ -1075,13 +1077,10 @@ void EnableCursor(void) void DisableCursor(void) { // Reset mouse position within the window area before disabling cursor - SetMousePosition(CORE.Window.screen.width, CORE.Window.screen.height); + SetMousePosition(CORE.Window.screen.width/2, CORE.Window.screen.height/2); glfwSetInputMode(platform.handle, GLFW_CURSOR, GLFW_CURSOR_DISABLED); - // Set cursor position in the middle - SetMousePosition(CORE.Window.screen.width/2, CORE.Window.screen.height/2); - if (glfwRawMouseMotionSupported()) glfwSetInputMode(platform.handle, GLFW_RAW_MOUSE_MOTION, GLFW_TRUE); CORE.Input.Mouse.cursorLocked = true; diff --git a/src/platforms/rcore_desktop_rgfw.c b/src/platforms/rcore_desktop_rgfw.c index 52ec6ac94..86842140d 100644 --- a/src/platforms/rcore_desktop_rgfw.c +++ b/src/platforms/rcore_desktop_rgfw.c @@ -80,7 +80,7 @@ void CloseWindow(void); #define CloseWindow CloseWindow_win32 #define ShowCursor __imp_ShowCursor #define _APISETSTRING_ - + #undef MAX_PATH #if defined(__cplusplus) @@ -262,7 +262,7 @@ static int RGFW_gpConvTable[18] = { [RGFW_gamepadRight] = GAMEPAD_BUTTON_LEFT_FACE_RIGHT, [RGFW_gamepadDown] = GAMEPAD_BUTTON_LEFT_FACE_DOWN, [RGFW_gamepadLeft] = GAMEPAD_BUTTON_LEFT_FACE_LEFT, - [RGFW_gamepadL3] = GAMEPAD_BUTTON_LEFT_THUMB, + [RGFW_gamepadL3] = GAMEPAD_BUTTON_LEFT_THUMB, [RGFW_gamepadR3] = GAMEPAD_BUTTON_RIGHT_THUMB, }; @@ -933,7 +933,7 @@ void PollInputEvents(void) // because ProcessGestureEvent() is just called on an event, not every frame UpdateGestures(); #endif - + // Reset keys/chars pressed registered CORE.Input.Keyboard.keyPressedQueueCount = 0; CORE.Input.Keyboard.charPressedQueueCount = 0; @@ -1025,7 +1025,7 @@ void PollInputEvents(void) CORE.Window.dropFilepaths[CORE.Window.dropFileCount] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char)); strcpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event->droppedFiles[i]); - + CORE.Window.dropFileCount++; } else if (CORE.Window.dropFileCount < 1024) @@ -1229,7 +1229,7 @@ void PollInputEvents(void) int button = (axis == GAMEPAD_AXIS_LEFT_TRIGGER)? GAMEPAD_BUTTON_LEFT_TRIGGER_2 : GAMEPAD_BUTTON_RIGHT_TRIGGER_2; int pressed = (value > 0.1f); CORE.Input.Gamepad.currentButtonState[event->gamepad][button] = pressed; - + if (pressed) CORE.Input.Gamepad.lastButtonPressed = button; else if (CORE.Input.Gamepad.lastButtonPressed == button) CORE.Input.Gamepad.lastButtonPressed = 0; } @@ -1345,7 +1345,7 @@ int InitPlatform(void) // TODO: Is this needed by raylib now? // If so, rcore_desktop_sdl should be updated too //SetupFramebuffer(CORE.Window.display.width, CORE.Window.display.height); - + if (CORE.Window.flags & FLAG_VSYNC_HINT) RGFW_window_swapInterval(platform.window, 1); RGFW_window_makeCurrent(platform.window); diff --git a/src/platforms/rcore_desktop_win32.c b/src/platforms/rcore_desktop_win32.c index 7ac6138bd..de9a66911 100644 --- a/src/platforms/rcore_desktop_win32.c +++ b/src/platforms/rcore_desktop_win32.c @@ -84,8 +84,8 @@ // Types and Structures Definition //---------------------------------------------------------------------------------- -// NOTE: appScreenSize is the last screen size requested by the app, -// the backend must keep the client area this size (after DPI scaling is applied) +// NOTE: appScreenSize is the last screen size requested by the app, +// the backend must keep the client area this size (after DPI scaling is applied) // when the window isn't fullscreen/maximized/minimized typedef struct { HWND hwnd; // Window handler @@ -141,7 +141,7 @@ static PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = NULL; AToWCopy(inAnsi, outWstr, outLen); \ outWstr[outLen] = 0; \ } while (0) - + #define STYLE_MASK_ALL 0xffffffff #define STYLE_MASK_READONLY (WS_MINIMIZE | WS_MAXIMIZE) #define STYLE_MASK_WRITABLE (~STYLE_MASK_READONLY) @@ -206,10 +206,10 @@ static PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = NULL; // Types and Structures Definition //---------------------------------------------------------------------------------- // Maximize-minimize request types -typedef enum { - MIZED_NONE, - MIZED_MIN, - MIZED_MAX +typedef enum { + MIZED_NONE, + MIZED_MIN, + MIZED_MAX } Mized; // Flag operations @@ -234,7 +234,7 @@ typedef struct { static size_t AToWLen(const char *ascii) { int sizeNeeded = MultiByteToWideChar(CP_UTF8, 0, ascii, -1, NULL, 0); - + if (sizeNeeded < 0) TRACELOG(LOG_ERROR, "WIN32: Failed to calculate wide length [ERROR: %u]", GetLastError()); return sizeNeeded; @@ -268,7 +268,7 @@ static DWORD MakeWindowStyle(unsigned flags) // it improves efficiency, plus, windows adds this flag automatically anyway // so it keeps our flags in sync with the OS DWORD style = WS_CLIPSIBLINGS; - + style |= (flags & FLAG_WINDOW_HIDDEN)? 0 : WS_VISIBLE; style |= (flags & FLAG_WINDOW_RESIZABLE)? STYLE_FLAGS_RESIZABLE : 0; style |= (flags & FLAG_WINDOW_UNDECORATED)? STYLE_FLAGS_UNDECORATED_ON : STYLE_FLAGS_UNDECORATED_OFF; @@ -339,7 +339,7 @@ static void CheckFlags(const char *context, HWND hwnd, DWORD flags, DWORD expect static SIZE CalcWindowSize(UINT dpi, SIZE clientSize, DWORD style) { RECT rect = { 0, 0, clientSize.cx, clientSize.cy }; - + int result = AdjustWindowRectExForDpi(&rect, style, 0, WINDOW_STYLE_EX, dpi); if (result == 0) TRACELOG(LOG_ERROR, "WIN32: Failed to adjust window rect [ERROR: %lu]", GetLastError()); @@ -442,8 +442,8 @@ static bool UpdateWindowSize(int mode, HWND hwnd, int width, int height, unsigne static BOOL IsWindows10Version1703OrGreaterWin32(void) { HMODULE ntdll = LoadLibraryW(L"ntdll.dll"); - - DWORD (*Verify)(RTL_OSVERSIONINFOEXW*, ULONG, ULONGLONG) = + + DWORD (*Verify)(RTL_OSVERSIONINFOEXW*, ULONG, ULONGLONG) = (DWORD (*)(RTL_OSVERSIONINFOEXW*, ULONG, ULONGLONG))GetProcAddress(ntdll, "RtlVerifyVersionInfo"); if (!Verify) { @@ -461,7 +461,7 @@ static BOOL IsWindows10Version1703OrGreaterWin32(void) VER_SET_CONDITION(cond, VER_MAJORVERSION, VER_GREATER_EQUAL); VER_SET_CONDITION(cond, VER_MINORVERSION, VER_GREATER_EQUAL); VER_SET_CONDITION(cond, VER_BUILDNUMBER, VER_GREATER_EQUAL); - + return 0 == (*Verify)(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_BUILDNUMBER, cond); } @@ -473,8 +473,8 @@ static void *WglGetProcAddress(const char *procname) if ((proc == NULL) || // NOTE: Some GPU drivers could return following // invalid sentinel values instead of NULL - (proc == (void *)0x1) || - (proc == (void *)0x2) || + (proc == (void *)0x1) || + (proc == (void *)0x2) || (proc == (void *)0x3) || (proc == (void *)-1)) { @@ -767,7 +767,7 @@ static void GetStyleChangeFlagOps(DWORD coreWindowFlags, STYLESTRUCT *style, Fla } // Adopt window resize -// NOTE: Call when the window is rezised, returns true +// NOTE: Call when the window is rezised, returns true // if the new window size should update the desired app size static bool AdoptWindowResize(unsigned flags) { @@ -776,7 +776,7 @@ static bool AdoptWindowResize(unsigned flags) if (flags & FLAG_FULLSCREEN_MODE) return false; if (flags & FLAG_BORDERLESS_WINDOWED_MODE) return false; if (!(flags & FLAG_WINDOW_RESIZABLE)) return false; - + return true; } @@ -947,10 +947,10 @@ void SetWindowIcons(Image *images, int count) void SetWindowTitle(const char *title) { CORE.Window.title = title; - + WCHAR *titleWide = NULL; A_TO_W_ALLOCA(titleWide, CORE.Window.title); - + int result = SetWindowTextW(platform.hwnd, titleWide); if (result == 0) TRACELOG(LOG_WARNING, "WIN32: Failed to set window title [ERROR: %lu]", GetLastError()); } @@ -1023,7 +1023,7 @@ void *GetWindowHandle(void) int GetMonitorCount(void) { int count = 0; - + int result = EnumDisplayMonitors(NULL, NULL, CountMonitorsProc, (LPARAM)&count); if (result == 0) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "EnumDisplayMonitors", GetLastError()); @@ -1040,7 +1040,7 @@ int GetCurrentMonitor(void) info.needle = monitor; info.index = 0; info.matchIndex = -1; - + int result = EnumDisplayMonitors(NULL, NULL, FindMonitorProc, (LPARAM)&info); if (result == 0) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "EnumDisplayMonitors", GetLastError()); @@ -1127,7 +1127,7 @@ const char *GetClipboardText(void) Image GetClipboardImage(void) { Image image = { 0 }; - + TRACELOG(LOG_WARNING, "GetClipboardText not implemented"); return image; @@ -1193,7 +1193,7 @@ void DisableCursor(void) TRACELOG(LOG_INFO, "WIN32: Clip cursor client rect: [%d,%d %d,%d], top-left: (%d,%d)", clientRect.left, clientRect.top, clientRect.right, clientRect.bottom, topleft.x, topleft.y); - + LONG centerX = topleft.x + width/2; LONG centerY = topleft.y + height/2; RECT clipRect = { centerX, centerY, centerX + 1, centerY + 1 }; @@ -1502,7 +1502,7 @@ int InitPlatform(void) if (IsWindows10Version1703OrGreaterWin32()) { TRACELOG(LOG_INFO, "DpiAware: >=Win10Creators"); - if (!SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2)) + if (!SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2)) TRACELOG(LOG_ERROR, "%s failed, error %u", "SetProcessDpiAwarenessContext", GetLastError()); } else @@ -1620,7 +1620,7 @@ int InitPlatform(void) } CORE.Window.ready = true; - + // TODO: Should this function be called before or after drawing context is created? --> After swInit() called! //UpdateWindowSize(UPDATE_WINDOW_FIRST, platform.hwnd, platform.appScreenWidth, platform.appScreenHeight, platform.desiredFlags); UpdateFlags(platform.hwnd, platform.desiredFlags, platform.appScreenWidth, platform.appScreenHeight); @@ -1660,7 +1660,7 @@ int InitPlatform(void) //---------------------------------------------------------------------------- TRACELOG(LOG_INFO, "PLATFORM: DESKTOP: WIN32: Initialized successfully"); - + return 0; } @@ -1691,7 +1691,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara FlagsOp flagsOp = { 0 }; FlagsOp *deferredFlags = &flagsOp; - + // Message processing //------------------------------------------------------------------------------------ switch (msg) @@ -1707,13 +1707,13 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara // Clean up for window destruction if (rlGetVersion() == RL_OPENGL_11_SOFTWARE) // Using software renderer { - if (platform.hdcmem) + if (platform.hdcmem) { DeleteDC(platform.hdcmem); platform.hdcmem = NULL; } - if (platform.hbitmap) + if (platform.hbitmap) { DeleteObject(platform.hbitmap); // Clears platform.pixels data platform.hbitmap = NULL; @@ -1751,9 +1751,9 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara if (CORE.Window.flags & FLAG_WINDOW_RESIZABLE) { // TODO: Enforce min/max size - } + } else TRACELOG(LOG_WARNING, "WIN32: WINDOW: Trying to resize a non-resizable window"); - + result = TRUE; } break; case WM_STYLECHANGING: @@ -1770,11 +1770,11 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara SIZE clientSize = { rect.right, rect.bottom }; SIZE oldSize = CalcWindowSize(dpi, clientSize, ss->styleOld); SIZE newSize = CalcWindowSize(dpi, clientSize, ss->styleNew); - + if (oldSize.cx != newSize.cx || oldSize.cy != newSize.cy) { TRACELOG(LOG_INFO, "WIN32: WINDOW: Resize from style change [%dx%d] to [%dx%d]", oldSize.cx, oldSize.cy, newSize.cx, newSize.cy); - + if (CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) { // looks like windows will automatically "unminimize" a window @@ -1795,7 +1795,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara bool isIconic = IsIconic(hwnd); bool styleMinimized = !!(WS_MINIMIZE & GetWindowLongPtrW(hwnd, GWL_STYLE)); if (isIconic != styleMinimized) TRACELOG(LOG_WARNING, "WIN32: IsIconic state different from WS_MINIMIZED state"); - + if (isIconic) mized = MIZED_MIN; else { @@ -1871,7 +1871,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara }; inoutSize->cx = desired.cx; inoutSize->cy = desired.cy; - + result = TRUE; } break; case WM_DPICHANGED: @@ -1929,7 +1929,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara case WM_RBUTTONUP : HandleMouseButton(MOUSE_BUTTON_RIGHT, 0); break; case WM_MBUTTONDOWN: HandleMouseButton(MOUSE_BUTTON_MIDDLE, 1); break; case WM_MBUTTONUP : HandleMouseButton(MOUSE_BUTTON_MIDDLE, 0); break; - case WM_XBUTTONDOWN: + case WM_XBUTTONDOWN: { switch (HIWORD(wparam)) { @@ -1975,11 +1975,11 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara static void HandleKey(WPARAM wparam, LPARAM lparam, char state) { KeyboardKey key = GetKeyFromWparam(wparam); - + // TODO: Use scancode? //BYTE scancode = lparam >> 16; //TRACELOG(LOG_INFO, "KEY key=%d vk=%lu scan=%u = %u", key, wparam, scancode, state); - + if (key != KEY_NULL) { CORE.Input.Keyboard.currentKeyState[key] = state; @@ -2003,9 +2003,9 @@ static void HandleRawInput(LPARAM lparam) UINT inputSize = sizeof(input); UINT size = GetRawInputData((HRAWINPUT)lparam, RID_INPUT, &input, &inputSize, sizeof(RAWINPUTHEADER)); - + if (size == (UINT)-1) TRACELOG(LOG_ERROR, "WIN32: Failed to get raw input data [ERROR: %lu]", GetLastError()); - + if (input.header.dwType != RIM_TYPEMOUSE) TRACELOG(LOG_ERROR, "WIN32: Unexpected WM_INPUT type %lu", input.header.dwType); if (input.data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) TRACELOG(LOG_ERROR, "TODO: handle absolute mouse inputs!"); @@ -2043,7 +2043,7 @@ static void HandleWindowResize(HWND hwnd, int *width, int *height) unsigned int screenHeight = highdpi? (unsigned int)(((float)clientSize.cy)/dpiScale) : clientSize.cy; CORE.Window.screen.width = screenWidth; CORE.Window.screen.height = screenHeight; - + if (AdoptWindowResize(CORE.Window.flags)) { TRACELOG(LOG_DEBUG, "WIN32: WINDOW: Updating app size to [%ix%i] from window resize", screenWidth, screenHeight); @@ -2062,7 +2062,7 @@ static void UpdateWindowStyle(HWND hwnd, unsigned desiredFlags) { DWORD current = STYLE_MASK_WRITABLE & MakeWindowStyle(CORE.Window.flags); DWORD desired = STYLE_MASK_WRITABLE & MakeWindowStyle(desiredFlags); - + if (current != desired) { SetLastError(0); diff --git a/src/platforms/rcore_drm.c b/src/platforms/rcore_drm.c index 58e820af1..a08a76bce 100644 --- a/src/platforms/rcore_drm.c +++ b/src/platforms/rcore_drm.c @@ -864,7 +864,7 @@ void SwapScreenBuffer(void) // Create framebuffer with the correct format uint32_t fb = 0; result = drmModeAddFB(platform.fd, width, height, depth, bpp, creq.pitch, creq.handle, &fb); - if (result != 0) + if (result != 0) { TRACELOG(LOG_ERROR, "DISPLAY: drmModeAddFB() failed with result: %d (%s)", result, strerror(errno)); struct drm_mode_destroy_dumb dreq = { 0 }; @@ -974,12 +974,12 @@ void SwapScreenBuffer(void) // Set CRTC with better error handling result = drmModeSetCrtc(platform.fd, crtcId, fb, 0, 0, &platform.connector->connector_id, 1, mode); - if (result != 0) + if (result != 0) { TRACELOG(LOG_ERROR, "DISPLAY: drmModeSetCrtc() failed with result: %d (%s)", result, strerror(errno)); TRACELOG(LOG_ERROR, "DISPLAY: CRTC ID: %u, FB ID: %u, Connector ID: %u", crtcId, fb, platform.connector->connector_id); TRACELOG(LOG_ERROR, "DISPLAY: Mode: %dx%d@%d", mode->hdisplay, mode->vdisplay, mode->vrefresh); - + drmModeRmFB(platform.fd, fb); struct drm_mode_destroy_dumb dreq = {0}; dreq.handle = creq.handle; @@ -1229,7 +1229,7 @@ int InitPlatform(void) } TRACELOG(LOG_TRACE, "DISPLAY: Connector %i modes detected: %i", i, con->count_modes); - TRACELOG(LOG_TRACE, "DISPLAY: Connector %i status: %s", i, + TRACELOG(LOG_TRACE, "DISPLAY: Connector %i status: %s", i, (con->connection == DRM_MODE_CONNECTED) ? "CONNECTED" : (con->connection == DRM_MODE_DISCONNECTED) ? "DISCONNECTED" : (con->connection == DRM_MODE_UNKNOWNCONNECTION) ? "UNKNOWN" : "OTHER"); @@ -1357,10 +1357,10 @@ int InitPlatform(void) platform.modeIndex = 0; CORE.Window.display.width = platform.connector->modes[0].hdisplay; CORE.Window.display.height = platform.connector->modes[0].vdisplay; - - TRACELOG(LOG_INFO, "DISPLAY: Selected DRM connector mode %s (%ux%u%c@%u) for software rendering", + + TRACELOG(LOG_INFO, "DISPLAY: Selected DRM connector mode %s (%ux%u%c@%u) for software rendering", platform.connector->modes[0].name, - platform.connector->modes[0].hdisplay, + platform.connector->modes[0].hdisplay, platform.connector->modes[0].vdisplay, (platform.connector->modes[0].flags & DRM_MODE_FLAG_INTERLACE) ? 'i' : 'p', platform.connector->modes[0].vrefresh); diff --git a/src/rcore.c b/src/rcore.c index 5dea97c22..350490ad1 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -2524,7 +2524,7 @@ int MakeDirectory(const char *dirPath) // Create final directory if (!DirectoryExists(pathcpy)) MKDIR(pathcpy); RL_FREE(pathcpy); - + // In case something failed and requested directory // was not successfully created, return -1 if (!DirectoryExists(dirPath)) return -1; @@ -3148,7 +3148,7 @@ unsigned int *ComputeSHA256(unsigned char *data, int dataSize) unsigned char *block = buffer + (blockN*64); unsigned int w[64]; for (int i = 0; i < 16; i++) - { + { w[i] = ((unsigned int)block[i*4 + 0] << 24) | ((unsigned int)block[i*4 + 1] << 16) | diff --git a/src/rtext.c b/src/rtext.c index 9951dc66d..b4cd560ba 100644 --- a/src/rtext.c +++ b/src/rtext.c @@ -1701,9 +1701,9 @@ char *GetTextBetween(const char *text, const char *begin, const char *end) char *TextReplace(const char *text, const char *search, const char *replacement) { char *result = NULL; - + if (!text || !search) return NULL; // Sanity check - + char *insertPoint = NULL; // Next insert point char *temp = NULL; // Temp pointer int searchLen = 0; // Search string length of (the string to remove) @@ -1753,7 +1753,7 @@ char *TextReplaceBetween(const char *text, const char *begin, const char *end, c char *result = NULL; if (!text || !begin || !end) return NULL; // Sanity check - + int beginIndex = TextFindIndex(text, begin); if (beginIndex > -1) diff --git a/tools/rexm/rexm.c b/tools/rexm/rexm.c index 20fc1d5e5..d668655c8 100644 --- a/tools/rexm/rexm.c +++ b/tools/rexm/rexm.c @@ -239,7 +239,7 @@ int main(int argc, char *argv[]) // build : Build example for Desktop and Web platforms // validate : Validate examples collection, generates report // update : Validate and update examples collection, generates report - + if (strcmp(argv[1], "create") == 0) { // Check for valid upcoming argument @@ -394,8 +394,8 @@ int main(int argc, char *argv[]) { // Support building not only individual examples but categories and "ALL" if ((strcmp(argv[2], "ALL") == 0) || TextInList(argv[2], exCategories, REXM_MAX_EXAMPLE_CATEGORIES)) - { - // Category/ALL rebuilt requested + { + // Category/ALL rebuilt requested strcpy(exRebuildRequested, argv[2]); } else @@ -2432,7 +2432,7 @@ static void UpdateWebMetadata(const char *exHtmlPath, const char *exFilePath) static bool TextInList(const char *text, const char **list, int listCount) { bool result = false; - + for (int i = 0; i < listCount; i++) { if (TextIsEqual(text, list[i])) { result = true; break; } From 77b9214575ec60abe6824fd7c8abf40169c8e966 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 21 Oct 2025 20:07:32 +0200 Subject: [PATCH 28/30] Update rcore_desktop_sdl.c --- src/platforms/rcore_desktop_sdl.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/platforms/rcore_desktop_sdl.c b/src/platforms/rcore_desktop_sdl.c index 6655db460..a5f626ecc 100644 --- a/src/platforms/rcore_desktop_sdl.c +++ b/src/platforms/rcore_desktop_sdl.c @@ -104,7 +104,6 @@ typedef struct { SDL_GameController *gamepad[MAX_GAMEPADS]; SDL_JoystickID gamepadId[MAX_GAMEPADS]; // Joystick instance ids, they do not start from 0 SDL_Cursor *cursor; - bool cursorRelative; } PlatformData; //---------------------------------------------------------------------------------- @@ -1209,13 +1208,13 @@ void EnableCursor(void) SDL_SetRelativeMouseMode(SDL_FALSE); #if defined(USING_VERSION_SDL3) - // SDL_ShowCursor() has been split into three functions: SDL_ShowCursor(), SDL_HideCursor(), and SDL_CursorVisible() + // NOTE: SDL_ShowCursor() has been split into three functions: + // SDL_ShowCursor(), SDL_HideCursor(), and SDL_CursorVisible() SDL_ShowCursor(); #else SDL_ShowCursor(SDL_ENABLE); #endif - platform.cursorRelative = false; CORE.Input.Mouse.cursorLocked = false; } @@ -1224,7 +1223,6 @@ void DisableCursor(void) { SDL_SetRelativeMouseMode(SDL_TRUE); - platform.cursorRelative = true; CORE.Input.Mouse.cursorLocked = true; } @@ -1332,7 +1330,7 @@ void PollInputEvents(void) CORE.Input.Mouse.currentWheelMove.y = 0; // Register previous mouse position - if (platform.cursorRelative) CORE.Input.Mouse.currentPosition = (Vector2){ 0.0f, 0.0f }; + if (CORE.Input.Mouse.cursorLocked) CORE.Input.Mouse.currentPosition = (Vector2){ 0.0f, 0.0f }; else CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition; // Reset last gamepad button/axis registered state @@ -1634,7 +1632,7 @@ void PollInputEvents(void) } break; case SDL_MOUSEMOTION: { - if (platform.cursorRelative) + if (CORE.Input.Mouse.cursorLocked) { CORE.Input.Mouse.currentPosition.x = (float)event.motion.xrel; CORE.Input.Mouse.currentPosition.y = (float)event.motion.yrel; From 99ed81461526b37583cac323a51a5d019b49b16c Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 21 Oct 2025 20:07:42 +0200 Subject: [PATCH 29/30] Update rcore_desktop_win32.c --- src/platforms/rcore_desktop_win32.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/platforms/rcore_desktop_win32.c b/src/platforms/rcore_desktop_win32.c index de9a66911..9b66f8c4b 100644 --- a/src/platforms/rcore_desktop_win32.c +++ b/src/platforms/rcore_desktop_win32.c @@ -1136,17 +1136,17 @@ Image GetClipboardImage(void) // Show mouse cursor void ShowCursor(void) { - CORE.Input.Mouse.cursorHidden = false; SetCursor(LoadCursorW(NULL, (LPCWSTR)IDC_ARROW)); + CORE.Input.Mouse.cursorHidden = false; } // Hides mouse cursor void HideCursor(void) { - // NOTE: we use SetCursor instead of ShowCursor because it makes it easy - // to only hide the cursor while it's inside the client area - CORE.Input.Mouse.cursorHidden = true; + // NOTE: We use SetCursor() instead of ShowCursor() because + // it makes it easy to only hide the cursor while it's inside the client area SetCursor(NULL); + CORE.Input.Mouse.cursorHidden = true; } // Enables cursor (unlock cursor) @@ -1346,7 +1346,7 @@ void PollInputEvents(void) //---------------------------------------------------------------------------------- // Initialize modern OpenGL context -// NOTE: We need to create a dummy context first to query requried extensions +// NOTE: We need to create a dummy context first to query required extensions HGLRC InitOpenGL(HWND hwnd, HDC hdc) { // First, create a dummy context to get WGL extensions @@ -1621,8 +1621,7 @@ int InitPlatform(void) CORE.Window.ready = true; - // TODO: Should this function be called before or after drawing context is created? --> After swInit() called! - //UpdateWindowSize(UPDATE_WINDOW_FIRST, platform.hwnd, platform.appScreenWidth, platform.appScreenHeight, platform.desiredFlags); + // Update flags (in case of deferred state change required) UpdateFlags(platform.hwnd, platform.desiredFlags, platform.appScreenWidth, platform.appScreenHeight); CORE.Window.render.width = CORE.Window.screen.width; @@ -1887,6 +1886,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara } break; case WM_SETCURSOR: { + // Called when mouse moves, enters/leaves window... if (LOWORD(lparam) == HTCLIENT) { SetCursor(CORE.Input.Mouse.cursorHidden? NULL : LoadCursorW(NULL, (LPCWSTR)IDC_ARROW)); @@ -1972,6 +1972,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara return result; } +// Handle keyboard input event static void HandleKey(WPARAM wparam, LPARAM lparam, char state) { KeyboardKey key = GetKeyFromWparam(wparam); @@ -1991,12 +1992,15 @@ static void HandleKey(WPARAM wparam, LPARAM lparam, char state) // TODO: Add key to the queue as well? } +// Handle mouse button input event static void HandleMouseButton(int button, char state) { + // Register current mouse button state CORE.Input.Mouse.currentButtonState[button] = state; CORE.Input.Touch.currentTouchState[button] = state; } +// Handle raw input event static void HandleRawInput(LPARAM lparam) { RAWINPUT input = { 0 }; @@ -2020,6 +2024,7 @@ static void HandleRawInput(LPARAM lparam) //if (CORE.Input.Mouse.currentPosition.y != 0) abort(); } +// Handle window resizing event static void HandleWindowResize(HWND hwnd, int *width, int *height) { if (CORE.Window.flags & FLAG_WINDOW_MINIMIZED) return; @@ -2051,10 +2056,8 @@ static void HandleWindowResize(HWND hwnd, int *width, int *height) *height = screenHeight; } - CORE.Window.screenScale = MatrixScale( - (float)CORE.Window.render.width/CORE.Window.screen.width, - (float)CORE.Window.render.height/CORE.Window.screen.height, - 1.0f); + CORE.Window.screenScale = MatrixScale( (float)CORE.Window.render.width/CORE.Window.screen.width, + (float)CORE.Window.render.height/CORE.Window.screen.height, 1.0f); } // Update window style From 1b5a14e5167755d54e8b4e9851b9167302641d2f Mon Sep 17 00:00:00 2001 From: sleeptightAnsiC <91839286+sleeptightAnsiC@users.noreply.github.com> Date: Tue, 21 Oct 2025 22:07:04 +0200 Subject: [PATCH 30/30] [rcore_desktop_sdl] fix: handle monitor ID correctly on SDL3 (#5290) SDL3 uses ID when dealing with monitors, unlike SDL2 which uses Index for the same thing. This problem was already fixed in multiple places by use of preprocessor branches, so I did the very same thing. Please, notice that this is a pretty bad solution to this problem, and I only did it to keep it consistent with the rest of the code. The more about why it's not correct is mentioned here: https://github.com/raysan5/raylib/issues/5256#issuecomment-3429156919 Hopefully, someone will refactor it someday :) Fixes: https://github.com/raysan5/raylib/issues/5256 --- src/platforms/rcore_desktop_sdl.c | 37 ++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/src/platforms/rcore_desktop_sdl.c b/src/platforms/rcore_desktop_sdl.c index a5f626ecc..e135cd848 100644 --- a/src/platforms/rcore_desktop_sdl.c +++ b/src/platforms/rcore_desktop_sdl.c @@ -837,7 +837,11 @@ void SetWindowPosition(int x, int y) void SetWindowMonitor(int monitor) { const int monitorCount = SDL_GetNumVideoDisplays(); +#if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure + if ((monitor > 0) && (monitor <= monitorCount)) +#else if ((monitor >= 0) && (monitor < monitorCount)) +#endif { // NOTE: // 1. SDL started supporting moving exclusive fullscreen windows between displays on SDL3, @@ -961,7 +965,11 @@ int GetCurrentMonitor(void) Vector2 GetMonitorPosition(int monitor) { const int monitorCount = SDL_GetNumVideoDisplays(); +#if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure + if ((monitor > 0) && (monitor <= monitorCount)) +#else if ((monitor >= 0) && (monitor < monitorCount)) +#endif { SDL_Rect displayBounds; @@ -985,7 +993,11 @@ int GetMonitorWidth(int monitor) int width = 0; const int monitorCount = SDL_GetNumVideoDisplays(); +#if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure + if ((monitor > 0) && (monitor <= monitorCount)) +#else if ((monitor >= 0) && (monitor < monitorCount)) +#endif { SDL_DisplayMode mode; SDL_GetCurrentDisplayMode(monitor, &mode); @@ -1002,7 +1014,11 @@ int GetMonitorHeight(int monitor) int height = 0; const int monitorCount = SDL_GetNumVideoDisplays(); +#if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure + if ((monitor > 0) && (monitor <= monitorCount)) +#else if ((monitor >= 0) && (monitor < monitorCount)) +#endif { SDL_DisplayMode mode; SDL_GetCurrentDisplayMode(monitor, &mode); @@ -1019,7 +1035,11 @@ int GetMonitorPhysicalWidth(int monitor) int width = 0; const int monitorCount = SDL_GetNumVideoDisplays(); +#if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure + if ((monitor > 0) && (monitor <= monitorCount)) +#else if ((monitor >= 0) && (monitor < monitorCount)) +#endif { float ddpi = 0.0f; SDL_GetDisplayDPI(monitor, &ddpi, NULL, NULL); @@ -1039,7 +1059,11 @@ int GetMonitorPhysicalHeight(int monitor) int height = 0; const int monitorCount = SDL_GetNumVideoDisplays(); +#if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure + if ((monitor > 0) && (monitor <= monitorCount)) +#else if ((monitor >= 0) && (monitor < monitorCount)) +#endif { float ddpi = 0.0f; SDL_GetDisplayDPI(monitor, &ddpi, NULL, NULL); @@ -1059,7 +1083,11 @@ int GetMonitorRefreshRate(int monitor) int refresh = 0; const int monitorCount = SDL_GetNumVideoDisplays(); +#if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure + if ((monitor > 0) && (monitor <= monitorCount)) +#else if ((monitor >= 0) && (monitor < monitorCount)) +#endif { SDL_DisplayMode mode; SDL_GetCurrentDisplayMode(monitor, &mode); @@ -1075,7 +1103,14 @@ const char *GetMonitorName(int monitor) { const int monitorCount = SDL_GetNumVideoDisplays(); - if ((monitor >= 0) && (monitor < monitorCount)) return SDL_GetDisplayName(monitor); +#if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure + if ((monitor > 0) && (monitor <= monitorCount)) +#else + if ((monitor >= 0) && (monitor < monitorCount)) +#endif + { + return SDL_GetDisplayName(monitor); + } else TRACELOG(LOG_WARNING, "SDL: Failed to find selected monitor"); return "";