From c1615aaac4fbb3b66cc97da7674929b0467cb7c7 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 14 Sep 2025 10:22:56 +0200 Subject: [PATCH 001/167] Update examples_template.c --- examples/examples_template.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/examples_template.c b/examples/examples_template.c index 2bb223a9c..39a19351d 100644 --- a/examples/examples_template.c +++ b/examples/examples_template.c @@ -36,8 +36,9 @@ 10. Have fun! - The following files should be updated when adding a new example, it's planned to create some - script to automatize this process but not available yet + The following files must be updated when adding a new example, + but it can be automatically done using the raylib provided tool: rexm + So, no worries if just the .c/.png are provided when adding the example. - raylib/examples//_example_name.c - raylib/examples//_example_name.png From 068978d5b3a44d6bb9e3b0ee3492e3a7b83f0bde Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 14 Sep 2025 10:26:04 +0200 Subject: [PATCH 002/167] REXM: RENAME: example: `models_gpu_skinning` --> `models_animation_gpu_skinning` --- examples/Makefile | 2 +- examples/Makefile.Web | 4 +- examples/README.md | 2 +- examples/examples_list.txt | 2 +- ...ning.c => models_animation_gpu_skinning.c} | 240 ++-- ....png => models_animation_gpu_skinning.png} | Bin ... => models_animation_gpu_skinning.vcxproj} | 1136 ++++++++--------- projects/VS2022/raylib.sln | 2 +- 8 files changed, 694 insertions(+), 694 deletions(-) rename examples/models/{models_gpu_skinning.c => models_animation_gpu_skinning.c} (96%) rename examples/models/{models_gpu_skinning.png => models_animation_gpu_skinning.png} (100%) rename projects/VS2022/examples/{models_gpu_skinning.vcxproj => models_animation_gpu_skinning.vcxproj} (98%) diff --git a/examples/Makefile b/examples/Makefile index 0f5af45fa..366327ffe 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -611,7 +611,7 @@ MODELS = \ models/models_cubicmap_rendering \ models/models_first_person_maze \ models/models_geometric_shapes \ - models/models_gpu_skinning \ + models/models_animation_gpu_skinning \ models/models_heightmap_rendering \ models/models_loading \ models/models_loading_gltf \ diff --git a/examples/Makefile.Web b/examples/Makefile.Web index 943ddb42a..7aa216493 100644 --- a/examples/Makefile.Web +++ b/examples/Makefile.Web @@ -611,7 +611,7 @@ MODELS = \ models/models_cubicmap_rendering \ models/models_first_person_maze \ models/models_geometric_shapes \ - models/models_gpu_skinning \ + models/models_animation_gpu_skinning \ models/models_heightmap_rendering \ models/models_loading \ models/models_loading_gltf \ @@ -1063,7 +1063,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_gpu_skinning: models/models_gpu_skinning.c +models/models_animation_gpu_skinning: models/models_animation_gpu_skinning.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \ --preload-file models/resources/models/gltf/greenman.glb@resources/models/gltf/greenman.glb \ --preload-file models/resources/shaders/glsl100/skinning.vs@resources/shaders/glsl100/skinning.vs \ diff --git a/examples/README.md b/examples/README.md index 56cf8fb3e..1753a31bc 100644 --- a/examples/README.md +++ b/examples/README.md @@ -170,7 +170,7 @@ Examples using raylib models functionality, including models loading/generation | [models_heightmap_rendering](models/models_heightmap_rendering.c) | models_heightmap_rendering | ⭐☆☆☆ | 1.8 | 3.5 | [Ramon Santamaria](https://github.com/raysan5) | | [models_skybox_rendering](models/models_skybox_rendering.c) | models_skybox_rendering | ⭐⭐☆☆ | 1.8 | 4.0 | [Ramon Santamaria](https://github.com/raysan5) | | [models_textured_cube](models/models_textured_cube.c) | models_textured_cube | ⭐⭐☆☆ | 4.5 | 4.5 | [Ramon Santamaria](https://github.com/raysan5) | -| [models_gpu_skinning](models/models_gpu_skinning.c) | models_gpu_skinning | ⭐⭐⭐☆ | 4.5 | 4.5 | [Daniel Holden](https://github.com/orangeduck) | +| [models_animation_gpu_skinning](models/models_animation_gpu_skinning.c) | models_animation_gpu_skinning | ⭐⭐⭐☆ | 4.5 | 4.5 | [Daniel Holden](https://github.com/orangeduck) | | [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) | diff --git a/examples/examples_list.txt b/examples/examples_list.txt index ec00f3961..ead1bf220 100644 --- a/examples/examples_list.txt +++ b/examples/examples_list.txt @@ -124,7 +124,7 @@ models;models_waving_cubes;★★★☆;2.5;3.7;2019;2025;"Codecat";@codecat models;models_heightmap_rendering;★☆☆☆;1.8;3.5;2015;2025;"Ramon Santamaria";@raysan5 models;models_skybox_rendering;★★☆☆;1.8;4.0;2017;2025;"Ramon Santamaria";@raysan5 models;models_textured_cube;★★☆☆;4.5;4.5;2022;2025;"Ramon Santamaria";@raysan5 -models;models_gpu_skinning;★★★☆;4.5;4.5;2024;2025;"Daniel Holden";@orangeduck +models;models_animation_gpu_skinning;★★★☆;4.5;4.5;2024;2025;"Daniel Holden";@orangeduck 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 shaders;shaders_basic_lighting;★★★★;3.0;4.2;2019;2025;"Chris Camacho";@chriscamacho diff --git a/examples/models/models_gpu_skinning.c b/examples/models/models_animation_gpu_skinning.c similarity index 96% rename from examples/models/models_gpu_skinning.c rename to examples/models/models_animation_gpu_skinning.c index ac989aa60..337df931c 100644 --- a/examples/models/models_gpu_skinning.c +++ b/examples/models/models_animation_gpu_skinning.c @@ -1,121 +1,121 @@ -/******************************************************************************************* -* -* raylib [models] example - gpu skinning -* -* Example complexity rating: [★★★☆] 3/4 -* -* Example originally created with raylib 4.5, last time updated with raylib 4.5 -* -* Example contributed by Daniel Holden (@orangeduck) 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-2025 Daniel Holden (@orangeduck) -* -* Note: Due to limitations in the Apple OpenGL driver, this feature does not work on MacOS -* -********************************************************************************************/ - -#include "raylib.h" - -#include "raymath.h" - -#if defined(PLATFORM_DESKTOP) - #define GLSL_VERSION 330 -#else // PLATFORM_ANDROID, PLATFORM_WEB - #define GLSL_VERSION 100 -#endif - -//------------------------------------------------------------------------------------ -// Program main entry point -//------------------------------------------------------------------------------------ -int main(void) -{ - // Initialization - //-------------------------------------------------------------------------------------- - const int screenWidth = 800; - const int screenHeight = 450; - - InitWindow(screenWidth, screenHeight, "raylib [models] example - gpu skinning"); - - // Define the camera to look into our 3d world - Camera camera = { 0 }; - camera.position = (Vector3){ 5.0f, 5.0f, 5.0f }; // Camera position - camera.target = (Vector3){ 0.0f, 2.0f, 0.0f }; // Camera looking at point - camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Camera up vector (rotation towards target) - camera.fovy = 45.0f; // Camera field-of-view Y - camera.projection = CAMERA_PERSPECTIVE; // Camera projection type - - // Load gltf model - Model characterModel = LoadModel("resources/models/gltf/greenman.glb"); // Load character model - - // Load skinning shader - Shader skinningShader = LoadShader(TextFormat("resources/shaders/glsl%i/skinning.vs", GLSL_VERSION), - TextFormat("resources/shaders/glsl%i/skinning.fs", GLSL_VERSION)); - - characterModel.materials[1].shader = skinningShader; - - // Load gltf model animations - int animsCount = 0; - unsigned int animIndex = 0; - unsigned int animCurrentFrame = 0; - ModelAnimation *modelAnimations = LoadModelAnimations("resources/models/gltf/greenman.glb", &animsCount); - - Vector3 position = { 0.0f, 0.0f, 0.0f }; // Set model position - - DisableCursor(); // Limit cursor to relative movement inside the window - - 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 - //---------------------------------------------------------------------------------- - UpdateCamera(&camera, CAMERA_THIRD_PERSON); - - // Select current animation - if (IsKeyPressed(KEY_T)) animIndex = (animIndex + 1)%animsCount; - else if (IsKeyPressed(KEY_G)) animIndex = (animIndex + animsCount - 1)%animsCount; - - // Update model animation - ModelAnimation anim = modelAnimations[animIndex]; - animCurrentFrame = (animCurrentFrame + 1)%anim.frameCount; - characterModel.transform = MatrixTranslate(position.x, position.y, position.z); - UpdateModelAnimationBones(characterModel, anim, animCurrentFrame); - //---------------------------------------------------------------------------------- - - // Draw - //---------------------------------------------------------------------------------- - BeginDrawing(); - - ClearBackground(RAYWHITE); - - BeginMode3D(camera); - - // Draw character mesh, pose calculation is done in shader (GPU skinning) - DrawMesh(characterModel.meshes[0], characterModel.materials[1], characterModel.transform); - - DrawGrid(10, 1.0f); - - EndMode3D(); - - DrawText("Use the T/G to switch animation", 10, 10, 20, GRAY); - - EndDrawing(); - //---------------------------------------------------------------------------------- - } - - // De-Initialization - //-------------------------------------------------------------------------------------- - UnloadModelAnimations(modelAnimations, animsCount); // Unload model animation - UnloadModel(characterModel); // Unload model and meshes/material - UnloadShader(skinningShader); // Unload GPU skinning shader - - CloseWindow(); // Close window and OpenGL context - //-------------------------------------------------------------------------------------- - - return 0; +/******************************************************************************************* +* +* raylib [models] example - animation gpu skinning +* +* Example complexity rating: [★★★☆] 3/4 +* +* Example originally created with raylib 4.5, last time updated with raylib 4.5 +* +* Example contributed by Daniel Holden (@orangeduck) 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-2025 Daniel Holden (@orangeduck) +* +* Note: Due to limitations in the Apple OpenGL driver, this feature does not work on MacOS +* +********************************************************************************************/ + +#include "raylib.h" + +#include "raymath.h" + +#if defined(PLATFORM_DESKTOP) + #define GLSL_VERSION 330 +#else // PLATFORM_ANDROID, PLATFORM_WEB + #define GLSL_VERSION 100 +#endif + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [models] example - animation gpu skinning"); + + // Define the camera to look into our 3d world + Camera camera = { 0 }; + camera.position = (Vector3){ 5.0f, 5.0f, 5.0f }; // Camera position + camera.target = (Vector3){ 0.0f, 2.0f, 0.0f }; // Camera looking at point + camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Camera up vector (rotation towards target) + camera.fovy = 45.0f; // Camera field-of-view Y + camera.projection = CAMERA_PERSPECTIVE; // Camera projection type + + // Load gltf model + Model characterModel = LoadModel("resources/models/gltf/greenman.glb"); // Load character model + + // Load skinning shader + Shader skinningShader = LoadShader(TextFormat("resources/shaders/glsl%i/skinning.vs", GLSL_VERSION), + TextFormat("resources/shaders/glsl%i/skinning.fs", GLSL_VERSION)); + + characterModel.materials[1].shader = skinningShader; + + // Load gltf model animations + int animsCount = 0; + unsigned int animIndex = 0; + unsigned int animCurrentFrame = 0; + ModelAnimation *modelAnimations = LoadModelAnimations("resources/models/gltf/greenman.glb", &animsCount); + + Vector3 position = { 0.0f, 0.0f, 0.0f }; // Set model position + + DisableCursor(); // Limit cursor to relative movement inside the window + + 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 + //---------------------------------------------------------------------------------- + UpdateCamera(&camera, CAMERA_THIRD_PERSON); + + // Select current animation + if (IsKeyPressed(KEY_T)) animIndex = (animIndex + 1)%animsCount; + else if (IsKeyPressed(KEY_G)) animIndex = (animIndex + animsCount - 1)%animsCount; + + // Update model animation + ModelAnimation anim = modelAnimations[animIndex]; + animCurrentFrame = (animCurrentFrame + 1)%anim.frameCount; + characterModel.transform = MatrixTranslate(position.x, position.y, position.z); + UpdateModelAnimationBones(characterModel, anim, animCurrentFrame); + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + BeginMode3D(camera); + + // Draw character mesh, pose calculation is done in shader (GPU skinning) + DrawMesh(characterModel.meshes[0], characterModel.materials[1], characterModel.transform); + + DrawGrid(10, 1.0f); + + EndMode3D(); + + DrawText("Use the T/G to switch animation", 10, 10, 20, GRAY); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + UnloadModelAnimations(modelAnimations, animsCount); // Unload model animation + UnloadModel(characterModel); // Unload model and meshes/material + UnloadShader(skinningShader); // Unload GPU skinning shader + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; } \ No newline at end of file diff --git a/examples/models/models_gpu_skinning.png b/examples/models/models_animation_gpu_skinning.png similarity index 100% rename from examples/models/models_gpu_skinning.png rename to examples/models/models_animation_gpu_skinning.png diff --git a/projects/VS2022/examples/models_gpu_skinning.vcxproj b/projects/VS2022/examples/models_animation_gpu_skinning.vcxproj similarity index 98% rename from projects/VS2022/examples/models_gpu_skinning.vcxproj rename to projects/VS2022/examples/models_animation_gpu_skinning.vcxproj index 25b94488f..54cf73094 100644 --- a/projects/VS2022/examples/models_gpu_skinning.vcxproj +++ b/projects/VS2022/examples/models_animation_gpu_skinning.vcxproj @@ -1,569 +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 - - - - {8245DAD9-D402-4D5C-8F45-32229CD3B263} - Win32Proj - models_loading - 10.0 - models_gpu_skinning - - - - 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\models - WindowsLocalDebugger - - - $(SolutionDir)..\..\examples\models - WindowsLocalDebugger - - - $(SolutionDir)..\..\examples\models - WindowsLocalDebugger - - - $(SolutionDir)..\..\examples\models - WindowsLocalDebugger - - - $(SolutionDir)..\..\examples\models - WindowsLocalDebugger - - - $(SolutionDir)..\..\examples\models - WindowsLocalDebugger - - - $(SolutionDir)..\..\examples\models - WindowsLocalDebugger - - - $(SolutionDir)..\..\examples\models - WindowsLocalDebugger - - - $(SolutionDir)..\..\examples\models - WindowsLocalDebugger - - - $(SolutionDir)..\..\examples\models - WindowsLocalDebugger - - - $(SolutionDir)..\..\examples\models - WindowsLocalDebugger - - - $(SolutionDir)..\..\examples\models - 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} - - - - - + + + + + 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 + + + + {8245DAD9-D402-4D5C-8F45-32229CD3B263} + Win32Proj + models_loading + 10.0 + models_animation_gpu_skinning + + + + 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\models + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\models + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\models + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\models + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\models + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\models + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\models + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\models + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\models + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\models + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\models + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\models + 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 9fb624a20..fe2241434 100644 --- a/projects/VS2022/raylib.sln +++ b/projects/VS2022/raylib.sln @@ -299,7 +299,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_top_down_lights", "e EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_rectangle_advanced", "examples\shapes_rectangle_advanced.vcxproj", "{FAFEE2F9-24B0-4AF1-B512-433E9590033F}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "models_gpu_skinning", "examples\models_gpu_skinning.vcxproj", "{8245DAD9-D402-4D5C-8F45-32229CD3B263}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "models_animation_gpu_skinning", "examples\models_animation_gpu_skinning.vcxproj", "{8245DAD9-D402-4D5C-8F45-32229CD3B263}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shaders_shadowmap_rendering", "examples\shaders_shadowmap_rendering.vcxproj", "{41BBCC10-6FDE-48A1-B2E0-A0EC6A668629}" EndProject From ed8f1a22d139493410a9c3ac327d406dcb76565a Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 14 Sep 2025 18:07:58 +0200 Subject: [PATCH 003/167] Remove trailing spaces --- examples/core/core_input_gestures_testbed.c | 10 +- src/platforms/rcore_desktop_glfw.c | 6 +- src/platforms/rcore_web.c | 4 +- src/rcore.c | 8 +- src/rmodels.c | 8 +- src/rtext.c | 4 +- src/rtextures.c | 2 +- tools/rexm/rexm.c | 178 ++++++++++---------- 8 files changed, 110 insertions(+), 110 deletions(-) diff --git a/examples/core/core_input_gestures_testbed.c b/examples/core/core_input_gestures_testbed.c index 07b2ceece..055240801 100644 --- a/examples/core/core_input_gestures_testbed.c +++ b/examples/core/core_input_gestures_testbed.c @@ -39,7 +39,7 @@ int main(void) const int screenHeight = 450; InitWindow(screenWidth, screenHeight, "raylib [core] example - input gestures testbed"); - + Vector2 messagePosition = { 160, 7 }; // Last gesture variables definitions @@ -53,12 +53,12 @@ int main(void) int gestureLogIndex = GESTURE_LOG_SIZE; int previousGesture = 0; - // Log mode values: + // Log mode values: // - 0 shows repeated events // - 1 hides repeated events // - 2 shows repeated events but hide hold events // - 3 hides repeated events and hide hold events - int logMode = 1; + int logMode = 1; Color gestureColor = { 0, 0, 0, 255 }; Rectangle logButton1 = { 53, 7, 48, 26 }; @@ -88,7 +88,7 @@ int main(void) const int touchCount = GetTouchPointCount(); // Handle last gesture - if ((currentGesture != 0) && (currentGesture != 4) && (currentGesture != previousGesture)) + if ((currentGesture != 0) && (currentGesture != 4) && (currentGesture != previousGesture)) lastGesture = currentGesture; // Filter the meaningful gestures (1, 2, 8 to 512) for the display // Handle gesture log @@ -155,7 +155,7 @@ int main(void) float currentAngleRadians = ((currentAngleDegrees + 90.0f)*PI/180); // Convert the current angle to Radians // Calculate the final vector for display - finalVector = (Vector2){ (angleLength*sinf(currentAngleRadians)) + protractorPosition.x, + finalVector = (Vector2){ (angleLength*sinf(currentAngleRadians)) + protractorPosition.x, (angleLength*cosf(currentAngleRadians)) + protractorPosition.y }; // Handle touch and mouse pointer points diff --git a/src/platforms/rcore_desktop_glfw.c b/src/platforms/rcore_desktop_glfw.c index cfddf75b7..b719c698a 100644 --- a/src/platforms/rcore_desktop_glfw.c +++ b/src/platforms/rcore_desktop_glfw.c @@ -83,14 +83,14 @@ // Works as long as the current file consistently references any X11 Font as X11Font // Since it is never referenced (as of writing), this does not pose an issue #endif - + #if defined(_GLFW_WAYLAND) #define GLFW_EXPOSE_NATIVE_WAYLAND #endif - + #include "GLFW/glfw3native.h" // Include native header only once, regardless of how many backends are defined // Required for: glfwGetX11Window() and glfwGetWaylandWindow() - + #if defined(_GLFW_X11) // Clean up X11-specific hacks #undef Font // Revert hack and allow normal raylib Font usage #endif diff --git a/src/platforms/rcore_web.c b/src/platforms/rcore_web.c index a32f9c59a..9703a7bec 100644 --- a/src/platforms/rcore_web.c +++ b/src/platforms/rcore_web.c @@ -1495,8 +1495,8 @@ static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, i // WARNING: GLFW could return GLFW_REPEAT, we need to consider it as 1 // to work properly with our implementation (IsKeyDown/IsKeyUp checks) if (action == GLFW_RELEASE) CORE.Input.Keyboard.currentKeyState[key] = 0; - else if(action == GLFW_PRESS) CORE.Input.Keyboard.currentKeyState[key] = 1; - else if(action == GLFW_REPEAT) CORE.Input.Keyboard.keyRepeatInFrame[key] = 1; + else if (action == GLFW_PRESS) CORE.Input.Keyboard.currentKeyState[key] = 1; + else if (action == GLFW_REPEAT) CORE.Input.Keyboard.keyRepeatInFrame[key] = 1; // Check if there is space available in the key queue if ((CORE.Input.Keyboard.keyPressedQueueCount < MAX_KEY_PRESSED_QUEUE) && (action == GLFW_PRESS)) diff --git a/src/rcore.c b/src/rcore.c index 3455ff8c3..735851c8e 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -2565,14 +2565,14 @@ unsigned char *DecompressData(const unsigned char *compData, int compDataSize, i unsigned char *data0 = (unsigned char *)RL_CALLOC(MAX_DECOMPRESSION_SIZE*1024*1024, 1); int size = sinflate(data0, MAX_DECOMPRESSION_SIZE*1024*1024, compData, compDataSize); - // WARNING: RL_REALLOC can make (and leave) data copies in memory, + // WARNING: RL_REALLOC can make (and leave) data copies in memory, // that can be a security concern in case of compression of sensitive data // So, we use a second buffer to copy data manually, wiping original buffer memory data = (unsigned char *)RL_CALLOC(size, 1); memcpy(data, data0, size); memset(data0, 0, MAX_DECOMPRESSION_SIZE*1024*1024); // Wipe memory, is memset() safe? RL_FREE(data0); - + TRACELOG(LOG_INFO, "SYSTEM: Decompress data: Comp. size: %i -> Original size: %i", compDataSize, size); *dataSize = size; @@ -2689,7 +2689,7 @@ unsigned char *DecodeDataBase64(const char *text, int *outputSize) TRACELOG(LOG_WARNING, "BASE64: Decoding error: Output data size is too small"); break; } - + decodedData[outputCount + 0] = (octetPack >> 16) & 0xff; decodedData[outputCount + 1] = (octetPack >> 8) & 0xff; decodedData[outputCount + 2] = octetPack & 0xff; @@ -3018,7 +3018,7 @@ AutomationEventList LoadAutomationEventList(const char *fileName) char *result = fgets(buffer, 256, raeFile); if (result != buffer) TRACELOG(LOG_WARNING, "AUTOMATION: [%s] Issue reading line to buffer", fileName); - + while (!feof(raeFile)) { switch (buffer[0]) diff --git a/src/rmodels.c b/src/rmodels.c index 111df133b..128d5303b 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -1432,7 +1432,7 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform) else rlEnableStatePointer(GL_VERTEX_ARRAY, mesh.vertices); rlEnableStatePointer(GL_TEXTURE_COORD_ARRAY, mesh.texcoords); - + if (mesh.animNormals) rlEnableStatePointer(GL_NORMAL_ARRAY, mesh.animNormals); else rlEnableStatePointer(GL_NORMAL_ARRAY, mesh.normals); @@ -5536,7 +5536,7 @@ static Model LoadGLTF(const char *fileName) cgltf_accessor *attribute = mesh->primitives[p].attributes[j].data; // WARNING: SPECS: POSITION accessor MUST have its min and max properties defined - + if (model.meshes[meshIndex].vertices != NULL) TRACELOG(LOG_WARNING, "MODEL: [%s] Vertices attribute data already loaded", fileName); else { @@ -5882,7 +5882,7 @@ static Model LoadGLTF(const char *fileName) }; MatrixDecompose(worldMatrix, &(model.bindPose[i].translation), &(model.bindPose[i].rotation), &(model.bindPose[i].scale)); } - + if (data->skins_count > 1) TRACELOG(LOG_WARNING, "MODEL: [%s] can only load one skin (armature) per model, but gltf skins_count == %i", fileName, data->skins_count); } @@ -6578,7 +6578,7 @@ static Model LoadM3D(const char *fileName) if (k + 1 >= model.meshCount) { model.meshCount++; - + // Create a second buffer for mesh re-allocation Mesh *tempMeshes = (Mesh *)RL_CALLOC(model.meshCount, sizeof(Mesh)); memcpy(tempMeshes, model.meshes, (model.meshCount - 1)*sizeof(Mesh)); diff --git a/src/rtext.c b/src/rtext.c index 60c2c1f18..b8866f190 100644 --- a/src/rtext.c +++ b/src/rtext.c @@ -760,7 +760,7 @@ GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSiz // NOTE: For optimum results, bitmap font should be generated at base pixel size for (int p = 0; p < cpWidth*cpHeight; p++) { - if (((unsigned char *)glyphs[k].image.data)[p] < FONT_BITMAP_ALPHA_THRESHOLD) + if (((unsigned char *)glyphs[k].image.data)[p] < FONT_BITMAP_ALPHA_THRESHOLD) ((unsigned char *)glyphs[k].image.data)[p] = 0; else ((unsigned char *)glyphs[k].image.data)[p] = 255; } @@ -774,7 +774,7 @@ GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSiz // WARNING: Glyph not found on font, optionally use a fallback glyph } } - + if (glyphCounter < codepointCount) TRACELOG(LOG_WARNING, "FONT: Requested codepoints glyphs found: [%i/%i]", k, codepointCount); } else TRACELOG(LOG_WARNING, "FONT: Failed to process TTF font data"); diff --git a/src/rtextures.c b/src/rtextures.c index 18ee1af99..778c174fc 100644 --- a/src/rtextures.c +++ b/src/rtextures.c @@ -702,7 +702,7 @@ bool ExportImage(Image image, const char *fileName) result = SaveFileData(fileName, image.data, GetPixelDataSize(image.width, image.height, image.format)); } else TRACELOG(LOG_WARNING, "IMAGE: Export image format requested not supported"); - + if (allocatedData) RL_FREE(imgData); #endif // SUPPORT_IMAGE_EXPORT diff --git a/tools/rexm/rexm.c b/tools/rexm/rexm.c index 03b62e639..cbb04a07f 100644 --- a/tools/rexm/rexm.c +++ b/tools/rexm/rexm.c @@ -175,8 +175,8 @@ static void ClearExampleResources(char **resPaths); static int AddVSProjectToSolution(const char *slnFile, const char *projFile, const char *category); static int RemoveVSProjectFromSolution(const char *slnFile, const char *exName); -// Generate unique UUID v4 string -// Output format: {9A2F48CC-0DA8-47C0-884E-02E37F9BE6C1} +// Generate unique UUID v4 string +// Output format: {9A2F48CC-0DA8-47C0-884E-02E37F9BE6C1} static const char *GenerateUUIDv4(void); // Update source code header and comments metadata @@ -219,7 +219,7 @@ int main(int argc, char *argv[]) char exRename[64] = { 0 }; // Example re-name, without extension int opCode = OP_NONE; // Operation code: 0-None(Help), 1-Create, 2-Add, 3-Rename, 4-Remove - + /* // Testing code for UpdateSourceMetadata() rlExampleInfo test = { 0 }; @@ -263,8 +263,8 @@ int main(int argc, char *argv[]) char cat[12] = { 0 }; strncpy(cat, argv[2], catIndex); bool catFound = false; - for (int i = 0; i < REXM_MAX_EXAMPLE_CATEGORIES; i++) - { + for (int i = 0; i < REXM_MAX_EXAMPLE_CATEGORIES; i++) + { if (TextIsEqual(cat, exCategories[i])) { catFound = true; break; } } @@ -297,8 +297,8 @@ int main(int argc, char *argv[]) char cat[12] = { 0 }; strncpy(cat, GetFileName(argv[2]), catIndex); bool catFound = false; - for (int i = 0; i < REXM_MAX_EXAMPLE_CATEGORIES; i++) - { + for (int i = 0; i < REXM_MAX_EXAMPLE_CATEGORIES; i++) + { if (TextIsEqual(cat, exCategories[i])) { catFound = true; break; } } @@ -336,8 +336,8 @@ int main(int argc, char *argv[]) char cat[12] = { 0 }; strncpy(cat, argv[3], newCatIndex); bool newCatFound = false; - for (int i = 0; i < REXM_MAX_EXAMPLE_CATEGORIES; i++) - { + for (int i = 0; i < REXM_MAX_EXAMPLE_CATEGORIES; i++) + { if (TextIsEqual(cat, exCategories[i])) { newCatFound = true; break; } } @@ -423,7 +423,7 @@ int main(int argc, char *argv[]) char *exText = LoadFileText(exTemplateFilePath); char *exTextUpdated[6] = { 0 }; int exIndex = TextFindIndex(exText, "/****************"); - + // Update required info with some defaults exTextUpdated[0] = TextReplace(exText + exIndex, "", exCategory); exTextUpdated[1] = TextReplace(exTextUpdated[0], "", exName + strlen(exCategory) + 1); @@ -431,7 +431,7 @@ int main(int argc, char *argv[]) //TextReplace(newExample, "@", "@raysan5"); //TextReplace(newExample, "", 2025); //TextReplace(newExample, "", 2025); - + SaveFileText(TextFormat("%s/%s/%s.c", exBasePath, exCategory, exName), exTextUpdated[1]); for (int i = 0; i < 6; i++) { MemFree(exTextUpdated[i]); exTextUpdated[i] = NULL; } UnloadFileText(exText); @@ -444,10 +444,10 @@ int main(int argc, char *argv[]) // Create: raylib/examples//_example_name.png if (FileExists(TextFormat("%s/%s.png", GetDirectoryPath(inFileName), exName))) { - FileCopy(TextFormat("%s/%s.png", GetDirectoryPath(inFileName), exName), + FileCopy(TextFormat("%s/%s.png", GetDirectoryPath(inFileName), exName), TextFormat("%s/%s/%s.png", exBasePath, exCategory, exName)); } - else // No screenshot available next to source file + else // No screenshot available next to source file { // Copy screenshot template FileCopy(exTemplateScreenshot, TextFormat("%s/%s/%s.png", exBasePath, exCategory, exName)); @@ -456,7 +456,7 @@ int main(int argc, char *argv[]) // Copy: raylib/examples//resources/... // ----------------------------------------------------------------------------------------- // Scan resources used in example to copy - // NOTE: resources path will be relative to example source file directory + // NOTE: resources path will be relative to example source file directory int resPathCount = 0; char **resPaths = ScanExampleResources(TextFormat("%s/%s.c", GetDirectoryPath(inFileName), exName), &resPathCount); @@ -516,7 +516,7 @@ int main(int argc, char *argv[]) ClearExampleResources(resPaths); // ----------------------------------------------------------------------------------------- - + // Add example to the collection list, if not already there // NOTE: Required format: shapes;shapes_basic_shapes;★☆☆☆;1.0;4.2;2014;2025;"Ray";@raysan5 //------------------------------------------------------------------------------------------------ @@ -524,7 +524,7 @@ int main(int argc, char *argv[]) if (TextFindIndex(exCollectionList, exName) == -1) // Example not found { char *exCollectionListUpdated = (char *)RL_CALLOC(REXM_MAX_BUFFER_SIZE, 1); // Updated list copy, 2MB - + // Add example to the main list, by category // by default add it last in the category list // NOTE: When populating to other files, lists are sorted by name @@ -542,7 +542,7 @@ int main(int argc, char *argv[]) // NOTE: If no example info is provided (other than category/name), just using some default values rlExampleInfo *exInfo = LoadExampleInfo(TextFormat("%s/%s/%s.c", exBasePath, exCategory, exName)); - + // Get example difficulty stars text char starsText[16] = { 0 }; for (int i = 0; i < 4; i++) @@ -557,7 +557,7 @@ int main(int argc, char *argv[]) // Add example to collection at the EOF int endIndex = (int)strlen(exCollectionList); memcpy(exCollectionListUpdated, exCollectionList, endIndex); - sprintf(exCollectionListUpdated + endIndex, TextFormat("%s;%s;%s;%s;%s;%i;%i;\"%s\";@%s\n", + sprintf(exCollectionListUpdated + endIndex, TextFormat("%s;%s;%s;%s;%s;%i;%i;\"%s\";@%s\n", exInfo->category, exInfo->name, starsText, exInfo->verCreated, exInfo->verUpdated, exInfo->yearCreated, exInfo->yearReviewed, exInfo->author, exInfo->authorGitHub)); } else @@ -571,7 +571,7 @@ int main(int argc, char *argv[]) } UnloadExampleInfo(exInfo); - + SaveFileText(exCollectionFilePath, exCollectionListUpdated); RL_FREE(exCollectionListUpdated); } @@ -583,23 +583,23 @@ int main(int argc, char *argv[]) //------------------------------------------------------------------------------------------------ UpdateRequiredFiles(); //------------------------------------------------------------------------------------------------ - + // Create: raylib/projects/VS2022/examples/_example_name.vcxproj //------------------------------------------------------------------------------------------------ // WARNING: When adding new project a unique UUID should be assigned! FileCopy(TextFormat("%s/../projects/VS2022/examples/core_basic_window.vcxproj", exBasePath), TextFormat("%s/../projects/VS2022/examples/%s.vcxproj", exBasePath, exName)); - FileTextReplace(TextFormat("%s/../projects/VS2022/examples/%s.vcxproj", exBasePath, exName), + FileTextReplace(TextFormat("%s/../projects/VS2022/examples/%s.vcxproj", exBasePath, exName), "core_basic_window", exName); - FileTextReplace(TextFormat("%s/../projects/VS2022/examples/%s.vcxproj", exBasePath, exName), + FileTextReplace(TextFormat("%s/../projects/VS2022/examples/%s.vcxproj", exBasePath, exName), "..\\..\\examples\\core", TextFormat("..\\..\\examples\\%s", exCategory)); - + // Edit: raylib/projects/VS2022/raylib.sln --> Add new example project // WARNING: This function uses TextFormat() extensively inside, // we must store provided file paths because pointers will be overwriten // TODO: It seems projects are added to solution BUT not to required solution folder, // that process still requires to be done manually - AddVSProjectToSolution(exVSProjectSolutionFile, + AddVSProjectToSolution(exVSProjectSolutionFile, TextFormat("%s/../projects/VS2022/examples/%s.vcxproj", exBasePath, exName), exCategory); //------------------------------------------------------------------------------------------------ @@ -620,7 +620,7 @@ int main(int argc, char *argv[]) system(TextFormat("make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exCategory, exName)); #endif // Update generated .html metadata - UpdateWebMetadata(TextFormat("%s/%s/%s.html", exBasePath, exCategory, exName), + UpdateWebMetadata(TextFormat("%s/%s/%s.html", exBasePath, exCategory, exName), TextFormat("%s/%s/%s.c", exBasePath, exCategory, exName)); // Copy results to web side @@ -642,7 +642,7 @@ int main(int argc, char *argv[]) if (strcmp(exCategory, exRecategory) == 0) { // Rename example on collection - FileTextReplace(exCollectionFilePath, TextFormat("%s;%s", exCategory, exName), + FileTextReplace(exCollectionFilePath, TextFormat("%s;%s", exCategory, exName), TextFormat("%s;%s", exRecategory, exRename)); // Edit: Rename example code and screenshot files .c and .png @@ -656,7 +656,7 @@ int main(int argc, char *argv[]) rlExampleInfo *exList = LoadExamplesData(exCollectionFilePath, exCategory, false, &exListCount); for (int i = 0; i < exListCount; i++) { - if (strcmp(exList[i].name, exRename) == 0) + if (strcmp(exList[i].name, exRename) == 0) UpdateSourceMetadata(TextFormat("%s/%s/%s.c", exBasePath, exCategory, exRename), &exList[i]); } UnloadExamplesData(exList); @@ -668,7 +668,7 @@ int main(int argc, char *argv[]) FileTextReplace(TextFormat("%s/Makefile", exBasePath), exName, exRename); FileTextReplace(TextFormat("%s/Makefile.Web", exBasePath), exName, exRename); FileTextReplace(TextFormat("%s/README.md", exBasePath), exName, exRename); - FileTextReplace(TextFormat("%s/../common/examples.js", exWebPath), + FileTextReplace(TextFormat("%s/../common/examples.js", exWebPath), exName + strlen(exCategory) + 1, exRename + strlen(exRecategory) + 1); // Skip category // Edit: Rename example project and solution @@ -681,7 +681,7 @@ int main(int argc, char *argv[]) { // WARNING: Rename with change of category // TODO: Reorder collection to place renamed example at the end of category - FileTextReplace(exCollectionFilePath, TextFormat("%s;%s", exCategory, exName), + FileTextReplace(exCollectionFilePath, TextFormat("%s;%s", exCategory, exName), TextFormat("%s;%s", exRecategory, exRename)); // TODO: Move example resources from /resources to /resources @@ -715,7 +715,7 @@ int main(int argc, char *argv[]) system(TextFormat("make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exRecategory, exRename)); #endif // Update generated .html metadata - UpdateWebMetadata(TextFormat("%s/%s/%s.html", exBasePath, exCategory, exRename), + UpdateWebMetadata(TextFormat("%s/%s/%s.html", exBasePath, exCategory, exRename), TextFormat("%s/%s/%s.c", exBasePath, exCategory, exRename)); // Copy results to web side @@ -768,7 +768,7 @@ int main(int argc, char *argv[]) else LOG("WARNING: REMOVE: Example not found in the collection\n"); UnloadFileText(exCollectionList); //------------------------------------------------------------------------------------------------ - + // Remove: raylib/examples//resources/.. // WARNING: Some of those resources could be used by other examples, // just leave this process to manual update for now! @@ -807,16 +807,16 @@ int main(int argc, char *argv[]) // Remove: raylib/examples//_example_name.png FileRemove(TextFormat("%s/%s/%s.c", exBasePath, exCategory, exName)); FileRemove(TextFormat("%s/%s/%s.png", exBasePath, exCategory, exName)); - + // Edit: Update required files: Makefile, Makefile.Web, README.md, examples.js UpdateRequiredFiles(); - + // Remove: raylib/projects/VS2022/examples/_example_name.vcxproj FileRemove(TextFormat("%s/../projects/VS2022/examples/%s.vcxproj", exBasePath, exName)); // Edit: raylib/projects/VS2022/raylib.sln --> Remove example project RemoveVSProjectFromSolution(TextFormat("%s/../projects/VS2022/raylib.sln", exBasePath), exName); - + // Remove: raylib.com/examples//_example_name.html // Remove: raylib.com/examples//_example_name.data // Remove: raylib.com/examples//_example_name.wasm @@ -860,7 +860,7 @@ int main(int argc, char *argv[]) int exListLen = (int)strlen(exList); strcpy(exListUpdated, exList); - // Copy examples list into an update list + // Copy examples list into an update list // NOTE: Checking and removing duplicate entries int lineCount = 0; char **exListLines = LoadTextLines(exList, &lineCount); @@ -928,11 +928,11 @@ int main(int argc, char *argv[]) // Validate: raylib/examples//_example_name.png -> File exists? if (!FileExists(TextFormat("%s/%s/%s.png", exBasePath, exInfo->category, exInfo->name))) exInfo->status |= VALID_MISSING_PNG; - + // Validate: example screenshot is not the template default one Image imScreenshot = LoadImage(TextFormat("%s/%s/%s.png", exBasePath, exInfo->category, exInfo->name)); Image imTemplate = LoadImage(TextFormat("%s/examples_template.png", exBasePath)); - if (memcmp(imScreenshot.data, imTemplate.data, GetPixelDataSize(imScreenshot.width, imScreenshot.height, imScreenshot.format)) == 0) + if (memcmp(imScreenshot.data, imTemplate.data, GetPixelDataSize(imScreenshot.width, imScreenshot.height, imScreenshot.format)) == 0) exInfo->status |= VALID_INVALID_PNG; UnloadImage(imTemplate); UnloadImage(imScreenshot); @@ -945,7 +945,7 @@ int main(int argc, char *argv[]) // Validate: raylib/examples/README.md -> Example listed? if (FileTextFind(TextFormat("%s/README.md", exBasePath), exInfo->name) == -1) exInfo->status |= VALID_NOT_IN_README; - + // Validate: raylib.com/common/examples.js -> Example listed? if (FileTextFind(TextFormat("%s/../common/examples.js", exWebPath), exInfo->name + TextFindIndex(exInfo->name, "_") + 1) == -1) exInfo->status |= VALID_NOT_IN_JS; @@ -1025,10 +1025,10 @@ int main(int argc, char *argv[]) // NOTE: Additional validation elements // Validate: Example naming conventions: /_example_name, valid category - if ((TextFindIndex(exInfo->name, exInfo->category) == -1) || - (!TextIsEqual(exInfo->category, "core") && !TextIsEqual(exInfo->category, "shapes") && - !TextIsEqual(exInfo->category, "textures") && !TextIsEqual(exInfo->category, "text") && - !TextIsEqual(exInfo->category, "models") && !TextIsEqual(exInfo->category, "shaders") && + if ((TextFindIndex(exInfo->name, exInfo->category) == -1) || + (!TextIsEqual(exInfo->category, "core") && !TextIsEqual(exInfo->category, "shapes") && + !TextIsEqual(exInfo->category, "textures") && !TextIsEqual(exInfo->category, "text") && + !TextIsEqual(exInfo->category, "models") && !TextIsEqual(exInfo->category, "shaders") && !TextIsEqual(exInfo->category, "audio") && !TextIsEqual(exInfo->category, "others"))) exInfo->status |= VALID_INVALID_CATEGORY; // Validate: Example info (stars, author, github) missmatches with example header content @@ -1081,9 +1081,9 @@ int main(int argc, char *argv[]) { FileCopy(TextFormat("%s/../projects/VS2022/examples/core_basic_window.vcxproj", exBasePath), TextFormat("%s/../projects/VS2022/examples/%s.vcxproj", exBasePath, exInfo->name)); - FileTextReplace(TextFormat("%s/../projects/VS2022/examples/%s.vcxproj", exBasePath, exInfo->name), + FileTextReplace(TextFormat("%s/../projects/VS2022/examples/%s.vcxproj", exBasePath, exInfo->name), "core_basic_window", exInfo->name); - FileTextReplace(TextFormat("%s/../projects/VS2022/examples/%s.vcxproj", exBasePath, exInfo->name), + FileTextReplace(TextFormat("%s/../projects/VS2022/examples/%s.vcxproj", exBasePath, exInfo->name), "..\\..\\examples\\core", TextFormat("..\\..\\examples\\%s", exInfo->category)); exInfo->status &= ~VALID_MISSING_VCXPROJ; @@ -1092,7 +1092,7 @@ int main(int argc, char *argv[]) // Add project (.vcxproj) to raylib solution (.sln) if (exInfo->status & VALID_NOT_IN_VCXSOL) { - AddVSProjectToSolution(exVSProjectSolutionFile, + AddVSProjectToSolution(exVSProjectSolutionFile, TextFormat("%s/../projects/VS2022/examples/%s.vcxproj", exBasePath, exInfo->name), exInfo->category); exInfo->status &= ~VALID_NOT_IN_VCXSOL; @@ -1115,11 +1115,11 @@ int main(int argc, char *argv[]) #endif // Update generated .html metadata - UpdateWebMetadata(TextFormat("%s/%s/%s.html", exBasePath, exInfo->category, exInfo->name), + UpdateWebMetadata(TextFormat("%s/%s/%s.html", exBasePath, exInfo->category, exInfo->name), TextFormat("%s/%s/%s.c", exBasePath, exInfo->category, exInfo->name)); // Copy results to web side - FileCopy(TextFormat("%s/%s/%s.html", exBasePath, exInfo->category, exInfo->name), + FileCopy(TextFormat("%s/%s/%s.html", exBasePath, exInfo->category, exInfo->name), TextFormat("%s/%s/%s.html", exWebPath, exInfo->category, exInfo->name)); FileCopy(TextFormat("%s/%s/%s.data", exBasePath, exInfo->category, exInfo->name), TextFormat("%s/%s/%s.data", exWebPath, exInfo->category, exInfo->name)); @@ -1284,7 +1284,7 @@ int main(int argc, char *argv[]) UnloadExamplesData(exCollection); //------------------------------------------------------------------------------------------------ - + } break; case OP_BUILD: { @@ -1301,7 +1301,7 @@ int main(int argc, char *argv[]) //putenv("MAKE=mingw32-make"); //ChangeDirectory(exBasePath); system(TextFormat("mingw32-make -C %s %s/%s PLATFORM=PLATFORM_DESKTOP -B", exBasePath, exCategory, exName)); - #else + #else system(TextFormat("make -C %s %s/%s PLATFORM=PLATFORM_DESKTOP -B", exBasePath, exCategory, exName)); #endif @@ -1311,10 +1311,10 @@ int main(int argc, char *argv[]) system(TextFormat("mingw32-make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exCategory, exName)); #else system(TextFormat("make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exCategory, exName)); - #endif + #endif // Update generated .html metadata - UpdateWebMetadata(TextFormat("%s/%s/%s.html", exBasePath, exCategory, exName), + UpdateWebMetadata(TextFormat("%s/%s/%s.html", exBasePath, exCategory, exName), TextFormat("%s/%s/%s.c", exBasePath, exCategory, exName)); // Copy results to web side @@ -1384,7 +1384,7 @@ static int UpdateRequiredFiles(void) //------------------------------------------------------------------------------------------------ int exListCount = 0; rlExampleInfo *exList = LoadExamplesData(exCollectionFilePath, "ALL", true, &exListCount); - for (int i = 0; i < exListCount; i++) + for (int i = 0; i < exListCount; i++) { rlExampleInfo *info = &exList[i]; UpdateSourceMetadata(TextFormat("%s/%s/%s.c", exBasePath, info->category, info->name), info); @@ -1490,7 +1490,7 @@ static int UpdateRequiredFiles(void) --preload-file shaders/resources/shaders/glsl100/vertex_displacement.fs@resources/shaders/glsl100/vertex_displacement.fs \ --preload-file shaders/resources/shaders/glsl330/vertex_displacement.fs@resources/shaders/glsl330/vertex_displacement.fs */ - mkwIndex += sprintf(mkwTextUpdated + mkwListStartIndex + mkwIndex, + mkwIndex += sprintf(mkwTextUpdated + mkwListStartIndex + mkwIndex, TextFormat("%s/%s: %s/%s.c\n", exCollection[x].category, exCollection[x].name, exCollection[x].category, exCollection[x].name)); mkwIndex += sprintf(mkwTextUpdated + mkwListStartIndex + mkwIndex, " $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \\\n"); @@ -1525,7 +1525,7 @@ static int UpdateRequiredFiles(void) core/core_2d_camera: core/core_2d_camera.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) */ - mkwIndex += sprintf(mkwTextUpdated + mkwListStartIndex + mkwIndex, + mkwIndex += sprintf(mkwTextUpdated + mkwListStartIndex + mkwIndex, TextFormat("%s/%s: %s/%s.c\n", exCollection[x].category, exCollection[x].name, exCollection[x].category, exCollection[x].name)); mkwIndex += sprintf(mkwTextUpdated + mkwListStartIndex + mkwIndex, " $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)\n\n"); } @@ -1567,7 +1567,7 @@ static int UpdateRequiredFiles(void) for (int i = 0; i < REXM_MAX_EXAMPLE_CATEGORIES; i++) { int exCollectionCount = 0; - rlExampleInfo *exCollection = LoadExamplesData(exCollectionFilePath, exCategories[i], false, &exCollectionCount); + rlExampleInfo *exCollection = LoadExamplesData(exCollectionFilePath, exCategories[i], false, &exCollectionCount); // Every category includes some introductory text, as it is quite short, just copying it here if (i == 0) // "core" @@ -1633,7 +1633,7 @@ static int UpdateRequiredFiles(void) } mdIndex += sprintf(mdTextUpdated + mdListStartIndex + mdIndex, - TextFormat("| [%s](%s/%s.c) | \"%s\" | %s | %s | %s | [%s](https://github.com/%s) |\n", + TextFormat("| [%s](%s/%s.c) | \"%s\" | %s | %s | %s | [%s](https://github.com/%s) |\n", exCollection[x].name, exCollection[x].category, exCollection[x].name, exCollection[x].category, exCollection[x].name, exCollection[x].name, starsText, exCollection[x].verCreated, exCollection[x].verUpdated, exCollection[x].author, exCollection[x].authorGitHub)); } @@ -1672,7 +1672,7 @@ static int UpdateRequiredFiles(void) for (int i = 0; i < REXM_MAX_EXAMPLE_CATEGORIES - 1; i++) { int exCollectionCount = 0; - rlExampleInfo *exCollection = LoadExamplesData(exCollectionFilePath, exCategories[i], false, &exCollectionCount); + rlExampleInfo *exCollection = LoadExamplesData(exCollectionFilePath, exCategories[i], false, &exCollectionCount); for (int x = 0; x < exCollectionCount; x++) { for (int s = 0; s < 4; s++) @@ -1713,22 +1713,22 @@ static int UpdateRequiredFiles(void) static rlExampleInfo *LoadExamplesData(const char *fileName, const char *category, bool sort, int *exCount) { #define MAX_EXAMPLES_INFO 256 - + rlExampleInfo *exInfo = (rlExampleInfo *)RL_CALLOC(MAX_EXAMPLES_INFO, sizeof(rlExampleInfo)); int exCounter = 0; *exCount = 0; - + char *text = LoadFileText(fileName); - + if (text != NULL) { int lineCount = 0; char **lines = LoadTextLines(text, &lineCount); - + for (int i = 0; i < lineCount; i++) { // Basic validation for lines start categories - if ((lines[i][0] != '#') && + if ((lines[i][0] != '#') && ((lines[i][0] == 'c') || // core (lines[i][0] == 's') || // shapes, shaders (lines[i][0] == 't') || // textures, text @@ -1755,11 +1755,11 @@ static rlExampleInfo *LoadExamplesData(const char *fileName, const char *categor } } } - + UnloadTextLines(lines, lineCount); UnloadFileText(text); } - + // Sorting required if (sort) SortExampleByName(exInfo, exCounter); @@ -1785,7 +1785,7 @@ static int FileTextFind(const char *fileName, const char *find) UnloadFileText(fileText); } - return result; + return result; } // Replace text in an existing file @@ -1794,7 +1794,7 @@ static int FileTextReplace(const char *fileName, const char *textLookUp, const c int result = 0; char *fileText = NULL; char *fileTextUpdated = { 0 }; - + if (FileExists(fileName)) { fileText = LoadFileText(fileName); @@ -1814,12 +1814,12 @@ static int FileCopy(const char *srcPath, const char *dstPath) int result = 0; int srcDataSize = 0; unsigned char *srcFileData = LoadFileData(srcPath, &srcDataSize); - + // Create required paths if they do not exist if (!DirectoryExists(GetDirectoryPath(dstPath))) MakeDirectory(GetDirectoryPath(dstPath)); - if ((srcFileData != NULL) && (srcDataSize > 0)) + if ((srcFileData != NULL) && (srcDataSize > 0)) result = SaveFileData(dstPath, srcFileData, srcDataSize); UnloadFileData(srcFileData); @@ -1877,7 +1877,7 @@ static int FileMove(const char *srcPath, const char *dstPath) static rlExampleInfo *LoadExampleInfo(const char *exFileName) { rlExampleInfo *exInfo = (rlExampleInfo *)RL_CALLOC(1, sizeof(rlExampleInfo)); - + if (FileExists(exFileName) && IsFileExtension(exFileName, ".c")) { strcpy(exInfo->name, GetFileNameWithoutExt(exFileName)); @@ -1972,14 +1972,14 @@ static void UnloadExampleInfo(rlExampleInfo *exInfo) static int ParseExampleInfoLine(const char *line, rlExampleInfo *entry) { #define MAX_EXAMPLE_INFO_LINE_LEN 512 - + char temp[MAX_EXAMPLE_INFO_LINE_LEN] = { 0 }; strncpy(temp, line, MAX_EXAMPLE_INFO_LINE_LEN); temp[MAX_EXAMPLE_INFO_LINE_LEN - 1] = '\0'; // Ensure null termination - + int tokenCount = 0; char **tokens = TextSplit(line, ';', &tokenCount); - + if (tokenCount != 9) LOG("REXM: WARNING: Example collection line contains invalid number of tokens: %i\n", tokenCount); // Get category and name @@ -1989,10 +1989,10 @@ static int ParseExampleInfoLine(const char *line, rlExampleInfo *entry) // Parsing stars // NOTE: Counting the unicode char occurrences: ★ const char *starPtr = tokens[2]; - while (*starPtr) + while (*starPtr) { - if (((unsigned char)starPtr[0] == 0xe2) && - ((unsigned char)starPtr[1] == 0x98) && + if (((unsigned char)starPtr[0] == 0xe2) && + ((unsigned char)starPtr[1] == 0x98) && ((unsigned char)starPtr[2] == 0x85)) { entry->stars++; @@ -2009,7 +2009,7 @@ static int ParseExampleInfoLine(const char *line, rlExampleInfo *entry) entry->yearCreated = TextToInteger(tokens[5]); entry->yearReviewed = TextToInteger(tokens[6]); - // Get author and github + // Get author and github if (tokens[7][0] == '"') tokens[7] += 1; if (tokens[7][strlen(tokens[7]) - 1] == '"') tokens[7][strlen(tokens[7]) - 1] = '\0'; strcpy(entry->author, tokens[7]); @@ -2023,7 +2023,7 @@ static int rlExampleInfoCompare(const void *a, const void *b) { const rlExampleInfo *ex1 = (const rlExampleInfo *)a; const rlExampleInfo *ex2 = (const rlExampleInfo *)b; - + return strcmp(ex1->name, ex2->name); } @@ -2125,7 +2125,7 @@ static void ClearExampleResources(char **resPaths) } // Add VS project (.vcxproj) to existing VS solution (.sln) -// WARNING: Adding a .vcxproj to .sln can not be automated with: +// WARNING: Adding a .vcxproj to .sln can not be automated with: // - "dotnet" tool (C# projects only) // - "devenv" tool (no adding support, only building) // It must be done manually editing the .sln file @@ -2133,7 +2133,7 @@ static int AddVSProjectToSolution(const char *slnFile, const char *projFile, con { int result = 0; - // WARNING: Function uses extensively TextFormat(), + // WARNING: Function uses extensively TextFormat(), // *projFile ptr will be overwriten after a while // Generate unique UUID @@ -2160,7 +2160,7 @@ static int AddVSProjectToSolution(const char *slnFile, const char *projFile, con offsetIndex += prjStartIndex; offsetIndex += sprintf(slnTextUpdated + offsetIndex, "EndProject\n"); //---------------------------------------------------------------------------------------- - + // Update project config //---------------------------------------------------------------------------------------- // Find position to add project config: At the end of global section, same strategy as VS2022 "Add Project" @@ -2272,7 +2272,7 @@ static int RemoveVSProjectFromSolution(const char *slnFile, const char *exName) { // Found line with project --> get UUID strncpy(uuid, lines[i] + index + exNameLen*2 + 26, 36); - + // Skip copying line and also next one i++; } @@ -2292,8 +2292,8 @@ static int RemoveVSProjectFromSolution(const char *slnFile, const char *exName) return result; } -// Generate unique UUID v4 string -// Output format: {9A2F48CC-0DA8-47C0-884E-02E37F9BE6C1} +// Generate unique UUID v4 string +// Output format: {9A2F48CC-0DA8-47C0-884E-02E37F9BE6C1} static const char *GenerateUUIDv4(void) { static char uuid[38] = { 0 }; @@ -2339,7 +2339,7 @@ static void UpdateSourceMetadata(const char *exSrcPath, const rlExampleInfo *inf // Update example header title (line #3 - ALWAYS) // String: "* raylib [shaders] example - texture drawing" - exTextUpdated[0] = TextReplaceBetween(exTextUpdatedPtr, "* raylib [", "\n", + exTextUpdated[0] = TextReplaceBetween(exTextUpdatedPtr, "* raylib [", "\n", TextFormat("%s] example - %s", info->category, exNameFormated)); if (exTextUpdated[0] != NULL) exTextUpdatedPtr = exTextUpdated[0]; @@ -2359,7 +2359,7 @@ static void UpdateSourceMetadata(const char *exSrcPath, const rlExampleInfo *inf // Update example creation/update raylib versions // String: "* Example originally created with raylib 2.0, last time updated with raylib 3.7 - exTextUpdated[2] = TextReplaceBetween(exTextUpdatedPtr, "* Example originally created with raylib ", "\n", + exTextUpdated[2] = TextReplaceBetween(exTextUpdatedPtr, "* Example originally created with raylib ", "\n", TextFormat("%s, last time updated with raylib %s", info->verCreated, info->verUpdated)); if (exTextUpdated[2] != NULL) exTextUpdatedPtr = exTextUpdated[2]; @@ -2367,13 +2367,13 @@ static void UpdateSourceMetadata(const char *exSrcPath, const rlExampleInfo *inf // String: "* Copyright (c) 2019-2025 Contributor Name (@github_user) and Ramon Santamaria (@raysan5)" if (info->yearCreated == info->yearReviewed) { - exTextUpdated[3] = TextReplaceBetween(exTextUpdatedPtr, "Copyright (c) ", ")", + exTextUpdated[3] = TextReplaceBetween(exTextUpdatedPtr, "Copyright (c) ", ")", TextFormat("%i %s (@%s", info->yearCreated, info->author, info->authorGitHub)); if (exTextUpdated[3] != NULL) exTextUpdatedPtr = exTextUpdated[3]; } else { - exTextUpdated[3] = TextReplaceBetween(exTextUpdatedPtr, "Copyright (c) ", ")", + exTextUpdated[3] = TextReplaceBetween(exTextUpdatedPtr, "Copyright (c) ", ")", TextFormat("%i-%i %s (@%s", info->yearCreated, info->yearReviewed, info->author, info->authorGitHub)); if (exTextUpdated[3] != NULL) exTextUpdatedPtr = exTextUpdated[3]; } @@ -2387,10 +2387,10 @@ static void UpdateSourceMetadata(const char *exSrcPath, const rlExampleInfo *inf // Update contributors names // String: "* Example contributed by Contributor Name (@github_user) and reviewed by Ramon Santamaria (@raysan5)" // WARNING: Not all examples are contributed by someone, so the result of this replace can be NULL (string not found) - exTextUpdated[5] = TextReplaceBetween(exTextUpdatedPtr, "* Example contributed by ", ")", + exTextUpdated[5] = TextReplaceBetween(exTextUpdatedPtr, "* Example contributed by ", ")", TextFormat("%s (@%s", info->author, info->authorGitHub)); if (exTextUpdated[5] != NULL) exTextUpdatedPtr = exTextUpdated[5]; - + if (exTextUpdatedPtr != NULL) SaveFileText(exSourcePath, exTextUpdatedPtr); for (int i = 0; i < 6; i++) { MemFree(exTextUpdated[i]); exTextUpdated[i] = NULL; } From fbdf5e4fd2cb2ddd37d81e1c499797f3a2801ab5 Mon Sep 17 00:00:00 2001 From: Max Coplan Date: Tue, 16 Sep 2025 10:37:05 -0700 Subject: [PATCH 004/167] fix(rcore): correctly scale content on macOS (#5186) Currently, scaling doesn't work correctly on macOS (see #5185). This commit works around this issue by disabling SCALE_FRAMEBUFFER on macOS when `FLAG_WINDOW_HIGHDPI` is unset. --- src/platforms/rcore_desktop_glfw.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/platforms/rcore_desktop_glfw.c b/src/platforms/rcore_desktop_glfw.c index b719c698a..aacc456b5 100644 --- a/src/platforms/rcore_desktop_glfw.c +++ b/src/platforms/rcore_desktop_glfw.c @@ -1428,10 +1428,18 @@ int InitPlatform(void) // was enabled by default. Disabling it gets back the old behavior. A // complete fix will require removing a lot of CORE.Window.render // manipulation code - glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_FALSE); + // NOTE: This currently doesn't work on macOS(see #5185), so we skip it there + // when FLAG_WINDOW_HIGHDPI is *unset* +#if !defined(__APPLE__) + glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_FALSE); +#endif if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0) { + // since we skipped it before, now make sure to set this on macOS +#if defined(__APPLE__) + glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_FALSE); +#endif // Resize window content area based on the monitor content scale // NOTE: This hint only has an effect on platforms where screen coordinates and pixels always map 1:1 such as Windows and X11 // On platforms like macOS the resolution of the framebuffer is changed independently of the window size From a15651f4fe8c4a91a149eecb8ebe125d0cf60eba Mon Sep 17 00:00:00 2001 From: Peter0x44 Date: Wed, 17 Sep 2025 10:22:53 -0700 Subject: [PATCH 005/167] Restore projects/CMake/CMakeLists.txt (#5191) For some reason, #5181 deleted it. This project is intended to be a simple template to set up a project consuming raylib with CMake. --- projects/CMake/CMakeLists.txt | 41 +++++++++++++++ projects/CMake/README.md | 27 ++++++++++ projects/CMake/core_basic_window.c | 83 ++++++++++++++++++++++++++++++ 3 files changed, 151 insertions(+) create mode 100644 projects/CMake/CMakeLists.txt create mode 100644 projects/CMake/README.md create mode 100644 projects/CMake/core_basic_window.c diff --git a/projects/CMake/CMakeLists.txt b/projects/CMake/CMakeLists.txt new file mode 100644 index 000000000..56a5a5f51 --- /dev/null +++ b/projects/CMake/CMakeLists.txt @@ -0,0 +1,41 @@ +cmake_minimum_required(VERSION 3.11) # FetchContent is available in 3.11+ +project(example) + +# Generate compile_commands.json +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +# Dependencies +set(RAYLIB_VERSION 5.5) +find_package(raylib ${RAYLIB_VERSION} QUIET) # QUIET or REQUIRED +if (NOT raylib_FOUND) # If there's none, fetch and build raylib + include(FetchContent) + FetchContent_Declare( + raylib + DOWNLOAD_EXTRACT_TIMESTAMP OFF + URL https://github.com/raysan5/raylib/archive/refs/tags/${RAYLIB_VERSION}.tar.gz + ) + FetchContent_GetProperties(raylib) + if (NOT raylib_POPULATED) # Have we downloaded raylib yet? + set(FETCHCONTENT_QUIET NO) + FetchContent_MakeAvailable(raylib) + endif() +endif() + +# Our Project + +add_executable(${PROJECT_NAME} core_basic_window.c) +#set(raylib_VERBOSE 1) +target_link_libraries(${PROJECT_NAME} raylib) + +# Web Configurations +if (${PLATFORM} STREQUAL "Web") + set_target_properties(${PROJECT_NAME} PROPERTIES SUFFIX ".html") # Tell Emscripten to build an example.html file. + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s USE_GLFW=3 -s ASSERTIONS=1 -s WASM=1 -s ASYNCIFY -s GL_ENABLE_GET_PROC_ADDRESS=1") +endif() + +# Checks if OSX and links appropriate frameworks (Only required on MacOS) +if (APPLE) + target_link_libraries(${PROJECT_NAME} "-framework IOKit") + target_link_libraries(${PROJECT_NAME} "-framework Cocoa") + target_link_libraries(${PROJECT_NAME} "-framework OpenGL") +endif() diff --git a/projects/CMake/README.md b/projects/CMake/README.md new file mode 100644 index 000000000..fc4fe5542 --- /dev/null +++ b/projects/CMake/README.md @@ -0,0 +1,27 @@ +# raylib CMake Project + +This provides a base project template which builds with [CMake](https://cmake.org). + +## Usage + +To compile the example, use one of the following dependending on your build target... + +### Desktop + +Use the following to build for desktop: + +``` bash +cmake -B build +cmake --build build +``` + +### Web + +Compiling for the web requires the [Emscripten SDK](https://emscripten.org/docs/getting_started/downloads.html): + +``` bash +mkdir build +cd build +emcmake cmake .. -DPLATFORM=Web -DCMAKE_BUILD_TYPE=Release -DCMAKE_EXECUTABLE_SUFFIX=".html" +emmake make +``` diff --git a/projects/CMake/core_basic_window.c b/projects/CMake/core_basic_window.c new file mode 100644 index 000000000..cb23a6f87 --- /dev/null +++ b/projects/CMake/core_basic_window.c @@ -0,0 +1,83 @@ +/******************************************************************************************* +* +* raylib [core] example - Basic window (adapted for HTML5 platform) +* +* This example is prepared to compile for PLATFORM_WEB and PLATFORM_DESKTOP +* As you will notice, code structure is slightly different to the other examples... +* To compile it for PLATFORM_WEB just uncomment #define PLATFORM_WEB at beginning +* +* This example has been created using raylib 1.3 (www.raylib.com) +* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* +* Copyright (c) 2015 Ramon Santamaria (@raysan5) +* +********************************************************************************************/ + +#include "raylib.h" + +#if defined(PLATFORM_WEB) + #include +#endif + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +int screenWidth = 800; +int screenHeight = 450; + +//---------------------------------------------------------------------------------- +// Module Functions Declaration +//---------------------------------------------------------------------------------- +void UpdateDrawFrame(void); // Update and Draw one frame + +//---------------------------------------------------------------------------------- +// Program main entry point +//---------------------------------------------------------------------------------- +int main() +{ + // Initialization + //-------------------------------------------------------------------------------------- + InitWindow(screenWidth, screenHeight, "raylib [core] example - basic window"); + +#if defined(PLATFORM_WEB) + emscripten_set_main_loop(UpdateDrawFrame, 0, 1); +#else + SetTargetFPS(60); // Set our game to run at 60 frames-per-second + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + UpdateDrawFrame(); + } +#endif + + // De-Initialization + //-------------------------------------------------------------------------------------- + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} + +//---------------------------------------------------------------------------------- +// Module Functions Definition +//---------------------------------------------------------------------------------- +void UpdateDrawFrame(void) +{ + // Update + //---------------------------------------------------------------------------------- + // TODO: Update your variables here + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + DrawText("Congrats! You created your first window!", 190, 200, 20, LIGHTGRAY); + + EndDrawing(); + //---------------------------------------------------------------------------------- +} From 77297277524d4239034eb9fe7a09c82eb2965e5b Mon Sep 17 00:00:00 2001 From: Jeffery Myers Date: Wed, 17 Sep 2025 15:01:24 -0700 Subject: [PATCH 006/167] Use the render size not the screen size for screenshots so we use the actual framebuffer size. (#5192) --- src/rtextures.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/rtextures.c b/src/rtextures.c index 778c174fc..6366e4645 100644 --- a/src/rtextures.c +++ b/src/rtextures.c @@ -592,11 +592,10 @@ Image LoadImageFromTexture(Texture2D texture) // Load image from screen buffer and (screenshot) Image LoadImageFromScreen(void) { - Vector2 scale = GetWindowScaleDPI(); Image image = { 0 }; - image.width = (int)(GetScreenWidth()*scale.x); - image.height = (int)(GetScreenHeight()*scale.y); + image.width = (int)(GetRenderWidth()); + image.height = (int)(GetRenderHeight()); image.mipmaps = 1; image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; image.data = rlReadScreenPixels(image.width, image.height); From dc1632c17abd265dab5281846ec9a54050ec9333 Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 18 Sep 2025 15:28:03 +0200 Subject: [PATCH 007/167] REVIEWED: Platform code formatting and organization --- src/platforms/rcore_desktop_glfw.c | 72 +++++++++++----------- src/platforms/rcore_desktop_rgfw.c | 44 ++++++------- src/platforms/rcore_desktop_sdl.c | 99 ++++++++++++++---------------- src/platforms/rcore_drm.c | 3 +- src/platforms/rcore_web.c | 5 +- 5 files changed, 108 insertions(+), 115 deletions(-) diff --git a/src/platforms/rcore_desktop_glfw.c b/src/platforms/rcore_desktop_glfw.c index aacc456b5..cab497266 100644 --- a/src/platforms/rcore_desktop_glfw.c +++ b/src/platforms/rcore_desktop_glfw.c @@ -130,27 +130,29 @@ void ClosePlatform(void); // Close platform static void ErrorCallback(int error, const char *description); // GLFW3 Error Callback, runs on GLFW3 error // Window callbacks events -static void WindowSizeCallback(GLFWwindow *window, int width, int height); // GLFW3 WindowSize Callback, runs when window is resized -static void WindowPosCallback(GLFWwindow* window, int x, int y); // GLFW3 WindowPos Callback, runs when window is moved -static void WindowIconifyCallback(GLFWwindow *window, int iconified); // GLFW3 WindowIconify Callback, runs when window is minimized/restored -static void WindowMaximizeCallback(GLFWwindow* window, int maximized); // GLFW3 Window Maximize Callback, runs when window is maximized -static void WindowFocusCallback(GLFWwindow *window, int focused); // GLFW3 WindowFocus Callback, runs when window get/lose focus -static void WindowDropCallback(GLFWwindow *window, int count, const char **paths); // GLFW3 Window Drop Callback, runs when drop files into window -static void WindowContentScaleCallback(GLFWwindow *window, float scalex, float scaley); // GLFW3 Window Content Scale Callback, runs when window changes scale +static void WindowSizeCallback(GLFWwindow *window, int width, int height); // GLFW3 WindowSize Callback, runs when window is resized +static void WindowPosCallback(GLFWwindow* window, int x, int y); // GLFW3 WindowPos Callback, runs when window is moved +static void WindowIconifyCallback(GLFWwindow *window, int iconified); // GLFW3 WindowIconify Callback, runs when window is minimized/restored +static void WindowMaximizeCallback(GLFWwindow* window, int maximized); // GLFW3 Window Maximize Callback, runs when window is maximized +static void WindowFocusCallback(GLFWwindow *window, int focused); // GLFW3 WindowFocus Callback, runs when window get/lose focus +static void WindowDropCallback(GLFWwindow *window, int count, const char **paths); // GLFW3 Window Drop Callback, runs when drop files into window +static void WindowContentScaleCallback(GLFWwindow *window, float scalex, float scaley); // GLFW3 Window Content Scale Callback, runs when window changes scale // Input callbacks events -static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods); // GLFW3 Keyboard Callback, runs on key pressed -static void CharCallback(GLFWwindow *window, unsigned int codepoint); // GLFW3 Char Callback, runs on key pressed (get codepoint value) -static void MouseButtonCallback(GLFWwindow *window, int button, int action, int mods); // GLFW3 Mouse Button Callback, runs on mouse button pressed -static void MouseCursorPosCallback(GLFWwindow *window, double x, double y); // GLFW3 Cursor Position Callback, runs on mouse move -static void MouseScrollCallback(GLFWwindow *window, double xoffset, double yoffset); // GLFW3 Scrolling Callback, runs on mouse wheel -static void CursorEnterCallback(GLFWwindow *window, int enter); // GLFW3 Cursor Enter Callback, cursor enters client area -static void JoystickCallback(int jid, int event); // GLFW3 Joystick Connected/Disconnected Callback +static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods); // GLFW3 Keyboard Callback, runs on key pressed +static void CharCallback(GLFWwindow *window, unsigned int codepoint); // GLFW3 Char Callback, runs on key pressed (get codepoint value) +static void MouseButtonCallback(GLFWwindow *window, int button, int action, int mods); // GLFW3 Mouse Button Callback, runs on mouse button pressed +static void MouseCursorPosCallback(GLFWwindow *window, double x, double y); // GLFW3 Cursor Position Callback, runs on mouse move +static void MouseScrollCallback(GLFWwindow *window, double xoffset, double yoffset); // GLFW3 Scrolling Callback, runs on mouse wheel +static void CursorEnterCallback(GLFWwindow *window, int enter); // GLFW3 Cursor Enter Callback, cursor enters client area +static void JoystickCallback(int jid, int event); // GLFW3 Joystick Connected/Disconnected Callback -// Wrappers used by glfwInitAllocator -static void *AllocateWrapper(size_t size, void *user); // GLFW3 GLFWallocatefun, wrapps around RL_CALLOC macro -static void *ReallocateWrapper(void *block, size_t size, void *user); // GLFW3 GLFWreallocatefun, wrapps around RL_REALLOC macro -static void DeallocateWrapper(void *block, void *user); // GLFW3 GLFWdeallocatefun, wraps around RL_FREE macro +// Memory allocator wrappers [used by glfwInitAllocator()] +static void *AllocateWrapper(size_t size, void *user); // GLFW3 GLFWallocatefun, wrapps around RL_CALLOC macro +static void *ReallocateWrapper(void *block, size_t size, void *user); // GLFW3 GLFWreallocatefun, wrapps around RL_REALLOC macro +static void DeallocateWrapper(void *block, void *user); // GLFW3 GLFWdeallocatefun, wraps around RL_FREE macro + +static void SetDimensionsFromMonitor(GLFWmonitor *monitor); // Set screen dimensions from monitor/display dimensions //---------------------------------------------------------------------------------- // Module Functions Declaration @@ -435,7 +437,7 @@ void SetWindowState(unsigned int flags) // State change: FLAG_INTERLACED_HINT if (((CORE.Window.flags & FLAG_INTERLACED_HINT) != (flags & FLAG_INTERLACED_HINT)) && ((flags & FLAG_INTERLACED_HINT) > 0)) { - TRACELOG(LOG_WARNING, "RPI: Interlaced mode can only be configured before window initialization"); + TRACELOG(LOG_WARNING, "WINDOW: Interlaced mode can only be configured before window initialization"); } } @@ -993,7 +995,7 @@ Vector2 GetWindowPosition(void) // Get window scale DPI factor for current monitor Vector2 GetWindowScaleDPI(void) { - Vector2 scale = {0}; + Vector2 scale = { 0 }; glfwGetWindowContentScale(platform.handle, &scale.x, &scale.y); return scale; } @@ -1321,20 +1323,6 @@ void PollInputEvents(void) //---------------------------------------------------------------------------------- // Module Internal Functions Definition //---------------------------------------------------------------------------------- - -static void SetDimensionsFromMonitor(GLFWmonitor *monitor) -{ - const GLFWvidmode *mode = glfwGetVideoMode(monitor); - - // Default display resolution to that of the current mode - CORE.Window.display.width = mode->width; - CORE.Window.display.height = mode->height; - - // Set screen width/height to the display width/height if they are 0 - if (CORE.Window.screen.width == 0) CORE.Window.screen.width = CORE.Window.display.width; - if (CORE.Window.screen.height == 0) CORE.Window.screen.height = CORE.Window.display.height; -} - // Function wrappers around RL_*alloc macros, used by glfwInitAllocator() inside of InitPlatform() // We need to provide these because GLFWallocator expects function pointers with specific signatures // Similar wrappers exist in utils.c but we cannot reuse them here due to declaration mismatch @@ -1929,8 +1917,6 @@ static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, i // GLFW3 Char Callback, get unicode codepoint value static void CharCallback(GLFWwindow *window, unsigned int codepoint) { - //TRACELOG(LOG_DEBUG, "Char Callback: Codepoint: %i", codepoint); - // NOTE: Registers any key down considering OS keyboard layout but // does not detect action events, those should be managed by user... // Ref: https://github.com/glfw/glfw/issues/668#issuecomment-166794907 @@ -2041,6 +2027,20 @@ static void JoystickCallback(int jid, int event) } } +// Set screen dimensions from monitor/display dimensions +static void SetDimensionsFromMonitor(GLFWmonitor *monitor) +{ + const GLFWvidmode *mode = glfwGetVideoMode(monitor); + + // Default display resolution to that of the current mode + CORE.Window.display.width = mode->width; + CORE.Window.display.height = mode->height; + + // Set screen width/height to the display width/height if they are 0 + if (CORE.Window.screen.width == 0) CORE.Window.screen.width = CORE.Window.display.width; + if (CORE.Window.screen.height == 0) CORE.Window.screen.height = CORE.Window.display.height; +} + #ifdef _WIN32 # define WIN32_CLIPBOARD_IMPLEMENTATION # include "../external/win32_clipboard.h" diff --git a/src/platforms/rcore_desktop_rgfw.c b/src/platforms/rcore_desktop_rgfw.c index da1bded6d..f2e2a7407 100644 --- a/src/platforms/rcore_desktop_rgfw.c +++ b/src/platforms/rcore_desktop_rgfw.c @@ -240,12 +240,34 @@ static const unsigned short keyMappingRGFW[] = { [RGFW_scrollLock] = KEY_SCROLL_LOCK, }; +static int RGFW_gpConvTable[18] = { + [RGFW_gamepadY] = GAMEPAD_BUTTON_RIGHT_FACE_UP, + [RGFW_gamepadB] = GAMEPAD_BUTTON_RIGHT_FACE_RIGHT, + [RGFW_gamepadA] = GAMEPAD_BUTTON_RIGHT_FACE_DOWN, + [RGFW_gamepadX] = GAMEPAD_BUTTON_RIGHT_FACE_LEFT, + [RGFW_gamepadL1] = GAMEPAD_BUTTON_LEFT_TRIGGER_1, + [RGFW_gamepadR1] = GAMEPAD_BUTTON_RIGHT_TRIGGER_1, + [RGFW_gamepadL2] = GAMEPAD_BUTTON_LEFT_TRIGGER_2, + [RGFW_gamepadR2] = GAMEPAD_BUTTON_RIGHT_TRIGGER_2, + [RGFW_gamepadSelect] = GAMEPAD_BUTTON_MIDDLE_LEFT, + [RGFW_gamepadHome] = GAMEPAD_BUTTON_MIDDLE, + [RGFW_gamepadStart] = GAMEPAD_BUTTON_MIDDLE_RIGHT, + [RGFW_gamepadUp] = GAMEPAD_BUTTON_LEFT_FACE_UP, + [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_gamepadR3] = GAMEPAD_BUTTON_RIGHT_THUMB, +}; + //---------------------------------------------------------------------------------- // Module Internal Functions Declaration //---------------------------------------------------------------------------------- int InitPlatform(void); // Initialize platform (graphics, inputs and more) bool InitGraphicsDevice(void); // Initialize graphics device +static KeyboardKey ConvertScancodeToKey(u32 keycode); + //---------------------------------------------------------------------------------- // Module Functions Declaration //---------------------------------------------------------------------------------- @@ -897,28 +919,6 @@ const char *GetKeyName(int key) return ""; } -static KeyboardKey ConvertScancodeToKey(u32 keycode); - -int RGFW_gpConvTable[18] = { - [RGFW_gamepadY] = GAMEPAD_BUTTON_RIGHT_FACE_UP, - [RGFW_gamepadB] = GAMEPAD_BUTTON_RIGHT_FACE_RIGHT, - [RGFW_gamepadA] = GAMEPAD_BUTTON_RIGHT_FACE_DOWN, - [RGFW_gamepadX] = GAMEPAD_BUTTON_RIGHT_FACE_LEFT, - [RGFW_gamepadL1] = GAMEPAD_BUTTON_LEFT_TRIGGER_1, - [RGFW_gamepadR1] = GAMEPAD_BUTTON_RIGHT_TRIGGER_1, - [RGFW_gamepadL2] = GAMEPAD_BUTTON_LEFT_TRIGGER_2, - [RGFW_gamepadR2] = GAMEPAD_BUTTON_RIGHT_TRIGGER_2, - [RGFW_gamepadSelect] = GAMEPAD_BUTTON_MIDDLE_LEFT, - [RGFW_gamepadHome] = GAMEPAD_BUTTON_MIDDLE, - [RGFW_gamepadStart] = GAMEPAD_BUTTON_MIDDLE_RIGHT, - [RGFW_gamepadUp] = GAMEPAD_BUTTON_LEFT_FACE_UP, - [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_gamepadR3] = GAMEPAD_BUTTON_RIGHT_THUMB, -}; - // Register all input events void PollInputEvents(void) { diff --git a/src/platforms/rcore_desktop_sdl.c b/src/platforms/rcore_desktop_sdl.c index a0ddac075..71265e718 100644 --- a/src/platforms/rcore_desktop_sdl.c +++ b/src/platforms/rcore_desktop_sdl.c @@ -90,6 +90,8 @@ #endif #endif +#define SCANCODE_MAPPED_NUM 232 + //---------------------------------------------------------------------------------- // Types and Structures Definition //---------------------------------------------------------------------------------- @@ -110,10 +112,6 @@ extern CoreData CORE; // Global CORE state context static PlatformData platform = { 0 }; // Platform specific data -//---------------------------------------------------------------------------------- -// Global Variables Definition -//---------------------------------------------------------------------------------- -#define SCANCODE_MAPPED_NUM 232 static const KeyboardKey mapScancodeToKey[SCANCODE_MAPPED_NUM] = { KEY_NULL, // SDL_SCANCODE_UNKNOWN 0, @@ -321,7 +319,7 @@ Uint8 SDL_EventState(Uint32 type, int state) { case SDL_DISABLE: SDL_SetEventEnabled(type, false); break; case SDL_ENABLE: SDL_SetEventEnabled(type, true); break; - default: TRACELOG(LOG_WARNING, "Event sate: unknow type"); + default: TRACELOG(LOG_WARNING, "SDL: Event state of unknow type"); } return stateBefore; @@ -329,10 +327,10 @@ Uint8 SDL_EventState(Uint32 type, int state) void SDL_GetCurrentDisplayMode_Adapter(SDL_DisplayID displayID, SDL_DisplayMode* mode) { - const SDL_DisplayMode* currMode = SDL_GetCurrentDisplayMode(displayID); + const SDL_DisplayMode *currentMode = SDL_GetCurrentDisplayMode(displayID); - if (currMode == NULL) TRACELOG(LOG_WARNING, "No current display mode"); - else *mode = *currMode; + if (currentMode == NULL) TRACELOG(LOG_WARNING, "SDL: No possible to get current display mode"); + else *mode = *currentMode; } // SDL3 Migration: Renamed @@ -423,7 +421,7 @@ int SDL_GetNumTouchFingers(SDL_TouchID touchID) // SDL_GetClipboardData function is available since SDL 3.1.3. (e.g. SDL3) void *SDL_GetClipboardData(const char *mime_type, size_t *size) { - TRACELOG(LOG_WARNING, "Getting clipboard data that is not text is only available in SDL3"); + TRACELOG(LOG_WARNING, "SDL: Getting clipboard data that is not text not available in SDL2"); // We could possibly implement it ourselves in this case for some easier platforms return NULL; @@ -438,8 +436,8 @@ int InitPlatform(void); // Initialize platf void ClosePlatform(void); // Close platform static KeyboardKey ConvertScancodeToKey(SDL_Scancode sdlScancode); // Help convert SDL scancodes to raylib key - static int GetCodepointNextSDL(const char *text, int *codepointSize); // Get next codepoint in a byte sequence and bytes processed +static void UpdateTouchPointsSDL(SDL_TouchFingerEvent event); // Update CORE input touch point info from SDL touch data //---------------------------------------------------------------------------------- // Module Functions Declaration @@ -1307,41 +1305,6 @@ const char *GetKeyName(int key) return SDL_GetKeyName(key); } -static void UpdateTouchPointsSDL(SDL_TouchFingerEvent event) -{ -#if defined(USING_VERSION_SDL3) // SDL3 - int count = 0; - SDL_Finger **fingers = SDL_GetTouchFingers(event.touchID, &count); - CORE.Input.Touch.pointCount = count; - - for (int i = 0; i < CORE.Input.Touch.pointCount; i++) - { - SDL_Finger *finger = fingers[i]; - CORE.Input.Touch.pointId[i] = finger->id; - CORE.Input.Touch.position[i].x = finger->x*CORE.Window.screen.width; - CORE.Input.Touch.position[i].y = finger->y*CORE.Window.screen.height; - CORE.Input.Touch.currentTouchState[i] = 1; - } - - SDL_free(fingers); - -#else // SDL2 - - CORE.Input.Touch.pointCount = SDL_GetNumTouchFingers(event.touchId); - - for (int i = 0; i < CORE.Input.Touch.pointCount; i++) - { - SDL_Finger *finger = SDL_GetTouchFinger(event.touchId, i); - CORE.Input.Touch.pointId[i] = finger->id; - CORE.Input.Touch.position[i].x = finger->x*CORE.Window.screen.width; - CORE.Input.Touch.position[i].y = finger->y*CORE.Window.screen.height; - CORE.Input.Touch.currentTouchState[i] = 1; - } -#endif - - for (int i = CORE.Input.Touch.pointCount; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.currentTouchState[i] = 0; -} - // Register all input events void PollInputEvents(void) { @@ -1399,15 +1362,9 @@ void PollInputEvents(void) // Poll input events for current platform //----------------------------------------------------------------------------- - /* // WARNING: Indexes into this array are obtained by using SDL_Scancode values, not SDL_Keycode values - const Uint8 *keys = SDL_GetKeyboardState(NULL); - for (int i = 0; i < 256; ++i) - { - CORE.Input.Keyboard.currentKeyState[i] = keys[i]; - //if (keys[i]) TRACELOG(LOG_WARNING, "Pressed key: %i", i); - } - */ + //const Uint8 *keys = SDL_GetKeyboardState(NULL); + //for (int i = 0; i < 256; ++i) CORE.Input.Keyboard.currentKeyState[i] = keys[i]; CORE.Window.resizedLastFrame = false; @@ -2174,3 +2131,39 @@ static int GetCodepointNextSDL(const char *text, int *codepointSize) return codepoint; } + +// Update CORE input touch point info from SDL touch data +static void UpdateTouchPointsSDL(SDL_TouchFingerEvent event) +{ +#if defined(USING_VERSION_SDL3) // SDL3 + int count = 0; + SDL_Finger **fingers = SDL_GetTouchFingers(event.touchID, &count); + CORE.Input.Touch.pointCount = count; + + for (int i = 0; i < CORE.Input.Touch.pointCount; i++) + { + SDL_Finger *finger = fingers[i]; + CORE.Input.Touch.pointId[i] = finger->id; + CORE.Input.Touch.position[i].x = finger->x*CORE.Window.screen.width; + CORE.Input.Touch.position[i].y = finger->y*CORE.Window.screen.height; + CORE.Input.Touch.currentTouchState[i] = 1; + } + + SDL_free(fingers); + +#else // SDL2 + + CORE.Input.Touch.pointCount = SDL_GetNumTouchFingers(event.touchId); + + for (int i = 0; i < CORE.Input.Touch.pointCount; i++) + { + SDL_Finger *finger = SDL_GetTouchFinger(event.touchId, i); + CORE.Input.Touch.pointId[i] = finger->id; + CORE.Input.Touch.position[i].x = finger->x*CORE.Window.screen.width; + CORE.Input.Touch.position[i].y = finger->y*CORE.Window.screen.height; + CORE.Input.Touch.currentTouchState[i] = 1; + } +#endif + + for (int i = CORE.Input.Touch.pointCount; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.currentTouchState[i] = 0; +} diff --git a/src/platforms/rcore_drm.c b/src/platforms/rcore_drm.c index b15df2dea..a399092ad 100644 --- a/src/platforms/rcore_drm.c +++ b/src/platforms/rcore_drm.c @@ -245,6 +245,7 @@ static void RestoreKeyboard(void); // Restore keyboard system static void ProcessKeyboard(void); // Process keyboard events #endif +// Input management functions static void InitEvdevInput(void); // Initialize evdev inputs static void ConfigureEvdevDevice(char *device); // Identifies a input device and configures it for use if appropriate static void PollKeyboardEvents(void); // Process evdev keyboard events @@ -703,7 +704,7 @@ void SwapScreenBuffer() if (!crtcSet || !platform.gbmSurface) return; static int loopCnt = 0; - static int errCnt[5] = {0}; + static int errCnt[5] = { 0 }; loopCnt++; // Call this only, if pendingFlip is not set diff --git a/src/platforms/rcore_web.c b/src/platforms/rcore_web.c index 9703a7bec..c8fe0cfe7 100644 --- a/src/platforms/rcore_web.c +++ b/src/platforms/rcore_web.c @@ -1722,8 +1722,7 @@ static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent } #if defined(SUPPORT_GESTURES_SYSTEM) - GestureEvent gestureEvent = {0}; - + GestureEvent gestureEvent = { 0 }; gestureEvent.pointCount = CORE.Input.Touch.pointCount; // Register touch actions @@ -1852,7 +1851,7 @@ static EM_BOOL EmscriptenVisibilityChangeCallback(int eventType, const Emscripte //------------------------------------------------------------------------------------------------------- // JS: Get the canvas id provided by the module configuration -EM_JS(char*, GetCanvasIdJs, (), { +EM_JS(char *, GetCanvasIdJs, (), { var canvasId = "#" + Module.canvas.id; var lengthBytes = lengthBytesUTF8(canvasId) + 1; var stringOnWasmHeap = _malloc(lengthBytes); From bd6065a4fd20f329f9a638e8550f66ccd800853b Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 18 Sep 2025 15:29:13 +0200 Subject: [PATCH 008/167] Update rlgl.h --- src/rlgl.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rlgl.h b/src/rlgl.h index 9038e2a48..e58302ceb 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -2474,7 +2474,7 @@ void rlLoadExtensions(void *loader) } // Check instanced rendering support - if (strstr(extList[i], (const char*)"instanced_arrays") != NULL) // Broad check for instanced_arrays + if (strstr(extList[i], (const char *)"instanced_arrays") != NULL) // Broad check for instanced_arrays { // Specific check if (strcmp(extList[i], (const char *)"GL_ANGLE_instanced_arrays") == 0) // ANGLE @@ -2507,7 +2507,7 @@ void rlLoadExtensions(void *loader) glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawArraysInstancedEXT"); glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawElementsInstancedEXT"); } - else if (strcmp(extList[i], (const char*)"GL_NV_draw_instanced") == 0) + else if (strcmp(extList[i], (const char *)"GL_NV_draw_instanced") == 0) { glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawArraysInstancedNV"); glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawElementsInstancedNV"); From c264c86ee0a6334f3ac5fa3b6e9df5f76a973b1e Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 18 Sep 2025 15:34:09 +0200 Subject: [PATCH 009/167] ADDED: Some useful functions for Files and Text management // File management functions - int FileRename(const char *fileName, const char *fileRename); // Rename file (if exists) - iint FileRemove(const char *fileName); // Remove file (if exists) - iint FileCopy(const char *srcPath, const char *dstPath); // Copy file from one path to another, dstPath created if it doesn't exist - iint FileMove(const char *srcPath, const char *dstPath); // Move file from one directory to another, dstPath created if it doesn't exist - int FileTextReplace(const char *fileName, const char *search, const char *replacement); // Replace text in an existing file - iint FileTextFindIndex(const char *fileName, const char *search); // Find text in existing file // Text management functions - const char *TextRemoveSpaces(const char *text); // Remove text spaces, concat words - char *GetTextBetween(const char *text, const char *begin, const char *end); // Get text between two strings - char *TextReplace(const char *text, const char *search, const char *replacement); // Replace text string (WARNING: memory must be freed!) - char *TextReplaceBetween(const char *text, const char *begin, const char *end, const char *replacement); // Replace text between two specific strings (WARNING: memory must be freed!) --- src/raylib.h | 77 ++++++++++++++------------ src/rcore.c | 149 ++++++++++++++++++++++++++++++++++++++++++++------- src/rtext.c | 130 +++++++++++++++++++++++++++++++++++--------- 3 files changed, 278 insertions(+), 78 deletions(-) diff --git a/src/raylib.h b/src/raylib.h index 5635546e0..642f9318c 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1110,45 +1110,51 @@ RLAPI void MemFree(void *ptr); // Internal me // Set custom callbacks // WARNING: Callbacks setup is intended for advanced users -RLAPI void SetTraceLogCallback(TraceLogCallback callback); // Set custom trace log -RLAPI void SetLoadFileDataCallback(LoadFileDataCallback callback); // Set custom file binary data loader -RLAPI void SetSaveFileDataCallback(SaveFileDataCallback callback); // Set custom file binary data saver -RLAPI void SetLoadFileTextCallback(LoadFileTextCallback callback); // Set custom file text data loader -RLAPI void SetSaveFileTextCallback(SaveFileTextCallback callback); // Set custom file text data saver +RLAPI void SetTraceLogCallback(TraceLogCallback callback); // Set custom trace log +RLAPI void SetLoadFileDataCallback(LoadFileDataCallback callback); // Set custom file binary data loader +RLAPI void SetSaveFileDataCallback(SaveFileDataCallback callback); // Set custom file binary data saver +RLAPI void SetLoadFileTextCallback(LoadFileTextCallback callback); // Set custom file text data loader +RLAPI void SetSaveFileTextCallback(SaveFileTextCallback callback); // Set custom file text data saver // Files management functions RLAPI unsigned char *LoadFileData(const char *fileName, int *dataSize); // Load file data as byte array (read) -RLAPI void UnloadFileData(unsigned char *data); // Unload file data allocated by LoadFileData() +RLAPI void UnloadFileData(unsigned char *data); // Unload file data allocated by LoadFileData() RLAPI bool SaveFileData(const char *fileName, void *data, int dataSize); // Save data to file from byte array (write), returns true on success RLAPI bool ExportDataAsCode(const unsigned char *data, int dataSize, const char *fileName); // Export data to code (.h), returns true on success -RLAPI char *LoadFileText(const char *fileName); // Load text data from file (read), returns a '\0' terminated string -RLAPI void UnloadFileText(char *text); // Unload file text data allocated by LoadFileText() -RLAPI bool SaveFileText(const char *fileName, const char *text); // Save text data to file (write), string must be '\0' terminated, returns true on success +RLAPI char *LoadFileText(const char *fileName); // Load text data from file (read), returns a '\0' terminated string +RLAPI void UnloadFileText(char *text); // Unload file text data allocated by LoadFileText() +RLAPI bool SaveFileText(const char *fileName, const char *text); // Save text data to file (write), string must be '\0' terminated, returns true on success //------------------------------------------------------------------ // File system functions -RLAPI bool FileExists(const char *fileName); // Check if file exists -RLAPI bool DirectoryExists(const char *dirPath); // Check if a directory path exists -RLAPI bool IsFileExtension(const char *fileName, const char *ext); // Check file extension (recommended include point: .png, .wav) -RLAPI int GetFileLength(const char *fileName); // Get file length in bytes (NOTE: GetFileSize() conflicts with windows.h) -RLAPI const char *GetFileExtension(const char *fileName); // Get pointer to extension for a filename string (includes dot: '.png') -RLAPI const char *GetFileName(const char *filePath); // Get pointer to filename for a path string -RLAPI const char *GetFileNameWithoutExt(const char *filePath); // Get filename string without extension (uses static string) -RLAPI const char *GetDirectoryPath(const char *filePath); // Get full path for a given fileName with path (uses static string) -RLAPI const char *GetPrevDirectoryPath(const char *dirPath); // Get previous directory path for a given path (uses static string) -RLAPI const char *GetWorkingDirectory(void); // Get current working directory (uses static string) -RLAPI const char *GetApplicationDirectory(void); // Get the directory of the running application (uses static string) -RLAPI int MakeDirectory(const char *dirPath); // Create directories (including full path requested), returns 0 on success -RLAPI bool ChangeDirectory(const char *dir); // Change working directory, return true on success -RLAPI bool IsPathFile(const char *path); // Check if a given path is a file or a directory -RLAPI bool IsFileNameValid(const char *fileName); // Check if fileName is valid for the platform/OS -RLAPI FilePathList LoadDirectoryFiles(const char *dirPath); // Load directory filepaths +RLAPI int FileRename(const char *fileName, const char *fileRename); // Rename file (if exists) +RLAPI int FileRemove(const char *fileName); // Remove file (if exists) +RLAPI int FileCopy(const char *srcPath, const char *dstPath); // Copy file from one path to another, dstPath created if it doesn't exist +RLAPI int FileMove(const char *srcPath, const char *dstPath); // Move file from one directory to another, dstPath created if it doesn't exist +RLAPI int FileTextReplace(const char *fileName, const char *search, const char *replacement); // Replace text in an existing file +RLAPI int FileTextFindIndex(const char *fileName, const char *search); // Find text in existing file +RLAPI bool FileExists(const char *fileName); // Check if file exists +RLAPI bool DirectoryExists(const char *dirPath); // Check if a directory path exists +RLAPI bool IsFileExtension(const char *fileName, const char *ext); // Check file extension (recommended include point: .png, .wav) +RLAPI int GetFileLength(const char *fileName); // Get file length in bytes (NOTE: GetFileSize() conflicts with windows.h) +RLAPI long GetFileModTime(const char *fileName); // Get file modification time (last write time) +RLAPI const char *GetFileExtension(const char *fileName); // Get pointer to extension for a filename string (includes dot: '.png') +RLAPI const char *GetFileName(const char *filePath); // Get pointer to filename for a path string +RLAPI const char *GetFileNameWithoutExt(const char *filePath); // Get filename string without extension (uses static string) +RLAPI const char *GetDirectoryPath(const char *filePath); // Get full path for a given fileName with path (uses static string) +RLAPI const char *GetPrevDirectoryPath(const char *dirPath); // Get previous directory path for a given path (uses static string) +RLAPI const char *GetWorkingDirectory(void); // Get current working directory (uses static string) +RLAPI const char *GetApplicationDirectory(void); // Get the directory of the running application (uses static string) +RLAPI int MakeDirectory(const char *dirPath); // Create directories (including full path requested), returns 0 on success +RLAPI bool ChangeDirectory(const char *dir); // Change working directory, return true on success +RLAPI bool IsPathFile(const char *path); // Check if a given path is a file or a directory +RLAPI bool IsFileNameValid(const char *fileName); // Check if fileName is valid for the platform/OS +RLAPI FilePathList LoadDirectoryFiles(const char *dirPath); // Load directory filepaths RLAPI FilePathList LoadDirectoryFilesEx(const char *basePath, const char *filter, bool scanSubdirs); // Load directory filepaths with extension filtering and recursive directory scan. Use 'DIR' in the filter string to include directories in the result -RLAPI void UnloadDirectoryFiles(FilePathList files); // Unload filepaths -RLAPI bool IsFileDropped(void); // Check if a file has been dropped into window -RLAPI FilePathList LoadDroppedFiles(void); // Load dropped filepaths -RLAPI void UnloadDroppedFiles(FilePathList files); // Unload dropped filepaths -RLAPI long GetFileModTime(const char *fileName); // Get file modification time (last write time) +RLAPI void UnloadDirectoryFiles(FilePathList files); // Unload filepaths +RLAPI bool IsFileDropped(void); // Check if a file has been dropped into window +RLAPI FilePathList LoadDroppedFiles(void); // Load dropped filepaths +RLAPI void UnloadDroppedFiles(FilePathList files); // Unload dropped filepaths // Compression/Encoding functionality RLAPI unsigned char *CompressData(const unsigned char *data, int dataSize, int *compDataSize); // Compress data (DEFLATE algorithm), memory must be MemFree() @@ -1504,7 +1510,7 @@ RLAPI int GetCodepointPrevious(const char *text, int *codepointSize); RLAPI const char *CodepointToUTF8(int codepoint, int *utf8Size); // Encode one codepoint into UTF-8 byte array (array length returned as parameter) // Text strings management functions (no UTF-8 strings, only byte chars) -// WARNING 1: Most of these functions use internal static buffers, it's recommended to store returned data on user-side for re-use +// WARNING 1: Most of these functions use internal static buffers[], it's recommended to store returned data on user-side for re-use // WARNING 2: Some strings allocate memory internally for the returned strings, those strings must be free by user using MemFree() RLAPI char **LoadTextLines(const char *text, int *count); // Load text as separate lines ('\n') RLAPI void UnloadTextLines(char **text, int lineCount); // Unload text lines @@ -1513,12 +1519,15 @@ RLAPI bool TextIsEqual(const char *text1, const char *text2); RLAPI unsigned int TextLength(const char *text); // Get text length, checks for '\0' ending RLAPI const char *TextFormat(const char *text, ...); // Text formatting with variables (sprintf() style) RLAPI const char *TextSubtext(const char *text, int position, int length); // Get a piece of a text string -RLAPI char *TextReplace(const char *text, const char *replace, const char *by); // Replace text string (WARNING: memory must be freed!) +RLAPI const char *TextRemoveSpaces(const char *text); // Remove text spaces, concat words +RLAPI char *GetTextBetween(const char *text, const char *begin, const char *end); // Get text between two strings +RLAPI char *TextReplace(const char *text, const char *search, const char *replacement); // Replace text string (WARNING: memory must be freed!) +RLAPI char *TextReplaceBetween(const char *text, const char *begin, const char *end, const char *replacement); // Replace text between two specific strings (WARNING: memory must be freed!) RLAPI char *TextInsert(const char *text, const char *insert, int position); // Insert text in a position (WARNING: memory must be freed!) RLAPI char *TextJoin(char **textList, int count, const char *delimiter); // Join text strings with delimiter RLAPI char **TextSplit(const char *text, char delimiter, int *count); // Split text into multiple strings, using MAX_TEXTSPLIT_COUNT static strings -RLAPI void TextAppend(char *text, const char *append, int *position); // Append text at specific position and move cursor! -RLAPI int TextFindIndex(const char *text, const char *find); // Find first text occurrence within a string, -1 if not found +RLAPI void TextAppend(char *text, const char *append, int *position); // Append text at specific position and move cursor +RLAPI int TextFindIndex(const char *text, const char *search); // Find first text occurrence within a string, -1 if not found RLAPI char *TextToUpper(const char *text); // Get upper case version of provided string RLAPI char *TextToLower(const char *text); // Get lower case version of provided string RLAPI char *TextToPascal(const char *text); // Get Pascal case notation version of provided string diff --git a/src/rcore.c b/src/rcore.c index 735851c8e..7a17d7f6f 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -1927,6 +1927,115 @@ void SetConfigFlags(unsigned int flags) // Module Functions Definition: File system //---------------------------------------------------------------------------------- +// Rename file (if exists) +// NOTE: Only rename file name required, not full path +int FileRename(const char *fileName, const char *fileRename) +{ + int result = 0; + + if (FileExists(fileName)) + { + result = rename(fileName, fileRename); + } + else result = -1; + + return result; +} + +// Remove file (if exists) +int FileRemove(const char *fileName) +{ + int result = 0; + + if (FileExists(fileName)) + { + result = remove(fileName); + } + else result = -1; + + return result; +} + +// Copy file from one path to another +// NOTE: If destination path does not exist, it is created! +int FileCopy(const char *srcPath, const char *dstPath) +{ + int result = 0; + int srcDataSize = 0; + unsigned char *srcFileData = LoadFileData(srcPath, &srcDataSize); + + // Create required paths if they do not exist + if (!DirectoryExists(GetDirectoryPath(dstPath))) + result = MakeDirectory(GetDirectoryPath(dstPath)); + + if (result == 0) // Directory created successfully (or already exists) + { + if ((srcFileData != NULL) && (srcDataSize > 0)) + result = SaveFileData(dstPath, srcFileData, srcDataSize); + } + + UnloadFileData(srcFileData); + + return result; +} + +// Move file from one directory to another +// NOTE: If dst directories do not exists they are created +int FileMove(const char *srcPath, const char *dstPath) +{ + int result = 0; + + if (FileExists(srcPath)) + { + FileCopy(srcPath, dstPath); + FileRemove(srcPath); + } + else result = -1; + + return result; +} + +// Replace text in an existing file +// WARNING: DEPENDENCY: [rtext] module +int FileTextReplace(const char *fileName, const char *search, const char *replacement) +{ + int result = 0; + char *fileText = NULL; + char *fileTextUpdated = { 0 }; + +#if defined(SUPPORT_MODULE_RTEXT) + if (FileExists(fileName)) + { + fileText = LoadFileText(fileName); + fileTextUpdated = TextReplace(fileText, search, replacement); + result = SaveFileText(fileName, fileTextUpdated); + MemFree(fileTextUpdated); + UnloadFileText(fileText); + } +#else + TRACELOG(LOG_WARNING, "FILE: File text replace requires [rtext] module"); +#endif + + return result; +} + +// Find text index position in existing file +// WARNING: DEPENDENCY: [rtext] module +int FileTextFindIndex(const char *fileName, const char *search) +{ + int result = -1; + + if (FileExists(fileName)) + { + char *fileText = LoadFileText(fileName); + char *ptr = strstr(fileText, search); + if (ptr != NULL) result = (int)(ptr - fileText); + UnloadFileText(fileText); + } + + return result; +} + // Check if the file exists bool FileExists(const char *fileName) { @@ -2054,6 +2163,21 @@ int GetFileLength(const char *fileName) return size; } +// Get file modification time (last write time) +long GetFileModTime(const char *fileName) +{ + struct stat result = { 0 }; + long modTime = 0; + + if (stat(fileName, &result) == 0) + { + time_t mod = result.st_mtime; + modTime = (long)mod; + } + + return modTime; +} + // Get pointer to extension for a filename string (includes the dot: .png) // WARNING: We just get the ptr but not the extension as a separate string const char *GetFileExtension(const char *fileName) @@ -2367,7 +2491,7 @@ void UnloadDirectoryFiles(FilePathList files) // Create directories (including full path requested), returns 0 on success int MakeDirectory(const char *dirPath) { - if ((dirPath == NULL) || (dirPath[0] == '\0')) return 1; // Path is not valid + if ((dirPath == NULL) || (dirPath[0] == '\0')) return -1; // Path is not valid if (DirectoryExists(dirPath)) return 0; // Path already exists (is valid) // Copy path string to avoid modifying original @@ -2392,8 +2516,11 @@ 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; return 0; } @@ -2513,22 +2640,6 @@ void UnloadDroppedFiles(FilePathList files) } } -// Get file modification time (last write time) -long GetFileModTime(const char *fileName) -{ - struct stat result = { 0 }; - long modTime = 0; - - if (stat(fileName, &result) == 0) - { - time_t mod = result.st_mtime; - - modTime = (long)mod; - } - - return modTime; -} - //---------------------------------------------------------------------------------- // Module Functions Definition: Compression and Encoding //---------------------------------------------------------------------------------- @@ -2903,7 +3014,7 @@ unsigned int *ComputeSHA1(unsigned char *data, int dataSize) for (int offset = 0; offset < newDataSize; offset += (512/8)) { // Break chunk into sixteen 32-bit words w[j], 0 <= j <= 15 - unsigned int w[80] = {0}; + unsigned int w[80] = { 0 }; for (int i = 0; i < 16; i++) { w[i] = (msg[offset + (i*4) + 0] << 24) | diff --git a/src/rtext.c b/src/rtext.c index b8866f190..d965b706a 100644 --- a/src/rtext.c +++ b/src/rtext.c @@ -1649,34 +1649,79 @@ const char *TextSubtext(const char *text, int position, int length) return buffer; } +// Remove text spaces, concat words +const char *TextRemoveSpaces(const char *text) +{ + static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 }; + memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH); + + if (text != NULL) + { + // Avoid copying the ' ' characters + for (int i = 0, j = 0; (i < MAX_TEXT_BUFFER_LENGTH - 1) && (text[j] != '\0'); i++) + { + if (text[i] != ' ') { buffer[j] = text[i]; j++; } + } + } + + return buffer; +} + +// Get text between two strings +static char *GetTextBetween(const char *text, const char *begin, const char *end) +{ + #define MAX_TEXT_BETWEEN_SIZE 1024 + + static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 }; + memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH); + + int beginIndex = TextFindIndex(text, begin); + + if (beginIndex > -1) + { + int beginLen = strlen(begin); + int endIndex = TextFindIndex(text + beginIndex + beginLen, end); + + if (endIndex > -1) + { + endIndex += (beginIndex + beginLen); + int len = (endIndex - beginIndex - beginLen); + if (len < (MAX_TEXT_BETWEEN_SIZE - 1)) strncpy(buffer, text + beginIndex + beginLen, len); + else strncpy(buffer, text + beginIndex + beginLen, MAX_TEXT_BETWEEN_SIZE - 1); + } + } + + return buffer; +} + // Replace text string // REQUIRES: strstr(), strncpy(), strcpy() +// TODO: If (replacement == NULL) remove "search" text // WARNING: Allocated memory must be manually freed -char *TextReplace(const char *text, const char *replace, const char *by) +char *TextReplace(const char *text, const char *search, const char *replacement) { - // Sanity checks and initialization - if (!text || !replace || !by) return NULL; - char *result = NULL; - + + if (!text || !search) return NULL; // Sanity check + char *insertPoint = NULL; // Next insert point char *temp = NULL; // Temp pointer - int replaceLen = 0; // Replace string length of (the string to remove) - int byLen = 0; // Replacement length (the string to replace by) - int lastReplacePos = 0; // Distance between replace and end of last replace + int searchLen = 0; // Search string length of (the string to remove) + int replaceLen = 0; // Replacement length (the string to replace by) + int lastReplacePos = 0; // Distance between next search and end of last replace int count = 0; // Number of replacements - replaceLen = TextLength(replace); - if (replaceLen == 0) return NULL; // Empty replace causes infinite loop during count + searchLen = TextLength(search); + if (searchLen == 0) return NULL; // Empty search causes infinite loop during count - byLen = TextLength(by); + replaceLen = TextLength(replacement); // Count the number of replacements needed insertPoint = (char *)text; - for (count = 0; (temp = strstr(insertPoint, replace)); count++) insertPoint = temp + replaceLen; + for (count = 0; (temp = strstr(insertPoint, search)); count++) insertPoint = temp + searchLen; // Allocate returning string and point temp to it - temp = result = (char *)RL_MALLOC(TextLength(text) + (byLen - replaceLen)*count + 1); + temp = result = (char *)RL_MALLOC(TextLength(text) + (replaceLen - searchLen)*count + 1); if (!result) return NULL; // Memory could not be allocated @@ -1686,11 +1731,11 @@ char *TextReplace(const char *text, const char *replace, const char *by) // - 'text' points to the remainder of text after "end of replace" while (count--) { - insertPoint = strstr(text, replace); + insertPoint = strstr(text, search); lastReplacePos = (int)(insertPoint - text); temp = strncpy(temp, text, lastReplacePos) + lastReplacePos; - temp = strcpy(temp, by) + byLen; - text += lastReplacePos + replaceLen; // Move to next "end of replace" + temp = strcpy(temp, replacement) + replaceLen; + text += lastReplacePos + searchLen; // Move to next "end of replace" } // Copy remaind text part after replacement to result (pointed by moving temp) @@ -1699,6 +1744,41 @@ char *TextReplace(const char *text, const char *replace, const char *by) return result; } +// Replace text between two specific strings +// REQUIRES: strlen(), strncpy() +// NOTE: If (replacement == NULL) remove "begin"[ ]"end" text +// WARNING: Returned string must be freed by user +char *TextReplaceBetween(const char *text, const char *begin, const char *end, const char *replacement) +{ + char *result = NULL; + + if (!text || !begin || !end) return NULL; // Sanity check + + int beginIndex = TextFindIndex(text, begin); + + if (beginIndex > -1) + { + int beginLen = strlen(begin); + int endIndex = TextFindIndex(text + beginIndex + beginLen, end); + + if (endIndex > -1) + { + endIndex += (beginIndex + beginLen); + + int textLen = strlen(text); + int replaceLen = (replacement == NULL)? 0 : strlen(replacement); + int toreplaceLen = endIndex - beginIndex - beginLen; + result = (char *)RL_CALLOC(textLen + replaceLen - toreplaceLen + 1, sizeof(char)); + + strncpy(result, text, beginIndex + beginLen); // Copy first text part + if (replacement != NULL) strncpy(result + beginIndex + beginLen, replacement, replaceLen); // Copy replacement (if provided) + strncpy(result + beginIndex + beginLen + replaceLen, text + endIndex, textLen - endIndex); // Copy end text part + } + } + + return result; +} + // Insert text in a specific position, moves all text forward // WARNING: Allocated memory must be manually freed char *TextInsert(const char *text, const char *insert, int position) @@ -1761,11 +1841,11 @@ char **TextSplit(const char *text, char delimiter, int *count) // 1. Maximum number of possible split strings is set by MAX_TEXTSPLIT_COUNT // 2. Maximum size of text to split is MAX_TEXT_BUFFER_LENGTH - static char *result[MAX_TEXTSPLIT_COUNT] = { NULL }; - static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 }; + static char *buffers[MAX_TEXTSPLIT_COUNT] = { NULL }; // Pointers to buffer[] text data + static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 }; // Text data with '\0' separators memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH); - result[0] = buffer; + buffers[0] = buffer; int counter = 0; if (text != NULL) @@ -1780,7 +1860,7 @@ char **TextSplit(const char *text, char delimiter, int *count) else if (buffer[i] == delimiter) { buffer[i] = '\0'; // Set an end of string at this point - result[counter] = buffer + i + 1; + buffers[counter] = buffer + i + 1; counter++; if (counter == MAX_TEXTSPLIT_COUNT) break; @@ -1789,7 +1869,7 @@ char **TextSplit(const char *text, char delimiter, int *count) } *count = counter; - return result; + return buffers; } // Append text at specific position and move cursor @@ -1803,11 +1883,11 @@ void TextAppend(char *text, const char *append, int *position) // Find first text occurrence within a string // REQUIRES: strstr() -int TextFindIndex(const char *text, const char *find) +int TextFindIndex(const char *text, const char *search) { int position = -1; - char *ptr = strstr(text, find); + char *ptr = strstr(text, search); if (ptr != NULL) position = (int)(ptr - text); @@ -1885,7 +1965,7 @@ char *TextToPascal(const char *text) // WARNING: Limited functionality, only basic characters set char *TextToSnake(const char *text) { - static char buffer[MAX_TEXT_BUFFER_LENGTH] = {0}; + static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 }; memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH); if (text != NULL) @@ -1913,7 +1993,7 @@ char *TextToSnake(const char *text) // WARNING: Limited functionality, only basic characters set char *TextToCamel(const char *text) { - static char buffer[MAX_TEXT_BUFFER_LENGTH] = {0}; + static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 }; memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH); if (text != NULL) From 97e214fc687d98786620f33efb63941da372c729 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 18 Sep 2025 13:34:30 +0000 Subject: [PATCH 010/167] Update raylib_api.* by CI --- tools/parser/output/raylib_api.json | 173 ++++- tools/parser/output/raylib_api.lua | 107 ++- tools/parser/output/raylib_api.txt | 1000 ++++++++++++++------------- tools/parser/output/raylib_api.xml | 54 +- 4 files changed, 827 insertions(+), 507 deletions(-) diff --git a/tools/parser/output/raylib_api.json b/tools/parser/output/raylib_api.json index 58ba0be01..5c641bac3 100644 --- a/tools/parser/output/raylib_api.json +++ b/tools/parser/output/raylib_api.json @@ -4414,6 +4414,96 @@ } ] }, + { + "name": "FileRename", + "description": "Rename file (if exists)", + "returnType": "int", + "params": [ + { + "type": "const char *", + "name": "fileName" + }, + { + "type": "const char *", + "name": "fileRename" + } + ] + }, + { + "name": "FileRemove", + "description": "Remove file (if exists)", + "returnType": "int", + "params": [ + { + "type": "const char *", + "name": "fileName" + } + ] + }, + { + "name": "FileCopy", + "description": "Copy file from one path to another, dstPath created if it doesn't exist", + "returnType": "int", + "params": [ + { + "type": "const char *", + "name": "srcPath" + }, + { + "type": "const char *", + "name": "dstPath" + } + ] + }, + { + "name": "FileMove", + "description": "Move file from one directory to another, dstPath created if it doesn't exist", + "returnType": "int", + "params": [ + { + "type": "const char *", + "name": "srcPath" + }, + { + "type": "const char *", + "name": "dstPath" + } + ] + }, + { + "name": "FileTextReplace", + "description": "Replace text in an existing file", + "returnType": "int", + "params": [ + { + "type": "const char *", + "name": "fileName" + }, + { + "type": "const char *", + "name": "search" + }, + { + "type": "const char *", + "name": "replacement" + } + ] + }, + { + "name": "FileTextFindIndex", + "description": "Find text in existing file", + "returnType": "int", + "params": [ + { + "type": "const char *", + "name": "fileName" + }, + { + "type": "const char *", + "name": "search" + } + ] + }, { "name": "FileExists", "description": "Check if file exists", @@ -4462,6 +4552,17 @@ } ] }, + { + "name": "GetFileModTime", + "description": "Get file modification time (last write time)", + "returnType": "long", + "params": [ + { + "type": "const char *", + "name": "fileName" + } + ] + }, { "name": "GetFileExtension", "description": "Get pointer to extension for a filename string (includes dot: '.png')", @@ -4633,17 +4734,6 @@ } ] }, - { - "name": "GetFileModTime", - "description": "Get file modification time (last write time)", - "returnType": "long", - "params": [ - { - "type": "const char *", - "name": "fileName" - } - ] - }, { "name": "CompressData", "description": "Compress data (DEFLATE algorithm), memory must be MemFree()", @@ -9714,6 +9804,36 @@ } ] }, + { + "name": "TextRemoveSpaces", + "description": "Remove text spaces, concat words", + "returnType": "const char *", + "params": [ + { + "type": "const char *", + "name": "text" + } + ] + }, + { + "name": "GetTextBetween", + "description": "Get text between two strings", + "returnType": "char *", + "params": [ + { + "type": "const char *", + "name": "text" + }, + { + "type": "const char *", + "name": "begin" + }, + { + "type": "const char *", + "name": "end" + } + ] + }, { "name": "TextReplace", "description": "Replace text string (WARNING: memory must be freed!)", @@ -9725,11 +9845,34 @@ }, { "type": "const char *", - "name": "replace" + "name": "search" }, { "type": "const char *", - "name": "by" + "name": "replacement" + } + ] + }, + { + "name": "TextReplaceBetween", + "description": "Replace text between two specific strings (WARNING: memory must be freed!)", + "returnType": "char *", + "params": [ + { + "type": "const char *", + "name": "text" + }, + { + "type": "const char *", + "name": "begin" + }, + { + "type": "const char *", + "name": "end" + }, + { + "type": "const char *", + "name": "replacement" } ] }, @@ -9792,7 +9935,7 @@ }, { "name": "TextAppend", - "description": "Append text at specific position and move cursor!", + "description": "Append text at specific position and move cursor", "returnType": "void", "params": [ { @@ -9820,7 +9963,7 @@ }, { "type": "const char *", - "name": "find" + "name": "search" } ] }, diff --git a/tools/parser/output/raylib_api.lua b/tools/parser/output/raylib_api.lua index 2a385b237..ce3671159 100644 --- a/tools/parser/output/raylib_api.lua +++ b/tools/parser/output/raylib_api.lua @@ -4009,6 +4009,60 @@ return { {type = "const char *", name = "text"} } }, + { + name = "FileRename", + description = "Rename file (if exists)", + returnType = "int", + params = { + {type = "const char *", name = "fileName"}, + {type = "const char *", name = "fileRename"} + } + }, + { + name = "FileRemove", + description = "Remove file (if exists)", + returnType = "int", + params = { + {type = "const char *", name = "fileName"} + } + }, + { + name = "FileCopy", + description = "Copy file from one path to another, dstPath created if it doesn't exist", + returnType = "int", + params = { + {type = "const char *", name = "srcPath"}, + {type = "const char *", name = "dstPath"} + } + }, + { + name = "FileMove", + description = "Move file from one directory to another, dstPath created if it doesn't exist", + returnType = "int", + params = { + {type = "const char *", name = "srcPath"}, + {type = "const char *", name = "dstPath"} + } + }, + { + name = "FileTextReplace", + description = "Replace text in an existing file", + returnType = "int", + params = { + {type = "const char *", name = "fileName"}, + {type = "const char *", name = "search"}, + {type = "const char *", name = "replacement"} + } + }, + { + name = "FileTextFindIndex", + description = "Find text in existing file", + returnType = "int", + params = { + {type = "const char *", name = "fileName"}, + {type = "const char *", name = "search"} + } + }, { name = "FileExists", description = "Check if file exists", @@ -4042,6 +4096,14 @@ return { {type = "const char *", name = "fileName"} } }, + { + name = "GetFileModTime", + description = "Get file modification time (last write time)", + returnType = "long", + params = { + {type = "const char *", name = "fileName"} + } + }, { name = "GetFileExtension", description = "Get pointer to extension for a filename string (includes dot: '.png')", @@ -4168,14 +4230,6 @@ return { {type = "FilePathList", name = "files"} } }, - { - name = "GetFileModTime", - description = "Get file modification time (last write time)", - returnType = "long", - params = { - {type = "const char *", name = "fileName"} - } - }, { name = "CompressData", description = "Compress data (DEFLATE algorithm), memory must be MemFree()", @@ -6909,14 +6963,43 @@ return { {type = "int", name = "length"} } }, + { + name = "TextRemoveSpaces", + description = "Remove text spaces, concat words", + returnType = "const char *", + params = { + {type = "const char *", name = "text"} + } + }, + { + name = "GetTextBetween", + description = "Get text between two strings", + returnType = "char *", + params = { + {type = "const char *", name = "text"}, + {type = "const char *", name = "begin"}, + {type = "const char *", name = "end"} + } + }, { name = "TextReplace", description = "Replace text string (WARNING: memory must be freed!)", returnType = "char *", params = { {type = "const char *", name = "text"}, - {type = "const char *", name = "replace"}, - {type = "const char *", name = "by"} + {type = "const char *", name = "search"}, + {type = "const char *", name = "replacement"} + } + }, + { + name = "TextReplaceBetween", + description = "Replace text between two specific strings (WARNING: memory must be freed!)", + returnType = "char *", + params = { + {type = "const char *", name = "text"}, + {type = "const char *", name = "begin"}, + {type = "const char *", name = "end"}, + {type = "const char *", name = "replacement"} } }, { @@ -6951,7 +7034,7 @@ return { }, { name = "TextAppend", - description = "Append text at specific position and move cursor!", + description = "Append text at specific position and move cursor", returnType = "void", params = { {type = "char *", name = "text"}, @@ -6965,7 +7048,7 @@ return { returnType = "int", params = { {type = "const char *", name = "text"}, - {type = "const char *", name = "find"} + {type = "const char *", name = "search"} } }, { diff --git a/tools/parser/output/raylib_api.txt b/tools/parser/output/raylib_api.txt index 9ff8a7735..94568b690 100644 --- a/tools/parser/output/raylib_api.txt +++ b/tools/parser/output/raylib_api.txt @@ -993,7 +993,7 @@ Callback 006: AudioCallback() (2 input parameters) Param[1]: bufferData (type: void *) Param[2]: frames (type: unsigned int) -Functions found: 586 +Functions found: 595 Function 001: InitWindow() (3 input parameters) Name: InitWindow @@ -1657,306 +1657,342 @@ Function 123: SaveFileText() (2 input parameters) Description: Save text data to file (write), string must be '\0' terminated, returns true on success Param[1]: fileName (type: const char *) Param[2]: text (type: const char *) -Function 124: FileExists() (1 input parameters) +Function 124: FileRename() (2 input parameters) + Name: FileRename + Return type: int + Description: Rename file (if exists) + Param[1]: fileName (type: const char *) + Param[2]: fileRename (type: const char *) +Function 125: FileRemove() (1 input parameters) + Name: FileRemove + Return type: int + Description: Remove file (if exists) + Param[1]: fileName (type: const char *) +Function 126: FileCopy() (2 input parameters) + Name: FileCopy + Return type: int + Description: Copy file from one path to another, dstPath created if it doesn't exist + Param[1]: srcPath (type: const char *) + Param[2]: dstPath (type: const char *) +Function 127: FileMove() (2 input parameters) + Name: FileMove + Return type: int + Description: Move file from one directory to another, dstPath created if it doesn't exist + Param[1]: srcPath (type: const char *) + Param[2]: dstPath (type: const char *) +Function 128: FileTextReplace() (3 input parameters) + Name: FileTextReplace + Return type: int + Description: Replace text in an existing file + Param[1]: fileName (type: const char *) + Param[2]: search (type: const char *) + Param[3]: replacement (type: const char *) +Function 129: FileTextFindIndex() (2 input parameters) + Name: FileTextFindIndex + Return type: int + Description: Find text in existing file + Param[1]: fileName (type: const char *) + Param[2]: search (type: const char *) +Function 130: FileExists() (1 input parameters) Name: FileExists Return type: bool Description: Check if file exists Param[1]: fileName (type: const char *) -Function 125: DirectoryExists() (1 input parameters) +Function 131: DirectoryExists() (1 input parameters) Name: DirectoryExists Return type: bool Description: Check if a directory path exists Param[1]: dirPath (type: const char *) -Function 126: IsFileExtension() (2 input parameters) +Function 132: IsFileExtension() (2 input parameters) Name: IsFileExtension Return type: bool Description: Check file extension (recommended include point: .png, .wav) Param[1]: fileName (type: const char *) Param[2]: ext (type: const char *) -Function 127: GetFileLength() (1 input parameters) +Function 133: GetFileLength() (1 input parameters) Name: GetFileLength Return type: int Description: Get file length in bytes (NOTE: GetFileSize() conflicts with windows.h) Param[1]: fileName (type: const char *) -Function 128: GetFileExtension() (1 input parameters) +Function 134: GetFileModTime() (1 input parameters) + Name: GetFileModTime + Return type: long + Description: Get file modification time (last write time) + Param[1]: fileName (type: const char *) +Function 135: GetFileExtension() (1 input parameters) Name: GetFileExtension Return type: const char * Description: Get pointer to extension for a filename string (includes dot: '.png') Param[1]: fileName (type: const char *) -Function 129: GetFileName() (1 input parameters) +Function 136: GetFileName() (1 input parameters) Name: GetFileName Return type: const char * Description: Get pointer to filename for a path string Param[1]: filePath (type: const char *) -Function 130: GetFileNameWithoutExt() (1 input parameters) +Function 137: GetFileNameWithoutExt() (1 input parameters) Name: GetFileNameWithoutExt Return type: const char * Description: Get filename string without extension (uses static string) Param[1]: filePath (type: const char *) -Function 131: GetDirectoryPath() (1 input parameters) +Function 138: GetDirectoryPath() (1 input parameters) Name: GetDirectoryPath Return type: const char * Description: Get full path for a given fileName with path (uses static string) Param[1]: filePath (type: const char *) -Function 132: GetPrevDirectoryPath() (1 input parameters) +Function 139: GetPrevDirectoryPath() (1 input parameters) Name: GetPrevDirectoryPath Return type: const char * Description: Get previous directory path for a given path (uses static string) Param[1]: dirPath (type: const char *) -Function 133: GetWorkingDirectory() (0 input parameters) +Function 140: GetWorkingDirectory() (0 input parameters) Name: GetWorkingDirectory Return type: const char * Description: Get current working directory (uses static string) No input parameters -Function 134: GetApplicationDirectory() (0 input parameters) +Function 141: GetApplicationDirectory() (0 input parameters) Name: GetApplicationDirectory Return type: const char * Description: Get the directory of the running application (uses static string) No input parameters -Function 135: MakeDirectory() (1 input parameters) +Function 142: MakeDirectory() (1 input parameters) Name: MakeDirectory Return type: int Description: Create directories (including full path requested), returns 0 on success Param[1]: dirPath (type: const char *) -Function 136: ChangeDirectory() (1 input parameters) +Function 143: ChangeDirectory() (1 input parameters) Name: ChangeDirectory Return type: bool Description: Change working directory, return true on success Param[1]: dir (type: const char *) -Function 137: IsPathFile() (1 input parameters) +Function 144: IsPathFile() (1 input parameters) Name: IsPathFile Return type: bool Description: Check if a given path is a file or a directory Param[1]: path (type: const char *) -Function 138: IsFileNameValid() (1 input parameters) +Function 145: IsFileNameValid() (1 input parameters) Name: IsFileNameValid Return type: bool Description: Check if fileName is valid for the platform/OS Param[1]: fileName (type: const char *) -Function 139: LoadDirectoryFiles() (1 input parameters) +Function 146: LoadDirectoryFiles() (1 input parameters) Name: LoadDirectoryFiles Return type: FilePathList Description: Load directory filepaths Param[1]: dirPath (type: const char *) -Function 140: LoadDirectoryFilesEx() (3 input parameters) +Function 147: LoadDirectoryFilesEx() (3 input parameters) Name: LoadDirectoryFilesEx Return type: FilePathList Description: Load directory filepaths with extension filtering and recursive directory scan. Use 'DIR' in the filter string to include directories in the result Param[1]: basePath (type: const char *) Param[2]: filter (type: const char *) Param[3]: scanSubdirs (type: bool) -Function 141: UnloadDirectoryFiles() (1 input parameters) +Function 148: UnloadDirectoryFiles() (1 input parameters) Name: UnloadDirectoryFiles Return type: void Description: Unload filepaths Param[1]: files (type: FilePathList) -Function 142: IsFileDropped() (0 input parameters) +Function 149: IsFileDropped() (0 input parameters) Name: IsFileDropped Return type: bool Description: Check if a file has been dropped into window No input parameters -Function 143: LoadDroppedFiles() (0 input parameters) +Function 150: LoadDroppedFiles() (0 input parameters) Name: LoadDroppedFiles Return type: FilePathList Description: Load dropped filepaths No input parameters -Function 144: UnloadDroppedFiles() (1 input parameters) +Function 151: UnloadDroppedFiles() (1 input parameters) Name: UnloadDroppedFiles Return type: void Description: Unload dropped filepaths Param[1]: files (type: FilePathList) -Function 145: GetFileModTime() (1 input parameters) - Name: GetFileModTime - Return type: long - Description: Get file modification time (last write time) - Param[1]: fileName (type: const char *) -Function 146: CompressData() (3 input parameters) +Function 152: CompressData() (3 input parameters) Name: CompressData Return type: unsigned char * Description: Compress data (DEFLATE algorithm), memory must be MemFree() Param[1]: data (type: const unsigned char *) Param[2]: dataSize (type: int) Param[3]: compDataSize (type: int *) -Function 147: DecompressData() (3 input parameters) +Function 153: DecompressData() (3 input parameters) Name: DecompressData Return type: unsigned char * Description: Decompress data (DEFLATE algorithm), memory must be MemFree() Param[1]: compData (type: const unsigned char *) Param[2]: compDataSize (type: int) Param[3]: dataSize (type: int *) -Function 148: EncodeDataBase64() (3 input parameters) +Function 154: EncodeDataBase64() (3 input parameters) Name: EncodeDataBase64 Return type: char * Description: Encode data to Base64 string (includes NULL terminator), memory must be MemFree() Param[1]: data (type: const unsigned char *) Param[2]: dataSize (type: int) Param[3]: outputSize (type: int *) -Function 149: DecodeDataBase64() (2 input parameters) +Function 155: DecodeDataBase64() (2 input parameters) Name: DecodeDataBase64 Return type: unsigned char * Description: Decode Base64 string (expected NULL terminated), memory must be MemFree() Param[1]: text (type: const char *) Param[2]: outputSize (type: int *) -Function 150: ComputeCRC32() (2 input parameters) +Function 156: ComputeCRC32() (2 input parameters) Name: ComputeCRC32 Return type: unsigned int Description: Compute CRC32 hash code Param[1]: data (type: unsigned char *) Param[2]: dataSize (type: int) -Function 151: ComputeMD5() (2 input parameters) +Function 157: ComputeMD5() (2 input parameters) Name: ComputeMD5 Return type: unsigned int * Description: Compute MD5 hash code, returns static int[4] (16 bytes) Param[1]: data (type: unsigned char *) Param[2]: dataSize (type: int) -Function 152: ComputeSHA1() (2 input parameters) +Function 158: ComputeSHA1() (2 input parameters) Name: ComputeSHA1 Return type: unsigned int * Description: Compute SHA1 hash code, returns static int[5] (20 bytes) Param[1]: data (type: unsigned char *) Param[2]: dataSize (type: int) -Function 153: LoadAutomationEventList() (1 input parameters) +Function 159: LoadAutomationEventList() (1 input parameters) Name: LoadAutomationEventList Return type: AutomationEventList Description: Load automation events list from file, NULL for empty list, capacity = MAX_AUTOMATION_EVENTS Param[1]: fileName (type: const char *) -Function 154: UnloadAutomationEventList() (1 input parameters) +Function 160: UnloadAutomationEventList() (1 input parameters) Name: UnloadAutomationEventList Return type: void Description: Unload automation events list from file Param[1]: list (type: AutomationEventList) -Function 155: ExportAutomationEventList() (2 input parameters) +Function 161: ExportAutomationEventList() (2 input parameters) Name: ExportAutomationEventList Return type: bool Description: Export automation events list as text file Param[1]: list (type: AutomationEventList) Param[2]: fileName (type: const char *) -Function 156: SetAutomationEventList() (1 input parameters) +Function 162: SetAutomationEventList() (1 input parameters) Name: SetAutomationEventList Return type: void Description: Set automation event list to record to Param[1]: list (type: AutomationEventList *) -Function 157: SetAutomationEventBaseFrame() (1 input parameters) +Function 163: SetAutomationEventBaseFrame() (1 input parameters) Name: SetAutomationEventBaseFrame Return type: void Description: Set automation event internal base frame to start recording Param[1]: frame (type: int) -Function 158: StartAutomationEventRecording() (0 input parameters) +Function 164: StartAutomationEventRecording() (0 input parameters) Name: StartAutomationEventRecording Return type: void Description: Start recording automation events (AutomationEventList must be set) No input parameters -Function 159: StopAutomationEventRecording() (0 input parameters) +Function 165: StopAutomationEventRecording() (0 input parameters) Name: StopAutomationEventRecording Return type: void Description: Stop recording automation events No input parameters -Function 160: PlayAutomationEvent() (1 input parameters) +Function 166: PlayAutomationEvent() (1 input parameters) Name: PlayAutomationEvent Return type: void Description: Play a recorded automation event Param[1]: event (type: AutomationEvent) -Function 161: IsKeyPressed() (1 input parameters) +Function 167: IsKeyPressed() (1 input parameters) Name: IsKeyPressed Return type: bool Description: Check if a key has been pressed once Param[1]: key (type: int) -Function 162: IsKeyPressedRepeat() (1 input parameters) +Function 168: IsKeyPressedRepeat() (1 input parameters) Name: IsKeyPressedRepeat Return type: bool Description: Check if a key has been pressed again Param[1]: key (type: int) -Function 163: IsKeyDown() (1 input parameters) +Function 169: IsKeyDown() (1 input parameters) Name: IsKeyDown Return type: bool Description: Check if a key is being pressed Param[1]: key (type: int) -Function 164: IsKeyReleased() (1 input parameters) +Function 170: IsKeyReleased() (1 input parameters) Name: IsKeyReleased Return type: bool Description: Check if a key has been released once Param[1]: key (type: int) -Function 165: IsKeyUp() (1 input parameters) +Function 171: IsKeyUp() (1 input parameters) Name: IsKeyUp Return type: bool Description: Check if a key is NOT being pressed Param[1]: key (type: int) -Function 166: GetKeyPressed() (0 input parameters) +Function 172: GetKeyPressed() (0 input parameters) Name: GetKeyPressed Return type: int Description: Get key pressed (keycode), call it multiple times for keys queued, returns 0 when the queue is empty No input parameters -Function 167: GetCharPressed() (0 input parameters) +Function 173: GetCharPressed() (0 input parameters) Name: GetCharPressed Return type: int Description: Get char pressed (unicode), call it multiple times for chars queued, returns 0 when the queue is empty No input parameters -Function 168: GetKeyName() (1 input parameters) +Function 174: GetKeyName() (1 input parameters) Name: GetKeyName Return type: const char * Description: Get name of a QWERTY key on the current keyboard layout (eg returns string 'q' for KEY_A on an AZERTY keyboard) Param[1]: key (type: int) -Function 169: SetExitKey() (1 input parameters) +Function 175: SetExitKey() (1 input parameters) Name: SetExitKey Return type: void Description: Set a custom key to exit program (default is ESC) Param[1]: key (type: int) -Function 170: IsGamepadAvailable() (1 input parameters) +Function 176: IsGamepadAvailable() (1 input parameters) Name: IsGamepadAvailable Return type: bool Description: Check if a gamepad is available Param[1]: gamepad (type: int) -Function 171: GetGamepadName() (1 input parameters) +Function 177: GetGamepadName() (1 input parameters) Name: GetGamepadName Return type: const char * Description: Get gamepad internal name id Param[1]: gamepad (type: int) -Function 172: IsGamepadButtonPressed() (2 input parameters) +Function 178: IsGamepadButtonPressed() (2 input parameters) Name: IsGamepadButtonPressed Return type: bool Description: Check if a gamepad button has been pressed once Param[1]: gamepad (type: int) Param[2]: button (type: int) -Function 173: IsGamepadButtonDown() (2 input parameters) +Function 179: IsGamepadButtonDown() (2 input parameters) Name: IsGamepadButtonDown Return type: bool Description: Check if a gamepad button is being pressed Param[1]: gamepad (type: int) Param[2]: button (type: int) -Function 174: IsGamepadButtonReleased() (2 input parameters) +Function 180: IsGamepadButtonReleased() (2 input parameters) Name: IsGamepadButtonReleased Return type: bool Description: Check if a gamepad button has been released once Param[1]: gamepad (type: int) Param[2]: button (type: int) -Function 175: IsGamepadButtonUp() (2 input parameters) +Function 181: IsGamepadButtonUp() (2 input parameters) Name: IsGamepadButtonUp Return type: bool Description: Check if a gamepad button is NOT being pressed Param[1]: gamepad (type: int) Param[2]: button (type: int) -Function 176: GetGamepadButtonPressed() (0 input parameters) +Function 182: GetGamepadButtonPressed() (0 input parameters) Name: GetGamepadButtonPressed Return type: int Description: Get the last gamepad button pressed No input parameters -Function 177: GetGamepadAxisCount() (1 input parameters) +Function 183: GetGamepadAxisCount() (1 input parameters) Name: GetGamepadAxisCount Return type: int Description: Get axis count for a gamepad Param[1]: gamepad (type: int) -Function 178: GetGamepadAxisMovement() (2 input parameters) +Function 184: GetGamepadAxisMovement() (2 input parameters) Name: GetGamepadAxisMovement Return type: float Description: Get movement value for a gamepad axis Param[1]: gamepad (type: int) Param[2]: axis (type: int) -Function 179: SetGamepadMappings() (1 input parameters) +Function 185: SetGamepadMappings() (1 input parameters) Name: SetGamepadMappings Return type: int Description: Set internal gamepad mappings (SDL_GameControllerDB) Param[1]: mappings (type: const char *) -Function 180: SetGamepadVibration() (4 input parameters) +Function 186: SetGamepadVibration() (4 input parameters) Name: SetGamepadVibration Return type: void Description: Set gamepad vibration for both motors (duration in seconds) @@ -1964,151 +2000,151 @@ Function 180: SetGamepadVibration() (4 input parameters) Param[2]: leftMotor (type: float) Param[3]: rightMotor (type: float) Param[4]: duration (type: float) -Function 181: IsMouseButtonPressed() (1 input parameters) +Function 187: IsMouseButtonPressed() (1 input parameters) Name: IsMouseButtonPressed Return type: bool Description: Check if a mouse button has been pressed once Param[1]: button (type: int) -Function 182: IsMouseButtonDown() (1 input parameters) +Function 188: IsMouseButtonDown() (1 input parameters) Name: IsMouseButtonDown Return type: bool Description: Check if a mouse button is being pressed Param[1]: button (type: int) -Function 183: IsMouseButtonReleased() (1 input parameters) +Function 189: IsMouseButtonReleased() (1 input parameters) Name: IsMouseButtonReleased Return type: bool Description: Check if a mouse button has been released once Param[1]: button (type: int) -Function 184: IsMouseButtonUp() (1 input parameters) +Function 190: IsMouseButtonUp() (1 input parameters) Name: IsMouseButtonUp Return type: bool Description: Check if a mouse button is NOT being pressed Param[1]: button (type: int) -Function 185: GetMouseX() (0 input parameters) +Function 191: GetMouseX() (0 input parameters) Name: GetMouseX Return type: int Description: Get mouse position X No input parameters -Function 186: GetMouseY() (0 input parameters) +Function 192: GetMouseY() (0 input parameters) Name: GetMouseY Return type: int Description: Get mouse position Y No input parameters -Function 187: GetMousePosition() (0 input parameters) +Function 193: GetMousePosition() (0 input parameters) Name: GetMousePosition Return type: Vector2 Description: Get mouse position XY No input parameters -Function 188: GetMouseDelta() (0 input parameters) +Function 194: GetMouseDelta() (0 input parameters) Name: GetMouseDelta Return type: Vector2 Description: Get mouse delta between frames No input parameters -Function 189: SetMousePosition() (2 input parameters) +Function 195: SetMousePosition() (2 input parameters) Name: SetMousePosition Return type: void Description: Set mouse position XY Param[1]: x (type: int) Param[2]: y (type: int) -Function 190: SetMouseOffset() (2 input parameters) +Function 196: SetMouseOffset() (2 input parameters) Name: SetMouseOffset Return type: void Description: Set mouse offset Param[1]: offsetX (type: int) Param[2]: offsetY (type: int) -Function 191: SetMouseScale() (2 input parameters) +Function 197: SetMouseScale() (2 input parameters) Name: SetMouseScale Return type: void Description: Set mouse scaling Param[1]: scaleX (type: float) Param[2]: scaleY (type: float) -Function 192: GetMouseWheelMove() (0 input parameters) +Function 198: GetMouseWheelMove() (0 input parameters) Name: GetMouseWheelMove Return type: float Description: Get mouse wheel movement for X or Y, whichever is larger No input parameters -Function 193: GetMouseWheelMoveV() (0 input parameters) +Function 199: GetMouseWheelMoveV() (0 input parameters) Name: GetMouseWheelMoveV Return type: Vector2 Description: Get mouse wheel movement for both X and Y No input parameters -Function 194: SetMouseCursor() (1 input parameters) +Function 200: SetMouseCursor() (1 input parameters) Name: SetMouseCursor Return type: void Description: Set mouse cursor Param[1]: cursor (type: int) -Function 195: GetTouchX() (0 input parameters) +Function 201: GetTouchX() (0 input parameters) Name: GetTouchX Return type: int Description: Get touch position X for touch point 0 (relative to screen size) No input parameters -Function 196: GetTouchY() (0 input parameters) +Function 202: GetTouchY() (0 input parameters) Name: GetTouchY Return type: int Description: Get touch position Y for touch point 0 (relative to screen size) No input parameters -Function 197: GetTouchPosition() (1 input parameters) +Function 203: GetTouchPosition() (1 input parameters) Name: GetTouchPosition Return type: Vector2 Description: Get touch position XY for a touch point index (relative to screen size) Param[1]: index (type: int) -Function 198: GetTouchPointId() (1 input parameters) +Function 204: GetTouchPointId() (1 input parameters) Name: GetTouchPointId Return type: int Description: Get touch point identifier for given index Param[1]: index (type: int) -Function 199: GetTouchPointCount() (0 input parameters) +Function 205: GetTouchPointCount() (0 input parameters) Name: GetTouchPointCount Return type: int Description: Get number of touch points No input parameters -Function 200: SetGesturesEnabled() (1 input parameters) +Function 206: SetGesturesEnabled() (1 input parameters) Name: SetGesturesEnabled Return type: void Description: Enable a set of gestures using flags Param[1]: flags (type: unsigned int) -Function 201: IsGestureDetected() (1 input parameters) +Function 207: IsGestureDetected() (1 input parameters) Name: IsGestureDetected Return type: bool Description: Check if a gesture have been detected Param[1]: gesture (type: unsigned int) -Function 202: GetGestureDetected() (0 input parameters) +Function 208: GetGestureDetected() (0 input parameters) Name: GetGestureDetected Return type: int Description: Get latest detected gesture No input parameters -Function 203: GetGestureHoldDuration() (0 input parameters) +Function 209: GetGestureHoldDuration() (0 input parameters) Name: GetGestureHoldDuration Return type: float Description: Get gesture hold time in seconds No input parameters -Function 204: GetGestureDragVector() (0 input parameters) +Function 210: GetGestureDragVector() (0 input parameters) Name: GetGestureDragVector Return type: Vector2 Description: Get gesture drag vector No input parameters -Function 205: GetGestureDragAngle() (0 input parameters) +Function 211: GetGestureDragAngle() (0 input parameters) Name: GetGestureDragAngle Return type: float Description: Get gesture drag angle No input parameters -Function 206: GetGesturePinchVector() (0 input parameters) +Function 212: GetGesturePinchVector() (0 input parameters) Name: GetGesturePinchVector Return type: Vector2 Description: Get gesture pinch delta No input parameters -Function 207: GetGesturePinchAngle() (0 input parameters) +Function 213: GetGesturePinchAngle() (0 input parameters) Name: GetGesturePinchAngle Return type: float Description: Get gesture pinch angle No input parameters -Function 208: UpdateCamera() (2 input parameters) +Function 214: UpdateCamera() (2 input parameters) Name: UpdateCamera Return type: void Description: Update camera position for selected mode Param[1]: camera (type: Camera *) Param[2]: mode (type: int) -Function 209: UpdateCameraPro() (4 input parameters) +Function 215: UpdateCameraPro() (4 input parameters) Name: UpdateCameraPro Return type: void Description: Update camera movement/rotation @@ -2116,36 +2152,36 @@ Function 209: UpdateCameraPro() (4 input parameters) Param[2]: movement (type: Vector3) Param[3]: rotation (type: Vector3) Param[4]: zoom (type: float) -Function 210: SetShapesTexture() (2 input parameters) +Function 216: SetShapesTexture() (2 input parameters) Name: SetShapesTexture Return type: void Description: Set texture and rectangle to be used on shapes drawing Param[1]: texture (type: Texture2D) Param[2]: source (type: Rectangle) -Function 211: GetShapesTexture() (0 input parameters) +Function 217: GetShapesTexture() (0 input parameters) Name: GetShapesTexture Return type: Texture2D Description: Get texture that is used for shapes drawing No input parameters -Function 212: GetShapesTextureRectangle() (0 input parameters) +Function 218: GetShapesTextureRectangle() (0 input parameters) Name: GetShapesTextureRectangle Return type: Rectangle Description: Get texture source rectangle that is used for shapes drawing No input parameters -Function 213: DrawPixel() (3 input parameters) +Function 219: DrawPixel() (3 input parameters) Name: DrawPixel Return type: void Description: Draw a pixel using geometry [Can be slow, use with care] Param[1]: posX (type: int) Param[2]: posY (type: int) Param[3]: color (type: Color) -Function 214: DrawPixelV() (2 input parameters) +Function 220: DrawPixelV() (2 input parameters) Name: DrawPixelV Return type: void Description: Draw a pixel using geometry (Vector version) [Can be slow, use with care] Param[1]: position (type: Vector2) Param[2]: color (type: Color) -Function 215: DrawLine() (5 input parameters) +Function 221: DrawLine() (5 input parameters) Name: DrawLine Return type: void Description: Draw a line @@ -2154,14 +2190,14 @@ Function 215: DrawLine() (5 input parameters) Param[3]: endPosX (type: int) Param[4]: endPosY (type: int) Param[5]: color (type: Color) -Function 216: DrawLineV() (3 input parameters) +Function 222: DrawLineV() (3 input parameters) Name: DrawLineV Return type: void Description: Draw a line (using gl lines) Param[1]: startPos (type: Vector2) Param[2]: endPos (type: Vector2) Param[3]: color (type: Color) -Function 217: DrawLineEx() (4 input parameters) +Function 223: DrawLineEx() (4 input parameters) Name: DrawLineEx Return type: void Description: Draw a line (using triangles/quads) @@ -2169,14 +2205,14 @@ Function 217: DrawLineEx() (4 input parameters) Param[2]: endPos (type: Vector2) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 218: DrawLineStrip() (3 input parameters) +Function 224: DrawLineStrip() (3 input parameters) Name: DrawLineStrip Return type: void Description: Draw lines sequence (using gl lines) Param[1]: points (type: const Vector2 *) Param[2]: pointCount (type: int) Param[3]: color (type: Color) -Function 219: DrawLineBezier() (4 input parameters) +Function 225: DrawLineBezier() (4 input parameters) Name: DrawLineBezier Return type: void Description: Draw line segment cubic-bezier in-out interpolation @@ -2184,7 +2220,7 @@ Function 219: DrawLineBezier() (4 input parameters) Param[2]: endPos (type: Vector2) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 220: DrawCircle() (4 input parameters) +Function 226: DrawCircle() (4 input parameters) Name: DrawCircle Return type: void Description: Draw a color-filled circle @@ -2192,7 +2228,7 @@ Function 220: DrawCircle() (4 input parameters) Param[2]: centerY (type: int) Param[3]: radius (type: float) Param[4]: color (type: Color) -Function 221: DrawCircleSector() (6 input parameters) +Function 227: DrawCircleSector() (6 input parameters) Name: DrawCircleSector Return type: void Description: Draw a piece of a circle @@ -2202,7 +2238,7 @@ Function 221: DrawCircleSector() (6 input parameters) Param[4]: endAngle (type: float) Param[5]: segments (type: int) Param[6]: color (type: Color) -Function 222: DrawCircleSectorLines() (6 input parameters) +Function 228: DrawCircleSectorLines() (6 input parameters) Name: DrawCircleSectorLines Return type: void Description: Draw circle sector outline @@ -2212,7 +2248,7 @@ Function 222: DrawCircleSectorLines() (6 input parameters) Param[4]: endAngle (type: float) Param[5]: segments (type: int) Param[6]: color (type: Color) -Function 223: DrawCircleGradient() (5 input parameters) +Function 229: DrawCircleGradient() (5 input parameters) Name: DrawCircleGradient Return type: void Description: Draw a gradient-filled circle @@ -2221,14 +2257,14 @@ Function 223: DrawCircleGradient() (5 input parameters) Param[3]: radius (type: float) Param[4]: inner (type: Color) Param[5]: outer (type: Color) -Function 224: DrawCircleV() (3 input parameters) +Function 230: DrawCircleV() (3 input parameters) Name: DrawCircleV Return type: void Description: Draw a color-filled circle (Vector version) Param[1]: center (type: Vector2) Param[2]: radius (type: float) Param[3]: color (type: Color) -Function 225: DrawCircleLines() (4 input parameters) +Function 231: DrawCircleLines() (4 input parameters) Name: DrawCircleLines Return type: void Description: Draw circle outline @@ -2236,14 +2272,14 @@ Function 225: DrawCircleLines() (4 input parameters) Param[2]: centerY (type: int) Param[3]: radius (type: float) Param[4]: color (type: Color) -Function 226: DrawCircleLinesV() (3 input parameters) +Function 232: DrawCircleLinesV() (3 input parameters) Name: DrawCircleLinesV Return type: void Description: Draw circle outline (Vector version) Param[1]: center (type: Vector2) Param[2]: radius (type: float) Param[3]: color (type: Color) -Function 227: DrawEllipse() (5 input parameters) +Function 233: DrawEllipse() (5 input parameters) Name: DrawEllipse Return type: void Description: Draw ellipse @@ -2252,7 +2288,7 @@ Function 227: DrawEllipse() (5 input parameters) Param[3]: radiusH (type: float) Param[4]: radiusV (type: float) Param[5]: color (type: Color) -Function 228: DrawEllipseV() (4 input parameters) +Function 234: DrawEllipseV() (4 input parameters) Name: DrawEllipseV Return type: void Description: Draw ellipse (Vector version) @@ -2260,7 +2296,7 @@ Function 228: DrawEllipseV() (4 input parameters) Param[2]: radiusH (type: float) Param[3]: radiusV (type: float) Param[4]: color (type: Color) -Function 229: DrawEllipseLines() (5 input parameters) +Function 235: DrawEllipseLines() (5 input parameters) Name: DrawEllipseLines Return type: void Description: Draw ellipse outline @@ -2269,7 +2305,7 @@ Function 229: DrawEllipseLines() (5 input parameters) Param[3]: radiusH (type: float) Param[4]: radiusV (type: float) Param[5]: color (type: Color) -Function 230: DrawEllipseLinesV() (4 input parameters) +Function 236: DrawEllipseLinesV() (4 input parameters) Name: DrawEllipseLinesV Return type: void Description: Draw ellipse outline (Vector version) @@ -2277,7 +2313,7 @@ Function 230: DrawEllipseLinesV() (4 input parameters) Param[2]: radiusH (type: float) Param[3]: radiusV (type: float) Param[4]: color (type: Color) -Function 231: DrawRing() (7 input parameters) +Function 237: DrawRing() (7 input parameters) Name: DrawRing Return type: void Description: Draw ring @@ -2288,7 +2324,7 @@ Function 231: DrawRing() (7 input parameters) Param[5]: endAngle (type: float) Param[6]: segments (type: int) Param[7]: color (type: Color) -Function 232: DrawRingLines() (7 input parameters) +Function 238: DrawRingLines() (7 input parameters) Name: DrawRingLines Return type: void Description: Draw ring outline @@ -2299,7 +2335,7 @@ Function 232: DrawRingLines() (7 input parameters) Param[5]: endAngle (type: float) Param[6]: segments (type: int) Param[7]: color (type: Color) -Function 233: DrawRectangle() (5 input parameters) +Function 239: DrawRectangle() (5 input parameters) Name: DrawRectangle Return type: void Description: Draw a color-filled rectangle @@ -2308,20 +2344,20 @@ Function 233: DrawRectangle() (5 input parameters) Param[3]: width (type: int) Param[4]: height (type: int) Param[5]: color (type: Color) -Function 234: DrawRectangleV() (3 input parameters) +Function 240: DrawRectangleV() (3 input parameters) Name: DrawRectangleV Return type: void Description: Draw a color-filled rectangle (Vector version) Param[1]: position (type: Vector2) Param[2]: size (type: Vector2) Param[3]: color (type: Color) -Function 235: DrawRectangleRec() (2 input parameters) +Function 241: DrawRectangleRec() (2 input parameters) Name: DrawRectangleRec Return type: void Description: Draw a color-filled rectangle Param[1]: rec (type: Rectangle) Param[2]: color (type: Color) -Function 236: DrawRectanglePro() (4 input parameters) +Function 242: DrawRectanglePro() (4 input parameters) Name: DrawRectanglePro Return type: void Description: Draw a color-filled rectangle with pro parameters @@ -2329,7 +2365,7 @@ Function 236: DrawRectanglePro() (4 input parameters) Param[2]: origin (type: Vector2) Param[3]: rotation (type: float) Param[4]: color (type: Color) -Function 237: DrawRectangleGradientV() (6 input parameters) +Function 243: DrawRectangleGradientV() (6 input parameters) Name: DrawRectangleGradientV Return type: void Description: Draw a vertical-gradient-filled rectangle @@ -2339,7 +2375,7 @@ Function 237: DrawRectangleGradientV() (6 input parameters) Param[4]: height (type: int) Param[5]: top (type: Color) Param[6]: bottom (type: Color) -Function 238: DrawRectangleGradientH() (6 input parameters) +Function 244: DrawRectangleGradientH() (6 input parameters) Name: DrawRectangleGradientH Return type: void Description: Draw a horizontal-gradient-filled rectangle @@ -2349,7 +2385,7 @@ Function 238: DrawRectangleGradientH() (6 input parameters) Param[4]: height (type: int) Param[5]: left (type: Color) Param[6]: right (type: Color) -Function 239: DrawRectangleGradientEx() (5 input parameters) +Function 245: DrawRectangleGradientEx() (5 input parameters) Name: DrawRectangleGradientEx Return type: void Description: Draw a gradient-filled rectangle with custom vertex colors @@ -2358,7 +2394,7 @@ Function 239: DrawRectangleGradientEx() (5 input parameters) Param[3]: bottomLeft (type: Color) Param[4]: bottomRight (type: Color) Param[5]: topRight (type: Color) -Function 240: DrawRectangleLines() (5 input parameters) +Function 246: DrawRectangleLines() (5 input parameters) Name: DrawRectangleLines Return type: void Description: Draw rectangle outline @@ -2367,14 +2403,14 @@ Function 240: DrawRectangleLines() (5 input parameters) Param[3]: width (type: int) Param[4]: height (type: int) Param[5]: color (type: Color) -Function 241: DrawRectangleLinesEx() (3 input parameters) +Function 247: DrawRectangleLinesEx() (3 input parameters) Name: DrawRectangleLinesEx Return type: void Description: Draw rectangle outline with extended parameters Param[1]: rec (type: Rectangle) Param[2]: lineThick (type: float) Param[3]: color (type: Color) -Function 242: DrawRectangleRounded() (4 input parameters) +Function 248: DrawRectangleRounded() (4 input parameters) Name: DrawRectangleRounded Return type: void Description: Draw rectangle with rounded edges @@ -2382,7 +2418,7 @@ Function 242: DrawRectangleRounded() (4 input parameters) Param[2]: roundness (type: float) Param[3]: segments (type: int) Param[4]: color (type: Color) -Function 243: DrawRectangleRoundedLines() (4 input parameters) +Function 249: DrawRectangleRoundedLines() (4 input parameters) Name: DrawRectangleRoundedLines Return type: void Description: Draw rectangle lines with rounded edges @@ -2390,7 +2426,7 @@ Function 243: DrawRectangleRoundedLines() (4 input parameters) Param[2]: roundness (type: float) Param[3]: segments (type: int) Param[4]: color (type: Color) -Function 244: DrawRectangleRoundedLinesEx() (5 input parameters) +Function 250: DrawRectangleRoundedLinesEx() (5 input parameters) Name: DrawRectangleRoundedLinesEx Return type: void Description: Draw rectangle with rounded edges outline @@ -2399,7 +2435,7 @@ Function 244: DrawRectangleRoundedLinesEx() (5 input parameters) Param[3]: segments (type: int) Param[4]: lineThick (type: float) Param[5]: color (type: Color) -Function 245: DrawTriangle() (4 input parameters) +Function 251: DrawTriangle() (4 input parameters) Name: DrawTriangle Return type: void Description: Draw a color-filled triangle (vertex in counter-clockwise order!) @@ -2407,7 +2443,7 @@ Function 245: DrawTriangle() (4 input parameters) Param[2]: v2 (type: Vector2) Param[3]: v3 (type: Vector2) Param[4]: color (type: Color) -Function 246: DrawTriangleLines() (4 input parameters) +Function 252: DrawTriangleLines() (4 input parameters) Name: DrawTriangleLines Return type: void Description: Draw triangle outline (vertex in counter-clockwise order!) @@ -2415,21 +2451,21 @@ Function 246: DrawTriangleLines() (4 input parameters) Param[2]: v2 (type: Vector2) Param[3]: v3 (type: Vector2) Param[4]: color (type: Color) -Function 247: DrawTriangleFan() (3 input parameters) +Function 253: DrawTriangleFan() (3 input parameters) Name: DrawTriangleFan Return type: void Description: Draw a triangle fan defined by points (first vertex is the center) Param[1]: points (type: const Vector2 *) Param[2]: pointCount (type: int) Param[3]: color (type: Color) -Function 248: DrawTriangleStrip() (3 input parameters) +Function 254: DrawTriangleStrip() (3 input parameters) Name: DrawTriangleStrip Return type: void Description: Draw a triangle strip defined by points Param[1]: points (type: const Vector2 *) Param[2]: pointCount (type: int) Param[3]: color (type: Color) -Function 249: DrawPoly() (5 input parameters) +Function 255: DrawPoly() (5 input parameters) Name: DrawPoly Return type: void Description: Draw a regular polygon (Vector version) @@ -2438,7 +2474,7 @@ Function 249: DrawPoly() (5 input parameters) Param[3]: radius (type: float) Param[4]: rotation (type: float) Param[5]: color (type: Color) -Function 250: DrawPolyLines() (5 input parameters) +Function 256: DrawPolyLines() (5 input parameters) Name: DrawPolyLines Return type: void Description: Draw a polygon outline of n sides @@ -2447,7 +2483,7 @@ Function 250: DrawPolyLines() (5 input parameters) Param[3]: radius (type: float) Param[4]: rotation (type: float) Param[5]: color (type: Color) -Function 251: DrawPolyLinesEx() (6 input parameters) +Function 257: DrawPolyLinesEx() (6 input parameters) Name: DrawPolyLinesEx Return type: void Description: Draw a polygon outline of n sides with extended parameters @@ -2457,7 +2493,7 @@ Function 251: DrawPolyLinesEx() (6 input parameters) Param[4]: rotation (type: float) Param[5]: lineThick (type: float) Param[6]: color (type: Color) -Function 252: DrawSplineLinear() (4 input parameters) +Function 258: DrawSplineLinear() (4 input parameters) Name: DrawSplineLinear Return type: void Description: Draw spline: Linear, minimum 2 points @@ -2465,7 +2501,7 @@ Function 252: DrawSplineLinear() (4 input parameters) Param[2]: pointCount (type: int) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 253: DrawSplineBasis() (4 input parameters) +Function 259: DrawSplineBasis() (4 input parameters) Name: DrawSplineBasis Return type: void Description: Draw spline: B-Spline, minimum 4 points @@ -2473,7 +2509,7 @@ Function 253: DrawSplineBasis() (4 input parameters) Param[2]: pointCount (type: int) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 254: DrawSplineCatmullRom() (4 input parameters) +Function 260: DrawSplineCatmullRom() (4 input parameters) Name: DrawSplineCatmullRom Return type: void Description: Draw spline: Catmull-Rom, minimum 4 points @@ -2481,7 +2517,7 @@ Function 254: DrawSplineCatmullRom() (4 input parameters) Param[2]: pointCount (type: int) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 255: DrawSplineBezierQuadratic() (4 input parameters) +Function 261: DrawSplineBezierQuadratic() (4 input parameters) Name: DrawSplineBezierQuadratic Return type: void Description: Draw spline: Quadratic Bezier, minimum 3 points (1 control point): [p1, c2, p3, c4...] @@ -2489,7 +2525,7 @@ Function 255: DrawSplineBezierQuadratic() (4 input parameters) Param[2]: pointCount (type: int) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 256: DrawSplineBezierCubic() (4 input parameters) +Function 262: DrawSplineBezierCubic() (4 input parameters) Name: DrawSplineBezierCubic Return type: void Description: Draw spline: Cubic Bezier, minimum 4 points (2 control points): [p1, c2, c3, p4, c5, c6...] @@ -2497,7 +2533,7 @@ Function 256: DrawSplineBezierCubic() (4 input parameters) Param[2]: pointCount (type: int) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 257: DrawSplineSegmentLinear() (4 input parameters) +Function 263: DrawSplineSegmentLinear() (4 input parameters) Name: DrawSplineSegmentLinear Return type: void Description: Draw spline segment: Linear, 2 points @@ -2505,7 +2541,7 @@ Function 257: DrawSplineSegmentLinear() (4 input parameters) Param[2]: p2 (type: Vector2) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 258: DrawSplineSegmentBasis() (6 input parameters) +Function 264: DrawSplineSegmentBasis() (6 input parameters) Name: DrawSplineSegmentBasis Return type: void Description: Draw spline segment: B-Spline, 4 points @@ -2515,7 +2551,7 @@ Function 258: DrawSplineSegmentBasis() (6 input parameters) Param[4]: p4 (type: Vector2) Param[5]: thick (type: float) Param[6]: color (type: Color) -Function 259: DrawSplineSegmentCatmullRom() (6 input parameters) +Function 265: DrawSplineSegmentCatmullRom() (6 input parameters) Name: DrawSplineSegmentCatmullRom Return type: void Description: Draw spline segment: Catmull-Rom, 4 points @@ -2525,7 +2561,7 @@ Function 259: DrawSplineSegmentCatmullRom() (6 input parameters) Param[4]: p4 (type: Vector2) Param[5]: thick (type: float) Param[6]: color (type: Color) -Function 260: DrawSplineSegmentBezierQuadratic() (5 input parameters) +Function 266: DrawSplineSegmentBezierQuadratic() (5 input parameters) Name: DrawSplineSegmentBezierQuadratic Return type: void Description: Draw spline segment: Quadratic Bezier, 2 points, 1 control point @@ -2534,7 +2570,7 @@ Function 260: DrawSplineSegmentBezierQuadratic() (5 input parameters) Param[3]: p3 (type: Vector2) Param[4]: thick (type: float) Param[5]: color (type: Color) -Function 261: DrawSplineSegmentBezierCubic() (6 input parameters) +Function 267: DrawSplineSegmentBezierCubic() (6 input parameters) Name: DrawSplineSegmentBezierCubic Return type: void Description: Draw spline segment: Cubic Bezier, 2 points, 2 control points @@ -2544,14 +2580,14 @@ Function 261: DrawSplineSegmentBezierCubic() (6 input parameters) Param[4]: p4 (type: Vector2) Param[5]: thick (type: float) Param[6]: color (type: Color) -Function 262: GetSplinePointLinear() (3 input parameters) +Function 268: GetSplinePointLinear() (3 input parameters) Name: GetSplinePointLinear Return type: Vector2 Description: Get (evaluate) spline point: Linear Param[1]: startPos (type: Vector2) Param[2]: endPos (type: Vector2) Param[3]: t (type: float) -Function 263: GetSplinePointBasis() (5 input parameters) +Function 269: GetSplinePointBasis() (5 input parameters) Name: GetSplinePointBasis Return type: Vector2 Description: Get (evaluate) spline point: B-Spline @@ -2560,7 +2596,7 @@ Function 263: GetSplinePointBasis() (5 input parameters) Param[3]: p3 (type: Vector2) Param[4]: p4 (type: Vector2) Param[5]: t (type: float) -Function 264: GetSplinePointCatmullRom() (5 input parameters) +Function 270: GetSplinePointCatmullRom() (5 input parameters) Name: GetSplinePointCatmullRom Return type: Vector2 Description: Get (evaluate) spline point: Catmull-Rom @@ -2569,7 +2605,7 @@ Function 264: GetSplinePointCatmullRom() (5 input parameters) Param[3]: p3 (type: Vector2) Param[4]: p4 (type: Vector2) Param[5]: t (type: float) -Function 265: GetSplinePointBezierQuad() (4 input parameters) +Function 271: GetSplinePointBezierQuad() (4 input parameters) Name: GetSplinePointBezierQuad Return type: Vector2 Description: Get (evaluate) spline point: Quadratic Bezier @@ -2577,7 +2613,7 @@ Function 265: GetSplinePointBezierQuad() (4 input parameters) Param[2]: c2 (type: Vector2) Param[3]: p3 (type: Vector2) Param[4]: t (type: float) -Function 266: GetSplinePointBezierCubic() (5 input parameters) +Function 272: GetSplinePointBezierCubic() (5 input parameters) Name: GetSplinePointBezierCubic Return type: Vector2 Description: Get (evaluate) spline point: Cubic Bezier @@ -2586,13 +2622,13 @@ Function 266: GetSplinePointBezierCubic() (5 input parameters) Param[3]: c3 (type: Vector2) Param[4]: p4 (type: Vector2) Param[5]: t (type: float) -Function 267: CheckCollisionRecs() (2 input parameters) +Function 273: CheckCollisionRecs() (2 input parameters) Name: CheckCollisionRecs Return type: bool Description: Check collision between two rectangles Param[1]: rec1 (type: Rectangle) Param[2]: rec2 (type: Rectangle) -Function 268: CheckCollisionCircles() (4 input parameters) +Function 274: CheckCollisionCircles() (4 input parameters) Name: CheckCollisionCircles Return type: bool Description: Check collision between two circles @@ -2600,14 +2636,14 @@ Function 268: CheckCollisionCircles() (4 input parameters) Param[2]: radius1 (type: float) Param[3]: center2 (type: Vector2) Param[4]: radius2 (type: float) -Function 269: CheckCollisionCircleRec() (3 input parameters) +Function 275: CheckCollisionCircleRec() (3 input parameters) Name: CheckCollisionCircleRec Return type: bool Description: Check collision between circle and rectangle Param[1]: center (type: Vector2) Param[2]: radius (type: float) Param[3]: rec (type: Rectangle) -Function 270: CheckCollisionCircleLine() (4 input parameters) +Function 276: CheckCollisionCircleLine() (4 input parameters) Name: CheckCollisionCircleLine Return type: bool Description: Check if circle collides with a line created betweeen two points [p1] and [p2] @@ -2615,20 +2651,20 @@ Function 270: CheckCollisionCircleLine() (4 input parameters) Param[2]: radius (type: float) Param[3]: p1 (type: Vector2) Param[4]: p2 (type: Vector2) -Function 271: CheckCollisionPointRec() (2 input parameters) +Function 277: CheckCollisionPointRec() (2 input parameters) Name: CheckCollisionPointRec Return type: bool Description: Check if point is inside rectangle Param[1]: point (type: Vector2) Param[2]: rec (type: Rectangle) -Function 272: CheckCollisionPointCircle() (3 input parameters) +Function 278: CheckCollisionPointCircle() (3 input parameters) Name: CheckCollisionPointCircle Return type: bool Description: Check if point is inside circle Param[1]: point (type: Vector2) Param[2]: center (type: Vector2) Param[3]: radius (type: float) -Function 273: CheckCollisionPointTriangle() (4 input parameters) +Function 279: CheckCollisionPointTriangle() (4 input parameters) Name: CheckCollisionPointTriangle Return type: bool Description: Check if point is inside a triangle @@ -2636,7 +2672,7 @@ Function 273: CheckCollisionPointTriangle() (4 input parameters) Param[2]: p1 (type: Vector2) Param[3]: p2 (type: Vector2) Param[4]: p3 (type: Vector2) -Function 274: CheckCollisionPointLine() (4 input parameters) +Function 280: CheckCollisionPointLine() (4 input parameters) Name: CheckCollisionPointLine Return type: bool Description: Check if point belongs to line created between two points [p1] and [p2] with defined margin in pixels [threshold] @@ -2644,14 +2680,14 @@ Function 274: CheckCollisionPointLine() (4 input parameters) Param[2]: p1 (type: Vector2) Param[3]: p2 (type: Vector2) Param[4]: threshold (type: int) -Function 275: CheckCollisionPointPoly() (3 input parameters) +Function 281: CheckCollisionPointPoly() (3 input parameters) Name: CheckCollisionPointPoly Return type: bool Description: Check if point is within a polygon described by array of vertices Param[1]: point (type: Vector2) Param[2]: points (type: const Vector2 *) Param[3]: pointCount (type: int) -Function 276: CheckCollisionLines() (5 input parameters) +Function 282: CheckCollisionLines() (5 input parameters) Name: CheckCollisionLines Return type: bool Description: Check the collision between two lines defined by two points each, returns collision point by reference @@ -2660,18 +2696,18 @@ Function 276: CheckCollisionLines() (5 input parameters) Param[3]: startPos2 (type: Vector2) Param[4]: endPos2 (type: Vector2) Param[5]: collisionPoint (type: Vector2 *) -Function 277: GetCollisionRec() (2 input parameters) +Function 283: GetCollisionRec() (2 input parameters) Name: GetCollisionRec Return type: Rectangle Description: Get collision rectangle for two rectangles collision Param[1]: rec1 (type: Rectangle) Param[2]: rec2 (type: Rectangle) -Function 278: LoadImage() (1 input parameters) +Function 284: LoadImage() (1 input parameters) Name: LoadImage Return type: Image Description: Load image from file into CPU memory (RAM) Param[1]: fileName (type: const char *) -Function 279: LoadImageRaw() (5 input parameters) +Function 285: LoadImageRaw() (5 input parameters) Name: LoadImageRaw Return type: Image Description: Load image from RAW file data @@ -2680,13 +2716,13 @@ Function 279: LoadImageRaw() (5 input parameters) Param[3]: height (type: int) Param[4]: format (type: int) Param[5]: headerSize (type: int) -Function 280: LoadImageAnim() (2 input parameters) +Function 286: LoadImageAnim() (2 input parameters) Name: LoadImageAnim Return type: Image Description: Load image sequence from file (frames appended to image.data) Param[1]: fileName (type: const char *) Param[2]: frames (type: int *) -Function 281: LoadImageAnimFromMemory() (4 input parameters) +Function 287: LoadImageAnimFromMemory() (4 input parameters) Name: LoadImageAnimFromMemory Return type: Image Description: Load image sequence from memory buffer @@ -2694,60 +2730,60 @@ Function 281: LoadImageAnimFromMemory() (4 input parameters) Param[2]: fileData (type: const unsigned char *) Param[3]: dataSize (type: int) Param[4]: frames (type: int *) -Function 282: LoadImageFromMemory() (3 input parameters) +Function 288: LoadImageFromMemory() (3 input parameters) Name: LoadImageFromMemory Return type: Image Description: Load image from memory buffer, fileType refers to extension: i.e. '.png' Param[1]: fileType (type: const char *) Param[2]: fileData (type: const unsigned char *) Param[3]: dataSize (type: int) -Function 283: LoadImageFromTexture() (1 input parameters) +Function 289: LoadImageFromTexture() (1 input parameters) Name: LoadImageFromTexture Return type: Image Description: Load image from GPU texture data Param[1]: texture (type: Texture2D) -Function 284: LoadImageFromScreen() (0 input parameters) +Function 290: LoadImageFromScreen() (0 input parameters) Name: LoadImageFromScreen Return type: Image Description: Load image from screen buffer and (screenshot) No input parameters -Function 285: IsImageValid() (1 input parameters) +Function 291: IsImageValid() (1 input parameters) Name: IsImageValid Return type: bool Description: Check if an image is valid (data and parameters) Param[1]: image (type: Image) -Function 286: UnloadImage() (1 input parameters) +Function 292: UnloadImage() (1 input parameters) Name: UnloadImage Return type: void Description: Unload image from CPU memory (RAM) Param[1]: image (type: Image) -Function 287: ExportImage() (2 input parameters) +Function 293: ExportImage() (2 input parameters) Name: ExportImage Return type: bool Description: Export image data to file, returns true on success Param[1]: image (type: Image) Param[2]: fileName (type: const char *) -Function 288: ExportImageToMemory() (3 input parameters) +Function 294: ExportImageToMemory() (3 input parameters) Name: ExportImageToMemory Return type: unsigned char * Description: Export image to memory buffer Param[1]: image (type: Image) Param[2]: fileType (type: const char *) Param[3]: fileSize (type: int *) -Function 289: ExportImageAsCode() (2 input parameters) +Function 295: ExportImageAsCode() (2 input parameters) Name: ExportImageAsCode Return type: bool Description: Export image as code file defining an array of bytes, returns true on success Param[1]: image (type: Image) Param[2]: fileName (type: const char *) -Function 290: GenImageColor() (3 input parameters) +Function 296: GenImageColor() (3 input parameters) Name: GenImageColor Return type: Image Description: Generate image: plain color Param[1]: width (type: int) Param[2]: height (type: int) Param[3]: color (type: Color) -Function 291: GenImageGradientLinear() (5 input parameters) +Function 297: GenImageGradientLinear() (5 input parameters) Name: GenImageGradientLinear Return type: Image Description: Generate image: linear gradient, direction in degrees [0..360], 0=Vertical gradient @@ -2756,7 +2792,7 @@ Function 291: GenImageGradientLinear() (5 input parameters) Param[3]: direction (type: int) Param[4]: start (type: Color) Param[5]: end (type: Color) -Function 292: GenImageGradientRadial() (5 input parameters) +Function 298: GenImageGradientRadial() (5 input parameters) Name: GenImageGradientRadial Return type: Image Description: Generate image: radial gradient @@ -2765,7 +2801,7 @@ Function 292: GenImageGradientRadial() (5 input parameters) Param[3]: density (type: float) Param[4]: inner (type: Color) Param[5]: outer (type: Color) -Function 293: GenImageGradientSquare() (5 input parameters) +Function 299: GenImageGradientSquare() (5 input parameters) Name: GenImageGradientSquare Return type: Image Description: Generate image: square gradient @@ -2774,7 +2810,7 @@ Function 293: GenImageGradientSquare() (5 input parameters) Param[3]: density (type: float) Param[4]: inner (type: Color) Param[5]: outer (type: Color) -Function 294: GenImageChecked() (6 input parameters) +Function 300: GenImageChecked() (6 input parameters) Name: GenImageChecked Return type: Image Description: Generate image: checked @@ -2784,14 +2820,14 @@ Function 294: GenImageChecked() (6 input parameters) Param[4]: checksY (type: int) Param[5]: col1 (type: Color) Param[6]: col2 (type: Color) -Function 295: GenImageWhiteNoise() (3 input parameters) +Function 301: GenImageWhiteNoise() (3 input parameters) Name: GenImageWhiteNoise Return type: Image Description: Generate image: white noise Param[1]: width (type: int) Param[2]: height (type: int) Param[3]: factor (type: float) -Function 296: GenImagePerlinNoise() (5 input parameters) +Function 302: GenImagePerlinNoise() (5 input parameters) Name: GenImagePerlinNoise Return type: Image Description: Generate image: perlin noise @@ -2800,45 +2836,45 @@ Function 296: GenImagePerlinNoise() (5 input parameters) Param[3]: offsetX (type: int) Param[4]: offsetY (type: int) Param[5]: scale (type: float) -Function 297: GenImageCellular() (3 input parameters) +Function 303: GenImageCellular() (3 input parameters) Name: GenImageCellular Return type: Image Description: Generate image: cellular algorithm, bigger tileSize means bigger cells Param[1]: width (type: int) Param[2]: height (type: int) Param[3]: tileSize (type: int) -Function 298: GenImageText() (3 input parameters) +Function 304: GenImageText() (3 input parameters) Name: GenImageText Return type: Image Description: Generate image: grayscale image from text data Param[1]: width (type: int) Param[2]: height (type: int) Param[3]: text (type: const char *) -Function 299: ImageCopy() (1 input parameters) +Function 305: ImageCopy() (1 input parameters) Name: ImageCopy Return type: Image Description: Create an image duplicate (useful for transformations) Param[1]: image (type: Image) -Function 300: ImageFromImage() (2 input parameters) +Function 306: ImageFromImage() (2 input parameters) Name: ImageFromImage Return type: Image Description: Create an image from another image piece Param[1]: image (type: Image) Param[2]: rec (type: Rectangle) -Function 301: ImageFromChannel() (2 input parameters) +Function 307: ImageFromChannel() (2 input parameters) Name: ImageFromChannel Return type: Image Description: Create an image from a selected channel of another image (GRAYSCALE) Param[1]: image (type: Image) Param[2]: selectedChannel (type: int) -Function 302: ImageText() (3 input parameters) +Function 308: ImageText() (3 input parameters) Name: ImageText Return type: Image Description: Create an image from text (default font) Param[1]: text (type: const char *) Param[2]: fontSize (type: int) Param[3]: color (type: Color) -Function 303: ImageTextEx() (5 input parameters) +Function 309: ImageTextEx() (5 input parameters) Name: ImageTextEx Return type: Image Description: Create an image from text (custom sprite font) @@ -2847,76 +2883,76 @@ Function 303: ImageTextEx() (5 input parameters) Param[3]: fontSize (type: float) Param[4]: spacing (type: float) Param[5]: tint (type: Color) -Function 304: ImageFormat() (2 input parameters) +Function 310: ImageFormat() (2 input parameters) Name: ImageFormat Return type: void Description: Convert image data to desired format Param[1]: image (type: Image *) Param[2]: newFormat (type: int) -Function 305: ImageToPOT() (2 input parameters) +Function 311: ImageToPOT() (2 input parameters) Name: ImageToPOT Return type: void Description: Convert image to POT (power-of-two) Param[1]: image (type: Image *) Param[2]: fill (type: Color) -Function 306: ImageCrop() (2 input parameters) +Function 312: ImageCrop() (2 input parameters) Name: ImageCrop Return type: void Description: Crop an image to a defined rectangle Param[1]: image (type: Image *) Param[2]: crop (type: Rectangle) -Function 307: ImageAlphaCrop() (2 input parameters) +Function 313: ImageAlphaCrop() (2 input parameters) Name: ImageAlphaCrop Return type: void Description: Crop image depending on alpha value Param[1]: image (type: Image *) Param[2]: threshold (type: float) -Function 308: ImageAlphaClear() (3 input parameters) +Function 314: ImageAlphaClear() (3 input parameters) Name: ImageAlphaClear Return type: void Description: Clear alpha channel to desired color Param[1]: image (type: Image *) Param[2]: color (type: Color) Param[3]: threshold (type: float) -Function 309: ImageAlphaMask() (2 input parameters) +Function 315: ImageAlphaMask() (2 input parameters) Name: ImageAlphaMask Return type: void Description: Apply alpha mask to image Param[1]: image (type: Image *) Param[2]: alphaMask (type: Image) -Function 310: ImageAlphaPremultiply() (1 input parameters) +Function 316: ImageAlphaPremultiply() (1 input parameters) Name: ImageAlphaPremultiply Return type: void Description: Premultiply alpha channel Param[1]: image (type: Image *) -Function 311: ImageBlurGaussian() (2 input parameters) +Function 317: ImageBlurGaussian() (2 input parameters) Name: ImageBlurGaussian Return type: void Description: Apply Gaussian blur using a box blur approximation Param[1]: image (type: Image *) Param[2]: blurSize (type: int) -Function 312: ImageKernelConvolution() (3 input parameters) +Function 318: ImageKernelConvolution() (3 input parameters) Name: ImageKernelConvolution Return type: void Description: Apply custom square convolution kernel to image Param[1]: image (type: Image *) Param[2]: kernel (type: const float *) Param[3]: kernelSize (type: int) -Function 313: ImageResize() (3 input parameters) +Function 319: ImageResize() (3 input parameters) Name: ImageResize Return type: void Description: Resize image (Bicubic scaling algorithm) Param[1]: image (type: Image *) Param[2]: newWidth (type: int) Param[3]: newHeight (type: int) -Function 314: ImageResizeNN() (3 input parameters) +Function 320: ImageResizeNN() (3 input parameters) Name: ImageResizeNN Return type: void Description: Resize image (Nearest-Neighbor scaling algorithm) Param[1]: image (type: Image *) Param[2]: newWidth (type: int) Param[3]: newHeight (type: int) -Function 315: ImageResizeCanvas() (6 input parameters) +Function 321: ImageResizeCanvas() (6 input parameters) Name: ImageResizeCanvas Return type: void Description: Resize canvas and fill with color @@ -2926,12 +2962,12 @@ Function 315: ImageResizeCanvas() (6 input parameters) Param[4]: offsetX (type: int) Param[5]: offsetY (type: int) Param[6]: fill (type: Color) -Function 316: ImageMipmaps() (1 input parameters) +Function 322: ImageMipmaps() (1 input parameters) Name: ImageMipmaps Return type: void Description: Compute all mipmap levels for a provided image Param[1]: image (type: Image *) -Function 317: ImageDither() (5 input parameters) +Function 323: ImageDither() (5 input parameters) Name: ImageDither Return type: void Description: Dither image data to 16bpp or lower (Floyd-Steinberg dithering) @@ -2940,109 +2976,109 @@ Function 317: ImageDither() (5 input parameters) Param[3]: gBpp (type: int) Param[4]: bBpp (type: int) Param[5]: aBpp (type: int) -Function 318: ImageFlipVertical() (1 input parameters) +Function 324: ImageFlipVertical() (1 input parameters) Name: ImageFlipVertical Return type: void Description: Flip image vertically Param[1]: image (type: Image *) -Function 319: ImageFlipHorizontal() (1 input parameters) +Function 325: ImageFlipHorizontal() (1 input parameters) Name: ImageFlipHorizontal Return type: void Description: Flip image horizontally Param[1]: image (type: Image *) -Function 320: ImageRotate() (2 input parameters) +Function 326: ImageRotate() (2 input parameters) Name: ImageRotate Return type: void Description: Rotate image by input angle in degrees (-359 to 359) Param[1]: image (type: Image *) Param[2]: degrees (type: int) -Function 321: ImageRotateCW() (1 input parameters) +Function 327: ImageRotateCW() (1 input parameters) Name: ImageRotateCW Return type: void Description: Rotate image clockwise 90deg Param[1]: image (type: Image *) -Function 322: ImageRotateCCW() (1 input parameters) +Function 328: ImageRotateCCW() (1 input parameters) Name: ImageRotateCCW Return type: void Description: Rotate image counter-clockwise 90deg Param[1]: image (type: Image *) -Function 323: ImageColorTint() (2 input parameters) +Function 329: ImageColorTint() (2 input parameters) Name: ImageColorTint Return type: void Description: Modify image color: tint Param[1]: image (type: Image *) Param[2]: color (type: Color) -Function 324: ImageColorInvert() (1 input parameters) +Function 330: ImageColorInvert() (1 input parameters) Name: ImageColorInvert Return type: void Description: Modify image color: invert Param[1]: image (type: Image *) -Function 325: ImageColorGrayscale() (1 input parameters) +Function 331: ImageColorGrayscale() (1 input parameters) Name: ImageColorGrayscale Return type: void Description: Modify image color: grayscale Param[1]: image (type: Image *) -Function 326: ImageColorContrast() (2 input parameters) +Function 332: ImageColorContrast() (2 input parameters) Name: ImageColorContrast Return type: void Description: Modify image color: contrast (-100 to 100) Param[1]: image (type: Image *) Param[2]: contrast (type: float) -Function 327: ImageColorBrightness() (2 input parameters) +Function 333: ImageColorBrightness() (2 input parameters) Name: ImageColorBrightness Return type: void Description: Modify image color: brightness (-255 to 255) Param[1]: image (type: Image *) Param[2]: brightness (type: int) -Function 328: ImageColorReplace() (3 input parameters) +Function 334: ImageColorReplace() (3 input parameters) Name: ImageColorReplace Return type: void Description: Modify image color: replace color Param[1]: image (type: Image *) Param[2]: color (type: Color) Param[3]: replace (type: Color) -Function 329: LoadImageColors() (1 input parameters) +Function 335: LoadImageColors() (1 input parameters) Name: LoadImageColors Return type: Color * Description: Load color data from image as a Color array (RGBA - 32bit) Param[1]: image (type: Image) -Function 330: LoadImagePalette() (3 input parameters) +Function 336: LoadImagePalette() (3 input parameters) Name: LoadImagePalette Return type: Color * Description: Load colors palette from image as a Color array (RGBA - 32bit) Param[1]: image (type: Image) Param[2]: maxPaletteSize (type: int) Param[3]: colorCount (type: int *) -Function 331: UnloadImageColors() (1 input parameters) +Function 337: UnloadImageColors() (1 input parameters) Name: UnloadImageColors Return type: void Description: Unload color data loaded with LoadImageColors() Param[1]: colors (type: Color *) -Function 332: UnloadImagePalette() (1 input parameters) +Function 338: UnloadImagePalette() (1 input parameters) Name: UnloadImagePalette Return type: void Description: Unload colors palette loaded with LoadImagePalette() Param[1]: colors (type: Color *) -Function 333: GetImageAlphaBorder() (2 input parameters) +Function 339: GetImageAlphaBorder() (2 input parameters) Name: GetImageAlphaBorder Return type: Rectangle Description: Get image alpha border rectangle Param[1]: image (type: Image) Param[2]: threshold (type: float) -Function 334: GetImageColor() (3 input parameters) +Function 340: GetImageColor() (3 input parameters) Name: GetImageColor Return type: Color Description: Get image pixel color at (x, y) position Param[1]: image (type: Image) Param[2]: x (type: int) Param[3]: y (type: int) -Function 335: ImageClearBackground() (2 input parameters) +Function 341: ImageClearBackground() (2 input parameters) Name: ImageClearBackground Return type: void Description: Clear image background with given color Param[1]: dst (type: Image *) Param[2]: color (type: Color) -Function 336: ImageDrawPixel() (4 input parameters) +Function 342: ImageDrawPixel() (4 input parameters) Name: ImageDrawPixel Return type: void Description: Draw pixel within an image @@ -3050,14 +3086,14 @@ Function 336: ImageDrawPixel() (4 input parameters) Param[2]: posX (type: int) Param[3]: posY (type: int) Param[4]: color (type: Color) -Function 337: ImageDrawPixelV() (3 input parameters) +Function 343: ImageDrawPixelV() (3 input parameters) Name: ImageDrawPixelV Return type: void Description: Draw pixel within an image (Vector version) Param[1]: dst (type: Image *) Param[2]: position (type: Vector2) Param[3]: color (type: Color) -Function 338: ImageDrawLine() (6 input parameters) +Function 344: ImageDrawLine() (6 input parameters) Name: ImageDrawLine Return type: void Description: Draw line within an image @@ -3067,7 +3103,7 @@ Function 338: ImageDrawLine() (6 input parameters) Param[4]: endPosX (type: int) Param[5]: endPosY (type: int) Param[6]: color (type: Color) -Function 339: ImageDrawLineV() (4 input parameters) +Function 345: ImageDrawLineV() (4 input parameters) Name: ImageDrawLineV Return type: void Description: Draw line within an image (Vector version) @@ -3075,7 +3111,7 @@ Function 339: ImageDrawLineV() (4 input parameters) Param[2]: start (type: Vector2) Param[3]: end (type: Vector2) Param[4]: color (type: Color) -Function 340: ImageDrawLineEx() (5 input parameters) +Function 346: ImageDrawLineEx() (5 input parameters) Name: ImageDrawLineEx Return type: void Description: Draw a line defining thickness within an image @@ -3084,7 +3120,7 @@ Function 340: ImageDrawLineEx() (5 input parameters) Param[3]: end (type: Vector2) Param[4]: thick (type: int) Param[5]: color (type: Color) -Function 341: ImageDrawCircle() (5 input parameters) +Function 347: ImageDrawCircle() (5 input parameters) Name: ImageDrawCircle Return type: void Description: Draw a filled circle within an image @@ -3093,7 +3129,7 @@ Function 341: ImageDrawCircle() (5 input parameters) Param[3]: centerY (type: int) Param[4]: radius (type: int) Param[5]: color (type: Color) -Function 342: ImageDrawCircleV() (4 input parameters) +Function 348: ImageDrawCircleV() (4 input parameters) Name: ImageDrawCircleV Return type: void Description: Draw a filled circle within an image (Vector version) @@ -3101,7 +3137,7 @@ Function 342: ImageDrawCircleV() (4 input parameters) Param[2]: center (type: Vector2) Param[3]: radius (type: int) Param[4]: color (type: Color) -Function 343: ImageDrawCircleLines() (5 input parameters) +Function 349: ImageDrawCircleLines() (5 input parameters) Name: ImageDrawCircleLines Return type: void Description: Draw circle outline within an image @@ -3110,7 +3146,7 @@ Function 343: ImageDrawCircleLines() (5 input parameters) Param[3]: centerY (type: int) Param[4]: radius (type: int) Param[5]: color (type: Color) -Function 344: ImageDrawCircleLinesV() (4 input parameters) +Function 350: ImageDrawCircleLinesV() (4 input parameters) Name: ImageDrawCircleLinesV Return type: void Description: Draw circle outline within an image (Vector version) @@ -3118,7 +3154,7 @@ Function 344: ImageDrawCircleLinesV() (4 input parameters) Param[2]: center (type: Vector2) Param[3]: radius (type: int) Param[4]: color (type: Color) -Function 345: ImageDrawRectangle() (6 input parameters) +Function 351: ImageDrawRectangle() (6 input parameters) Name: ImageDrawRectangle Return type: void Description: Draw rectangle within an image @@ -3128,7 +3164,7 @@ Function 345: ImageDrawRectangle() (6 input parameters) Param[4]: width (type: int) Param[5]: height (type: int) Param[6]: color (type: Color) -Function 346: ImageDrawRectangleV() (4 input parameters) +Function 352: ImageDrawRectangleV() (4 input parameters) Name: ImageDrawRectangleV Return type: void Description: Draw rectangle within an image (Vector version) @@ -3136,14 +3172,14 @@ Function 346: ImageDrawRectangleV() (4 input parameters) Param[2]: position (type: Vector2) Param[3]: size (type: Vector2) Param[4]: color (type: Color) -Function 347: ImageDrawRectangleRec() (3 input parameters) +Function 353: ImageDrawRectangleRec() (3 input parameters) Name: ImageDrawRectangleRec Return type: void Description: Draw rectangle within an image Param[1]: dst (type: Image *) Param[2]: rec (type: Rectangle) Param[3]: color (type: Color) -Function 348: ImageDrawRectangleLines() (4 input parameters) +Function 354: ImageDrawRectangleLines() (4 input parameters) Name: ImageDrawRectangleLines Return type: void Description: Draw rectangle lines within an image @@ -3151,7 +3187,7 @@ Function 348: ImageDrawRectangleLines() (4 input parameters) Param[2]: rec (type: Rectangle) Param[3]: thick (type: int) Param[4]: color (type: Color) -Function 349: ImageDrawTriangle() (5 input parameters) +Function 355: ImageDrawTriangle() (5 input parameters) Name: ImageDrawTriangle Return type: void Description: Draw triangle within an image @@ -3160,7 +3196,7 @@ Function 349: ImageDrawTriangle() (5 input parameters) Param[3]: v2 (type: Vector2) Param[4]: v3 (type: Vector2) Param[5]: color (type: Color) -Function 350: ImageDrawTriangleEx() (7 input parameters) +Function 356: ImageDrawTriangleEx() (7 input parameters) Name: ImageDrawTriangleEx Return type: void Description: Draw triangle with interpolated colors within an image @@ -3171,7 +3207,7 @@ Function 350: ImageDrawTriangleEx() (7 input parameters) Param[5]: c1 (type: Color) Param[6]: c2 (type: Color) Param[7]: c3 (type: Color) -Function 351: ImageDrawTriangleLines() (5 input parameters) +Function 357: ImageDrawTriangleLines() (5 input parameters) Name: ImageDrawTriangleLines Return type: void Description: Draw triangle outline within an image @@ -3180,7 +3216,7 @@ Function 351: ImageDrawTriangleLines() (5 input parameters) Param[3]: v2 (type: Vector2) Param[4]: v3 (type: Vector2) Param[5]: color (type: Color) -Function 352: ImageDrawTriangleFan() (4 input parameters) +Function 358: ImageDrawTriangleFan() (4 input parameters) Name: ImageDrawTriangleFan Return type: void Description: Draw a triangle fan defined by points within an image (first vertex is the center) @@ -3188,7 +3224,7 @@ Function 352: ImageDrawTriangleFan() (4 input parameters) Param[2]: points (type: const Vector2 *) Param[3]: pointCount (type: int) Param[4]: color (type: Color) -Function 353: ImageDrawTriangleStrip() (4 input parameters) +Function 359: ImageDrawTriangleStrip() (4 input parameters) Name: ImageDrawTriangleStrip Return type: void Description: Draw a triangle strip defined by points within an image @@ -3196,7 +3232,7 @@ Function 353: ImageDrawTriangleStrip() (4 input parameters) Param[2]: points (type: const Vector2 *) Param[3]: pointCount (type: int) Param[4]: color (type: Color) -Function 354: ImageDraw() (5 input parameters) +Function 360: ImageDraw() (5 input parameters) Name: ImageDraw Return type: void Description: Draw a source image within a destination image (tint applied to source) @@ -3205,7 +3241,7 @@ Function 354: ImageDraw() (5 input parameters) Param[3]: srcRec (type: Rectangle) Param[4]: dstRec (type: Rectangle) Param[5]: tint (type: Color) -Function 355: ImageDrawText() (6 input parameters) +Function 361: ImageDrawText() (6 input parameters) Name: ImageDrawText Return type: void Description: Draw text (using default font) within an image (destination) @@ -3215,7 +3251,7 @@ Function 355: ImageDrawText() (6 input parameters) Param[4]: posY (type: int) Param[5]: fontSize (type: int) Param[6]: color (type: Color) -Function 356: ImageDrawTextEx() (7 input parameters) +Function 362: ImageDrawTextEx() (7 input parameters) Name: ImageDrawTextEx Return type: void Description: Draw text (custom sprite font) within an image (destination) @@ -3226,79 +3262,79 @@ Function 356: ImageDrawTextEx() (7 input parameters) Param[5]: fontSize (type: float) Param[6]: spacing (type: float) Param[7]: tint (type: Color) -Function 357: LoadTexture() (1 input parameters) +Function 363: LoadTexture() (1 input parameters) Name: LoadTexture Return type: Texture2D Description: Load texture from file into GPU memory (VRAM) Param[1]: fileName (type: const char *) -Function 358: LoadTextureFromImage() (1 input parameters) +Function 364: LoadTextureFromImage() (1 input parameters) Name: LoadTextureFromImage Return type: Texture2D Description: Load texture from image data Param[1]: image (type: Image) -Function 359: LoadTextureCubemap() (2 input parameters) +Function 365: LoadTextureCubemap() (2 input parameters) Name: LoadTextureCubemap Return type: TextureCubemap Description: Load cubemap from image, multiple image cubemap layouts supported Param[1]: image (type: Image) Param[2]: layout (type: int) -Function 360: LoadRenderTexture() (2 input parameters) +Function 366: LoadRenderTexture() (2 input parameters) Name: LoadRenderTexture Return type: RenderTexture2D Description: Load texture for rendering (framebuffer) Param[1]: width (type: int) Param[2]: height (type: int) -Function 361: IsTextureValid() (1 input parameters) +Function 367: IsTextureValid() (1 input parameters) Name: IsTextureValid Return type: bool Description: Check if a texture is valid (loaded in GPU) Param[1]: texture (type: Texture2D) -Function 362: UnloadTexture() (1 input parameters) +Function 368: UnloadTexture() (1 input parameters) Name: UnloadTexture Return type: void Description: Unload texture from GPU memory (VRAM) Param[1]: texture (type: Texture2D) -Function 363: IsRenderTextureValid() (1 input parameters) +Function 369: IsRenderTextureValid() (1 input parameters) Name: IsRenderTextureValid Return type: bool Description: Check if a render texture is valid (loaded in GPU) Param[1]: target (type: RenderTexture2D) -Function 364: UnloadRenderTexture() (1 input parameters) +Function 370: UnloadRenderTexture() (1 input parameters) Name: UnloadRenderTexture Return type: void Description: Unload render texture from GPU memory (VRAM) Param[1]: target (type: RenderTexture2D) -Function 365: UpdateTexture() (2 input parameters) +Function 371: UpdateTexture() (2 input parameters) Name: UpdateTexture Return type: void Description: Update GPU texture with new data (pixels should be able to fill texture) Param[1]: texture (type: Texture2D) Param[2]: pixels (type: const void *) -Function 366: UpdateTextureRec() (3 input parameters) +Function 372: UpdateTextureRec() (3 input parameters) Name: UpdateTextureRec Return type: void Description: Update GPU texture rectangle with new data (pixels and rec should fit in texture) Param[1]: texture (type: Texture2D) Param[2]: rec (type: Rectangle) Param[3]: pixels (type: const void *) -Function 367: GenTextureMipmaps() (1 input parameters) +Function 373: GenTextureMipmaps() (1 input parameters) Name: GenTextureMipmaps Return type: void Description: Generate GPU mipmaps for a texture Param[1]: texture (type: Texture2D *) -Function 368: SetTextureFilter() (2 input parameters) +Function 374: SetTextureFilter() (2 input parameters) Name: SetTextureFilter Return type: void Description: Set texture scaling filter mode Param[1]: texture (type: Texture2D) Param[2]: filter (type: int) -Function 369: SetTextureWrap() (2 input parameters) +Function 375: SetTextureWrap() (2 input parameters) Name: SetTextureWrap Return type: void Description: Set texture wrapping mode Param[1]: texture (type: Texture2D) Param[2]: wrap (type: int) -Function 370: DrawTexture() (4 input parameters) +Function 376: DrawTexture() (4 input parameters) Name: DrawTexture Return type: void Description: Draw a Texture2D @@ -3306,14 +3342,14 @@ Function 370: DrawTexture() (4 input parameters) Param[2]: posX (type: int) Param[3]: posY (type: int) Param[4]: tint (type: Color) -Function 371: DrawTextureV() (3 input parameters) +Function 377: DrawTextureV() (3 input parameters) Name: DrawTextureV Return type: void Description: Draw a Texture2D with position defined as Vector2 Param[1]: texture (type: Texture2D) Param[2]: position (type: Vector2) Param[3]: tint (type: Color) -Function 372: DrawTextureEx() (5 input parameters) +Function 378: DrawTextureEx() (5 input parameters) Name: DrawTextureEx Return type: void Description: Draw a Texture2D with extended parameters @@ -3322,7 +3358,7 @@ Function 372: DrawTextureEx() (5 input parameters) Param[3]: rotation (type: float) Param[4]: scale (type: float) Param[5]: tint (type: Color) -Function 373: DrawTextureRec() (4 input parameters) +Function 379: DrawTextureRec() (4 input parameters) Name: DrawTextureRec Return type: void Description: Draw a part of a texture defined by a rectangle @@ -3330,7 +3366,7 @@ Function 373: DrawTextureRec() (4 input parameters) Param[2]: source (type: Rectangle) Param[3]: position (type: Vector2) Param[4]: tint (type: Color) -Function 374: DrawTexturePro() (6 input parameters) +Function 380: DrawTexturePro() (6 input parameters) Name: DrawTexturePro Return type: void Description: Draw a part of a texture defined by a rectangle with 'pro' parameters @@ -3340,7 +3376,7 @@ Function 374: DrawTexturePro() (6 input parameters) Param[4]: origin (type: Vector2) Param[5]: rotation (type: float) Param[6]: tint (type: Color) -Function 375: DrawTextureNPatch() (6 input parameters) +Function 381: DrawTextureNPatch() (6 input parameters) Name: DrawTextureNPatch Return type: void Description: Draws a texture (or part of it) that stretches or shrinks nicely @@ -3350,119 +3386,119 @@ Function 375: DrawTextureNPatch() (6 input parameters) Param[4]: origin (type: Vector2) Param[5]: rotation (type: float) Param[6]: tint (type: Color) -Function 376: ColorIsEqual() (2 input parameters) +Function 382: ColorIsEqual() (2 input parameters) Name: ColorIsEqual Return type: bool Description: Check if two colors are equal Param[1]: col1 (type: Color) Param[2]: col2 (type: Color) -Function 377: Fade() (2 input parameters) +Function 383: Fade() (2 input parameters) Name: Fade Return type: Color Description: Get color with alpha applied, alpha goes from 0.0f to 1.0f Param[1]: color (type: Color) Param[2]: alpha (type: float) -Function 378: ColorToInt() (1 input parameters) +Function 384: ColorToInt() (1 input parameters) Name: ColorToInt Return type: int Description: Get hexadecimal value for a Color (0xRRGGBBAA) Param[1]: color (type: Color) -Function 379: ColorNormalize() (1 input parameters) +Function 385: ColorNormalize() (1 input parameters) Name: ColorNormalize Return type: Vector4 Description: Get Color normalized as float [0..1] Param[1]: color (type: Color) -Function 380: ColorFromNormalized() (1 input parameters) +Function 386: ColorFromNormalized() (1 input parameters) Name: ColorFromNormalized Return type: Color Description: Get Color from normalized values [0..1] Param[1]: normalized (type: Vector4) -Function 381: ColorToHSV() (1 input parameters) +Function 387: ColorToHSV() (1 input parameters) Name: ColorToHSV Return type: Vector3 Description: Get HSV values for a Color, hue [0..360], saturation/value [0..1] Param[1]: color (type: Color) -Function 382: ColorFromHSV() (3 input parameters) +Function 388: ColorFromHSV() (3 input parameters) Name: ColorFromHSV Return type: Color Description: Get a Color from HSV values, hue [0..360], saturation/value [0..1] Param[1]: hue (type: float) Param[2]: saturation (type: float) Param[3]: value (type: float) -Function 383: ColorTint() (2 input parameters) +Function 389: ColorTint() (2 input parameters) Name: ColorTint Return type: Color Description: Get color multiplied with another color Param[1]: color (type: Color) Param[2]: tint (type: Color) -Function 384: ColorBrightness() (2 input parameters) +Function 390: ColorBrightness() (2 input parameters) Name: ColorBrightness Return type: Color Description: Get color with brightness correction, brightness factor goes from -1.0f to 1.0f Param[1]: color (type: Color) Param[2]: factor (type: float) -Function 385: ColorContrast() (2 input parameters) +Function 391: ColorContrast() (2 input parameters) Name: ColorContrast Return type: Color Description: Get color with contrast correction, contrast values between -1.0f and 1.0f Param[1]: color (type: Color) Param[2]: contrast (type: float) -Function 386: ColorAlpha() (2 input parameters) +Function 392: ColorAlpha() (2 input parameters) Name: ColorAlpha Return type: Color Description: Get color with alpha applied, alpha goes from 0.0f to 1.0f Param[1]: color (type: Color) Param[2]: alpha (type: float) -Function 387: ColorAlphaBlend() (3 input parameters) +Function 393: ColorAlphaBlend() (3 input parameters) Name: ColorAlphaBlend Return type: Color Description: Get src alpha-blended into dst color with tint Param[1]: dst (type: Color) Param[2]: src (type: Color) Param[3]: tint (type: Color) -Function 388: ColorLerp() (3 input parameters) +Function 394: ColorLerp() (3 input parameters) Name: ColorLerp Return type: Color Description: Get color lerp interpolation between two colors, factor [0.0f..1.0f] Param[1]: color1 (type: Color) Param[2]: color2 (type: Color) Param[3]: factor (type: float) -Function 389: GetColor() (1 input parameters) +Function 395: GetColor() (1 input parameters) Name: GetColor Return type: Color Description: Get Color structure from hexadecimal value Param[1]: hexValue (type: unsigned int) -Function 390: GetPixelColor() (2 input parameters) +Function 396: GetPixelColor() (2 input parameters) Name: GetPixelColor Return type: Color Description: Get Color from a source pixel pointer of certain format Param[1]: srcPtr (type: void *) Param[2]: format (type: int) -Function 391: SetPixelColor() (3 input parameters) +Function 397: SetPixelColor() (3 input parameters) Name: SetPixelColor Return type: void Description: Set color formatted into destination pixel pointer Param[1]: dstPtr (type: void *) Param[2]: color (type: Color) Param[3]: format (type: int) -Function 392: GetPixelDataSize() (3 input parameters) +Function 398: GetPixelDataSize() (3 input parameters) Name: GetPixelDataSize Return type: int Description: Get pixel data size in bytes for certain format Param[1]: width (type: int) Param[2]: height (type: int) Param[3]: format (type: int) -Function 393: GetFontDefault() (0 input parameters) +Function 399: GetFontDefault() (0 input parameters) Name: GetFontDefault Return type: Font Description: Get the default Font No input parameters -Function 394: LoadFont() (1 input parameters) +Function 400: LoadFont() (1 input parameters) Name: LoadFont Return type: Font Description: Load font from file into GPU memory (VRAM) Param[1]: fileName (type: const char *) -Function 395: LoadFontEx() (4 input parameters) +Function 401: LoadFontEx() (4 input parameters) Name: LoadFontEx Return type: Font Description: Load font from file with extended parameters, use NULL for codepoints and 0 for codepointCount to load the default character set, font size is provided in pixels height @@ -3470,14 +3506,14 @@ Function 395: LoadFontEx() (4 input parameters) Param[2]: fontSize (type: int) Param[3]: codepoints (type: const int *) Param[4]: codepointCount (type: int) -Function 396: LoadFontFromImage() (3 input parameters) +Function 402: LoadFontFromImage() (3 input parameters) Name: LoadFontFromImage Return type: Font Description: Load font from Image (XNA style) Param[1]: image (type: Image) Param[2]: key (type: Color) Param[3]: firstChar (type: int) -Function 397: LoadFontFromMemory() (6 input parameters) +Function 403: LoadFontFromMemory() (6 input parameters) Name: LoadFontFromMemory Return type: Font Description: Load font from memory buffer, fileType refers to extension: i.e. '.ttf' @@ -3487,12 +3523,12 @@ Function 397: LoadFontFromMemory() (6 input parameters) Param[4]: fontSize (type: int) Param[5]: codepoints (type: const int *) Param[6]: codepointCount (type: int) -Function 398: IsFontValid() (1 input parameters) +Function 404: IsFontValid() (1 input parameters) Name: IsFontValid Return type: bool Description: Check if a font is valid (font data loaded, WARNING: GPU texture not checked) Param[1]: font (type: Font) -Function 399: LoadFontData() (7 input parameters) +Function 405: LoadFontData() (7 input parameters) Name: LoadFontData Return type: GlyphInfo * Description: Load font data for further use @@ -3503,7 +3539,7 @@ Function 399: LoadFontData() (7 input parameters) Param[5]: codepointCount (type: int) Param[6]: type (type: int) Param[7]: glyphCount (type: int *) -Function 400: GenImageFontAtlas() (6 input parameters) +Function 406: GenImageFontAtlas() (6 input parameters) Name: GenImageFontAtlas Return type: Image Description: Generate image font atlas using chars info @@ -3513,30 +3549,30 @@ Function 400: GenImageFontAtlas() (6 input parameters) Param[4]: fontSize (type: int) Param[5]: padding (type: int) Param[6]: packMethod (type: int) -Function 401: UnloadFontData() (2 input parameters) +Function 407: UnloadFontData() (2 input parameters) Name: UnloadFontData Return type: void Description: Unload font chars info data (RAM) Param[1]: glyphs (type: GlyphInfo *) Param[2]: glyphCount (type: int) -Function 402: UnloadFont() (1 input parameters) +Function 408: UnloadFont() (1 input parameters) Name: UnloadFont Return type: void Description: Unload font from GPU memory (VRAM) Param[1]: font (type: Font) -Function 403: ExportFontAsCode() (2 input parameters) +Function 409: ExportFontAsCode() (2 input parameters) Name: ExportFontAsCode Return type: bool Description: Export font as code file, returns true on success Param[1]: font (type: Font) Param[2]: fileName (type: const char *) -Function 404: DrawFPS() (2 input parameters) +Function 410: DrawFPS() (2 input parameters) Name: DrawFPS Return type: void Description: Draw current FPS Param[1]: posX (type: int) Param[2]: posY (type: int) -Function 405: DrawText() (5 input parameters) +Function 411: DrawText() (5 input parameters) Name: DrawText Return type: void Description: Draw text (using default font) @@ -3545,7 +3581,7 @@ Function 405: DrawText() (5 input parameters) Param[3]: posY (type: int) Param[4]: fontSize (type: int) Param[5]: color (type: Color) -Function 406: DrawTextEx() (6 input parameters) +Function 412: DrawTextEx() (6 input parameters) Name: DrawTextEx Return type: void Description: Draw text using font and additional parameters @@ -3555,7 +3591,7 @@ Function 406: DrawTextEx() (6 input parameters) Param[4]: fontSize (type: float) Param[5]: spacing (type: float) Param[6]: tint (type: Color) -Function 407: DrawTextPro() (8 input parameters) +Function 413: DrawTextPro() (8 input parameters) Name: DrawTextPro Return type: void Description: Draw text using Font and pro parameters (rotation) @@ -3567,7 +3603,7 @@ Function 407: DrawTextPro() (8 input parameters) Param[6]: fontSize (type: float) Param[7]: spacing (type: float) Param[8]: tint (type: Color) -Function 408: DrawTextCodepoint() (5 input parameters) +Function 414: DrawTextCodepoint() (5 input parameters) Name: DrawTextCodepoint Return type: void Description: Draw one character (codepoint) @@ -3576,7 +3612,7 @@ Function 408: DrawTextCodepoint() (5 input parameters) Param[3]: position (type: Vector2) Param[4]: fontSize (type: float) Param[5]: tint (type: Color) -Function 409: DrawTextCodepoints() (7 input parameters) +Function 415: DrawTextCodepoints() (7 input parameters) Name: DrawTextCodepoints Return type: void Description: Draw multiple character (codepoint) @@ -3587,18 +3623,18 @@ Function 409: DrawTextCodepoints() (7 input parameters) Param[5]: fontSize (type: float) Param[6]: spacing (type: float) Param[7]: tint (type: Color) -Function 410: SetTextLineSpacing() (1 input parameters) +Function 416: SetTextLineSpacing() (1 input parameters) Name: SetTextLineSpacing Return type: void Description: Set vertical line spacing when drawing with line-breaks Param[1]: spacing (type: int) -Function 411: MeasureText() (2 input parameters) +Function 417: MeasureText() (2 input parameters) Name: MeasureText Return type: int Description: Measure string width for default font Param[1]: text (type: const char *) Param[2]: fontSize (type: int) -Function 412: MeasureTextEx() (4 input parameters) +Function 418: MeasureTextEx() (4 input parameters) Name: MeasureTextEx Return type: Vector2 Description: Measure string size for Font @@ -3606,207 +3642,227 @@ Function 412: MeasureTextEx() (4 input parameters) Param[2]: text (type: const char *) Param[3]: fontSize (type: float) Param[4]: spacing (type: float) -Function 413: GetGlyphIndex() (2 input parameters) +Function 419: GetGlyphIndex() (2 input parameters) Name: GetGlyphIndex Return type: int Description: Get glyph index position in font for a codepoint (unicode character), fallback to '?' if not found Param[1]: font (type: Font) Param[2]: codepoint (type: int) -Function 414: GetGlyphInfo() (2 input parameters) +Function 420: GetGlyphInfo() (2 input parameters) Name: GetGlyphInfo Return type: GlyphInfo Description: Get glyph font info data for a codepoint (unicode character), fallback to '?' if not found Param[1]: font (type: Font) Param[2]: codepoint (type: int) -Function 415: GetGlyphAtlasRec() (2 input parameters) +Function 421: GetGlyphAtlasRec() (2 input parameters) Name: GetGlyphAtlasRec Return type: Rectangle Description: Get glyph rectangle in font atlas for a codepoint (unicode character), fallback to '?' if not found Param[1]: font (type: Font) Param[2]: codepoint (type: int) -Function 416: LoadUTF8() (2 input parameters) +Function 422: LoadUTF8() (2 input parameters) Name: LoadUTF8 Return type: char * Description: Load UTF-8 text encoded from codepoints array Param[1]: codepoints (type: const int *) Param[2]: length (type: int) -Function 417: UnloadUTF8() (1 input parameters) +Function 423: UnloadUTF8() (1 input parameters) Name: UnloadUTF8 Return type: void Description: Unload UTF-8 text encoded from codepoints array Param[1]: text (type: char *) -Function 418: LoadCodepoints() (2 input parameters) +Function 424: LoadCodepoints() (2 input parameters) Name: LoadCodepoints Return type: int * Description: Load all codepoints from a UTF-8 text string, codepoints count returned by parameter Param[1]: text (type: const char *) Param[2]: count (type: int *) -Function 419: UnloadCodepoints() (1 input parameters) +Function 425: UnloadCodepoints() (1 input parameters) Name: UnloadCodepoints Return type: void Description: Unload codepoints data from memory Param[1]: codepoints (type: int *) -Function 420: GetCodepointCount() (1 input parameters) +Function 426: GetCodepointCount() (1 input parameters) Name: GetCodepointCount Return type: int Description: Get total number of codepoints in a UTF-8 encoded string Param[1]: text (type: const char *) -Function 421: GetCodepoint() (2 input parameters) +Function 427: GetCodepoint() (2 input parameters) Name: GetCodepoint Return type: int Description: Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure Param[1]: text (type: const char *) Param[2]: codepointSize (type: int *) -Function 422: GetCodepointNext() (2 input parameters) +Function 428: GetCodepointNext() (2 input parameters) Name: GetCodepointNext Return type: int Description: Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure Param[1]: text (type: const char *) Param[2]: codepointSize (type: int *) -Function 423: GetCodepointPrevious() (2 input parameters) +Function 429: GetCodepointPrevious() (2 input parameters) Name: GetCodepointPrevious Return type: int Description: Get previous codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure Param[1]: text (type: const char *) Param[2]: codepointSize (type: int *) -Function 424: CodepointToUTF8() (2 input parameters) +Function 430: CodepointToUTF8() (2 input parameters) Name: CodepointToUTF8 Return type: const char * Description: Encode one codepoint into UTF-8 byte array (array length returned as parameter) Param[1]: codepoint (type: int) Param[2]: utf8Size (type: int *) -Function 425: LoadTextLines() (2 input parameters) +Function 431: LoadTextLines() (2 input parameters) Name: LoadTextLines Return type: char ** Description: Load text as separate lines ('\n') Param[1]: text (type: const char *) Param[2]: count (type: int *) -Function 426: UnloadTextLines() (2 input parameters) +Function 432: UnloadTextLines() (2 input parameters) Name: UnloadTextLines Return type: void Description: Unload text lines Param[1]: text (type: char **) Param[2]: lineCount (type: int) -Function 427: TextCopy() (2 input parameters) +Function 433: TextCopy() (2 input parameters) Name: TextCopy Return type: int Description: Copy one string to another, returns bytes copied Param[1]: dst (type: char *) Param[2]: src (type: const char *) -Function 428: TextIsEqual() (2 input parameters) +Function 434: TextIsEqual() (2 input parameters) Name: TextIsEqual Return type: bool Description: Check if two text string are equal Param[1]: text1 (type: const char *) Param[2]: text2 (type: const char *) -Function 429: TextLength() (1 input parameters) +Function 435: TextLength() (1 input parameters) Name: TextLength Return type: unsigned int Description: Get text length, checks for '\0' ending Param[1]: text (type: const char *) -Function 430: TextFormat() (2 input parameters) +Function 436: TextFormat() (2 input parameters) Name: TextFormat Return type: const char * Description: Text formatting with variables (sprintf() style) Param[1]: text (type: const char *) Param[2]: args (type: ...) -Function 431: TextSubtext() (3 input parameters) +Function 437: TextSubtext() (3 input parameters) Name: TextSubtext Return type: const char * Description: Get a piece of a text string Param[1]: text (type: const char *) Param[2]: position (type: int) Param[3]: length (type: int) -Function 432: TextReplace() (3 input parameters) +Function 438: TextRemoveSpaces() (1 input parameters) + Name: TextRemoveSpaces + Return type: const char * + Description: Remove text spaces, concat words + Param[1]: text (type: const char *) +Function 439: GetTextBetween() (3 input parameters) + Name: GetTextBetween + Return type: char * + Description: Get text between two strings + Param[1]: text (type: const char *) + Param[2]: begin (type: const char *) + Param[3]: end (type: const char *) +Function 440: TextReplace() (3 input parameters) Name: TextReplace Return type: char * Description: Replace text string (WARNING: memory must be freed!) Param[1]: text (type: const char *) - Param[2]: replace (type: const char *) - Param[3]: by (type: const char *) -Function 433: TextInsert() (3 input parameters) + Param[2]: search (type: const char *) + Param[3]: replacement (type: const char *) +Function 441: TextReplaceBetween() (4 input parameters) + Name: TextReplaceBetween + Return type: char * + Description: Replace text between two specific strings (WARNING: memory must be freed!) + Param[1]: text (type: const char *) + Param[2]: begin (type: const char *) + Param[3]: end (type: const char *) + Param[4]: replacement (type: const char *) +Function 442: TextInsert() (3 input parameters) Name: TextInsert Return type: char * Description: Insert text in a position (WARNING: memory must be freed!) Param[1]: text (type: const char *) Param[2]: insert (type: const char *) Param[3]: position (type: int) -Function 434: TextJoin() (3 input parameters) +Function 443: TextJoin() (3 input parameters) Name: TextJoin Return type: char * Description: Join text strings with delimiter Param[1]: textList (type: char **) Param[2]: count (type: int) Param[3]: delimiter (type: const char *) -Function 435: TextSplit() (3 input parameters) +Function 444: TextSplit() (3 input parameters) Name: TextSplit Return type: char ** Description: Split text into multiple strings, using MAX_TEXTSPLIT_COUNT static strings Param[1]: text (type: const char *) Param[2]: delimiter (type: char) Param[3]: count (type: int *) -Function 436: TextAppend() (3 input parameters) +Function 445: TextAppend() (3 input parameters) Name: TextAppend Return type: void - Description: Append text at specific position and move cursor! + Description: Append text at specific position and move cursor Param[1]: text (type: char *) Param[2]: append (type: const char *) Param[3]: position (type: int *) -Function 437: TextFindIndex() (2 input parameters) +Function 446: TextFindIndex() (2 input parameters) Name: TextFindIndex Return type: int Description: Find first text occurrence within a string, -1 if not found Param[1]: text (type: const char *) - Param[2]: find (type: const char *) -Function 438: TextToUpper() (1 input parameters) + Param[2]: search (type: const char *) +Function 447: TextToUpper() (1 input parameters) Name: TextToUpper Return type: char * Description: Get upper case version of provided string Param[1]: text (type: const char *) -Function 439: TextToLower() (1 input parameters) +Function 448: TextToLower() (1 input parameters) Name: TextToLower Return type: char * Description: Get lower case version of provided string Param[1]: text (type: const char *) -Function 440: TextToPascal() (1 input parameters) +Function 449: TextToPascal() (1 input parameters) Name: TextToPascal Return type: char * Description: Get Pascal case notation version of provided string Param[1]: text (type: const char *) -Function 441: TextToSnake() (1 input parameters) +Function 450: TextToSnake() (1 input parameters) Name: TextToSnake Return type: char * Description: Get Snake case notation version of provided string Param[1]: text (type: const char *) -Function 442: TextToCamel() (1 input parameters) +Function 451: TextToCamel() (1 input parameters) Name: TextToCamel Return type: char * Description: Get Camel case notation version of provided string Param[1]: text (type: const char *) -Function 443: TextToInteger() (1 input parameters) +Function 452: TextToInteger() (1 input parameters) Name: TextToInteger Return type: int Description: Get integer value from text Param[1]: text (type: const char *) -Function 444: TextToFloat() (1 input parameters) +Function 453: TextToFloat() (1 input parameters) Name: TextToFloat Return type: float Description: Get float value from text Param[1]: text (type: const char *) -Function 445: DrawLine3D() (3 input parameters) +Function 454: DrawLine3D() (3 input parameters) Name: DrawLine3D Return type: void Description: Draw a line in 3D world space Param[1]: startPos (type: Vector3) Param[2]: endPos (type: Vector3) Param[3]: color (type: Color) -Function 446: DrawPoint3D() (2 input parameters) +Function 455: DrawPoint3D() (2 input parameters) Name: DrawPoint3D Return type: void Description: Draw a point in 3D space, actually a small line Param[1]: position (type: Vector3) Param[2]: color (type: Color) -Function 447: DrawCircle3D() (5 input parameters) +Function 456: DrawCircle3D() (5 input parameters) Name: DrawCircle3D Return type: void Description: Draw a circle in 3D world space @@ -3815,7 +3871,7 @@ Function 447: DrawCircle3D() (5 input parameters) Param[3]: rotationAxis (type: Vector3) Param[4]: rotationAngle (type: float) Param[5]: color (type: Color) -Function 448: DrawTriangle3D() (4 input parameters) +Function 457: DrawTriangle3D() (4 input parameters) Name: DrawTriangle3D Return type: void Description: Draw a color-filled triangle (vertex in counter-clockwise order!) @@ -3823,14 +3879,14 @@ Function 448: DrawTriangle3D() (4 input parameters) Param[2]: v2 (type: Vector3) Param[3]: v3 (type: Vector3) Param[4]: color (type: Color) -Function 449: DrawTriangleStrip3D() (3 input parameters) +Function 458: DrawTriangleStrip3D() (3 input parameters) Name: DrawTriangleStrip3D Return type: void Description: Draw a triangle strip defined by points Param[1]: points (type: const Vector3 *) Param[2]: pointCount (type: int) Param[3]: color (type: Color) -Function 450: DrawCube() (5 input parameters) +Function 459: DrawCube() (5 input parameters) Name: DrawCube Return type: void Description: Draw cube @@ -3839,14 +3895,14 @@ Function 450: DrawCube() (5 input parameters) Param[3]: height (type: float) Param[4]: length (type: float) Param[5]: color (type: Color) -Function 451: DrawCubeV() (3 input parameters) +Function 460: DrawCubeV() (3 input parameters) Name: DrawCubeV Return type: void Description: Draw cube (Vector version) Param[1]: position (type: Vector3) Param[2]: size (type: Vector3) Param[3]: color (type: Color) -Function 452: DrawCubeWires() (5 input parameters) +Function 461: DrawCubeWires() (5 input parameters) Name: DrawCubeWires Return type: void Description: Draw cube wires @@ -3855,21 +3911,21 @@ Function 452: DrawCubeWires() (5 input parameters) Param[3]: height (type: float) Param[4]: length (type: float) Param[5]: color (type: Color) -Function 453: DrawCubeWiresV() (3 input parameters) +Function 462: DrawCubeWiresV() (3 input parameters) Name: DrawCubeWiresV Return type: void Description: Draw cube wires (Vector version) Param[1]: position (type: Vector3) Param[2]: size (type: Vector3) Param[3]: color (type: Color) -Function 454: DrawSphere() (3 input parameters) +Function 463: DrawSphere() (3 input parameters) Name: DrawSphere Return type: void Description: Draw sphere Param[1]: centerPos (type: Vector3) Param[2]: radius (type: float) Param[3]: color (type: Color) -Function 455: DrawSphereEx() (5 input parameters) +Function 464: DrawSphereEx() (5 input parameters) Name: DrawSphereEx Return type: void Description: Draw sphere with extended parameters @@ -3878,7 +3934,7 @@ Function 455: DrawSphereEx() (5 input parameters) Param[3]: rings (type: int) Param[4]: slices (type: int) Param[5]: color (type: Color) -Function 456: DrawSphereWires() (5 input parameters) +Function 465: DrawSphereWires() (5 input parameters) Name: DrawSphereWires Return type: void Description: Draw sphere wires @@ -3887,7 +3943,7 @@ Function 456: DrawSphereWires() (5 input parameters) Param[3]: rings (type: int) Param[4]: slices (type: int) Param[5]: color (type: Color) -Function 457: DrawCylinder() (6 input parameters) +Function 466: DrawCylinder() (6 input parameters) Name: DrawCylinder Return type: void Description: Draw a cylinder/cone @@ -3897,7 +3953,7 @@ Function 457: DrawCylinder() (6 input parameters) Param[4]: height (type: float) Param[5]: slices (type: int) Param[6]: color (type: Color) -Function 458: DrawCylinderEx() (6 input parameters) +Function 467: DrawCylinderEx() (6 input parameters) Name: DrawCylinderEx Return type: void Description: Draw a cylinder with base at startPos and top at endPos @@ -3907,7 +3963,7 @@ Function 458: DrawCylinderEx() (6 input parameters) Param[4]: endRadius (type: float) Param[5]: sides (type: int) Param[6]: color (type: Color) -Function 459: DrawCylinderWires() (6 input parameters) +Function 468: DrawCylinderWires() (6 input parameters) Name: DrawCylinderWires Return type: void Description: Draw a cylinder/cone wires @@ -3917,7 +3973,7 @@ Function 459: DrawCylinderWires() (6 input parameters) Param[4]: height (type: float) Param[5]: slices (type: int) Param[6]: color (type: Color) -Function 460: DrawCylinderWiresEx() (6 input parameters) +Function 469: DrawCylinderWiresEx() (6 input parameters) Name: DrawCylinderWiresEx Return type: void Description: Draw a cylinder wires with base at startPos and top at endPos @@ -3927,7 +3983,7 @@ Function 460: DrawCylinderWiresEx() (6 input parameters) Param[4]: endRadius (type: float) Param[5]: sides (type: int) Param[6]: color (type: Color) -Function 461: DrawCapsule() (6 input parameters) +Function 470: DrawCapsule() (6 input parameters) Name: DrawCapsule Return type: void Description: Draw a capsule with the center of its sphere caps at startPos and endPos @@ -3937,7 +3993,7 @@ Function 461: DrawCapsule() (6 input parameters) Param[4]: slices (type: int) Param[5]: rings (type: int) Param[6]: color (type: Color) -Function 462: DrawCapsuleWires() (6 input parameters) +Function 471: DrawCapsuleWires() (6 input parameters) Name: DrawCapsuleWires Return type: void Description: Draw capsule wireframe with the center of its sphere caps at startPos and endPos @@ -3947,51 +4003,51 @@ Function 462: DrawCapsuleWires() (6 input parameters) Param[4]: slices (type: int) Param[5]: rings (type: int) Param[6]: color (type: Color) -Function 463: DrawPlane() (3 input parameters) +Function 472: DrawPlane() (3 input parameters) Name: DrawPlane Return type: void Description: Draw a plane XZ Param[1]: centerPos (type: Vector3) Param[2]: size (type: Vector2) Param[3]: color (type: Color) -Function 464: DrawRay() (2 input parameters) +Function 473: DrawRay() (2 input parameters) Name: DrawRay Return type: void Description: Draw a ray line Param[1]: ray (type: Ray) Param[2]: color (type: Color) -Function 465: DrawGrid() (2 input parameters) +Function 474: DrawGrid() (2 input parameters) Name: DrawGrid Return type: void Description: Draw a grid (centered at (0, 0, 0)) Param[1]: slices (type: int) Param[2]: spacing (type: float) -Function 466: LoadModel() (1 input parameters) +Function 475: LoadModel() (1 input parameters) Name: LoadModel Return type: Model Description: Load model from files (meshes and materials) Param[1]: fileName (type: const char *) -Function 467: LoadModelFromMesh() (1 input parameters) +Function 476: LoadModelFromMesh() (1 input parameters) Name: LoadModelFromMesh Return type: Model Description: Load model from generated mesh (default material) Param[1]: mesh (type: Mesh) -Function 468: IsModelValid() (1 input parameters) +Function 477: IsModelValid() (1 input parameters) Name: IsModelValid Return type: bool Description: Check if a model is valid (loaded in GPU, VAO/VBOs) Param[1]: model (type: Model) -Function 469: UnloadModel() (1 input parameters) +Function 478: UnloadModel() (1 input parameters) Name: UnloadModel Return type: void Description: Unload model (including meshes) from memory (RAM and/or VRAM) Param[1]: model (type: Model) -Function 470: GetModelBoundingBox() (1 input parameters) +Function 479: GetModelBoundingBox() (1 input parameters) Name: GetModelBoundingBox Return type: BoundingBox Description: Compute model bounding box limits (considers all meshes) Param[1]: model (type: Model) -Function 471: DrawModel() (4 input parameters) +Function 480: DrawModel() (4 input parameters) Name: DrawModel Return type: void Description: Draw a model (with texture if set) @@ -3999,7 +4055,7 @@ Function 471: DrawModel() (4 input parameters) Param[2]: position (type: Vector3) Param[3]: scale (type: float) Param[4]: tint (type: Color) -Function 472: DrawModelEx() (6 input parameters) +Function 481: DrawModelEx() (6 input parameters) Name: DrawModelEx Return type: void Description: Draw a model with extended parameters @@ -4009,7 +4065,7 @@ Function 472: DrawModelEx() (6 input parameters) Param[4]: rotationAngle (type: float) Param[5]: scale (type: Vector3) Param[6]: tint (type: Color) -Function 473: DrawModelWires() (4 input parameters) +Function 482: DrawModelWires() (4 input parameters) Name: DrawModelWires Return type: void Description: Draw a model wires (with texture if set) @@ -4017,7 +4073,7 @@ Function 473: DrawModelWires() (4 input parameters) Param[2]: position (type: Vector3) Param[3]: scale (type: float) Param[4]: tint (type: Color) -Function 474: DrawModelWiresEx() (6 input parameters) +Function 483: DrawModelWiresEx() (6 input parameters) Name: DrawModelWiresEx Return type: void Description: Draw a model wires (with texture if set) with extended parameters @@ -4027,7 +4083,7 @@ Function 474: DrawModelWiresEx() (6 input parameters) Param[4]: rotationAngle (type: float) Param[5]: scale (type: Vector3) Param[6]: tint (type: Color) -Function 475: DrawModelPoints() (4 input parameters) +Function 484: DrawModelPoints() (4 input parameters) Name: DrawModelPoints Return type: void Description: Draw a model as points @@ -4035,7 +4091,7 @@ Function 475: DrawModelPoints() (4 input parameters) Param[2]: position (type: Vector3) Param[3]: scale (type: float) Param[4]: tint (type: Color) -Function 476: DrawModelPointsEx() (6 input parameters) +Function 485: DrawModelPointsEx() (6 input parameters) Name: DrawModelPointsEx Return type: void Description: Draw a model as points with extended parameters @@ -4045,13 +4101,13 @@ Function 476: DrawModelPointsEx() (6 input parameters) Param[4]: rotationAngle (type: float) Param[5]: scale (type: Vector3) Param[6]: tint (type: Color) -Function 477: DrawBoundingBox() (2 input parameters) +Function 486: DrawBoundingBox() (2 input parameters) Name: DrawBoundingBox Return type: void Description: Draw bounding box (wires) Param[1]: box (type: BoundingBox) Param[2]: color (type: Color) -Function 478: DrawBillboard() (5 input parameters) +Function 487: DrawBillboard() (5 input parameters) Name: DrawBillboard Return type: void Description: Draw a billboard texture @@ -4060,7 +4116,7 @@ Function 478: DrawBillboard() (5 input parameters) Param[3]: position (type: Vector3) Param[4]: scale (type: float) Param[5]: tint (type: Color) -Function 479: DrawBillboardRec() (6 input parameters) +Function 488: DrawBillboardRec() (6 input parameters) Name: DrawBillboardRec Return type: void Description: Draw a billboard texture defined by source @@ -4070,7 +4126,7 @@ Function 479: DrawBillboardRec() (6 input parameters) Param[4]: position (type: Vector3) Param[5]: size (type: Vector2) Param[6]: tint (type: Color) -Function 480: DrawBillboardPro() (9 input parameters) +Function 489: DrawBillboardPro() (9 input parameters) Name: DrawBillboardPro Return type: void Description: Draw a billboard texture defined by source and rotation @@ -4083,13 +4139,13 @@ Function 480: DrawBillboardPro() (9 input parameters) Param[7]: origin (type: Vector2) Param[8]: rotation (type: float) Param[9]: tint (type: Color) -Function 481: UploadMesh() (2 input parameters) +Function 490: UploadMesh() (2 input parameters) Name: UploadMesh Return type: void Description: Upload mesh vertex data in GPU and provide VAO/VBO ids Param[1]: mesh (type: Mesh *) Param[2]: dynamic (type: bool) -Function 482: UpdateMeshBuffer() (5 input parameters) +Function 491: UpdateMeshBuffer() (5 input parameters) Name: UpdateMeshBuffer Return type: void Description: Update mesh vertex data in GPU for a specific buffer index @@ -4098,19 +4154,19 @@ Function 482: UpdateMeshBuffer() (5 input parameters) Param[3]: data (type: const void *) Param[4]: dataSize (type: int) Param[5]: offset (type: int) -Function 483: UnloadMesh() (1 input parameters) +Function 492: UnloadMesh() (1 input parameters) Name: UnloadMesh Return type: void Description: Unload mesh data from CPU and GPU Param[1]: mesh (type: Mesh) -Function 484: DrawMesh() (3 input parameters) +Function 493: DrawMesh() (3 input parameters) Name: DrawMesh Return type: void Description: Draw a 3d mesh with material and transform Param[1]: mesh (type: Mesh) Param[2]: material (type: Material) Param[3]: transform (type: Matrix) -Function 485: DrawMeshInstanced() (4 input parameters) +Function 494: DrawMeshInstanced() (4 input parameters) Name: DrawMeshInstanced Return type: void Description: Draw multiple mesh instances with material and different transforms @@ -4118,35 +4174,35 @@ Function 485: DrawMeshInstanced() (4 input parameters) Param[2]: material (type: Material) Param[3]: transforms (type: const Matrix *) Param[4]: instances (type: int) -Function 486: GetMeshBoundingBox() (1 input parameters) +Function 495: GetMeshBoundingBox() (1 input parameters) Name: GetMeshBoundingBox Return type: BoundingBox Description: Compute mesh bounding box limits Param[1]: mesh (type: Mesh) -Function 487: GenMeshTangents() (1 input parameters) +Function 496: GenMeshTangents() (1 input parameters) Name: GenMeshTangents Return type: void Description: Compute mesh tangents Param[1]: mesh (type: Mesh *) -Function 488: ExportMesh() (2 input parameters) +Function 497: ExportMesh() (2 input parameters) Name: ExportMesh Return type: bool Description: Export mesh data to file, returns true on success Param[1]: mesh (type: Mesh) Param[2]: fileName (type: const char *) -Function 489: ExportMeshAsCode() (2 input parameters) +Function 498: ExportMeshAsCode() (2 input parameters) Name: ExportMeshAsCode Return type: bool Description: Export mesh as code file (.h) defining multiple arrays of vertex attributes Param[1]: mesh (type: Mesh) Param[2]: fileName (type: const char *) -Function 490: GenMeshPoly() (2 input parameters) +Function 499: GenMeshPoly() (2 input parameters) Name: GenMeshPoly Return type: Mesh Description: Generate polygonal mesh Param[1]: sides (type: int) Param[2]: radius (type: float) -Function 491: GenMeshPlane() (4 input parameters) +Function 500: GenMeshPlane() (4 input parameters) Name: GenMeshPlane Return type: Mesh Description: Generate plane mesh (with subdivisions) @@ -4154,42 +4210,42 @@ Function 491: GenMeshPlane() (4 input parameters) Param[2]: length (type: float) Param[3]: resX (type: int) Param[4]: resZ (type: int) -Function 492: GenMeshCube() (3 input parameters) +Function 501: GenMeshCube() (3 input parameters) Name: GenMeshCube Return type: Mesh Description: Generate cuboid mesh Param[1]: width (type: float) Param[2]: height (type: float) Param[3]: length (type: float) -Function 493: GenMeshSphere() (3 input parameters) +Function 502: GenMeshSphere() (3 input parameters) Name: GenMeshSphere Return type: Mesh Description: Generate sphere mesh (standard sphere) Param[1]: radius (type: float) Param[2]: rings (type: int) Param[3]: slices (type: int) -Function 494: GenMeshHemiSphere() (3 input parameters) +Function 503: GenMeshHemiSphere() (3 input parameters) Name: GenMeshHemiSphere Return type: Mesh Description: Generate half-sphere mesh (no bottom cap) Param[1]: radius (type: float) Param[2]: rings (type: int) Param[3]: slices (type: int) -Function 495: GenMeshCylinder() (3 input parameters) +Function 504: GenMeshCylinder() (3 input parameters) Name: GenMeshCylinder Return type: Mesh Description: Generate cylinder mesh Param[1]: radius (type: float) Param[2]: height (type: float) Param[3]: slices (type: int) -Function 496: GenMeshCone() (3 input parameters) +Function 505: GenMeshCone() (3 input parameters) Name: GenMeshCone Return type: Mesh Description: Generate cone/pyramid mesh Param[1]: radius (type: float) Param[2]: height (type: float) Param[3]: slices (type: int) -Function 497: GenMeshTorus() (4 input parameters) +Function 506: GenMeshTorus() (4 input parameters) Name: GenMeshTorus Return type: Mesh Description: Generate torus mesh @@ -4197,7 +4253,7 @@ Function 497: GenMeshTorus() (4 input parameters) Param[2]: size (type: float) Param[3]: radSeg (type: int) Param[4]: sides (type: int) -Function 498: GenMeshKnot() (4 input parameters) +Function 507: GenMeshKnot() (4 input parameters) Name: GenMeshKnot Return type: Mesh Description: Generate trefoil knot mesh @@ -4205,91 +4261,91 @@ Function 498: GenMeshKnot() (4 input parameters) Param[2]: size (type: float) Param[3]: radSeg (type: int) Param[4]: sides (type: int) -Function 499: GenMeshHeightmap() (2 input parameters) +Function 508: GenMeshHeightmap() (2 input parameters) Name: GenMeshHeightmap Return type: Mesh Description: Generate heightmap mesh from image data Param[1]: heightmap (type: Image) Param[2]: size (type: Vector3) -Function 500: GenMeshCubicmap() (2 input parameters) +Function 509: GenMeshCubicmap() (2 input parameters) Name: GenMeshCubicmap Return type: Mesh Description: Generate cubes-based map mesh from image data Param[1]: cubicmap (type: Image) Param[2]: cubeSize (type: Vector3) -Function 501: LoadMaterials() (2 input parameters) +Function 510: LoadMaterials() (2 input parameters) Name: LoadMaterials Return type: Material * Description: Load materials from model file Param[1]: fileName (type: const char *) Param[2]: materialCount (type: int *) -Function 502: LoadMaterialDefault() (0 input parameters) +Function 511: LoadMaterialDefault() (0 input parameters) Name: LoadMaterialDefault Return type: Material Description: Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps) No input parameters -Function 503: IsMaterialValid() (1 input parameters) +Function 512: IsMaterialValid() (1 input parameters) Name: IsMaterialValid Return type: bool Description: Check if a material is valid (shader assigned, map textures loaded in GPU) Param[1]: material (type: Material) -Function 504: UnloadMaterial() (1 input parameters) +Function 513: UnloadMaterial() (1 input parameters) Name: UnloadMaterial Return type: void Description: Unload material from GPU memory (VRAM) Param[1]: material (type: Material) -Function 505: SetMaterialTexture() (3 input parameters) +Function 514: SetMaterialTexture() (3 input parameters) Name: SetMaterialTexture Return type: void Description: Set texture for a material map type (MATERIAL_MAP_DIFFUSE, MATERIAL_MAP_SPECULAR...) Param[1]: material (type: Material *) Param[2]: mapType (type: int) Param[3]: texture (type: Texture2D) -Function 506: SetModelMeshMaterial() (3 input parameters) +Function 515: SetModelMeshMaterial() (3 input parameters) Name: SetModelMeshMaterial Return type: void Description: Set material for a mesh Param[1]: model (type: Model *) Param[2]: meshId (type: int) Param[3]: materialId (type: int) -Function 507: LoadModelAnimations() (2 input parameters) +Function 516: LoadModelAnimations() (2 input parameters) Name: LoadModelAnimations Return type: ModelAnimation * Description: Load model animations from file Param[1]: fileName (type: const char *) Param[2]: animCount (type: int *) -Function 508: UpdateModelAnimation() (3 input parameters) +Function 517: UpdateModelAnimation() (3 input parameters) Name: UpdateModelAnimation Return type: void Description: Update model animation pose (CPU) Param[1]: model (type: Model) Param[2]: anim (type: ModelAnimation) Param[3]: frame (type: int) -Function 509: UpdateModelAnimationBones() (3 input parameters) +Function 518: UpdateModelAnimationBones() (3 input parameters) Name: UpdateModelAnimationBones Return type: void Description: Update model animation mesh bone matrices (GPU skinning) Param[1]: model (type: Model) Param[2]: anim (type: ModelAnimation) Param[3]: frame (type: int) -Function 510: UnloadModelAnimation() (1 input parameters) +Function 519: UnloadModelAnimation() (1 input parameters) Name: UnloadModelAnimation Return type: void Description: Unload animation data Param[1]: anim (type: ModelAnimation) -Function 511: UnloadModelAnimations() (2 input parameters) +Function 520: UnloadModelAnimations() (2 input parameters) Name: UnloadModelAnimations Return type: void Description: Unload animation array data Param[1]: animations (type: ModelAnimation *) Param[2]: animCount (type: int) -Function 512: IsModelAnimationValid() (2 input parameters) +Function 521: IsModelAnimationValid() (2 input parameters) Name: IsModelAnimationValid Return type: bool Description: Check model animation skeleton match Param[1]: model (type: Model) Param[2]: anim (type: ModelAnimation) -Function 513: CheckCollisionSpheres() (4 input parameters) +Function 522: CheckCollisionSpheres() (4 input parameters) Name: CheckCollisionSpheres Return type: bool Description: Check collision between two spheres @@ -4297,40 +4353,40 @@ Function 513: CheckCollisionSpheres() (4 input parameters) Param[2]: radius1 (type: float) Param[3]: center2 (type: Vector3) Param[4]: radius2 (type: float) -Function 514: CheckCollisionBoxes() (2 input parameters) +Function 523: CheckCollisionBoxes() (2 input parameters) Name: CheckCollisionBoxes Return type: bool Description: Check collision between two bounding boxes Param[1]: box1 (type: BoundingBox) Param[2]: box2 (type: BoundingBox) -Function 515: CheckCollisionBoxSphere() (3 input parameters) +Function 524: CheckCollisionBoxSphere() (3 input parameters) Name: CheckCollisionBoxSphere Return type: bool Description: Check collision between box and sphere Param[1]: box (type: BoundingBox) Param[2]: center (type: Vector3) Param[3]: radius (type: float) -Function 516: GetRayCollisionSphere() (3 input parameters) +Function 525: GetRayCollisionSphere() (3 input parameters) Name: GetRayCollisionSphere Return type: RayCollision Description: Get collision info between ray and sphere Param[1]: ray (type: Ray) Param[2]: center (type: Vector3) Param[3]: radius (type: float) -Function 517: GetRayCollisionBox() (2 input parameters) +Function 526: GetRayCollisionBox() (2 input parameters) Name: GetRayCollisionBox Return type: RayCollision Description: Get collision info between ray and box Param[1]: ray (type: Ray) Param[2]: box (type: BoundingBox) -Function 518: GetRayCollisionMesh() (3 input parameters) +Function 527: GetRayCollisionMesh() (3 input parameters) Name: GetRayCollisionMesh Return type: RayCollision Description: Get collision info between ray and mesh Param[1]: ray (type: Ray) Param[2]: mesh (type: Mesh) Param[3]: transform (type: Matrix) -Function 519: GetRayCollisionTriangle() (4 input parameters) +Function 528: GetRayCollisionTriangle() (4 input parameters) Name: GetRayCollisionTriangle Return type: RayCollision Description: Get collision info between ray and triangle @@ -4338,7 +4394,7 @@ Function 519: GetRayCollisionTriangle() (4 input parameters) Param[2]: p1 (type: Vector3) Param[3]: p2 (type: Vector3) Param[4]: p3 (type: Vector3) -Function 520: GetRayCollisionQuad() (5 input parameters) +Function 529: GetRayCollisionQuad() (5 input parameters) Name: GetRayCollisionQuad Return type: RayCollision Description: Get collision info between ray and quad @@ -4347,158 +4403,158 @@ Function 520: GetRayCollisionQuad() (5 input parameters) Param[3]: p2 (type: Vector3) Param[4]: p3 (type: Vector3) Param[5]: p4 (type: Vector3) -Function 521: InitAudioDevice() (0 input parameters) +Function 530: InitAudioDevice() (0 input parameters) Name: InitAudioDevice Return type: void Description: Initialize audio device and context No input parameters -Function 522: CloseAudioDevice() (0 input parameters) +Function 531: CloseAudioDevice() (0 input parameters) Name: CloseAudioDevice Return type: void Description: Close the audio device and context No input parameters -Function 523: IsAudioDeviceReady() (0 input parameters) +Function 532: IsAudioDeviceReady() (0 input parameters) Name: IsAudioDeviceReady Return type: bool Description: Check if audio device has been initialized successfully No input parameters -Function 524: SetMasterVolume() (1 input parameters) +Function 533: SetMasterVolume() (1 input parameters) Name: SetMasterVolume Return type: void Description: Set master volume (listener) Param[1]: volume (type: float) -Function 525: GetMasterVolume() (0 input parameters) +Function 534: GetMasterVolume() (0 input parameters) Name: GetMasterVolume Return type: float Description: Get master volume (listener) No input parameters -Function 526: LoadWave() (1 input parameters) +Function 535: LoadWave() (1 input parameters) Name: LoadWave Return type: Wave Description: Load wave data from file Param[1]: fileName (type: const char *) -Function 527: LoadWaveFromMemory() (3 input parameters) +Function 536: LoadWaveFromMemory() (3 input parameters) Name: LoadWaveFromMemory Return type: Wave Description: Load wave from memory buffer, fileType refers to extension: i.e. '.wav' Param[1]: fileType (type: const char *) Param[2]: fileData (type: const unsigned char *) Param[3]: dataSize (type: int) -Function 528: IsWaveValid() (1 input parameters) +Function 537: IsWaveValid() (1 input parameters) Name: IsWaveValid Return type: bool Description: Checks if wave data is valid (data loaded and parameters) Param[1]: wave (type: Wave) -Function 529: LoadSound() (1 input parameters) +Function 538: LoadSound() (1 input parameters) Name: LoadSound Return type: Sound Description: Load sound from file Param[1]: fileName (type: const char *) -Function 530: LoadSoundFromWave() (1 input parameters) +Function 539: LoadSoundFromWave() (1 input parameters) Name: LoadSoundFromWave Return type: Sound Description: Load sound from wave data Param[1]: wave (type: Wave) -Function 531: LoadSoundAlias() (1 input parameters) +Function 540: LoadSoundAlias() (1 input parameters) Name: LoadSoundAlias Return type: Sound Description: Create a new sound that shares the same sample data as the source sound, does not own the sound data Param[1]: source (type: Sound) -Function 532: IsSoundValid() (1 input parameters) +Function 541: IsSoundValid() (1 input parameters) Name: IsSoundValid Return type: bool Description: Checks if a sound is valid (data loaded and buffers initialized) Param[1]: sound (type: Sound) -Function 533: UpdateSound() (3 input parameters) +Function 542: UpdateSound() (3 input parameters) Name: UpdateSound Return type: void Description: Update sound buffer with new data (data and frame count should fit in sound) Param[1]: sound (type: Sound) Param[2]: data (type: const void *) Param[3]: sampleCount (type: int) -Function 534: UnloadWave() (1 input parameters) +Function 543: UnloadWave() (1 input parameters) Name: UnloadWave Return type: void Description: Unload wave data Param[1]: wave (type: Wave) -Function 535: UnloadSound() (1 input parameters) +Function 544: UnloadSound() (1 input parameters) Name: UnloadSound Return type: void Description: Unload sound Param[1]: sound (type: Sound) -Function 536: UnloadSoundAlias() (1 input parameters) +Function 545: UnloadSoundAlias() (1 input parameters) Name: UnloadSoundAlias Return type: void Description: Unload a sound alias (does not deallocate sample data) Param[1]: alias (type: Sound) -Function 537: ExportWave() (2 input parameters) +Function 546: ExportWave() (2 input parameters) Name: ExportWave Return type: bool Description: Export wave data to file, returns true on success Param[1]: wave (type: Wave) Param[2]: fileName (type: const char *) -Function 538: ExportWaveAsCode() (2 input parameters) +Function 547: ExportWaveAsCode() (2 input parameters) Name: ExportWaveAsCode Return type: bool Description: Export wave sample data to code (.h), returns true on success Param[1]: wave (type: Wave) Param[2]: fileName (type: const char *) -Function 539: PlaySound() (1 input parameters) +Function 548: PlaySound() (1 input parameters) Name: PlaySound Return type: void Description: Play a sound Param[1]: sound (type: Sound) -Function 540: StopSound() (1 input parameters) +Function 549: StopSound() (1 input parameters) Name: StopSound Return type: void Description: Stop playing a sound Param[1]: sound (type: Sound) -Function 541: PauseSound() (1 input parameters) +Function 550: PauseSound() (1 input parameters) Name: PauseSound Return type: void Description: Pause a sound Param[1]: sound (type: Sound) -Function 542: ResumeSound() (1 input parameters) +Function 551: ResumeSound() (1 input parameters) Name: ResumeSound Return type: void Description: Resume a paused sound Param[1]: sound (type: Sound) -Function 543: IsSoundPlaying() (1 input parameters) +Function 552: IsSoundPlaying() (1 input parameters) Name: IsSoundPlaying Return type: bool Description: Check if a sound is currently playing Param[1]: sound (type: Sound) -Function 544: SetSoundVolume() (2 input parameters) +Function 553: SetSoundVolume() (2 input parameters) Name: SetSoundVolume Return type: void Description: Set volume for a sound (1.0 is max level) Param[1]: sound (type: Sound) Param[2]: volume (type: float) -Function 545: SetSoundPitch() (2 input parameters) +Function 554: SetSoundPitch() (2 input parameters) Name: SetSoundPitch Return type: void Description: Set pitch for a sound (1.0 is base level) Param[1]: sound (type: Sound) Param[2]: pitch (type: float) -Function 546: SetSoundPan() (2 input parameters) +Function 555: SetSoundPan() (2 input parameters) Name: SetSoundPan Return type: void Description: Set pan for a sound (0.5 is center) Param[1]: sound (type: Sound) Param[2]: pan (type: float) -Function 547: WaveCopy() (1 input parameters) +Function 556: WaveCopy() (1 input parameters) Name: WaveCopy Return type: Wave Description: Copy a wave to a new wave Param[1]: wave (type: Wave) -Function 548: WaveCrop() (3 input parameters) +Function 557: WaveCrop() (3 input parameters) Name: WaveCrop Return type: void Description: Crop a wave to defined frames range Param[1]: wave (type: Wave *) Param[2]: initFrame (type: int) Param[3]: finalFrame (type: int) -Function 549: WaveFormat() (4 input parameters) +Function 558: WaveFormat() (4 input parameters) Name: WaveFormat Return type: void Description: Convert wave data to desired format @@ -4506,203 +4562,203 @@ Function 549: WaveFormat() (4 input parameters) Param[2]: sampleRate (type: int) Param[3]: sampleSize (type: int) Param[4]: channels (type: int) -Function 550: LoadWaveSamples() (1 input parameters) +Function 559: LoadWaveSamples() (1 input parameters) Name: LoadWaveSamples Return type: float * Description: Load samples data from wave as a 32bit float data array Param[1]: wave (type: Wave) -Function 551: UnloadWaveSamples() (1 input parameters) +Function 560: UnloadWaveSamples() (1 input parameters) Name: UnloadWaveSamples Return type: void Description: Unload samples data loaded with LoadWaveSamples() Param[1]: samples (type: float *) -Function 552: LoadMusicStream() (1 input parameters) +Function 561: LoadMusicStream() (1 input parameters) Name: LoadMusicStream Return type: Music Description: Load music stream from file Param[1]: fileName (type: const char *) -Function 553: LoadMusicStreamFromMemory() (3 input parameters) +Function 562: LoadMusicStreamFromMemory() (3 input parameters) Name: LoadMusicStreamFromMemory Return type: Music Description: Load music stream from data Param[1]: fileType (type: const char *) Param[2]: data (type: const unsigned char *) Param[3]: dataSize (type: int) -Function 554: IsMusicValid() (1 input parameters) +Function 563: IsMusicValid() (1 input parameters) Name: IsMusicValid Return type: bool Description: Checks if a music stream is valid (context and buffers initialized) Param[1]: music (type: Music) -Function 555: UnloadMusicStream() (1 input parameters) +Function 564: UnloadMusicStream() (1 input parameters) Name: UnloadMusicStream Return type: void Description: Unload music stream Param[1]: music (type: Music) -Function 556: PlayMusicStream() (1 input parameters) +Function 565: PlayMusicStream() (1 input parameters) Name: PlayMusicStream Return type: void Description: Start music playing Param[1]: music (type: Music) -Function 557: IsMusicStreamPlaying() (1 input parameters) +Function 566: IsMusicStreamPlaying() (1 input parameters) Name: IsMusicStreamPlaying Return type: bool Description: Check if music is playing Param[1]: music (type: Music) -Function 558: UpdateMusicStream() (1 input parameters) +Function 567: UpdateMusicStream() (1 input parameters) Name: UpdateMusicStream Return type: void Description: Updates buffers for music streaming Param[1]: music (type: Music) -Function 559: StopMusicStream() (1 input parameters) +Function 568: StopMusicStream() (1 input parameters) Name: StopMusicStream Return type: void Description: Stop music playing Param[1]: music (type: Music) -Function 560: PauseMusicStream() (1 input parameters) +Function 569: PauseMusicStream() (1 input parameters) Name: PauseMusicStream Return type: void Description: Pause music playing Param[1]: music (type: Music) -Function 561: ResumeMusicStream() (1 input parameters) +Function 570: ResumeMusicStream() (1 input parameters) Name: ResumeMusicStream Return type: void Description: Resume playing paused music Param[1]: music (type: Music) -Function 562: SeekMusicStream() (2 input parameters) +Function 571: SeekMusicStream() (2 input parameters) Name: SeekMusicStream Return type: void Description: Seek music to a position (in seconds) Param[1]: music (type: Music) Param[2]: position (type: float) -Function 563: SetMusicVolume() (2 input parameters) +Function 572: SetMusicVolume() (2 input parameters) Name: SetMusicVolume Return type: void Description: Set volume for music (1.0 is max level) Param[1]: music (type: Music) Param[2]: volume (type: float) -Function 564: SetMusicPitch() (2 input parameters) +Function 573: SetMusicPitch() (2 input parameters) Name: SetMusicPitch Return type: void Description: Set pitch for a music (1.0 is base level) Param[1]: music (type: Music) Param[2]: pitch (type: float) -Function 565: SetMusicPan() (2 input parameters) +Function 574: SetMusicPan() (2 input parameters) Name: SetMusicPan Return type: void Description: Set pan for a music (0.5 is center) Param[1]: music (type: Music) Param[2]: pan (type: float) -Function 566: GetMusicTimeLength() (1 input parameters) +Function 575: GetMusicTimeLength() (1 input parameters) Name: GetMusicTimeLength Return type: float Description: Get music time length (in seconds) Param[1]: music (type: Music) -Function 567: GetMusicTimePlayed() (1 input parameters) +Function 576: GetMusicTimePlayed() (1 input parameters) Name: GetMusicTimePlayed Return type: float Description: Get current music time played (in seconds) Param[1]: music (type: Music) -Function 568: LoadAudioStream() (3 input parameters) +Function 577: LoadAudioStream() (3 input parameters) Name: LoadAudioStream Return type: AudioStream Description: Load audio stream (to stream raw audio pcm data) Param[1]: sampleRate (type: unsigned int) Param[2]: sampleSize (type: unsigned int) Param[3]: channels (type: unsigned int) -Function 569: IsAudioStreamValid() (1 input parameters) +Function 578: IsAudioStreamValid() (1 input parameters) Name: IsAudioStreamValid Return type: bool Description: Checks if an audio stream is valid (buffers initialized) Param[1]: stream (type: AudioStream) -Function 570: UnloadAudioStream() (1 input parameters) +Function 579: UnloadAudioStream() (1 input parameters) Name: UnloadAudioStream Return type: void Description: Unload audio stream and free memory Param[1]: stream (type: AudioStream) -Function 571: UpdateAudioStream() (3 input parameters) +Function 580: UpdateAudioStream() (3 input parameters) Name: UpdateAudioStream Return type: void Description: Update audio stream buffers with data Param[1]: stream (type: AudioStream) Param[2]: data (type: const void *) Param[3]: frameCount (type: int) -Function 572: IsAudioStreamProcessed() (1 input parameters) +Function 581: IsAudioStreamProcessed() (1 input parameters) Name: IsAudioStreamProcessed Return type: bool Description: Check if any audio stream buffers requires refill Param[1]: stream (type: AudioStream) -Function 573: PlayAudioStream() (1 input parameters) +Function 582: PlayAudioStream() (1 input parameters) Name: PlayAudioStream Return type: void Description: Play audio stream Param[1]: stream (type: AudioStream) -Function 574: PauseAudioStream() (1 input parameters) +Function 583: PauseAudioStream() (1 input parameters) Name: PauseAudioStream Return type: void Description: Pause audio stream Param[1]: stream (type: AudioStream) -Function 575: ResumeAudioStream() (1 input parameters) +Function 584: ResumeAudioStream() (1 input parameters) Name: ResumeAudioStream Return type: void Description: Resume audio stream Param[1]: stream (type: AudioStream) -Function 576: IsAudioStreamPlaying() (1 input parameters) +Function 585: IsAudioStreamPlaying() (1 input parameters) Name: IsAudioStreamPlaying Return type: bool Description: Check if audio stream is playing Param[1]: stream (type: AudioStream) -Function 577: StopAudioStream() (1 input parameters) +Function 586: StopAudioStream() (1 input parameters) Name: StopAudioStream Return type: void Description: Stop audio stream Param[1]: stream (type: AudioStream) -Function 578: SetAudioStreamVolume() (2 input parameters) +Function 587: SetAudioStreamVolume() (2 input parameters) Name: SetAudioStreamVolume Return type: void Description: Set volume for audio stream (1.0 is max level) Param[1]: stream (type: AudioStream) Param[2]: volume (type: float) -Function 579: SetAudioStreamPitch() (2 input parameters) +Function 588: SetAudioStreamPitch() (2 input parameters) Name: SetAudioStreamPitch Return type: void Description: Set pitch for audio stream (1.0 is base level) Param[1]: stream (type: AudioStream) Param[2]: pitch (type: float) -Function 580: SetAudioStreamPan() (2 input parameters) +Function 589: SetAudioStreamPan() (2 input parameters) Name: SetAudioStreamPan Return type: void Description: Set pan for audio stream (0.5 is centered) Param[1]: stream (type: AudioStream) Param[2]: pan (type: float) -Function 581: SetAudioStreamBufferSizeDefault() (1 input parameters) +Function 590: SetAudioStreamBufferSizeDefault() (1 input parameters) Name: SetAudioStreamBufferSizeDefault Return type: void Description: Default size for new audio streams Param[1]: size (type: int) -Function 582: SetAudioStreamCallback() (2 input parameters) +Function 591: SetAudioStreamCallback() (2 input parameters) Name: SetAudioStreamCallback Return type: void Description: Audio thread callback to request new data Param[1]: stream (type: AudioStream) Param[2]: callback (type: AudioCallback) -Function 583: AttachAudioStreamProcessor() (2 input parameters) +Function 592: AttachAudioStreamProcessor() (2 input parameters) Name: AttachAudioStreamProcessor Return type: void Description: Attach audio stream processor to stream, receives frames x 2 samples as 'float' (stereo) Param[1]: stream (type: AudioStream) Param[2]: processor (type: AudioCallback) -Function 584: DetachAudioStreamProcessor() (2 input parameters) +Function 593: DetachAudioStreamProcessor() (2 input parameters) Name: DetachAudioStreamProcessor Return type: void Description: Detach audio stream processor from stream Param[1]: stream (type: AudioStream) Param[2]: processor (type: AudioCallback) -Function 585: AttachAudioMixedProcessor() (1 input parameters) +Function 594: AttachAudioMixedProcessor() (1 input parameters) Name: AttachAudioMixedProcessor Return type: void Description: Attach audio stream processor to the entire audio pipeline, receives frames x 2 samples as 'float' (stereo) Param[1]: processor (type: AudioCallback) -Function 586: DetachAudioMixedProcessor() (1 input parameters) +Function 595: DetachAudioMixedProcessor() (1 input parameters) Name: DetachAudioMixedProcessor Return type: void Description: Detach audio stream processor from the entire audio pipeline diff --git a/tools/parser/output/raylib_api.xml b/tools/parser/output/raylib_api.xml index 063119ab5..6ea73d8dc 100644 --- a/tools/parser/output/raylib_api.xml +++ b/tools/parser/output/raylib_api.xml @@ -679,7 +679,7 @@ - + @@ -1048,6 +1048,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + @@ -1061,6 +1085,9 @@ + + + @@ -1110,9 +1137,6 @@ - - - @@ -2464,10 +2488,24 @@ + + + + + + + + - - + + + + + + + + @@ -2484,14 +2522,14 @@ - + - + From 23e0898c65c609283249fc3417827f7755cb7e31 Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 18 Sep 2025 15:51:18 +0200 Subject: [PATCH 011/167] Ouch! --- src/rtext.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rtext.c b/src/rtext.c index d965b706a..edfe33c8b 100644 --- a/src/rtext.c +++ b/src/rtext.c @@ -1668,7 +1668,7 @@ const char *TextRemoveSpaces(const char *text) } // Get text between two strings -static char *GetTextBetween(const char *text, const char *begin, const char *end) +char *GetTextBetween(const char *text, const char *begin, const char *end) { #define MAX_TEXT_BETWEEN_SIZE 1024 From 9268b0d029e85aa61db28ad5ecd3f35a4f06f6de Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 18 Sep 2025 15:51:48 +0200 Subject: [PATCH 012/167] REXM: Commented functions moved to main raylib API --- tools/rexm/rexm.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/tools/rexm/rexm.c b/tools/rexm/rexm.c index cbb04a07f..ced2653da 100644 --- a/tools/rexm/rexm.c +++ b/tools/rexm/rexm.c @@ -25,6 +25,7 @@ * - raylib.com/examples//_example_name.data * - raylib.com/examples//_example_name.wasm * - raylib.com/examples//_example_name.js +* - ... * * LICENSE: zlib/libpng * @@ -136,12 +137,12 @@ static const char *exVSProjectSolutionFile = NULL; // Env REXM_EXAMPLES_VS2022_S //---------------------------------------------------------------------------------- // Module Internal Functions Declaration //---------------------------------------------------------------------------------- -static int FileTextFind(const char *fileName, const char *find); -static int FileTextReplace(const char *fileName, const char *find, const char *replace); -static int FileCopy(const char *srcPath, const char *dstPath); -static int FileRename(const char *fileName, const char *fileRename); -static int FileMove(const char *srcPath, const char *dstPath); -static int FileRemove(const char *fileName); +//static int FileTextFind(const char *fileName, const char *find); +//static int FileTextReplace(const char *fileName, const char *find, const char *replace); +//static int FileCopy(const char *srcPath, const char *dstPath); +//static int FileRename(const char *fileName, const char *fileRename); +//static int FileMove(const char *srcPath, const char *dstPath); +//static int FileRemove(const char *fileName); // Update required files from examples collection // UPDATES: Makefile, Makefile.Web, README.md, examples.js @@ -185,9 +186,9 @@ static void UpdateSourceMetadata(const char *exSrcPath, const rlExampleInfo *inf static void UpdateWebMetadata(const char *exHtmlPath, const char *exFilePath); // Get text between two strings -static char *GetTextBetween(const char *text, const char *begin, const char *end); +//static char *GetTextBetween(const char *text, const char *begin, const char *end); // Replace text between two specific strings -static char *TextReplaceBetween(const char *text, const char *begin, const char *end, const char *replace); +//static char *TextReplaceBetween(const char *text, const char *begin, const char *end, const char *replace); //------------------------------------------------------------------------------------ // Program main entry point @@ -1773,6 +1774,7 @@ static void UnloadExamplesData(rlExampleInfo *exInfo) RL_FREE(exInfo); } +/* // Find text in existing file static int FileTextFind(const char *fileName, const char *find) { @@ -1808,7 +1810,7 @@ static int FileTextReplace(const char *fileName, const char *textLookUp, const c } // Copy file from one path to another -// WARNING: Destination path must exist +// NOTE: If destination path does not exist, it is created! static int FileCopy(const char *srcPath, const char *dstPath) { int result = 0; @@ -1817,10 +1819,13 @@ static int FileCopy(const char *srcPath, const char *dstPath) // Create required paths if they do not exist if (!DirectoryExists(GetDirectoryPath(dstPath))) - MakeDirectory(GetDirectoryPath(dstPath)); + result = MakeDirectory(GetDirectoryPath(dstPath)); - if ((srcFileData != NULL) && (srcDataSize > 0)) - result = SaveFileData(dstPath, srcFileData, srcDataSize); + if (result == 0) // Directory created successfully (or already exists) + { + if ((srcFileData != NULL) && (srcDataSize > 0)) + result = SaveFileData(dstPath, srcFileData, srcDataSize); + } UnloadFileData(srcFileData); @@ -1871,6 +1876,7 @@ static int FileMove(const char *srcPath, const char *dstPath) return result; } +*/ // Get example info from example file header // WARNING: Expecting the example to follow raylib_example_template.c @@ -2458,6 +2464,7 @@ static void UpdateWebMetadata(const char *exHtmlPath, const char *exFilePath) } } +/* // Get text between two strings // NOTE: Using static string to return result, MAX: 1024 bytes static char *GetTextBetween(const char *text, const char *begin, const char *end) @@ -2515,3 +2522,4 @@ static char *TextReplaceBetween(const char *text, const char *begin, const char return result; } +*/ From 1c3f9fa135cafa494af760c4cd0541c9a23cdf60 Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 18 Sep 2025 16:06:24 +0200 Subject: [PATCH 013/167] Update parse_api.yml --- .github/workflows/parse_api.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/parse_api.yml b/.github/workflows/parse_api.yml index ec76532ba..c8665e1d4 100644 --- a/.github/workflows/parse_api.yml +++ b/.github/workflows/parse_api.yml @@ -22,7 +22,7 @@ jobs: - name: Diff parse files id: diff run: | - git add -N parser + git add -N tools/parser git diff --name-only --exit-code continue-on-error: true From ff8333435a787bd07aeaf9caafafa7d267f989fe Mon Sep 17 00:00:00 2001 From: Connor O'Connor Date: Fri, 19 Sep 2025 11:06:43 -0400 Subject: [PATCH 014/167] use lowercase "message" to remove recommendation warning (#5196) It is recommended to use lowercase CMake commands --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ee095b844..da1b3bfe7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,7 +31,7 @@ include(CMakeOptions.txt) if (UNIX AND NOT APPLE AND NOT "${PLATFORM}" MATCHES "DRM" AND NOT "${PLATFORM}" MATCHES "Web") if (NOT GLFW_BUILD_WAYLAND AND NOT GLFW_BUILD_X11) - MESSAGE(FATAL_ERROR "Cannot disable both Wayland and X11") + message(FATAL_ERROR "Cannot disable both Wayland and X11") endif() endif() @@ -51,7 +51,7 @@ if(NOT TARGET uninstall AND PROJECT_IS_TOP_LEVEL) endif() if (${BUILD_EXAMPLES}) - MESSAGE(STATUS "Building examples is enabled") + message(STATUS "Building examples is enabled") add_subdirectory(examples) endif() From f0674676b6bbcd333088f04e3bac0d5026b891a3 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 21 Sep 2025 13:12:32 +0200 Subject: [PATCH 015/167] Update raylib_parser.c --- tools/parser/raylib_parser.c | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/parser/raylib_parser.c b/tools/parser/raylib_parser.c index 82e22f195..4b5fe1625 100644 --- a/tools/parser/raylib_parser.c +++ b/tools/parser/raylib_parser.c @@ -800,7 +800,6 @@ int main(int argc, char* argv[]) for (int i = 0; i < enumCount; i++) { - // Parse enum description // NOTE: This is not necessarily from the line immediately before, // some of the enums have extra lines between the "description" From 1161286d51eaff51cf68bc77c01f04dffbf46555 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 21 Sep 2025 13:13:46 +0200 Subject: [PATCH 016/167] Update rexm.c --- tools/rexm/rexm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/rexm/rexm.c b/tools/rexm/rexm.c index ced2653da..529f71884 100644 --- a/tools/rexm/rexm.c +++ b/tools/rexm/rexm.c @@ -1337,6 +1337,9 @@ int main(int argc, char *argv[]) // add : Add existing example, category extracted from name // rename : Rename an existing example // remove : Remove an existing example + // build : Build example for Desktop and Web platforms + // validate : Validate examples collection, generates report + // update : Validate and update examples collection, generates report printf("\n////////////////////////////////////////////////////////////////////////////////////////////\n"); printf("// //\n"); From 95cb0cbf679d2bc1b553e9d4586b044e517b4e25 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 21 Sep 2025 13:14:01 +0200 Subject: [PATCH 017/167] Update README.md --- tools/rexm/README.md | 107 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 96 insertions(+), 11 deletions(-) diff --git a/tools/rexm/README.md b/tools/rexm/README.md index 101a5b92e..232ef51d6 100644 --- a/tools/rexm/README.md +++ b/tools/rexm/README.md @@ -1,20 +1,105 @@ -## rexm -### Description +# `rexm` - raylib examples manager -raylib examples manager +rexm is a raylib support tool to help to manage the raylib examples collection. -### Features +## Why do we need a tool to manage raylib examples? - - $(Project Feature 01) - - $(Project Feature 02) - - $(Project Feature 03) +raylib has a big collection of examples to learn how to use the library. It started with just a few examples and it has grown to +160 in the last 12 years, with many of those examples contributed by the community (~50%). -### Command line +**Managing those examples has become a considerable amount of work.** Some years ago an [examples template](https://github.com/raysan5/raylib/blob/master/examples/examples_template.c) was created to standarize examples format and contents, it simplified the review process but implementing a new example is not enough; adding/modifying an new example from the collection implies a series of actions: + - Create the example `.c` code file, **following provided [examples template](https://github.com/raysan5/raylib/blob/master/examples/examples_template.c) guidelines**. + - Make sure example header lists all required metadata information + - Make sure example follows required structure and sections + - Copy required resources into `resource` directory, make sure they are based in a permissive license + - Create a screenshot for the example, illustrating main functionality. + - Add example to several raylib build systems: + - Examples `Makefile`: multi-platform build configuration + - Examples `Makefile.Web`: specific Web building configuration + - raylib Visual Studio 2022 solution: Include a separate project with example, in correct category + - Add example to examples `README.md` table, in corerct category + - Compile example for Web and upload to `raylib.com` open-source repository + - Update `raylib.com` webpage to include example running on real-time + +All the following files need to be require to be review every time an examples is added or modified: -### License +``` + - Add: raylib/examples//_example_name.c + - Add: raylib/examples//_example_name.png + - Add: raylib/examples//resources/.. + - Edit: raylib/examples/Makefile + - Edit: raylib/examples/Makefile.Web + - Add: raylib/projects/VS2022/examples/_example_name.vcxproj + - Edit: raylib/projects/VS2022/raylib.sln + - Edit: raylib/examples/README.md + - Edit: raylib.com/common/examples.js + - Generate: raylib.com/examples//_example_name.html + - Generate: raylib.com/examples//_example_name.data + - Generate: raylib.com/examples//_example_name.wasm + - Generate: raylib.com/examples//_example_name.js +``` -This project sources are licensed under an unmodified zlib/libpng license, which is an OSI-certified, BSD-like license that allows static linking with closed source software. Check [LICENSE](LICENSE) for further details. +This process has been done manually for many years and required a lot of time, it was also very prone to errors, like missing some edits or adding typos. -*Copyright (c) 2025 Ramon Santamaria (@raysan5)* +Finally I decided to automatize the process and create a pipeline to `add`, `rename`, `remove`, `validate` and `build` examples automatically edited. Additionally I decided to a `validation` process to verify the integrity of all the required files and even fix some of the potential issues. + +## `rexm` supported commands + +The following commands are supported by `rexm` to manage examples: + +``` + help : Provides command-line usage information + create : Creates an empty example, from internal template + add : Add existing example, category extracted from name + Supported categories: core, shapes, textures, text, models + rename : Rename an existing example + remove : Remove an existing example + build : Build example for Desktop and Web platforms + validate : Validate examples collection, generates report + update : Validate and update examples collection, generates report +``` + +## `rexm` examples **validation** and **update** + +Two commands have been added to `rexm` to validate all the examples, checking if the examples follow all requirements and all the files needed are available, that way the examples review has been automated, generating complete tables on examples status. + +As we were able to detect possible examples errors and inconsistencies, an additional command was implemented to **update** all examples with inconsistencies. + +## `rexm` technology used + +Usually this kind of pipelines are implemented with high-level scripting languages like Python due to all the functionality already provided, specially useful for files/paths management or text files editing but those languages also require the interpreter available to run. I decided to follow a less common route, implementing the tool directly in C, the language I use for raylib and all my tools. + +C standard library does not provide a lot of the high-level functionality required for files and text management but here is where raylib came to the rescue. raylib already contained some functions to work with the file system and to manage text, so I decided to implement the required additional ones to use raylib on pipelines building. + +The main benefit of using C and raylib is that the pipeline can be created in C and it can be build int an independent multi-platform dependency-free executable tool; it also open the door for a possible expansion into a UI interface, if required in the future. + +As mentioned, implementing the pipeline in C with raylib required some additional support functions to be added, to simplify some tasks and align with functionality provided by high-level languages; but it was not dramatic and the truth is that the development process just flowed smoothly. + +Some of the support functions implemented: + +```c +// File management functions +int FileRename(const char *fileName, const char *fileRename); // Rename file (if exists) +int FileRemove(const char *fileName); // Remove file (if exists) +int FileCopy(const char *srcPath, const char *dstPath); // Copy file from one path to another, dstPath created if it doesn't exist +int FileMove(const char *srcPath, const char *dstPath); // Move file from one directory to another, dstPath created if it doesn't exist +int FileTextReplace(const char *fileName, const char *search, const char *replacement); // Replace text in an existing file +iint FileTextFindIndex(const char *fileName, const char *search); // Find text in existing file + +// Text management functions +char **LoadTextLines(const char *text, int *count); // Load text lines from text block, separate by '\n' +void UnloadTextLines(char **text); // Unload text lines +const char *TextRemoveSpaces(const char *text); // Remove text spaces, concat words +char *GetTextBetween(const char *text, const char *begin, const char *end); // Get text between two strings +char *TextReplace(const char *text, const char *search, const char *replacement); // Replace text string +char *TextReplaceBetween(const char *text, const char *begin, const char *end, const char *replacement); // Replace text between two specific strings +``` + +**These functions have been added to raylib main library.** + +## License + +`rexm` is an **open source** project, licensed under an unmodified [zlib/libpng license](LICENSE) + +*Copyright (c) 2025 Ramon Santamaria ([@raysan5](https://github.com/raysan5))* From e7cfd3d4a304b724193edb8df3ed13407c802c1d Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 21 Sep 2025 13:28:27 +0200 Subject: [PATCH 018/167] Update depth_render.fs --- examples/shaders/resources/shaders/glsl100/depth_render.fs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/examples/shaders/resources/shaders/glsl100/depth_render.fs b/examples/shaders/resources/shaders/glsl100/depth_render.fs index b330bd9c6..362c1fb37 100644 --- a/examples/shaders/resources/shaders/glsl100/depth_render.fs +++ b/examples/shaders/resources/shaders/glsl100/depth_render.fs @@ -1,5 +1,7 @@ #version 100 +precision mediump float; + // Input vertex attributes (from vertex shader) varying vec2 fragTexCoord; @@ -14,8 +16,7 @@ void main() { // Handle potential Y-flipping vec2 texCoord = fragTexCoord; - if (flipY) - texCoord.y = 1.0 - texCoord.y; + if (flipY) texCoord.y = 1.0 - texCoord.y; // Sample depth texture float depth = texture2D(depthTexture, texCoord).r; @@ -25,4 +26,4 @@ void main() // Output final color gl_FragColor = vec4(vec3(linearDepth), 1.0); -} \ No newline at end of file +} From 8ada37d9671682f420a2be1f1afd4b06173b81ad Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 21 Sep 2025 13:28:30 +0200 Subject: [PATCH 019/167] Update depth_write.fs --- examples/shaders/resources/shaders/glsl100/depth_write.fs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/shaders/resources/shaders/glsl100/depth_write.fs b/examples/shaders/resources/shaders/glsl100/depth_write.fs index 6200bd23a..15095db11 100644 --- a/examples/shaders/resources/shaders/glsl100/depth_write.fs +++ b/examples/shaders/resources/shaders/glsl100/depth_write.fs @@ -1,11 +1,13 @@ #version 100 - #extension GL_EXT_frag_depth : enable + precision mediump float; +// Input vertex attributes (from vertex shader) varying vec2 fragTexCoord; varying vec4 fragColor; +// Input uniform values uniform sampler2D texture0; uniform vec4 colDiffuse; @@ -15,4 +17,4 @@ void main() gl_FragColor = texelColor*colDiffuse*fragColor; gl_FragDepthEXT = 1.0 - gl_FragCoord.z; -} \ No newline at end of file +} From 363855ec3e818a451de83bad0edb3a8817fba143 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 21 Sep 2025 20:21:42 +0200 Subject: [PATCH 020/167] Update rexm.c --- tools/rexm/rexm.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/rexm/rexm.c b/tools/rexm/rexm.c index 529f71884..6fdf74645 100644 --- a/tools/rexm/rexm.c +++ b/tools/rexm/rexm.c @@ -939,22 +939,22 @@ int main(int argc, char *argv[]) UnloadImage(imScreenshot); // Validate: raylib/examples/Makefile -> Example listed? - if (FileTextFind(TextFormat("%s/Makefile", exBasePath), exInfo->name) == -1) exInfo->status |= VALID_NOT_IN_MAKEFILE; + if (FileTextFindIndex(TextFormat("%s/Makefile", exBasePath), exInfo->name) == -1) exInfo->status |= VALID_NOT_IN_MAKEFILE; // Validate: raylib/examples/Makefile.Web -> Example listed? - if (FileTextFind(TextFormat("%s/Makefile.Web", exBasePath), exInfo->name) == -1) exInfo->status |= VALID_NOT_IN_MAKEFILE_WEB; + if (FileTextFindIndex(TextFormat("%s/Makefile.Web", exBasePath), exInfo->name) == -1) exInfo->status |= VALID_NOT_IN_MAKEFILE_WEB; // Validate: raylib/examples/README.md -> Example listed? - if (FileTextFind(TextFormat("%s/README.md", exBasePath), exInfo->name) == -1) exInfo->status |= VALID_NOT_IN_README; + if (FileTextFindIndex(TextFormat("%s/README.md", exBasePath), exInfo->name) == -1) exInfo->status |= VALID_NOT_IN_README; // Validate: raylib.com/common/examples.js -> Example listed? - if (FileTextFind(TextFormat("%s/../common/examples.js", exWebPath), exInfo->name + TextFindIndex(exInfo->name, "_") + 1) == -1) exInfo->status |= VALID_NOT_IN_JS; + if (FileTextFindIndex(TextFormat("%s/../common/examples.js", exWebPath), exInfo->name + TextFindIndex(exInfo->name, "_") + 1) == -1) exInfo->status |= VALID_NOT_IN_JS; // Validate: raylib/projects/VS2022/examples/_example_name.vcxproj -> File exists? if (!FileExists(TextFormat("%s/../projects/VS2022/examples/%s.vcxproj", exBasePath, exInfo->name))) exInfo->status |= VALID_MISSING_VCXPROJ; // Validate: raylib/projects/VS2022/raylib.sln -> Example listed? - if (FileTextFind(TextFormat("%s/../projects/VS2022/raylib.sln", exBasePath), exInfo->name) == -1) exInfo->status |= VALID_NOT_IN_VCXSOL; + if (FileTextFindIndex(TextFormat("%s/../projects/VS2022/raylib.sln", exBasePath), exInfo->name) == -1) exInfo->status |= VALID_NOT_IN_VCXSOL; // Validate: raylib/examples//resources/.. -> Example resources available? // Scan resources used in example to check for missing resource files From bb28d7fd0e7d54d2f4ac5a35254205ea369c7004 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 21 Sep 2025 20:37:01 +0200 Subject: [PATCH 021/167] Update normalmap.fs --- .../shaders/resources/shaders/glsl100/normalmap.fs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/shaders/resources/shaders/glsl100/normalmap.fs b/examples/shaders/resources/shaders/glsl100/normalmap.fs index 197e81ed1..a1b992811 100644 --- a/examples/shaders/resources/shaders/glsl100/normalmap.fs +++ b/examples/shaders/resources/shaders/glsl100/normalmap.fs @@ -23,20 +23,20 @@ uniform float specularExponent; void main() { - vec4 texelColor = texture(texture0, vec2(fragTexCoord.x, fragTexCoord.y)); + vec4 texelColor = texture2D(texture0, vec2(fragTexCoord.x, fragTexCoord.y)); vec3 specular = vec3(0.0); vec3 viewDir = normalize(viewPos - fragPosition); vec3 lightDir = normalize(lightPos - fragPosition); - vec3 normal; + vec3 normal = vec3(0.0); if (useNormalMap) { - normal = texture(normalMap, vec2(fragTexCoord.x, fragTexCoord.y)).rgb; + normal = texture2D(normalMap, vec2(fragTexCoord.x, fragTexCoord.y)).rgb; - //Transform normal values to the range -1.0 ... 1.0 + // Transform normal values to the range -1.0 ... 1.0 normal = normalize(normal*2.0 - 1.0); - //Transform the normal from tangent-space to world-space for lighting calculation + // Transform the normal from tangent-space to world-space for lighting calculation normal = normalize(normal*TBN); } else @@ -56,7 +56,7 @@ void main() specular += specCo; - finalColor = (texelColor*((tint + vec4(specular, 1.0))*vec4(lightDot, 1.0))); + vec4 finalColor = (texelColor*((tint + vec4(specular, 1.0))*vec4(lightDot, 1.0))); finalColor += texelColor*(vec4(1.0, 1.0, 1.0, 1.0)/40.0)*tint; // Gamma correction From 78a607b778cb806818c8a66d06190dc3548f3786 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 22 Sep 2025 11:40:06 +0200 Subject: [PATCH 022/167] Update twitter links --- CONTRIBUTING.md | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7d4c8acf1..6d6a2d1d9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -69,8 +69,8 @@ If you have any doubt, don't hesitate to [contact me](mailto:ray@raylib.com)!. You can write me a direct mail but you can also contact me on the following networks: - [raylib Discord](https://discord.gg/raylib) - A direct communication channel for project discussions. - - [raylib twitter](https://twitter.com/raysan5) - My personal twitter account, I usually post about raylib, you can send me PMs. - [raylib reddit](https://www.reddit.com/r/raylib/) - A good place for discussions or to ask for help. - [raylib web](http://www.raylib.com/) - On top-right corner there is a bunch of networks where you can find me. + - [raylib X](https://x.com/raysan5) - My personal X account, I usually post about raylib, you can send me PMs. Thank you very much for your time! :) diff --git a/README.md b/README.md index faf6c41f8..875792f18 100644 --- a/README.md +++ b/README.md @@ -129,7 +129,7 @@ raylib is present in several networks and raylib community is growing everyday. - Webpage: [https://www.raylib.com](https://www.raylib.com) - Discord: [https://discord.gg/raylib](https://discord.gg/raylib) - - Twitter: [https://www.twitter.com/raysan5](https://www.twitter.com/raysan5) + - X: [https://x.com/raysan5](https://x.com/raysan5) - BlueSky: [https://bsky.app/profile/raysan5](https://bsky.app/profile/raysan5.bsky.social) - Twitch: [https://www.twitch.tv/raysan5](https://www.twitch.tv/raysan5) - Reddit: [https://www.reddit.com/r/raylib](https://www.reddit.com/r/raylib) From fbae395e850e9715f879956db8c030e4e0d7e712 Mon Sep 17 00:00:00 2001 From: Arman Ommid <71801518+ArmanOmmid@users.noreply.github.com> Date: Tue, 23 Sep 2025 08:58:42 -0700 Subject: [PATCH 023/167] Update raymath.h (#5201) --- src/raymath.h | 118 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 72 insertions(+), 46 deletions(-) diff --git a/src/raymath.h b/src/raymath.h index f246f26d9..d3c8b9697 100644 --- a/src/raymath.h +++ b/src/raymath.h @@ -2552,65 +2552,91 @@ RMAPI int QuaternionEquals(Quaternion p, Quaternion q) return result; } -// Decompose a transformation matrix into its rotational, translational and scaling components +// Decompose a transformation matrix into its rotational, translational and scaling components and remove shear RMAPI void MatrixDecompose(Matrix mat, Vector3 *translation, Quaternion *rotation, Vector3 *scale) { - // Extract translation. + float eps = 1e-9; + + // Extract Translation translation->x = mat.m12; translation->y = mat.m13; translation->z = mat.m14; - // Extract upper-left for determinant computation - const float a = mat.m0; - const float b = mat.m4; - const float c = mat.m8; - const float d = mat.m1; - const float e = mat.m5; - const float f = mat.m9; - const float g = mat.m2; - const float h = mat.m6; - const float i = mat.m10; - const float A = e*i - f*h; - const float B = f*g - d*i; - const float C = d*h - e*g; + // Matrix Columns - Rotation will be extracted into here. + Vector3 matColumns[3] = { { mat.m0, mat.m4, mat.m8 }, + { mat.m1, mat.m5, mat.m9 }, + { mat.m2, mat.m6, mat.m10 } }; - // Extract scale - const float det = a*A + b*B + c*C; - Vector3 abc = { a, b, c }; - Vector3 def = { d, e, f }; - Vector3 ghi = { g, h, i }; + // Shear Parameters XY, XZ, and YZ (extract and ignored) + float shear[3] = { 0 }; - float scalex = Vector3Length(abc); - float scaley = Vector3Length(def); - float scalez = Vector3Length(ghi); - Vector3 s = { scalex, scaley, scalez }; + // Normalized Scale Parameters + Vector3 scl = { 0 }; - if (det < 0) s = Vector3Negate(s); - - *scale = s; - - // Remove scale from the matrix if it is not close to zero - Matrix clone = mat; - if (!FloatEquals(det, 0)) + // Max-Normalizing helps numerical stability + float stabilizer = eps; + for (int i = 0; i < 3; i++) { - clone.m0 /= s.x; - clone.m4 /= s.x; - clone.m8 /= s.x; - clone.m1 /= s.y; - clone.m5 /= s.y; - clone.m9 /= s.y; - clone.m2 /= s.z; - clone.m6 /= s.z; - clone.m10 /= s.z; + stabilizer = fmaxf(stabilizer, fabsf(matColumns[i].x)); + stabilizer = fmaxf(stabilizer, fabsf(matColumns[i].y)); + stabilizer = fmaxf(stabilizer, fabsf(matColumns[i].z)); + }; + matColumns[0] = Vector3Scale(matColumns[0], 1.0f / stabilizer); + matColumns[1] = Vector3Scale(matColumns[1], 1.0f / stabilizer); + matColumns[2] = Vector3Scale(matColumns[2], 1.0f / stabilizer); - // Extract rotation - *rotation = QuaternionFromMatrix(clone); - } - else + // X Scale + scl.x = Vector3Length(matColumns[0]); + if (scl.x > eps) { - // Set to identity if close to zero - *rotation = QuaternionIdentity(); + matColumns[0] = Vector3Scale(matColumns[0], 1.0f / scl.x); } + + // Compute XY shear and make col2 orthogonal + shear[0] = Vector3DotProduct(matColumns[0], matColumns[1]); + matColumns[1] = Vector3Subtract(matColumns[1], Vector3Scale(matColumns[0], shear[0])); + + // Y Scale + scl.y = Vector3Length(matColumns[1]); + if (scl.y > eps) + { + matColumns[1] = Vector3Scale(matColumns[1], 1.0f / scl.y); + shear[0] /= scl.y; // Correct XY shear + } + + // Compute XZ and YZ shears and make col3 orthogonal + shear[1] = Vector3DotProduct(matColumns[0], matColumns[2]); + matColumns[2] = Vector3Subtract(matColumns[2], Vector3Scale(matColumns[0], shear[1])); + shear[2] = Vector3DotProduct(matColumns[1], matColumns[2]); + matColumns[2] = Vector3Subtract(matColumns[2], Vector3Scale(matColumns[1], shear[2])); + + // Z Scale + scl.z = Vector3Length(matColumns[2]); + if (scl.z > eps) + { + matColumns[2] = Vector3Scale(matColumns[2], 1.0f / scl.z); + shear[1] /= scl.z; // Correct XZ shear + shear[2] /= scl.z; // Correct YZ shear + } + + // matColumns are now orthonormal in O(3). Now ensure its in SO(3) by enforcing det = 1. + if (Vector3DotProduct(matColumns[0], Vector3CrossProduct(matColumns[1], matColumns[2])) < 0) + { + scl = Vector3Negate(scl); + matColumns[0] = Vector3Negate(matColumns[0]); + matColumns[1] = Vector3Negate(matColumns[1]); + matColumns[2] = Vector3Negate(matColumns[2]); + } + + // Set Scale + *scale = Vector3Scale(scl, stabilizer); + + // Extract Rotation + Matrix rotationMatrix = { matColumns[0].x, matColumns[0].y, matColumns[0].z, 0, + matColumns[1].x, matColumns[1].y, matColumns[1].z, 0, + matColumns[2].x, matColumns[2].y, matColumns[2].z, 0, + 0, 0, 0, 1 }; + *rotation = QuaternionFromMatrix(rotationMatrix); } #if defined(__cplusplus) && !defined(RAYMATH_DISABLE_CPP_OPERATORS) From 085391e788f91735b795c61898dafe028e3b6a47 Mon Sep 17 00:00:00 2001 From: JohnnyCena123 Date: Tue, 23 Sep 2025 19:04:30 +0300 Subject: [PATCH 024/167] [build][cmake] fix issue introduced by #5181 (#5198) * fix web build issue with CMake introduced by #5181 * remove ASYNCIFY --- src/CMakeLists.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f31c4e578..087141447 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -68,6 +68,14 @@ else() ) endif() +if (${PLATFORM} MATCHES "Web") + target_link_options(raylib PUBLIC "-sUSE_GLFW=3" -sEXPORTED_RUNTIME_METHODS=ccall) + if(${GRAPHICS} MATCHES "GRAPHICS_API_OPENGL_ES3") + target_link_options(raylib PUBLIC "-sMIN_WEBGL_VERSION=2") + target_link_options(raylib PUBLIC "-sMAX_WEBGL_VERSION=2") + endif() +endif() + set_target_properties(raylib PROPERTIES PUBLIC_HEADER "${raylib_public_headers}" VERSION ${PROJECT_VERSION} From ca33d495b334232c073a5778869c68400c2022fa Mon Sep 17 00:00:00 2001 From: Bruno Cabral Date: Tue, 23 Sep 2025 09:07:11 -0700 Subject: [PATCH 025/167] [build][cmake] set lib m as public so it can be linked by consumer (#5193) * [build][cmake] set lib m as public so it can be linked by consumer * [build][cmake] removed redundancy when BSD systems --- cmake/LibraryConfigurations.cmake | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/cmake/LibraryConfigurations.cmake b/cmake/LibraryConfigurations.cmake index c0a7e3d4b..98c7f2362 100644 --- a/cmake/LibraryConfigurations.cmake +++ b/cmake/LibraryConfigurations.cmake @@ -38,7 +38,8 @@ if (${PLATFORM} MATCHES "Desktop") find_library(OSS_LIBRARY ossaudio) endif () - set(LIBS_PRIVATE m pthread ${OPENGL_LIBRARIES} ${OSS_LIBRARY}) + set(LIBS_PRIVATE pthread ${OPENGL_LIBRARIES} ${OSS_LIBRARY}) + set(LIBS_PUBLIC m) else () find_library(pthread NAMES pthread) find_package(OpenGL QUIET) @@ -46,11 +47,13 @@ if (${PLATFORM} MATCHES "Desktop") set(OPENGL_LIBRARIES "GL") endif () - set(LIBS_PRIVATE m atomic pthread ${OPENGL_LIBRARIES} ${OSS_LIBRARY}) + set(LIBS_PRIVATE pthread ${OPENGL_LIBRARIES} ${OSS_LIBRARY}) + set(LIBS_PUBLIC m) if ("${CMAKE_SYSTEM_NAME}" MATCHES "(Net|Open)BSD") find_library(OSS_LIBRARY ossaudio) - set(LIBS_PRIVATE m pthread ${OPENGL_LIBRARIES} ${OSS_LIBRARY}) + else () + set(LIBS_PRIVATE ${LIBS_PRIVATE} atomic) endif () if (NOT "${CMAKE_SYSTEM_NAME}" MATCHES "(Net|Open)BSD" AND USE_AUDIO) @@ -82,7 +85,8 @@ elseif (${PLATFORM} MATCHES "Android") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--exclude-libs,libatomic.a -Wl,--build-id -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -Wl,--warn-shared-textrel -Wl,--fatal-warnings -u ANativeActivity_onCreate -Wl,-undefined,dynamic_lookup") find_library(OPENGL_LIBRARY OpenGL) - set(LIBS_PRIVATE m log android EGL GLESv2 OpenSLES atomic c) + set(LIBS_PRIVATE log android EGL GLESv2 OpenSLES atomic c) + set(LIBS_PUBLIC m) elseif ("${PLATFORM}" MATCHES "DRM") set(PLATFORM_CPP "PLATFORM_DRM") @@ -100,7 +104,8 @@ elseif ("${PLATFORM}" MATCHES "DRM") if (NOT CMAKE_CROSSCOMPILING OR NOT CMAKE_SYSROOT) include_directories(/usr/include/libdrm) endif () - set(LIBS_PRIVATE ${GLESV2} ${EGL} ${DRM} ${GBM} atomic pthread m dl) + set(LIBS_PRIVATE ${GLESV2} ${EGL} ${DRM} ${GBM} atomic pthread dl) + set(LIBS_PUBLIC m) elseif ("${PLATFORM}" MATCHES "SDL") # First, check if SDL is included as a subdirectory From 4f9b933b34a74dd9f3acb4e33025dc6b8fa8f4a2 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 24 Sep 2025 10:17:34 +0200 Subject: [PATCH 026/167] REXM: Update examples; `text_unicode_emojis` requires additional resources on Web --- examples/Makefile | 2 +- examples/Makefile.Web | 19 +++++++++++-------- examples/text/text_unicode_emojis.c | 6 +++--- tools/rexm/examples_report.md | 2 +- 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/examples/Makefile b/examples/Makefile index 366327ffe..ee17bb350 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -604,6 +604,7 @@ TEXT = \ text/text_writing_anim MODELS = \ + models/models_animation_gpu_skinning \ models/models_animation_playing \ models/models_billboard_rendering \ models/models_bone_socket \ @@ -611,7 +612,6 @@ MODELS = \ models/models_cubicmap_rendering \ models/models_first_person_maze \ models/models_geometric_shapes \ - models/models_animation_gpu_skinning \ models/models_heightmap_rendering \ models/models_loading \ models/models_loading_gltf \ diff --git a/examples/Makefile.Web b/examples/Makefile.Web index 7aa216493..a16d57853 100644 --- a/examples/Makefile.Web +++ b/examples/Makefile.Web @@ -604,6 +604,7 @@ TEXT = \ text/text_writing_anim MODELS = \ + models/models_animation_gpu_skinning \ models/models_animation_playing \ models/models_billboard_rendering \ models/models_bone_socket \ @@ -611,7 +612,6 @@ MODELS = \ models/models_cubicmap_rendering \ models/models_first_person_maze \ models/models_geometric_shapes \ - models/models_animation_gpu_skinning \ models/models_heightmap_rendering \ models/models_loading \ models/models_loading_gltf \ @@ -1019,8 +1019,11 @@ text/text_sprite_fonts: text/text_sprite_fonts.c text/text_unicode_emojis: text/text_unicode_emojis.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \ --preload-file text/resources/dejavu.fnt@resources/dejavu.fnt \ + --preload-file text/resources/dejavu.png@resources/dejavu.png \ --preload-file text/resources/noto_cjk.fnt@resources/noto_cjk.fnt \ - --preload-file text/resources/symbola.fnt@resources/symbola.fnt + --preload-file text/resources/noto_cjk.png@resources/noto_cjk.png \ + --preload-file text/resources/symbola.fnt@resources/symbola.fnt \ + --preload-file text/resources/symbola.png@resources/symbola.png text/text_unicode_ranges: text/text_unicode_ranges.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \ @@ -1030,6 +1033,12 @@ text/text_writing_anim: text/text_writing_anim.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) # Compile MODELS examples +models/models_animation_gpu_skinning: models/models_animation_gpu_skinning.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \ + --preload-file models/resources/models/gltf/greenman.glb@resources/models/gltf/greenman.glb \ + --preload-file models/resources/shaders/glsl100/skinning.vs@resources/shaders/glsl100/skinning.vs \ + --preload-file models/resources/shaders/glsl100/skinning.fs@resources/shaders/glsl100/skinning.fs + models/models_animation_playing: models/models_animation_playing.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \ --preload-file models/resources/models/iqm/guy.iqm@resources/models/iqm/guy.iqm \ @@ -1063,12 +1072,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_animation_gpu_skinning: models/models_animation_gpu_skinning.c - $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \ - --preload-file models/resources/models/gltf/greenman.glb@resources/models/gltf/greenman.glb \ - --preload-file models/resources/shaders/glsl100/skinning.vs@resources/shaders/glsl100/skinning.vs \ - --preload-file models/resources/shaders/glsl100/skinning.fs@resources/shaders/glsl100/skinning.fs - 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 diff --git a/examples/text/text_unicode_emojis.c b/examples/text/text_unicode_emojis.c index 5c050abcf..30fcaa8b7 100644 --- a/examples/text/text_unicode_emojis.c +++ b/examples/text/text_unicode_emojis.c @@ -169,9 +169,9 @@ int main(void) // Load the font resources // NOTE: fontAsian is for asian languages, // fontEmoji is the emojis and fontDefault is used for everything else - Font fontDefault = LoadFont("resources/dejavu.fnt"); - Font fontAsian = LoadFont("resources/noto_cjk.fnt"); - Font fontEmoji = LoadFont("resources/symbola.fnt"); + Font fontDefault = LoadFont("resources/dejavu.fnt"); // Requires "resources/dejavu.png" + Font fontAsian = LoadFont("resources/noto_cjk.fnt"); // Requires "resources/noto_cjk.png" + Font fontEmoji = LoadFont("resources/symbola.fnt"); // Requires "resources/symbola.png" Vector2 hoveredPos = { 0.0f, 0.0f }; Vector2 selectedPos = { 0.0f, 0.0f }; diff --git a/tools/rexm/examples_report.md b/tools/rexm/examples_report.md index 384a89902..bb37b2db7 100644 --- a/tools/rexm/examples_report.md +++ b/tools/rexm/examples_report.md @@ -137,7 +137,7 @@ Example elements validated: | models_heightmap_rendering | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | models_skybox_rendering | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | models_textured_cube | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | -| models_gpu_skinning | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| models_animation_gpu_skinning | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | models_bone_socket | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | models_tesseract_view | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shaders_basic_lighting | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | From 2554dcba9b9175781ba042b7d13c9a80d7d5fb6d Mon Sep 17 00:00:00 2001 From: Maicon Santana Date: Wed, 24 Sep 2025 09:22:03 +0100 Subject: [PATCH 027/167] fix rlSetTexture not overriding default mode (#5200) --- src/rlgl.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/rlgl.h b/src/rlgl.h index e58302ceb..7db05251d 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -1067,6 +1067,7 @@ typedef struct rlglData { Matrix stack[RL_MAX_MATRIX_STACK_SIZE];// Matrix stack for push/pop int stackCounter; // Matrix stack counter + unsigned int currentTextureId; // Current texture id to be used on glBegin unsigned int defaultTextureId; // Default texture used on shapes/poly drawing (required by shader) unsigned int activeTextureId[RL_DEFAULT_BATCH_MAX_TEXTURE_UNITS]; // Active texture ids to be enabled on batch drawing (0 active by default) unsigned int defaultVShaderId; // Default vertex shader id (used by default shader program) @@ -1485,8 +1486,8 @@ void rlBegin(int mode) if (RLGL.currentBatch->drawCounter >= RL_DEFAULT_BATCH_DRAWCALLS) rlDrawRenderBatch(RLGL.currentBatch); RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].mode = mode; - RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount = 0; - RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].textureId = RLGL.State.defaultTextureId; + RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].textureId = RLGL.State.currentTextureId; + RLGL.State.currentTextureId = RLGL.State.defaultTextureId; } } @@ -1651,6 +1652,7 @@ void rlSetTexture(unsigned int id) { rlDrawRenderBatch(RLGL.currentBatch); } + RLGL.State.currentTextureId = RLGL.State.defaultTextureId; #endif } else @@ -1658,6 +1660,7 @@ void rlSetTexture(unsigned int id) #if defined(GRAPHICS_API_OPENGL_11) rlEnableTexture(id); #else + RLGL.State.currentTextureId = id; if (RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].textureId != id) { if (RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount > 0) @@ -1676,6 +1679,9 @@ void rlSetTexture(unsigned int id) RLGL.State.vertexCounter += RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexAlignment; RLGL.currentBatch->drawCounter++; + + RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].mode = RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 2].mode; + } } @@ -2257,6 +2263,7 @@ void rlglInit(int width, int height) // Init default white texture unsigned char pixels[4] = { 255, 255, 255, 255 }; // 1 pixel RGBA (4 bytes) RLGL.State.defaultTextureId = rlLoadTexture(pixels, 1, 1, RL_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, 1); + RLGL.State.currentTextureId = RLGL.State.defaultTextureId; if (RLGL.State.defaultTextureId != 0) TRACELOG(RL_LOG_INFO, "TEXTURE: [ID %i] Default texture loaded successfully", RLGL.State.defaultTextureId); else TRACELOG(RL_LOG_WARNING, "TEXTURE: Failed to load default texture"); From 07033cff904ef3a46ffd12e8f8235e06bdb1096d Mon Sep 17 00:00:00 2001 From: Maicon Santana Date: Wed, 24 Sep 2025 19:44:15 +0100 Subject: [PATCH 028/167] Fix polygon drawing example for opengl 1.1 (#5202) --- examples/textures/textures_polygon_drawing.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/textures/textures_polygon_drawing.c b/examples/textures/textures_polygon_drawing.c index 8005ad1a1..ec1869d67 100644 --- a/examples/textures/textures_polygon_drawing.c +++ b/examples/textures/textures_polygon_drawing.c @@ -115,9 +115,9 @@ int main(void) // without crossing perimeter, points must be in anticlockwise order void DrawTexturePoly(Texture2D texture, Vector2 center, Vector2 *points, Vector2 *texcoords, int pointCount, Color tint) { + rlSetTexture(texture.id); rlBegin(RL_TRIANGLES); - rlSetTexture(texture.id); rlColor4ub(tint.r, tint.g, tint.b, tint.a); From 3f6d67c61c59affa4561de2ddf988e487093bc80 Mon Sep 17 00:00:00 2001 From: Keks137 Date: Wed, 24 Sep 2025 20:45:55 +0200 Subject: [PATCH 029/167] [rcore_android] implement GetCurrentMonitor() (#5204) --- src/platforms/rcore_android.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/src/platforms/rcore_android.c b/src/platforms/rcore_android.c index bfbdd30b3..6c67dc893 100644 --- a/src/platforms/rcore_android.c +++ b/src/platforms/rcore_android.c @@ -49,7 +49,7 @@ #include // Required for: android_app struct and activity management #include // Required for: AWINDOW_FLAG_FULLSCREEN definition and others //#include // Required for: Android sensors functions (accelerometer, gyroscope, light...) -#include // Required for: JNIEnv and JavaVM [Used in OpenURL()] +#include // Required for: JNIEnv and JavaVM [Used in OpenURL() and GetCurrentMonitor()] #include // Native platform windowing system interface @@ -446,8 +446,32 @@ int GetMonitorCount(void) // Get current monitor where window is placed int GetCurrentMonitor(void) { - TRACELOG(LOG_WARNING, "GetCurrentMonitor() not implemented on target platform"); - return 0; + int displayId = -1; + JNIEnv* env = NULL; + JavaVM* vm = platform.app->activity->vm; + (*vm)->AttachCurrentThread(vm, &env, NULL); + + jobject activity = platform.app->activity->clazz; + jclass activityClass = (*env)->GetObjectClass(env, activity); + + jmethodID getDisplayMethod = (*env)->GetMethodID(env, activityClass, "getDisplay", "()Landroid/view/Display;"); + + jobject display = (*env)->CallObjectMethod(env, activity, getDisplayMethod); + + if (display == NULL) { + TRACELOG(LOG_ERROR, "GetCurrentMonitor() couldn't get the display object"); + } else { + jclass displayClass = (*env)->FindClass(env, "android/view/Display"); + jmethodID getDisplayIdMethod = (*env)->GetMethodID(env, displayClass, "getDisplayId", "()I"); + displayId = (int) (*env)->CallIntMethod(env, display, getDisplayIdMethod); + (*env)->DeleteLocalRef(env, displayClass); + } + + (*env)->DeleteLocalRef(env, activityClass); + (*env)->DeleteLocalRef(env, display); + + (*vm)->DetachCurrentThread(vm); + return displayId; } // Get selected monitor position From 15d234b79d357faa070d5cd7d29b08daaa23a944 Mon Sep 17 00:00:00 2001 From: Arman Ommid <71801518+ArmanOmmid@users.noreply.github.com> Date: Fri, 26 Sep 2025 11:56:37 -0700 Subject: [PATCH 030/167] GLTF anim correctly inherits world transform (#5206) --- src/rmodels.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/rmodels.c b/src/rmodels.c index 128d5303b..06180cd5d 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -4261,9 +4261,10 @@ static void BuildPoseFromParentJoints(BoneInfo *bones, int boneCount, Transform continue; } transforms[i].rotation = QuaternionMultiply(transforms[bones[i].parent].rotation, transforms[i].rotation); + transforms[i].scale = Vector3Multiply(transforms[i].scale, transforms[bones[i].parent].scale); + transforms[i].translation = Vector3Multiply(transforms[i].translation, transforms[bones[i].parent].scale); transforms[i].translation = Vector3RotateByQuaternion(transforms[i].translation, transforms[bones[i].parent].rotation); transforms[i].translation = Vector3Add(transforms[i].translation, transforms[bones[i].parent].translation); - transforms[i].scale = Vector3Multiply(transforms[i].scale, transforms[bones[i].parent].scale); } } } @@ -6238,6 +6239,20 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, int *animCo *animCount = (int)data->animations_count; animations = (ModelAnimation *)RL_CALLOC(data->animations_count, sizeof(ModelAnimation)); + Transform worldTransform; + { + cgltf_float cgltf_worldTransform[16]; + cgltf_node* node = skin.joints[0]; + cgltf_node_transform_world(node->parent, cgltf_worldTransform); + Matrix worldMatrix = { + cgltf_worldTransform[0], cgltf_worldTransform[4], cgltf_worldTransform[8], cgltf_worldTransform[12], + cgltf_worldTransform[1], cgltf_worldTransform[5], cgltf_worldTransform[9], cgltf_worldTransform[13], + cgltf_worldTransform[2], cgltf_worldTransform[6], cgltf_worldTransform[10], cgltf_worldTransform[14], + cgltf_worldTransform[3], cgltf_worldTransform[7], cgltf_worldTransform[11], cgltf_worldTransform[15] + }; + MatrixDecompose(worldMatrix, &(worldTransform.translation), &(worldTransform.rotation), &(worldTransform.scale)); + } + for (unsigned int i = 0; i < data->animations_count; i++) { animations[i].bones = LoadBoneInfoGLTF(skin, &animations[i].boneCount); @@ -6356,6 +6371,13 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, int *animCo }; } + Transform* root = &animations[i].framePoses[j][0]; + root->rotation = QuaternionMultiply(worldTransform.rotation, root->rotation); + root->scale = Vector3Multiply(root->scale, worldTransform.scale); + root->translation = Vector3Multiply(root->translation, worldTransform.scale); + root->translation = Vector3RotateByQuaternion(root->translation, worldTransform.rotation); + root->translation = Vector3Add(root->translation, worldTransform.translation); + BuildPoseFromParentJoints(animations[i].bones, animations[i].boneCount, animations[i].framePoses[j]); } From fe8c83b57d623e8343f09cd1a9e8b548defc4da0 Mon Sep 17 00:00:00 2001 From: Smallz3201 Date: Fri, 26 Sep 2025 14:56:54 -0400 Subject: [PATCH 031/167] Update palette_switch.fs (#5205) Removed unnecessary `a` in palette_switch.fs `note` comment --- examples/shaders/resources/shaders/glsl330/palette_switch.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/shaders/resources/shaders/glsl330/palette_switch.fs b/examples/shaders/resources/shaders/glsl330/palette_switch.fs index 6a82529b1..2db8880d1 100644 --- a/examples/shaders/resources/shaders/glsl330/palette_switch.fs +++ b/examples/shaders/resources/shaders/glsl330/palette_switch.fs @@ -17,7 +17,7 @@ out vec4 finalColor; void main() { // Texel color fetching from texture sampler - // NOTE: The texel is actually the a GRAYSCALE index color + // NOTE: The texel is actually the GRAYSCALE index color vec4 texelColor = texture(texture0, fragTexCoord)*fragColor; // Convert the (normalized) texel color RED component (GB would work, too) From 2724f07c9a2acadeea800e2e70d074ccb13d12e3 Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 26 Sep 2025 22:22:43 +0200 Subject: [PATCH 032/167] Update rexm.c --- tools/rexm/rexm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/rexm/rexm.c b/tools/rexm/rexm.c index 6fdf74645..7f303538c 100644 --- a/tools/rexm/rexm.c +++ b/tools/rexm/rexm.c @@ -2047,6 +2047,7 @@ static void SortExampleByName(rlExampleInfo *items, int count) // WARNING: Supported resource file extensions is hardcoded by used file types // but new examples could require other file extensions to be added, // maybe it should look for '.xxx")' patterns instead +// TODO: WARNING: Some resources could require linked resources: .fnt --> .png, .mtl --> .png, .gltf --> .png, ... static char **ScanExampleResources(const char *filePath, int *resPathCount) { #define REXM_MAX_RESOURCE_PATH_LEN 256 From 87f758f9b4796ed14ad844e68b651eaf891922d7 Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 26 Sep 2025 22:26:19 +0200 Subject: [PATCH 033/167] Review latest PRs formatting --- src/platforms/rcore_android.c | 13 ++++++++----- src/rmodels.c | 24 +++++++++++------------- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/platforms/rcore_android.c b/src/platforms/rcore_android.c index 6c67dc893..6ecc41888 100644 --- a/src/platforms/rcore_android.c +++ b/src/platforms/rcore_android.c @@ -447,8 +447,8 @@ int GetMonitorCount(void) int GetCurrentMonitor(void) { int displayId = -1; - JNIEnv* env = NULL; - JavaVM* vm = platform.app->activity->vm; + JNIEnv *env = NULL; + JavaVM *vm = platform.app->activity->vm; (*vm)->AttachCurrentThread(vm, &env, NULL); jobject activity = platform.app->activity->clazz; @@ -458,12 +458,15 @@ int GetCurrentMonitor(void) jobject display = (*env)->CallObjectMethod(env, activity, getDisplayMethod); - if (display == NULL) { + if (display == NULL) + { TRACELOG(LOG_ERROR, "GetCurrentMonitor() couldn't get the display object"); - } else { + } + else + { jclass displayClass = (*env)->FindClass(env, "android/view/Display"); jmethodID getDisplayIdMethod = (*env)->GetMethodID(env, displayClass, "getDisplayId", "()I"); - displayId = (int) (*env)->CallIntMethod(env, display, getDisplayIdMethod); + displayId = (int)(*env)->CallIntMethod(env, display, getDisplayIdMethod); (*env)->DeleteLocalRef(env, displayClass); } diff --git a/src/rmodels.c b/src/rmodels.c index 06180cd5d..9aca37a24 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -6239,19 +6239,17 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, int *animCo *animCount = (int)data->animations_count; animations = (ModelAnimation *)RL_CALLOC(data->animations_count, sizeof(ModelAnimation)); - Transform worldTransform; - { - cgltf_float cgltf_worldTransform[16]; - cgltf_node* node = skin.joints[0]; - cgltf_node_transform_world(node->parent, cgltf_worldTransform); - Matrix worldMatrix = { - cgltf_worldTransform[0], cgltf_worldTransform[4], cgltf_worldTransform[8], cgltf_worldTransform[12], - cgltf_worldTransform[1], cgltf_worldTransform[5], cgltf_worldTransform[9], cgltf_worldTransform[13], - cgltf_worldTransform[2], cgltf_worldTransform[6], cgltf_worldTransform[10], cgltf_worldTransform[14], - cgltf_worldTransform[3], cgltf_worldTransform[7], cgltf_worldTransform[11], cgltf_worldTransform[15] - }; - MatrixDecompose(worldMatrix, &(worldTransform.translation), &(worldTransform.rotation), &(worldTransform.scale)); - } + Transform worldTransform = { 0 }; + cgltf_float cgltf_worldTransform[16] = { 0 }; + cgltf_node *node = skin.joints[0]; + cgltf_node_transform_world(node->parent, cgltf_worldTransform); + Matrix worldMatrix = { + cgltf_worldTransform[0], cgltf_worldTransform[4], cgltf_worldTransform[8], cgltf_worldTransform[12], + cgltf_worldTransform[1], cgltf_worldTransform[5], cgltf_worldTransform[9], cgltf_worldTransform[13], + cgltf_worldTransform[2], cgltf_worldTransform[6], cgltf_worldTransform[10], cgltf_worldTransform[14], + cgltf_worldTransform[3], cgltf_worldTransform[7], cgltf_worldTransform[11], cgltf_worldTransform[15] + }; + MatrixDecompose(worldMatrix, &worldTransform.translation, &worldTransform.rotation, &worldTransform.scale); for (unsigned int i = 0; i < data->animations_count; i++) { From 06cfda6ff9e06da5ba54670243968b9f5b7216f0 Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 26 Sep 2025 23:03:10 +0200 Subject: [PATCH 034/167] Update raymath.h --- src/raymath.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/raymath.h b/src/raymath.h index d3c8b9697..65a20de59 100644 --- a/src/raymath.h +++ b/src/raymath.h @@ -2555,7 +2555,7 @@ RMAPI int QuaternionEquals(Quaternion p, Quaternion q) // Decompose a transformation matrix into its rotational, translational and scaling components and remove shear RMAPI void MatrixDecompose(Matrix mat, Vector3 *translation, Quaternion *rotation, Vector3 *scale) { - float eps = 1e-9; + float eps = (float)1e-9; // Extract Translation translation->x = mat.m12; From e79603d501387a1984d275888a20754033bd28d3 Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 26 Sep 2025 23:17:37 +0200 Subject: [PATCH 035/167] REDESIGNED: `rcore_desktop_win32` platform backend Now it works! but there is still work to do to support all required features... I really enjoyed reviewing and redesigning this platform backend! --- projects/VS2022/raylib/raylib.vcxproj | 14 + projects/VS2022/raylib/raylib.vcxproj.filters | 3 + src/platforms/rcore_desktop_win32.c | 2308 ++++++++--------- 3 files changed, 1067 insertions(+), 1258 deletions(-) diff --git a/projects/VS2022/raylib/raylib.vcxproj b/projects/VS2022/raylib/raylib.vcxproj index 64695d4de..7721a669a 100644 --- a/projects/VS2022/raylib/raylib.vcxproj +++ b/projects/VS2022/raylib/raylib.vcxproj @@ -504,6 +504,20 @@ true true + + true + true + true + true + true + true + true + true + true + true + true + true + true true diff --git a/projects/VS2022/raylib/raylib.vcxproj.filters b/projects/VS2022/raylib/raylib.vcxproj.filters index 182358229..4588f0521 100644 --- a/projects/VS2022/raylib/raylib.vcxproj.filters +++ b/projects/VS2022/raylib/raylib.vcxproj.filters @@ -46,6 +46,9 @@ Source Files\Platform Files + + Source Files\Platform Files + diff --git a/src/platforms/rcore_desktop_win32.c b/src/platforms/rcore_desktop_win32.c index a79fa692e..29669fd54 100644 --- a/src/platforms/rcore_desktop_win32.c +++ b/src/platforms/rcore_desktop_win32.c @@ -6,19 +6,23 @@ * - Windows (Win32, Win64) * * LIMITATIONS: -* - currently in initial development stage, alot is missing -* - unsure how to support MOUSE_BUTTON_FORWARD/MOUSE_BUTTON_BACK +* - Initial development stage, lot of functionality missing +* - No support for MOUSE_BUTTON_FORWARD/MOUSE_BUTTON_BACK * * POSSIBLE IMPROVEMENTS: +* - Improvement 01 +* - Improvement 02 * * ADDITIONAL NOTES: +* - TRACELOG() function is located in raylib [utils] module * * CONFIGURATION: * #define RCORE_PLATFORM_CUSTOM_FLAG * Custom flag for rcore on target platform -not used- * * DEPENDENCIES: -* - the win32 API, i.e. windows.h +* - Win32 API (windows.h) +* * * LICENSE: zlib/libpng * @@ -41,7 +45,7 @@ * **********************************************************************************************/ -// move windows.h functions to new names to avoid redefining the same functions as raylib +// Move windows.h symbols to new names to avoid redefining the same names as raylib #define CloseWindow CloseWindowWin32 #define Rectangle RectangleWin32 #define ShowCursor ShowCursorWin32 @@ -55,16 +59,16 @@ #define WIN32_LEAN_AND_MEAN #include -#undef CloseWindow -#undef Rectangle -#undef ShowCursor -#undef LoadImage +#undef CloseWindow // raylib symbol collision +#undef Rectangle // raylib symbol collision +#undef ShowCursor // raylib symbol collision +#undef LoadImage // raylib symbol collision #undef LoadImageA #undef LoadImageW -#undef DrawText +#undef DrawText // raylib symbol collision #undef DrawTextA #undef DrawTextW -#undef DrawTextEx +#undef DrawTextEx // raylib symbol collision #undef DrawTextExA #undef DrawTextExW @@ -73,99 +77,181 @@ #include #include -#include +//#include + +//---------------------------------------------------------------------------------- +// 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) +// when the window isn't fullscreen/maximized/minimized +typedef struct { + HWND hwnd; + HDC hdc; + HGLRC glContext; + LARGE_INTEGER timerFrequency; + unsigned int appScreenWidth; + unsigned int appScreenHeight; + unsigned int desiredFlags; + bool cursorEnabled; +} 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); + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +extern CoreData CORE; // Global CORE state context + +static PlatformData platform = { 0 }; // Platform specific data + +// Required WGL functions +static PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = NULL; +static PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = NULL; +static PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL; // -------------------------------------------------------------------------------- -// This part of the file contains pure functions that never access global state. +// This part of the file contains pure functions that never access global state // This distinction helps keep the backend maintainable as the inputs and outputs -// of every function called in this section can be fully derived from the -// call-site alone. +// of every function called in this section can be fully derived from the call-site alone // -------------------------------------------------------------------------------- // Prevent any code in this part of the file from accessing the global CORE state #define CORE DONT_USE_CORE_HERE +//---------------------------------------------------------------------------------- +// 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; \ +} while (0) + +#define STYLE_MASK_ALL 0xffffffff +#define STYLE_MASK_READONLY (WS_MINIMIZE | WS_MAXIMIZE) +#define STYLE_MASK_WRITABLE (~STYLE_MASK_READONLY) + +#define STYLE_FLAGS_RESIZABLE WS_THICKFRAME + +#define STYLE_FLAGS_UNDECORATED_OFF (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX) +#define STYLE_FLAGS_UNDECORATED_ON WS_POPUP + +#define WINDOW_STYLE_EX 0 + +#define CLASS_NAME L"RaylibWindow" + +#define FLAG_MASK_OPTIONAL (FLAG_VSYNC_HINT) +#define FLAG_MASK_REQUIRED ~(FLAG_MASK_OPTIONAL) + +// Flags that have no operations to perform during an update +#define FLAG_MASK_NO_UPDATE (FLAG_WINDOW_HIGHDPI | FLAG_MSAA_4X_HINT) + +#define WM_APP_UPDATE_WINDOW_SIZE (WM_APP + 1) + +#define WGL_DRAW_TO_WINDOW_ARB 0x2001 +#define WGL_ACCELERATION_ARB 0x2003 +#define WGL_SUPPORT_OPENGL_ARB 0x2010 +#define WGL_DOUBLE_BUFFER_ARB 0x2011 +#define WGL_PIXEL_TYPE_ARB 0x2013 +#define WGL_COLOR_BITS_ARB 0x2014 +#define WGL_RED_BITS_ARB 0x2015 +#define WGL_RED_SHIFT_ARB 0x2016 +#define WGL_GREEN_BITS_ARB 0x2017 +#define WGL_GREEN_SHIFT_ARB 0x2018 +#define WGL_BLUE_BITS_ARB 0x2019 +#define WGL_BLUE_SHIFT_ARB 0x201a +#define WGL_ALPHA_BITS_ARB 0x201b +#define WGL_ALPHA_SHIFT_ARB 0x201c +#define WGL_DEPTH_BITS_ARB 0x2022 +#define WGL_STENCIL_BITS_ARB 0x2023 +#define WGL_TYPE_RGBA_ARB 0x202b +#define WGL_NO_ACCELERATION_ARB 0x2025 // OpenGL 1.1 GDI software rasterizer +#define WGL_GENERIC_ACCELERATION_ARB 0x2026 +#define WGL_FULL_ACCELERATION_ARB 0x2027 // OpenGL hardware-accelerated, using GPU-drivers provided by vendor + +#define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000 +#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 +#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_SAMPLE_BUFFERS_ARB 0x2041 +#define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20a9 +#define WGL_TRANSPARENT_ARB 0x200A + +//---------------------------------------------------------------------------------- +// 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; + +typedef struct { + DWORD set; + DWORD clear; +} FlagsOp; + +//---------------------------------------------------------------------------------- +// Module Internal Functions Declaration +//---------------------------------------------------------------------------------- static size_t AToWLen(const char *a) { int sizeNeeded = MultiByteToWideChar(CP_UTF8, 0, a, -1, NULL, 0); - if (sizeNeeded < 0) - { - TRACELOG(LOG_ERROR, "failed to calculate wide length, result=%d, error=%u", sizeNeeded, GetLastError()); - abort(); - } + + if (sizeNeeded < 0) TRACELOG(LOG_ERROR, "Failed to calculate wide length, result=%d, error=%u", sizeNeeded, GetLastError()); return sizeNeeded; } static void AToWCopy(wchar_t *outPtr, size_t outLen, const char *a) { - int size = MultiByteToWideChar(CP_UTF8, 0, a, -1, outPtr, outLen); - if (size != outLen) - { - TRACELOG(LOG_ERROR, "expected to convert %zu utf8 chars to wide but converted %zu", outLen, size); - abort(); - } -} -#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; \ -} while (0) - -static void LogFail(const char *what, DWORD error) -{ - TRACELOG(LOG_ERROR, "%s failed, error=%lu", what, error); -} -static void LogFailHr(const char *what, HRESULT hr) -{ - TRACELOG(LOG_ERROR, "%s failed, hresult=0x%lx", what, (DWORD)hr); + 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); } -#define STYLE_FLAGS_RESIZABLE WS_THICKFRAME - -#define STYLE_FLAGS_UNDECORATED_OFF (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX) -#define STYLE_FLAGS_UNDECORATED_ON WS_POPUP - -static bool ResizableFromStyle(DWORD style) -{ - return 0 != (style & STYLE_FLAGS_RESIZABLE); -} static bool DecoratedFromStyle(DWORD style) { if (style & STYLE_FLAGS_UNDECORATED_ON) { - if (style & STYLE_FLAGS_UNDECORATED_OFF) - { - TRACELOG(LOG_ERROR, "style 0x%x has both undecorated on/off flags", style); - abort(); - } - - return false; // not decorated + if (style & STYLE_FLAGS_UNDECORATED_OFF) TRACELOG(LOG_ERROR, "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, "style 0x%x is missing these flags 0x%x", masked, masked ^ STYLE_FLAGS_UNDECORATED_OFF); - abort(); - } + 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); - return true; // decorated -} -static bool HiddenFromStyle(DWORD style) -{ - return 0 == (style & WS_VISIBLE); + return true; // Decorated } -typedef enum { MIZED_NONE, MIZED_MIN, MIZED_MAX } Mized; -Mized MizedFromStyle(DWORD style) +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; } -Mized MizedFromFlags(unsigned flags) + +static Mized MizedFromFlags(unsigned flags) { // minimized takes precedence over maximized if (flags & FLAG_WINDOW_MINIMIZED) return MIZED_MIN; @@ -175,12 +261,11 @@ Mized MizedFromFlags(unsigned flags) static DWORD MakeWindowStyle(unsigned flags) { - DWORD style = - // 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. - WS_CLIPSIBLINGS - ; + // 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 ; + 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; @@ -190,15 +275,9 @@ static DWORD MakeWindowStyle(unsigned flags) case MIZED_NONE: break; case MIZED_MIN: style |= WS_MINIMIZE; break; case MIZED_MAX: style |= WS_MAXIMIZE; break; - default: abort(); + default: break; } - // sanity checks, maybe remove later - if (ResizableFromStyle(style) != !!(flags & FLAG_WINDOW_RESIZABLE)) abort(); - if (DecoratedFromStyle(style) != !(flags & FLAG_WINDOW_UNDECORATED)) abort(); - if (HiddenFromStyle(style) != !!(flags & FLAG_WINDOW_HIDDEN)) abort(); - if (MizedFromStyle(style) != MizedFromFlags(flags)) abort(); - return style; } @@ -206,171 +285,91 @@ static bool IsMinimized2(HWND hwnd) { bool isIconic = IsIconic(hwnd); bool styleMinimized = !!(WS_MINIMIZE & GetWindowLongPtrW(hwnd, GWL_STYLE)); - if (isIconic != styleMinimized) - { - TRACELOG(LOG_ERROR, "IsIconic(%d) != WS_MINIMIZED(%d)", isIconic, styleMinimized); - abort(); - } + if (isIconic != styleMinimized) TRACELOG(LOG_WARNING, "IsIconic(%d) != WS_MINIMIZED(%d)", isIconic, styleMinimized); return isIconic; } -#define STYLE_MASK_ALL 0xffffffff -#define STYLE_MASK_READONLY (WS_MINIMIZE | WS_MAXIMIZE) -#define STYLE_MASK_WRITABLE (~STYLE_MASK_READONLY) - // 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 -) { +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)) { - 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)", - context, - flags, - styleFromFlags & styleCheckMask, - expectedStyle & styleCheckMask, - (styleFromFlags & styleCheckMask) ^ (expectedStyle & styleCheckMask), - styleCheckMask - ); - abort(); - } + TRACELOG(LOG_ERROR, "%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); } SetLastError(0); - LONG actualStyle = GetWindowLongPtrW(hwnd, GWL_STYLE); + 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)", - context, - expectedStyle & styleCheckMask, - actualStyle & styleCheckMask, + TRACELOG(LOG_ERROR, "%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() - ); - abort(); + styleCheckMask, GetLastError()); } if (styleCheckMask & WS_MINIMIZE) { bool isIconic = IsIconic(hwnd); bool styleMinimized = !!(WS_MINIMIZE & actualStyle); - if (isIconic != styleMinimized) { - TRACELOG(LOG_ERROR, "IsIconic(%d) != WS_MINIMIZED(%d)", isIconic, styleMinimized); - abort(); - } + if (isIconic != styleMinimized) TRACELOG(LOG_ERROR, "IsIconic(%d) != WS_MINIMIZED(%d)", isIconic, styleMinimized); } if (styleCheckMask & WS_MAXIMIZE) { WINDOWPLACEMENT placement; placement.length = sizeof(placement); - if (!GetWindowPlacement(hwnd, &placement)) { - LogFail("GetWindowPlacement", GetLastError()); - abort(); + if (!GetWindowPlacement(hwnd, &placement)) + { + TRACELOG(LOG_ERROR, "%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", - placementMaximized, - placement.showCmd, - styleMaximized - ); - abort(); + TRACELOG(LOG_ERROR, "maximized state desync, placement maximized=%d (showCmd=%lu) style maximized=%d", + placementMaximized, placement.showCmd, styleMaximized); } } } -static float PtFromPx(float dpiScale, bool highdpiEnabled, int pt) -{ - return highdpiEnabled? (((float)pt)/dpiScale) : pt; -} -static int PxFromPt(float dpiScale, bool highdpiEnabled, float pt) -{ - return highdpiEnabled? roundf(pt*dpiScale) : roundf(pt); -} -static SIZE PxFromPt2(float dpiScale, bool highdpiEnabled, Vector2 screenSize) +static SIZE PxFromPt2(float dpiScale, bool highdpiEnabled, int screenWidth, int screenHeight) { + // Get size in pixels from points return (SIZE){ - PxFromPt(dpiScale, highdpiEnabled, screenSize.x), - PxFromPt(dpiScale, highdpiEnabled, screenSize.y), + highdpiEnabled? (int)((float)screenWidth*dpiScale) : screenWidth, + highdpiEnabled? (int)((float)screenHeight*dpiScale) : screenHeight, }; } static SIZE GetClientSize(HWND hwnd) { - RECT rect; - if (0 == GetClientRect(hwnd, &rect)) - { - LogFail("GetClientRect", GetLastError()); - abort(); - } - - if (rect.left != 0) abort(); // never happens AFAIK - if (rect.top != 0) abort(); // never happens AFAIK + RECT rect = { 0 }; + + if (GetClientRect(hwnd, &rect) == 0) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "GetClientRect", GetLastError()); + return (SIZE){ rect.right, rect.bottom }; } -static UINT GetWindowDpi(HWND hwnd) -{ - UINT dpi = GetDpiForWindow(hwnd); - if (dpi == 0) - { - LogFail("GetWindowDpi", GetLastError()); - abort(); - } - - return dpi; -} - -static float ScaleFromDpi(UINT dpi) -{ - return ((float)dpi)/96.0f; -} - -#define WINDOW_STYLE_EX 0 - static SIZE CalcWindowSize(UINT dpi, SIZE clientSize, DWORD style) { RECT rect = { 0, 0, clientSize.cx, clientSize.cy }; - if (!AdjustWindowRectExForDpi(&rect, style, 0, WINDOW_STYLE_EX, dpi)) - { - LogFail("AdjustWindowRect", GetLastError()); - abort(); - } + + int result = AdjustWindowRectExForDpi(&rect, style, 0, WINDOW_STYLE_EX, dpi); + + if (result == 0) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "AdjustWindowRect", GetLastError()); return (SIZE){ rect.right - rect.left, rect.bottom - rect.top }; } -typedef enum { - UPDATE_WINDOW_FIRST, - UPDATE_WINDOW_NORMAL, -} UpdateWindowKind; - // returns true if the window size was updated, false otherwise -static bool UpdateWindowSize( - UpdateWindowKind kind, - HWND hwnd, - Vector2 appScreenSize, - unsigned flags -) { +static bool UpdateWindowSize(UpdateWindowKind kind, HWND hwnd, int width, int height, unsigned flags) +{ if (flags & FLAG_WINDOW_MINIMIZED) return false; if (flags & FLAG_WINDOW_MAXIMIZED) @@ -381,79 +380,52 @@ static bool UpdateWindowSize( if (flags & FLAG_BORDERLESS_WINDOWED_MODE) { + MONITORINFO info = { 0 }; HMONITOR monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY); - MONITORINFO info; info.cbSize = sizeof(info); - if (!GetMonitorInfoW(monitor, &info)) - { - LogFail("GetMonitorInfo", GetLastError()); - abort(); - } + if (!GetMonitorInfoW(monitor, &info)) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "GetMonitorInfo", GetLastError()); - RECT windowRect; - if (!GetWindowRect(hwnd, &windowRect)) - { - LogFail("GetWindowRect", GetLastError()); - abort(); - } + RECT windowRect = { 0 }; + if (!GetWindowRect(hwnd, &windowRect)) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "GetWindowRect", GetLastError()); - if ( - (windowRect.left == info.rcMonitor.left) && + if ((windowRect.left == info.rcMonitor.left) && (windowRect.top == info.rcMonitor.top) && ((windowRect.right - windowRect.left) == (info.rcMonitor.right - info.rcMonitor.left)) && - ((windowRect.bottom - windowRect.top) == (info.rcMonitor.bottom - info.rcMonitor.top)) - ) return false; + ((windowRect.bottom - windowRect.top) == (info.rcMonitor.bottom - info.rcMonitor.top))) return false; - if (!SetWindowPos( - hwnd, - HWND_TOP, + if (!SetWindowPos(hwnd, HWND_TOP, info.rcMonitor.left, info.rcMonitor.top, info.rcMonitor.right - info.rcMonitor.left, info.rcMonitor.bottom - info.rcMonitor.top, - SWP_NOOWNERZORDER - )) { - LogFail("SetWindowPos", GetLastError()); - abort(); + SWP_NOOWNERZORDER)) + { + TRACELOG(LOG_ERROR, "%s failed, error=%lu", "SetWindowPos", GetLastError()); } return true; } - UINT dpi = GetWindowDpi(hwnd); - float dpiScale = ScaleFromDpi(dpi); + UINT dpi = GetDpiForWindow(hwnd); + float dpiScale = ((float)dpi)/96.0f; bool dpiScaling = flags & FLAG_WINDOW_HIGHDPI; - SIZE desired = PxFromPt2(dpiScale, dpiScaling, appScreenSize); + SIZE desired = PxFromPt2(dpiScale, dpiScaling, width, height); SIZE actual = GetClientSize(hwnd); - if (actual.cx == desired.cx || actual.cy == desired.cy) - return false; + if ((actual.cx == desired.cx) || (actual.cy == desired.cy)) return false; + + 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); - TRACELOG( - LOG_INFO, - "restoring client size from %dx%d to %dx%d (dpi=%lu dpiScaling=%d app=%fx%f)", - actual.cx, actual.cy, - desired.cx, desired.cy, - dpi, dpiScaling, - appScreenSize.x, appScreenSize.y - ); SIZE windowSize = CalcWindowSize(dpi, desired, MakeWindowStyle(flags)); POINT windowPos = (POINT){ 0, 0 }; UINT swpFlags = SWP_NOZORDER | SWP_FRAMECHANGED; if (kind == UPDATE_WINDOW_FIRST) { HMONITOR monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY); - if (!monitor) - { - LogFail("MonitorFromWindow", GetLastError()); - abort(); - } + if (!monitor) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "MonitorFromWindow", GetLastError()); MONITORINFO info; info.cbSize = sizeof(info); - if (!GetMonitorInfoW(monitor, &info)) - { - LogFail("GetMonitorInfo", GetLastError()); - abort(); - } + if (!GetMonitorInfoW(monitor, &info)) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "GetMonitorInfo", GetLastError()); LONG monitorWidth = info.rcMonitor.right - info.rcMonitor.left; LONG monitorHeight = info.rcMonitor.bottom - info.rcMonitor.top; @@ -461,54 +433,26 @@ static bool UpdateWindowSize( MAX(0, (monitorWidth - windowSize.cx)/2), MAX(0, (monitorHeight - windowSize.cy)/2), }; - } else { - swpFlags |= SWP_NOMOVE; } + else swpFlags |= SWP_NOMOVE; - if (!SetWindowPos( - hwnd, NULL, - windowPos.x, windowPos.y, - windowSize.cx, windowSize.cy, - swpFlags - )) { - LogFail("SetWindowPos", GetLastError()); - abort(); + if (!SetWindowPos(hwnd, NULL, windowPos.x, windowPos.y, windowSize.cx, windowSize.cy, swpFlags)) + { + TRACELOG(LOG_ERROR, "%s failed, error=%lu", "SetWindowPos", GetLastError()); } return true; } -#define CLASS_NAME L"RaylibWindow" - -static void CreateWindowAlloca(const char *title, DWORD style) -{ - WCHAR *titleWide; - A_TO_W_ALLOCA(titleWide, title); - CreateWindowExW( - WINDOW_STYLE_EX, - CLASS_NAME, - titleWide, - style, - 0, 0, - 0, 0, - NULL, - NULL, - GetModuleHandleW(NULL), - NULL - ); -} - static BOOL IsWindows10Version1703OrGreaterWin32(void) { HMODULE ntdll = LoadLibraryW(L"ntdll.dll"); - DWORD (*Verify)( - RTL_OSVERSIONINFOEXW*, ULONG, ULONGLONG - ) = (DWORD (*)( - RTL_OSVERSIONINFOEXW*, ULONG, ULONGLONG - ))GetProcAddress(ntdll, "RtlVerifyVersionInfo"); + + DWORD (*Verify)(RTL_OSVERSIONINFOEXW*, ULONG, ULONGLONG) = + (DWORD (*)(RTL_OSVERSIONINFOEXW*, ULONG, ULONGLONG))GetProcAddress(ntdll, "RtlVerifyVersionInfo"); if (!Verify) { - LogFail("GetProcAddress 'RtlVerifyVersionInfo'", GetLastError()); + TRACELOG(LOG_ERROR, "%s failed, error=%lu", "GetProcAddress 'RtlVerifyVersionInfo'", GetLastError()); return 0; } @@ -521,42 +465,32 @@ 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); } -static void *FindProc(const char *name) +// Get OpenGL function pointers +static void *WglGetProcAddress(const char *procname) { + void *proc = (void *)wglGetProcAddress(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 *)0x3) || + (proc == (void *)-1)) { - void *proc = wglGetProcAddress(name); - if (proc) return proc; + // TODO: Keep gl module pointer as global platform data? + HMODULE glModule = LoadLibraryW(L"opengl32.dll"); + proc = (void *)GetProcAddress(glModule, procname); + + //if (proc == NULL) TRACELOG(LOG_ERROR, "GL: GetProcAddress() failed to get %s [%p], error=%u", procname, proc, GetLastError()); + //else TRACELOG(LOG_INFO, "GL: Found entry point for %s [%p]", procname, proc); } - static HMODULE opengl = NULL; - if (!opengl) - { - opengl = LoadLibraryW(L"opengl32"); - } - if (opengl) - { - void *proc = GetProcAddress(opengl, name); - if (proc) return proc; - } - - return NULL; -} -static void *WglGetProcAddress(const char *name) -{ - void *result = FindProc(name); - if (result) - { - //TRACELOG(LOG_DEBUG, "GetProcAddress '%s' > %p", name, result); - } - else - { - TRACELOG(LOG_ERROR, "GetProcAddress '%s' > %p failed, error=%u", name, result, GetLastError()); - } - - return result; + return proc; } static KeyboardKey KeyFromWparam(WPARAM wparam) @@ -744,40 +678,36 @@ static KeyboardKey KeyFromWparam(WPARAM wparam) static LPCWSTR GetCursorName(int cursor) { + LPCWSTR name = (LPCWSTR)IDC_ARROW; + switch (cursor) { - case MOUSE_CURSOR_DEFAULT : return (LPCWSTR)IDC_ARROW; - case MOUSE_CURSOR_ARROW : return (LPCWSTR)IDC_ARROW; - case MOUSE_CURSOR_IBEAM : return (LPCWSTR)IDC_IBEAM; - case MOUSE_CURSOR_CROSSHAIR : return (LPCWSTR)IDC_CROSS; - case MOUSE_CURSOR_POINTING_HAND: return (LPCWSTR)IDC_HAND; - case MOUSE_CURSOR_RESIZE_EW : return (LPCWSTR)IDC_SIZEWE; - case MOUSE_CURSOR_RESIZE_NS : return (LPCWSTR)IDC_SIZENS; - case MOUSE_CURSOR_RESIZE_NWSE : return (LPCWSTR)IDC_SIZENWSE; - case MOUSE_CURSOR_RESIZE_NESW : return (LPCWSTR)IDC_SIZENESW; - case MOUSE_CURSOR_RESIZE_ALL : return (LPCWSTR)IDC_SIZEALL; - case MOUSE_CURSOR_NOT_ALLOWED : return (LPCWSTR)IDC_NO; - default: abort(); + case MOUSE_CURSOR_DEFAULT: name = (LPCWSTR)IDC_ARROW; break; + case MOUSE_CURSOR_ARROW: name = (LPCWSTR)IDC_ARROW; break; + case MOUSE_CURSOR_IBEAM: name = (LPCWSTR)IDC_IBEAM; break; + case MOUSE_CURSOR_CROSSHAIR: name = (LPCWSTR)IDC_CROSS; break; + case MOUSE_CURSOR_POINTING_HAND: name = (LPCWSTR)IDC_HAND; break; + case MOUSE_CURSOR_RESIZE_EW: name = (LPCWSTR)IDC_SIZEWE; break; + case MOUSE_CURSOR_RESIZE_NS: name = (LPCWSTR)IDC_SIZENS; break; + case MOUSE_CURSOR_RESIZE_NWSE: name = (LPCWSTR)IDC_SIZENWSE; break; + case MOUSE_CURSOR_RESIZE_NESW: name = (LPCWSTR)IDC_SIZENESW; break; + case MOUSE_CURSOR_RESIZE_ALL: name = (LPCWSTR)IDC_SIZEALL; break; + case MOUSE_CURSOR_NOT_ALLOWED: name = (LPCWSTR)IDC_NO; break; + default: break; } -} + return name; +} static BOOL CALLBACK CountMonitorsProc(HMONITOR handle, HDC _, LPRECT rect, LPARAM lparam) { - int *count = (int*)lparam; + int *count = (int *)lparam; *count += 1; - // always return TRUE to continue the loop, otherwise, the caller + // Always return TRUE to continue the loop, otherwise, the caller // can't distinguish between stopping the loop and an error return TRUE; } -typedef struct { - HMONITOR needle; - int index; - int matchIndex; - RECT rect; -} FindMonitorContext; - static BOOL CALLBACK FindMonitorProc(HMONITOR handle, HDC _, LPRECT rect, LPARAM lparam) { FindMonitorContext *c = (FindMonitorContext*)lparam; @@ -788,96 +718,48 @@ static BOOL CALLBACK FindMonitorProc(HMONITOR handle, HDC _, LPRECT rect, LPARAM } c->index += 1; - // always return TRUE to continue the loop, otherwise, the caller + // Always return TRUE to continue the loop, otherwise, the caller // can't distinguish between stopping the loop and an error return TRUE; } -typedef struct { - DWORD set; - DWORD clear; -} FlagsOp; - -static void GetStyleChangeFlagOps( - DWORD coreWindowFlags, - STYLESTRUCT *ss, - FlagsOp *deferredFlags -) { +static void GetStyleChangeFlagOps(DWORD coreWindowFlags, STYLESTRUCT *ss, 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); + if (resizableOld != resizableNew) { - bool resizable = (coreWindowFlags & FLAG_WINDOW_RESIZABLE); - bool resizableOld = ResizableFromStyle(ss->styleOld); - bool resizableNew = ResizableFromStyle(ss->styleNew); - if (resizable != resizableOld) - { - TRACELOG(LOG_ERROR, "expected resizable %u but got %u", resizable, resizableOld); - abort(); - } - - if (resizableOld != resizableNew) - { - //TRACELOG(LOG_INFO, "resizable = %u", resizableNew); - if (resizableNew) - { - deferredFlags->set |= FLAG_WINDOW_RESIZABLE; - } - else - { - deferredFlags->clear |= FLAG_WINDOW_RESIZABLE; - } - } + if (resizableNew) deferredFlags->set |= FLAG_WINDOW_RESIZABLE; + else deferredFlags->clear |= FLAG_WINDOW_RESIZABLE; } + // 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); + if (decoratedOld != decoratedNew) { - 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); - abort(); - } - - if (decoratedOld != decoratedNew) - { - //TRACELOG(LOG_INFO, "decorated = %u", decoratedNew); - if (decoratedNew) - { - deferredFlags->clear |= FLAG_WINDOW_UNDECORATED; - } - else - { - deferredFlags->set |= FLAG_WINDOW_UNDECORATED; - } - } + if (decoratedNew) deferredFlags->clear |= FLAG_WINDOW_UNDECORATED; + else deferredFlags->set |= FLAG_WINDOW_UNDECORATED; } + // 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); + if (hiddenOld != hiddenNew) { - bool hidden = (coreWindowFlags & FLAG_WINDOW_HIDDEN); - bool hiddenOld = HiddenFromStyle(ss->styleOld); - bool hiddenNew = HiddenFromStyle(ss->styleNew); - if (hidden != hiddenOld) - { - TRACELOG(LOG_ERROR, "expected hidden %u but got %u", hidden, hiddenOld); - abort(); - } - - if (hiddenOld != hiddenNew) - { - TRACELOG(LOG_INFO, "hidden = %u", hiddenNew); - if (hiddenNew) - { - deferredFlags->set |= FLAG_WINDOW_HIDDEN; - } - else - { - deferredFlags->clear |= FLAG_WINDOW_HIDDEN; - } - } + if (hiddenNew) deferredFlags->set |= FLAG_WINDOW_HIDDEN; + else deferredFlags->clear |= FLAG_WINDOW_HIDDEN; } } -// call when the window is rezised, returns true if the new window size -// should update the desired app size +// 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; @@ -885,297 +767,58 @@ 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; } -// -------------------------------------------------------------------------------- -// Here's the end of the "pure function section", the rest of the file can access -// global state. -// -------------------------------------------------------------------------------- +// --------------------------------------------------------------------------------------------- +// Here's the end of the "pure function section", the rest of the file can access global state +// --------------------------------------------------------------------------------------------- -// unlock the ability to use CORE in the rest of the file +// Unlock the ability to use CORE in the rest of the file #undef CORE -// 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. -static Vector2 globalAppScreenSize = (Vector2){0, 0}; -static unsigned globalDesiredFlags = 0; -static HWND globalHwnd = NULL; -static HDC globalHdc = NULL; -static HGLRC globalGlContext = NULL; -static LARGE_INTEGER globalTimerFrequency; -static bool globalCursorEnabled = true; +//---------------------------------------------------------------------------------- +// Module Internal Functions Declaration +//---------------------------------------------------------------------------------- +int InitPlatform(void); // Initialize platform (graphics, inputs and more) +void ClosePlatform(void); // Close platform -static void HandleKey(WPARAM wparam, LPARAM lparam, char state) -{ - KeyboardKey key = KeyFromWparam(wparam); - // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - /* BYTE scancode = lparam >> 16; */ - /* TRACELOG(LOG_INFO, "KEY key=%d vk=%lu scan=%u = %u", key, wparam, scancode, state); */ - if (key != KEY_NULL) - { - /* TRACELOG(LOG_INFO, "KEY[%d] = %d (old=%d)\n", key, state, CORE.Input.Keyboard.currentKeyState[key]); */ - CORE.Input.Keyboard.currentKeyState[key] = state; - if (key == KEY_ESCAPE && state == 1) - { - CORE.Window.shouldClose = 1; - } - } - else - { - TRACELOG(LOG_WARNING, "unknown (or currently unhandled) virtual keycode %d (0x%x)", wparam, wparam); - } +// Win32 process messages management function +static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); - // TODO: add it to the queue as well? -} -static void HandleMouseButton(int button, char state) -{ - CORE.Input.Mouse.currentButtonState[button] = state; - CORE.Input.Touch.currentTouchState[button] = state; -} +// Win32: Handle inputs functions +static void HandleKey(WPARAM wparam, LPARAM lparam, char state); +static void HandleMouseButton(int button, char state); +static void HandleRawInput(LPARAM lparam); +static void HandleWindowResize(HWND hwnd, int *width, int *height); -static void HandleRawInput(LPARAM lparam) -{ - RAWINPUT input; +static void UpdateWindowStyle(HWND hwnd, unsigned desiredFlags); +static unsigned SanitizeFlags(SanitizeFlagsKind kind, unsigned flags); +static void UpdateFlags(HWND hwnd, unsigned desiredFlags, int width, int height); // Update window flags - { - UINT inputSize = sizeof(input); - UINT size = GetRawInputData((HRAWINPUT)lparam, RID_INPUT, &input, &inputSize, sizeof(RAWINPUTHEADER)); - if (size == (UINT)-1) { - LogFail("GetRawInputData", GetLastError()); - abort(); - } - if (size != inputSize) abort(); // bug? - } +//---------------------------------------------------------------------------------- +// Module Functions Declaration +//---------------------------------------------------------------------------------- +// NOTE: Functions declaration is provided by raylib.h - if (input.header.dwType != RIM_TYPEMOUSE) - { - TRACELOG(LOG_ERROR, "Unexpected WM_INPUT type %lu", input.header.dwType); - abort(); - } - - if (input.data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) - { - TRACELOG(LOG_ERROR, "TODO: handle absolute mouse inputs!"); - abort(); - } - - if (input.data.mouse.usFlags & MOUSE_VIRTUAL_DESKTOP) - { - TRACELOG(LOG_ERROR, "TODO: handle virtual desktop mouse inputs!"); - abort(); - } - - // bit of a trick, we keep the mouse position at 0,0 and instead move - // the previous position so we can still get a proper mouse delta - CORE.Input.Mouse.previousPosition.x -= input.data.mouse.lLastX; - CORE.Input.Mouse.previousPosition.y -= input.data.mouse.lLastY; - if (CORE.Input.Mouse.currentPosition.x != 0) abort(); - if (CORE.Input.Mouse.currentPosition.y != 0) abort(); -} - -static void HandleWindowResize(HWND hwnd, Vector2 *appScreenSizeRef) -{ - if (CORE.Window.flags & FLAG_WINDOW_MINIMIZED) - return; - - SIZE clientSize = GetClientSize(hwnd); - - // TODO: not sure if this function is doing what we need, leaving this disabled - // call to workaround unused function error - if (0) SetupFramebuffer(0, 0); - - TRACELOG(LOG_DEBUG, "NewClientSize %lux%lu", clientSize.cx, clientSize.cy); - /* CORE.Window.currentFbo.width = clientSize.cx; */ - /* CORE.Window.currentFbo.height = clientSize.cy; */ - /* glViewport(0, 0, clientSize.cx, clientSize.cy); */ - SetupViewport(clientSize.cx, clientSize.cy); - CORE.Window.resizedLastFrame = true; - float dpiScale = ScaleFromDpi(GetWindowDpi(hwnd)); - bool highdpi = !!(CORE.Window.flags & FLAG_WINDOW_HIGHDPI); - Vector2 screenSize = (Vector2){ - PtFromPx(dpiScale, highdpi, clientSize.cx), - PtFromPx(dpiScale, highdpi, clientSize.cy), - }; - CORE.Window.screen.width = roundf(screenSize.x); - CORE.Window.screen.height = roundf(screenSize.y); - if (AdoptWindowResize(CORE.Window.flags)) - { - TRACELOG( - LOG_DEBUG, - "updating app size to %fx%f from window resize", - screenSize.x, screenSize.y - ); - *appScreenSizeRef = screenSize; - } - - CORE.Window.screenScale = MatrixScale( - (float)CORE.Window.render.width/CORE.Window.screen.width, - (float)CORE.Window.render.height/CORE.Window.screen.height, - 1.0f - ); -} - -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); - 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)", - previous, - current, - previous ^ current, - GetLastError() - ); - abort(); - } - - CheckFlags("UpdateWindowStyle", hwnd, desiredFlags, desired, STYLE_MASK_WRITABLE); - } - } - - Mized currentMized = MizedFromStyle(MakeWindowStyle(CORE.Window.flags)); - Mized desiredMized = MizedFromStyle(MakeWindowStyle(desiredFlags)); - if (currentMized != desiredMized) - { - switch (desiredMized) - { - case MIZED_NONE: ShowWindow(hwnd, SW_RESTORE); break; - case MIZED_MIN: ShowWindow(hwnd, SW_MINIMIZE); break; - case MIZED_MAX: ShowWindow(hwnd, SW_MAXIMIZE); break; - } - } -} - -typedef enum { - SANITIZE_FLAGS_FIRST, - SANITIZE_FLAGS_NORMAL, -} SanitizeFlagsKind; - -static unsigned SanitizeFlags(SanitizeFlagsKind kind, unsigned flags) -{ - if ((flags & FLAG_WINDOW_MAXIMIZED) && (flags & FLAG_BORDERLESS_WINDOWED_MODE)) - { - TRACELOG(LOG_INFO, "borderless windows mode is overriding maximized"); - flags &= ~FLAG_WINDOW_MAXIMIZED; - } - - switch (kind) - { - 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; - } - - return flags; -} - -#define FLAG_MASK_OPTIONAL (FLAG_VSYNC_HINT) -#define FLAG_MASK_REQUIRED ~(FLAG_MASK_OPTIONAL) - -// flags that have no operations to perform during an update -#define FLAG_MASK_NO_UPDATE (FLAG_WINDOW_HIGHDPI | FLAG_MSAA_4X_HINT) - - -// All window state changes from raylib flags go through this function. It performs -// whatever operations are needed to update the window state to match the desired flags. -// In most cases this function should not update CORE.Window.flags directly, instead, -// the window itself should update CORE.Window.flags in response to actual state changes. -// This means that CORE.Window.flags should always represent the actual state of the -// window. This function will continue to perform these update operations so long as -// the state continues to change. -// -// This design takes care of many odd corner cases. For example, if you want to restore -// a window that was previously maximized AND minimized and you want to remove both these -// flags, you actually need to call ShowWindow with SW_RESTORE twice. Another example is -// if you have a maximized window, if the undecorated flag is modified then we'd need to -// update the window style, but updating the style would mean the window size would change -// causing the window to lose its Maximized state which would mean we'd need to update the -// window size and then update the window style a second time to restore that maximized -// state. This implementation is able to handle any/all of these special situations with a -// retry loop that continues until we either reach the desired state or the state stops -// changing. -static void UpdateFlags(HWND hwnd, unsigned desiredFlags, Vector2 appScreenSize) -{ - // flags that just apply immediately without needing any operations - CORE.Window.flags |= (desiredFlags & FLAG_MASK_NO_UPDATE); - - { - int vsync = (CORE.Window.flags & FLAG_VSYNC_HINT)? 1 : 0; - PFNWGLSWAPINTERVALEXTPROC f = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT"); - if (f) - { - (*f)(vsync); - if (vsync) - { - CORE.Window.flags |= FLAG_VSYNC_HINT; - } - else - { - CORE.Window.flags &= ~FLAG_VSYNC_HINT; - } - } - } - - DWORD previousStyle; - for (unsigned attempt = 1; ; attempt++) - { - CheckFlags("UpdateFlags", hwnd, CORE.Window.flags, MakeWindowStyle(CORE.Window.flags), STYLE_MASK_ALL); - - bool windowSizeUpdated = false; - if (MakeWindowStyle(CORE.Window.flags) == MakeWindowStyle(desiredFlags)) - { - windowSizeUpdated = UpdateWindowSize(UPDATE_WINDOW_NORMAL, hwnd, appScreenSize, desiredFlags); - if ((FLAG_MASK_REQUIRED & desiredFlags) == (FLAG_MASK_REQUIRED & CORE.Window.flags)) - break; - } - - if ( - (attempt > 1) && - (previousStyle == MakeWindowStyle(CORE.Window.flags)) && - !windowSizeUpdated - ) { - TRACELOG( - LOG_ERROR, - // TODO: print more information - "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 - ); - abort(); - } - - previousStyle = MakeWindowStyle(CORE.Window.flags); - UpdateWindowStyle(hwnd, desiredFlags); - } -} +//---------------------------------------------------------------------------------- +// Module Functions Definition: Window and Graphics Device +//---------------------------------------------------------------------------------- +// Check if application should close bool WindowShouldClose(void) { return CORE.Window.shouldClose; } +// Toggle fullscreen mode void ToggleFullscreen(void) { TRACELOG(LOG_WARNING, "ToggleFullscreen not implemented"); - assert(0); // crash debug builds only } +// Toggle borderless windowed mode void ToggleBorderlessWindowed(void) { if (CORE.Window.flags & FLAG_BORDERLESS_WINDOWED_MODE) @@ -1188,11 +831,13 @@ void ToggleBorderlessWindowed(void) } } +// Set window state: maximized, if resizable void MaximizeWindow(void) { SetWindowState(FLAG_WINDOW_MAXIMIZED); } +// Set window state: minimized void MinimizeWindow(void) { SetWindowState(FLAG_WINDOW_MINIMIZED); @@ -1215,62 +860,57 @@ void RestoreWindow(void) // Set window configuration state using flags void SetWindowState(unsigned int flags) { - globalDesiredFlags = SanitizeFlags(SANITIZE_FLAGS_NORMAL, CORE.Window.flags | flags); - UpdateFlags(globalHwnd, globalDesiredFlags, globalAppScreenSize); + platform.desiredFlags = SanitizeFlags(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) { - globalDesiredFlags = SanitizeFlags(SANITIZE_FLAGS_NORMAL, CORE.Window.flags & ~flags); - UpdateFlags(globalHwnd, globalDesiredFlags, globalAppScreenSize); + platform.desiredFlags = SanitizeFlags(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"); - assert(0); // crash debug builds only } // Set icon for window void SetWindowIcons(Image *images, int count) { TRACELOG(LOG_WARNING, "SetWindowIcons not implemented"); - assert(0); // crash debug builds only } void SetWindowTitle(const char *title) { CORE.Window.title = title; - WCHAR *titlew; - A_TO_W_ALLOCA(titlew, CORE.Window.title); - if (!SetWindowTextW(globalHwnd, titlew)) - { - LogFail("SetWindowText", GetLastError()); - abort(); - } + + WCHAR *titleWide = NULL; + 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()); } // Set window position on screen (windowed mode) void SetWindowPosition(int x, int y) { TRACELOG(LOG_WARNING, "SetWindowPosition not implemented"); - assert(0); // crash debug builds only } // Set monitor for the current window void SetWindowMonitor(int monitor) { TRACELOG(LOG_WARNING, "SetWindowMonitor not implemented"); - assert(0); // crash debug builds only } // Set window minimum dimensions (FLAG_WINDOW_RESIZABLE) void SetWindowMinSize(int width, int height) { TRACELOG(LOG_WARNING, "SetWindowMinSize not implemented"); - assert(0); // crash debug builds only + CORE.Window.screenMin.width = width; CORE.Window.screenMin.height = height; } @@ -1279,7 +919,7 @@ void SetWindowMinSize(int width, int height) void SetWindowMaxSize(int width, int height) { TRACELOG(LOG_WARNING, "SetWindowMaxSize not implemented"); - assert(0); // crash debug builds only + CORE.Window.screenMax.width = width; CORE.Window.screenMax.height = height; } @@ -1288,36 +928,32 @@ void SetWindowMaxSize(int width, int height) void SetWindowSize(int width, int height) { TRACELOG(LOG_WARNING, "SetWindowSize not implemented"); - assert(0); // crash debug builds only } // Set window opacity, value opacity is between 0.0 and 1.0 void SetWindowOpacity(float opacity) { TRACELOG(LOG_WARNING, "SetWindowOpacity not implemented"); - assert(0); // crash debug builds only } +// Set window focused void SetWindowFocused(void) { TRACELOG(LOG_WARNING, "SetWindowFocused not implemented"); - assert(0); // crash debug builds only } // Get native window handle void *GetWindowHandle(void) { - return globalHwnd; + return platform.hwnd; } int GetMonitorCount(void) { int count = 0; - if (!EnumDisplayMonitors(NULL, NULL, CountMonitorsProc, (LPARAM)&count)) - { - LogFail("EnumDisplayMonitors", GetLastError()); - abort(); - } + + int result = EnumDisplayMonitors(NULL, NULL, CountMonitorsProc, (LPARAM)&count); + if (result == 0) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "EnumDisplayMonitors", GetLastError()); return count; } @@ -1325,22 +961,16 @@ int GetMonitorCount(void) // Get current monitor where window is placed int GetCurrentMonitor(void) { - HMONITOR monitor = MonitorFromWindow(globalHwnd, MONITOR_DEFAULTTOPRIMARY); - if (!monitor) - { - LogFail("MonitorFromWindow", GetLastError()); - abort(); - } + 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; - if (!EnumDisplayMonitors(NULL, NULL, FindMonitorProc, (LPARAM)&context)) - { - LogFail("EnumDisplayMonitors", GetLastError()); - abort(); - } + + int result = EnumDisplayMonitors(NULL, NULL, FindMonitorProc, (LPARAM)&context); + if (result == 0) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "EnumDisplayMonitors", GetLastError()); return context.matchIndex; } @@ -1349,7 +979,6 @@ int GetCurrentMonitor(void) Vector2 GetMonitorPosition(int monitor) { TRACELOG(LOG_WARNING, "GetMonitorPosition not implemented"); - assert(0); // crash debug builds only return (Vector2){ 0, 0 }; } @@ -1357,7 +986,6 @@ Vector2 GetMonitorPosition(int monitor) int GetMonitorWidth(int monitor) { TRACELOG(LOG_WARNING, "GetMonitorWidth not implemented"); - assert(0); // crash debug builds only return 0; } @@ -1365,7 +993,6 @@ int GetMonitorWidth(int monitor) int GetMonitorHeight(int monitor) { TRACELOG(LOG_WARNING, "GetMonitorHeight not implemented"); - assert(0); // crash debug builds only return 0; } @@ -1373,7 +1000,6 @@ int GetMonitorHeight(int monitor) int GetMonitorPhysicalWidth(int monitor) { TRACELOG(LOG_WARNING, "GetMonitorPhysicalWidth not implemented"); - assert(0); // crash debug builds only return 0; } @@ -1381,7 +1007,6 @@ int GetMonitorPhysicalWidth(int monitor) int GetMonitorPhysicalHeight(int monitor) { TRACELOG(LOG_WARNING, "GetMonitorPhysicalHeight not implemented"); - assert(0); // crash debug builds only return 0; } @@ -1389,7 +1014,6 @@ int GetMonitorPhysicalHeight(int monitor) int GetMonitorRefreshRate(int monitor) { TRACELOG(LOG_WARNING, "GetMonitorRefreshRate not implemented"); - assert(0); // crash debug builds only return 0; } @@ -1397,7 +1021,6 @@ int GetMonitorRefreshRate(int monitor) const char *GetMonitorName(int monitor) { TRACELOG(LOG_WARNING, "GetMonitorName not implemented"); - assert(0); // crash debug builds only return 0; } @@ -1405,35 +1028,36 @@ const char *GetMonitorName(int monitor) Vector2 GetWindowPosition(void) { TRACELOG(LOG_WARNING, "GetWindowPosition not implemented"); - assert(0); // crash debug builds only return (Vector2){ 0, 0 }; } // Get window scale DPI factor for current monitor Vector2 GetWindowScaleDPI(void) { - float scale = ScaleFromDpi(GetWindowDpi(globalHwnd)); + float scale = ((float)GetDpiForWindow(platform.hwnd))/96.0f; return (Vector2){ scale, scale }; } +// Set clipboard text content void SetClipboardText(const char *text) { TRACELOG(LOG_WARNING, "SetClipboardText not implemented"); - assert(0); // crash debug builds only } +// Get clipboard text content const char *GetClipboardText(void) { TRACELOG(LOG_WARNING, "GetClipboardText not implemented"); - assert(0); // crash debug builds only return NULL; } +// Get clipboard image Image GetClipboardImage(void) { - TRACELOG(LOG_WARNING, "GetClipboardText not implemented"); - assert(0); // crash debug builds only Image image = { 0 }; + + TRACELOG(LOG_WARNING, "GetClipboardText not implemented"); + return image; } @@ -1448,7 +1072,7 @@ void ShowCursor(void) 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. + // to only hide the cursor while it's inside the client area CORE.Input.Mouse.cursorHidden = true; SetCursor(NULL); } @@ -1456,32 +1080,21 @@ void HideCursor(void) // Enables cursor (unlock cursor) void EnableCursor(void) { - if (globalCursorEnabled) - { - TRACELOG(LOG_INFO, "EnableCursor: already enabled"); - } + if (platform.cursorEnabled) TRACELOG(LOG_INFO, "EnableCursor: already enabled"); else { - if (!ClipCursor(NULL)) - { - LogFail("ClipCursor", GetLastError()); - abort(); - } + if (!ClipCursor(NULL)) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "ClipCursor", GetLastError()); - { - RAWINPUTDEVICE rid; - rid.usUsagePage = 0x01; // HID_USAGE_PAGE_GENERIC - rid.usUsage = 0x02; // HID_USAGE_GENERIC_MOUSE - rid.dwFlags = RIDEV_REMOVE; // Add to this window even in background - rid.hwndTarget = NULL; - if (!RegisterRawInputDevices(&rid, 1, sizeof(rid))) { - LogFail("RegisterRawInputDevices", GetLastError()); - abort(); - } - } + RAWINPUTDEVICE rid = { 0 }; + rid.usUsagePage = 0x01; // HID_USAGE_PAGE_GENERIC + rid.usUsage = 0x02; // HID_USAGE_GENERIC_MOUSE + 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()); ShowCursor(); - globalCursorEnabled = true; + platform.cursorEnabled = true; TRACELOG(LOG_INFO, "EnableCursor: enabled"); } } @@ -1489,95 +1102,67 @@ void EnableCursor(void) // Disables cursor (lock cursor) void DisableCursor(void) { - if (globalCursorEnabled) + if (platform.cursorEnabled) { + RAWINPUTDEVICE rid = { 0 }; + rid.usUsagePage = 0x01; // HID_USAGE_PAGE_GENERIC + rid.usUsage = 0x02; // HID_USAGE_GENERIC_MOUSE + 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()); - { - RAWINPUTDEVICE rid; - rid.usUsagePage = 0x01; // HID_USAGE_PAGE_GENERIC - rid.usUsage = 0x02; // HID_USAGE_GENERIC_MOUSE - rid.dwFlags = RIDEV_INPUTSINK; // Add to this window even in background - rid.hwndTarget = globalHwnd; - if (!RegisterRawInputDevices(&rid, 1, sizeof(rid))) { - LogFail("RegisterRawInputDevices", GetLastError()); - abort(); - } - } - - RECT clientRect; - if (!GetClientRect(globalHwnd, &clientRect)) - { - LogFail("GetClientRect", GetLastError()); - abort(); - } + RECT clientRect = { 0 }; + if (!GetClientRect(platform.hwnd, &clientRect)) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "GetClientRect", GetLastError()); POINT topleft = { clientRect.left, clientRect.top }; - if (!ClientToScreen(globalHwnd, &topleft)) - { - LogFail("ClientToScreen", GetLastError()); - abort(); - } + if (!ClientToScreen(platform.hwnd, &topleft)) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "ClientToScreen", 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)", - clientRect.left, - clientRect.top, - clientRect.right, - clientRect.bottom, - topleft.x, - topleft.y - ); + 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)) - { - LogFail("ClipCursor", GetLastError()); - abort(); - } + if (!ClipCursor(&clipRect)) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "ClipCursor", GetLastError()); CORE.Input.Mouse.previousPosition = (Vector2){ 0, 0 }; CORE.Input.Mouse.currentPosition = (Vector2){ 0, 0 }; HideCursor(); - globalCursorEnabled = false; + platform.cursorEnabled = false; TRACELOG(LOG_INFO, "DisableCursor: disabled"); } - else - { - TRACELOG(LOG_INFO, "DisableCursor: already disabled"); - } + else TRACELOG(LOG_INFO, "DisableCursor: already disabled"); } +// Swap back buffer with front buffer (screen drawing) void SwapScreenBuffer(void) { - if (!globalHdc) abort(); - if (!SwapBuffers(globalHdc)) - { - LogFail("SwapBuffers", GetLastError()); - abort(); - } - - if (!ValidateRect(globalHwnd, NULL)) - { - LogFail("ValidateRect", GetLastError()); - abort(); - } + if (!platform.hdc) abort(); + 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()); } +//---------------------------------------------------------------------------------- +// Module Functions Definition: Misc +//---------------------------------------------------------------------------------- + +// Get elapsed time measure in seconds double GetTime(void) { LARGE_INTEGER now; QueryPerformanceCounter(&now); - return (double)(now.QuadPart - CORE.Time.base)/(double)globalTimerFrequency.QuadPart; + return (double)(now.QuadPart - CORE.Time.base)/(double)platform.timerFrequency.QuadPart; } // Open URL with default system browser (if available) -// NOTE: This function is only safe to use if you control the URL given. -// A user could craft a malicious string performing another action. -// Only call this function yourself not with user input or make sure to check the string yourself. +// NOTE: This function is only safe to use if you control the URL given +// A user could craft a malicious string performing another action +// Only call this function yourself not with user input or make sure to check the string yourself // Ref: https://github.com/raysan5/raylib/issues/686 void OpenURL(const char *url) { @@ -1586,7 +1171,6 @@ void OpenURL(const char *url) else { TRACELOG(LOG_WARNING, "OpenURL not implemented"); - assert(0); // crash debug builds only } } @@ -1594,53 +1178,47 @@ void OpenURL(const char *url) // Module Functions Definition: Inputs //---------------------------------------------------------------------------------- +// Set internal gamepad mappings int SetGamepadMappings(const char *mappings) { TRACELOG(LOG_WARNING, "SetGamepadMappings not implemented"); - assert(0); // crash debug builds only + return -1; } +// Set gamepad vibration void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float duration) { TRACELOG(LOG_WARNING, "SetGamepadVibration not implemented"); - assert(0); // crash debug builds only } +// Set mouse position XY void SetMousePosition(int x, int y) { - if (globalCursorEnabled) + if (platform.cursorEnabled) { CORE.Input.Mouse.currentPosition = (Vector2){ (float)x, (float)y }; CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition; TRACELOG(LOG_WARNING, "SetMousePosition not implemented"); - assert(0); // crash debug builds only - } - else - { - TRACELOG(LOG_ERROR, "Possible? Should we allow this?"); - abort(); } + else TRACELOG(LOG_WARNING, "INPUT: MOUSE: Cursor not enabled"); } +// Set mouse cursor 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()); - abort(); - } + if (!hcursor) TRACELOG(LOG_ERROR, "LoadCursor %d (win32 %d) failed, error=%lu", cursor, (size_t)cursorName, GetLastError()); SetCursor(hcursor); CORE.Input.Mouse.cursorHidden = false; } +// Get physical key name const char *GetKeyName(int key) { TRACELOG(LOG_WARNING, "GetKeyName not implemented"); - assert(0); // crash debug builds only return NULL; } @@ -1666,11 +1244,7 @@ void PollInputEvents(void) // so, if mouse is not moved it returns a (0, 0) position... this behaviour should be reviewed! //for (int i = 0; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.position[i] = (Vector2){ 0, 0 }; - memcpy( - CORE.Input.Keyboard.previousKeyState, - CORE.Input.Keyboard.currentKeyState, - sizeof(CORE.Input.Keyboard.previousKeyState) - ); + memcpy(CORE.Input.Keyboard.previousKeyState, CORE.Input.Keyboard.currentKeyState, sizeof(CORE.Input.Keyboard.previousKeyState)); memset(CORE.Input.Keyboard.keyRepeatInFrame, 0, sizeof(CORE.Input.Keyboard.keyRepeatInFrame)); // Register previous mouse wheel state @@ -1680,11 +1254,11 @@ void PollInputEvents(void) // Register previous mouse position CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition; - MSG msg; + // Process windows messages + MSG msg = { 0 }; while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) { - if (msg.message == WM_PAINT) - return; + if (msg.message == WM_PAINT) return; TranslateMessage(&msg); DispatchMessageW(&msg); } @@ -1694,457 +1268,197 @@ void PollInputEvents(void) // Module Internal Functions Definition //---------------------------------------------------------------------------------- -#define WM_APP_UPDATE_WINDOW_SIZE (WM_APP + 1) - -static LRESULT WndProc2(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, FlagsOp *deferredFlags) +// Initialize modern OpenGL context +// NOTE: We need to create a dummy context first to query requried extensions +HGLRC InitOpenGL(HWND hwnd, HDC hdc) { - switch (msg) + // First, create a dummy context to get WGL extensions + PIXELFORMATDESCRIPTOR pixelFormatDesc = { + .nSize = sizeof(PIXELFORMATDESCRIPTOR), + .nVersion = 1, + .dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, + .iPixelType = PFD_TYPE_RGBA, + .cColorBits = 32, + .cAlphaBits = 8, + .cDepthBits = 24, + .iLayerType = PFD_MAIN_PLANE + }; + + int pixelFormat = ChoosePixelFormat(hdc, &pixelFormatDesc); + SetPixelFormat(hdc, pixelFormat, &pixelFormatDesc); + //int pixelFormat = ChoosePixelFormat(platform.hdc, &pixelFormatDesc); + //if (!pixelFormat) { TRACELOG(LOG_ERROR, "%s failed, error=%lu", "ChoosePixelFormat", GetLastError()); return -1; } + //if (!SetPixelFormat(platform.hdc, pixelFormat, &pixelFormatDesc)) { TRACELOG(LOG_ERROR, "%s failed, error=%lu", "SetPixelFormat", GetLastError()); return -1; } + + HGLRC tempContext = wglCreateContext(hdc); + //if (!tempContext) { TRACELOG(LOG_ERROR, "%s failed, error=%lu", "wglCreateContext", GetLastError()); return -1; } + BOOL result = wglMakeCurrent(hdc, tempContext); + //if (!result) { TRACELOG(LOG_ERROR, "%s failed, error=%lu", "wglMakeCurrent", GetLastError()); return -1; } + + // Load WGL extension entry points + wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB"); + wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB"); + wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT"); + + // Setup modern pixel format if extension is available + if (wglChoosePixelFormatARB) { - case WM_CREATE: + int pixelFormatAttribs[] = { + WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB, + WGL_DRAW_TO_WINDOW_ARB, GL_TRUE, + WGL_SUPPORT_OPENGL_ARB, GL_TRUE, + WGL_DOUBLE_BUFFER_ARB, GL_TRUE, + WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB, + WGL_COLOR_BITS_ARB, 32, + //WGL_RED_BITS_ARB, 8, + //WGL_GREEN_BITS_ARB, 8, + //WGL_BLUE_BITS_ARB, 8, + //WGL_ALPHA_BITS_ARB, 8, + WGL_DEPTH_BITS_ARB, 24, + WGL_STENCIL_BITS_ARB, 8, + 0 // Terminator + }; + + int format = 0; + UINT numFormats = 0; + if (wglChoosePixelFormatARB(hdc, pixelFormatAttribs, NULL, 1, &format, &numFormats) && (numFormats > 0)) { - globalHdc = GetDC(hwnd); - if (!globalHdc) - { - LogFail("GetDC", GetLastError()); - return -1; - } - - if (CORE.Window.flags & FLAG_MSAA_4X_HINT) - { - TRACELOG(LOG_ERROR, "TODO: implement FLAG_MSAA_4X_HINT"); - assert(0); - } - - PIXELFORMATDESCRIPTOR pixelFormatDesc = {0}; - pixelFormatDesc.nSize = sizeof(PIXELFORMATDESCRIPTOR); - pixelFormatDesc.nVersion = 1; - pixelFormatDesc.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL; - pixelFormatDesc.iPixelType = PFD_TYPE_RGBA; - pixelFormatDesc.cColorBits = 32; - pixelFormatDesc.cAlphaBits = 8; - pixelFormatDesc.cDepthBits = 24; - - int pixelFormat = ChoosePixelFormat(globalHdc, &pixelFormatDesc); - if (!pixelFormat) - { - LogFail("ChoosePixelFormat", GetLastError()); - return -1; - } - - if (!SetPixelFormat(globalHdc, pixelFormat, &pixelFormatDesc)) - { - LogFail("SetPixelFormat", GetLastError()); - return -1; - } - - globalGlContext = wglCreateContext(globalHdc); - if (!globalGlContext) - { - LogFail("wglCreateContext", GetLastError()); - return -1; - } - - if (!wglMakeCurrent(globalHdc, globalGlContext)) - { - LogFail("wglMakeCurrent", GetLastError()); - return -1; - } - - rlLoadExtensions(WglGetProcAddress); - - globalHwnd = hwnd; - - } return 0; - case WM_DESTROY: - wglMakeCurrent(globalHdc, NULL); - if (globalGlContext) - { - if (!wglDeleteContext(globalGlContext)) abort(); - globalGlContext = NULL; - } - - if (globalHdc) - { - if (!ReleaseDC(hwnd, globalHdc)) abort(); - globalHdc = NULL; - } - - return 0; - case WM_CLOSE: - CORE.Window.shouldClose = true; - return 0; - case WM_KILLFOCUS: - memset(CORE.Input.Keyboard.previousKeyState, 0, sizeof(CORE.Input.Keyboard.previousKeyState)); - memset(CORE.Input.Keyboard.currentKeyState, 0, sizeof(CORE.Input.Keyboard.currentKeyState)); - return 0; - case WM_SIZING: - if (CORE.Window.flags & FLAG_WINDOW_RESIZABLE) { - // TODO: enforce min/max size - TRACELOG(LOG_WARNING, "TODO: enforce min/max size!"); - } else { - TRACELOG(LOG_WARNING, "non-resizable window is being resized"); - // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - abort(); // TODO - } - return TRUE; - case WM_STYLECHANGING: - if (wparam == GWL_STYLE) - { - STYLESTRUCT *ss = (STYLESTRUCT*)lparam; - GetStyleChangeFlagOps(CORE.Window.flags, ss, deferredFlags); - - UINT dpi = GetWindowDpi(hwnd); - SIZE clientSize = GetClientSize(hwnd); - 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 - ); - 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"); - deferredFlags->clear |= FLAG_WINDOW_MAXIMIZED; - } - } - } - return 0; - 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; - } - - Mized mized = MIZED_NONE; - if (IsMinimized2(hwnd)) - { - mized = MIZED_MIN; - } - else - { - WINDOWPLACEMENT placement; - placement.length = sizeof(placement); - if (!GetWindowPlacement(hwnd, &placement)) - { - LogFail("GetWindowPlacement", GetLastError()); - abort(); - } - - if (placement.showCmd == SW_SHOWMAXIMIZED) { - mized = MIZED_MAX; - } - } - - // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - /* TRACELOG(LOG_INFO, "window pos=%d,%d size=%dx%d", pos->x, pos->y, pos->cx, pos->cy); */ - - switch (mized) - { - case MIZED_NONE: - { - deferredFlags->clear |= ( - FLAG_WINDOW_MINIMIZED | - FLAG_WINDOW_MAXIMIZED - ); - HMONITOR monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY); - MONITORINFO info; - info.cbSize = sizeof(info); - if (!GetMonitorInfoW(monitor, &info)) - { - LogFail("GetMonitorInfo", GetLastError()); - abort(); - } - - 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; - } - - } break; - case MIZED_MIN: - // !!! NOTE !!! Do not update the maximized/borderless - // flags because when hwnd is minimized it temporarily overrides - // the maximized state/flag which gets restored on SW_RESTORE - deferredFlags->set |= FLAG_WINDOW_MINIMIZED; - break; - case MIZED_MAX: - deferredFlags->clear |= FLAG_WINDOW_MINIMIZED; - deferredFlags->set |= FLAG_WINDOW_MAXIMIZED; - break; - } - - return 0; + PIXELFORMATDESCRIPTOR newPixelFormatDescriptor = { 0 }; + DescribePixelFormat(hdc, format, sizeof(newPixelFormatDescriptor), &newPixelFormatDescriptor); + SetPixelFormat(hdc, format, &newPixelFormatDescriptor); } - case WM_SIZE: - // don't trust the docs, they say you won't get this message if you don't call DefWindowProc - // in response to WM_WINDOWPOSCHANGED but looks like when a window is created you'll get this - // message without getting WM_WINDOWPOSCHANGED. - HandleWindowResize(hwnd, &globalAppScreenSize); - return 0; - case WM_WINDOWPOSCHANGED: { - WINDOWPOS *pos = (WINDOWPOS*)lparam; - if (!(pos->flags & SWP_NOSIZE)) - { - HandleWindowResize(hwnd, &globalAppScreenSize); - } - - return 0; - } - case WM_GETDPISCALEDSIZE: - { - SIZE *inoutSize = (SIZE*)lparam; - UINT newDpi = wparam; - - // for any of these other cases, we might want to post a window - // resize event after the dpi changes? - if (CORE.Window.flags & FLAG_WINDOW_MINIMIZED) return TRUE; - if (CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) return TRUE; - if (CORE.Window.flags & FLAG_BORDERLESS_WINDOWED_MODE) return TRUE; - - float dpiScale = ScaleFromDpi(newDpi); - bool dpiScaling = CORE.Window.flags & FLAG_WINDOW_HIGHDPI; - SIZE desired = PxFromPt2(dpiScale, dpiScaling, globalAppScreenSize); - inoutSize->cx = desired.cx; - inoutSize->cy = desired.cy; - } return TRUE; - case WM_DPICHANGED: - { - 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 - )) { - LogFail("SetWindowPos", GetLastError()); - abort(); - } - - } return 0; - case WM_SETCURSOR: - if (LOWORD(lparam) == HTCLIENT) - { - SetCursor(CORE.Input.Mouse.cursorHidden? NULL : LoadCursorW(NULL, (LPCWSTR)IDC_ARROW)); - return 0; - } - - return DefWindowProc(hwnd, msg, wparam, lparam); - case WM_INPUT: - if (globalCursorEnabled) - { - TRACELOG(LOG_ERROR, "Unexpected raw mouse input"); // impossible right? - abort(); - } - - HandleRawInput(lparam); - return 0; - case WM_MOUSEMOVE: - if (globalCursorEnabled) - { - CORE.Input.Mouse.currentPosition.x = (float)GET_X_LPARAM(lparam); - CORE.Input.Mouse.currentPosition.y = (float)GET_Y_LPARAM(lparam); - CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition; - } - - return 0; - case WM_KEYDOWN: HandleKey(wparam, lparam, 1); return 0; - case WM_KEYUP: HandleKey(wparam, lparam, 0); return 0; - case WM_LBUTTONDOWN: HandleMouseButton(MOUSE_BUTTON_LEFT, 1); return 0; - case WM_LBUTTONUP : HandleMouseButton(MOUSE_BUTTON_LEFT, 0); return 0; - case WM_RBUTTONDOWN: HandleMouseButton(MOUSE_BUTTON_RIGHT, 1); return 0; - case WM_RBUTTONUP : HandleMouseButton(MOUSE_BUTTON_RIGHT, 0); return 0; - case WM_MBUTTONDOWN: HandleMouseButton(MOUSE_BUTTON_MIDDLE, 1); return 0; - case WM_MBUTTONUP : HandleMouseButton(MOUSE_BUTTON_MIDDLE, 0); return 0; - case WM_XBUTTONDOWN: switch (HIWORD(wparam)) - { - case XBUTTON1: HandleMouseButton(MOUSE_BUTTON_SIDE, 1); return 0; - case XBUTTON2: HandleMouseButton(MOUSE_BUTTON_EXTRA, 1); return 0; - default: - TRACELOG(LOG_WARNING, "TODO: handle ex mouse button DOWN wparam=%u", HIWORD(wparam)); - return 0; - } - case WM_XBUTTONUP: switch (HIWORD(wparam)) - { - case XBUTTON1: HandleMouseButton(MOUSE_BUTTON_SIDE, 0); return 0; - case XBUTTON2: HandleMouseButton(MOUSE_BUTTON_EXTRA, 0); return 0; - default: - TRACELOG(LOG_WARNING, "TODO: handle ex mouse button UP wparam=%u", HIWORD(wparam)); - return 0; - } - case WM_MOUSEWHEEL: - CORE.Input.Mouse.currentWheelMove.y = ((float)GET_WHEEL_DELTA_WPARAM(wparam))/WHEEL_DELTA; - return 0; - case WM_MOUSEHWHEEL: - CORE.Input.Mouse.currentWheelMove.x = ((float)GET_WHEEL_DELTA_WPARAM(wparam))/WHEEL_DELTA; - return 0; - case WM_APP_UPDATE_WINDOW_SIZE: - UpdateWindowSize(UPDATE_WINDOW_NORMAL, hwnd, globalAppScreenSize, CORE.Window.flags); - return 0; - default: - return DefWindowProcW(hwnd, msg, wparam, lparam); } + + // Create real modern OpenGL context (3.3 core) + HGLRC realContext = NULL; + if (wglCreateContextAttribsARB) + { + 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_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB | WGL_CONTEXT_DEBUG_BIT_ARB [glDebugMessageCallback()] + 0 // Terminator + }; + + // NOTE: We are not sharing context resources so, second parameters is NULL + realContext = wglCreateContextAttribsARB(hdc, NULL, contextAttribs); + + // Check for error context creation errors + // ERROR_INVALID_VERSION_ARB (0x2095) + // ERROR_INVALID_PROFILE_ARB (0x2096) + if (realContext == NULL) TRACELOG(LOG_ERROR, "GL: Error creating requested context: %lu", GetLastError()); + } + + // Cleanup dummy temp context + wglMakeCurrent(NULL, NULL); + wglDeleteContext(tempContext); + + // Activate real context + if (realContext) wglMakeCurrent(hdc, realContext); + + // Once we got a real modern OpenGL context, + // we can load required extensions (function pointers) + rlLoadExtensions(WglGetProcAddress); + + return realContext; } -static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) -{ - // sanity check, should we remove this? - DWORD mask = STYLE_MASK_ALL; - if (globalHwnd == hwnd) - { - if (msg == WM_WINDOWPOSCHANGING) { - mask &= ~(WS_MINIMIZE | WS_MAXIMIZE); - } - CheckFlags("WndProc", hwnd, CORE.Window.flags, MakeWindowStyle(CORE.Window.flags), mask); - } - - FlagsOp flagsOp; - flagsOp.set = 0; - flagsOp.clear = 0; - LRESULT result = WndProc2(hwnd, msg, wparam, lparam, &flagsOp); - - // sanity check, should we remove this? - if (globalHwnd == 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); - abort(); - } - - { - 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 - ); - } - } - - return result; -} - - +// Initialize platform: graphics, inputs and more int InitPlatform(void) { - globalDesiredFlags = SanitizeFlags(SANITIZE_FLAGS_FIRST, CORE.Window.flags); - // from this point CORE.Window.flags should always reflect the actual state of the window - CORE.Window.flags = FLAG_WINDOW_HIDDEN | (globalDesiredFlags & FLAG_MASK_NO_UPDATE); + platform.desiredFlags = SanitizeFlags(SANITIZE_FLAGS_FIRST, CORE.Window.flags); + platform.appScreenWidth = CORE.Window.screen.width; + platform.appScreenHeight = CORE.Window.screen.height; - globalAppScreenSize = (Vector2){ CORE.Window.screen.width, CORE.Window.screen.height }; + // 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); +/* + // TODO: Review SetProcessDpiAwarenessContext() + // NOTE: SetProcessDpiAwarenessContext() requires Windows 10, version 1703 and shcore.lib linkage if (IsWindows10Version1703OrGreaterWin32()) { TRACELOG(LOG_INFO, "DpiAware: >=Win10Creators"); - if (!SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2)) { - LogFail("SetProcessDpiAwarenessContext", GetLastError()); - abort(); - } + if (!SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2)) + TRACELOG(LOG_ERROR, "%s failed, error %u", "SetProcessDpiAwarenessContext", GetLastError()); } else { TRACELOG(LOG_INFO, "DpiAware: Use default value as 0 + platform.cursorEnabled = true; TRACELOG(LOG_INFO, "PLATFORM: DESKTOP: WIN32: Initialized successfully"); + return 0; } +// Close platform void ClosePlatform(void) { - if (globalHwnd) + if (platform.hwnd) { - if (0 == DestroyWindow(globalHwnd)) - { - LogFail("DestroyWindow", GetLastError()); - abort(); - } - - globalHwnd = NULL; + int result = DestroyWindow(platform.hwnd); + if (result == 0) TRACELOG(LOG_WARNING, "WIN32: Error on window destroy: %u", GetLastError()); + platform.hwnd = NULL; + } +} + +// Window procedure, message processing callback +// NOTE: All window event messages are processed here +static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + LRESULT result = 0; + + // Sanity check + DWORD mask = STYLE_MASK_ALL; + if (platform.hwnd == hwnd) + { + if (msg == WM_WINDOWPOSCHANGING) mask &= ~(WS_MINIMIZE | WS_MAXIMIZE); + CheckFlags("WndProc", hwnd, CORE.Window.flags, MakeWindowStyle(CORE.Window.flags), mask); + } + + FlagsOp flagsOp = { 0 }; + FlagsOp *deferredFlags = &flagsOp; + + // Message processing + //------------------------------------------------------------------------------------ + switch (msg) + { + case WM_CREATE: + { + // WARNING: Not recommended to do OpenGL intialization at this point + + } break; + //case WM_ACTIVATE + case WM_DESTROY: + { + // Clean up for window destruction + wglMakeCurrent(platform.hdc, NULL); + if (platform.glContext) + { + if (!wglDeleteContext(platform.glContext)) abort(); + platform.glContext = NULL; + } + + if (platform.hdc) + { + if (!ReleaseDC(hwnd, platform.hdc)) abort(); + platform.hdc = NULL; + } + + } break; + case WM_CLOSE: CORE.Window.shouldClose = true; break; // Window close button [x], ALT+F4 + //case WM_QUIT: // Application closing, not related to window + case WM_KILLFOCUS: + { + memset(CORE.Input.Keyboard.previousKeyState, 0, sizeof(CORE.Input.Keyboard.previousKeyState)); + memset(CORE.Input.Keyboard.currentKeyState, 0, sizeof(CORE.Input.Keyboard.currentKeyState)); + } break; + case WM_SIZING: + { + if (CORE.Window.flags & FLAG_WINDOW_RESIZABLE) + { + // TODO: Enforce min/max size + } + else TRACELOG(LOG_WARNING, "WINDOW: Trying to resize a non-resizable window"); + + result = TRUE; + } break; + case WM_STYLECHANGING: + { + if (wparam == GWL_STYLE) + { + STYLESTRUCT *ss = (STYLESTRUCT *)lparam; + GetStyleChangeFlagOps(CORE.Window.flags, ss, deferredFlags); + + UINT dpi = GetDpiForWindow(hwnd); + SIZE clientSize = GetClientSize(hwnd); + 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); + + 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"); + deferredFlags->clear |= FLAG_WINDOW_MAXIMIZED; + } + } + } + } break; + 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; + } + + 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) mized = MIZED_MIN; + else + { + WINDOWPLACEMENT placement; + placement.length = sizeof(placement); + if (!GetWindowPlacement(hwnd, &placement)) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "GetWindowPlacement", GetLastError()); + + if (placement.showCmd == SW_SHOWMAXIMIZED) mized = MIZED_MAX; + } + + switch (mized) + { + case MIZED_NONE: + { + deferredFlags->clear |= (FLAG_WINDOW_MINIMIZED | FLAG_WINDOW_MAXIMIZED); + 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 ((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; + } + + } break; + case MIZED_MIN: + { + // !!! NOTE !!! Do not update the maximized/borderless + // flags because when hwnd is minimized it temporarily overrides + // the maximized state/flag which gets restored on SW_RESTORE + deferredFlags->set |= FLAG_WINDOW_MINIMIZED; + } break; + case MIZED_MAX: + { + deferredFlags->clear |= FLAG_WINDOW_MINIMIZED; + deferredFlags->set |= FLAG_WINDOW_MAXIMIZED; + } break; + default: break; + } + } break; + case WM_SIZE: + { + // WARNING: Don't trust the docs, they say you won't get this message if you don't call DefWindowProc + // in response to WM_WINDOWPOSCHANGED but looks like when a window is created you'll get this + // message without getting WM_WINDOWPOSCHANGED + HandleWindowResize(hwnd, &platform.appScreenWidth, &platform.appScreenHeight); + } break; + //case WM_MOVE + case WM_WINDOWPOSCHANGED: + { + WINDOWPOS *pos = (WINDOWPOS*)lparam; + if (!(pos->flags & SWP_NOSIZE)) HandleWindowResize(hwnd, &platform.appScreenWidth, &platform.appScreenHeight); + } break; + case WM_GETDPISCALEDSIZE: + { + SIZE *inoutSize = (SIZE *)lparam; + UINT newDpi = (UINT)wparam; // TODO: WARNING: Converting from WPARAM = UINT_PTR + + // for any of these other cases, we might want to post a window + // resize event after the dpi changes? + if (CORE.Window.flags & FLAG_WINDOW_MINIMIZED) return TRUE; + if (CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) return TRUE; + if (CORE.Window.flags & FLAG_BORDERLESS_WINDOWED_MODE) return TRUE; + + float dpiScale = ((float)newDpi)/96.0f; + bool dpiScaling = CORE.Window.flags & FLAG_WINDOW_HIGHDPI; + SIZE desired = PxFromPt2(dpiScale, dpiScaling, platform.appScreenWidth, platform.appScreenHeight); + inoutSize->cx = desired.cx; + inoutSize->cy = desired.cy; + + result = TRUE; + } break; + case WM_DPICHANGED: + { + 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()); + } + } break; + case WM_SETCURSOR: + { + if (LOWORD(lparam) == HTCLIENT) + { + SetCursor(CORE.Input.Mouse.cursorHidden? NULL : LoadCursorW(NULL, (LPCWSTR)IDC_ARROW)); + return 0; + } + + result = DefWindowProc(hwnd, msg, wparam, lparam); + } break; + //case WM_PAINT + case WM_INPUT: + { + HandleRawInput(lparam); + } break; + case WM_MOUSEMOVE: + { + if (platform.cursorEnabled) + { + CORE.Input.Mouse.currentPosition.x = (float)GET_X_LPARAM(lparam); + CORE.Input.Mouse.currentPosition.y = (float)GET_Y_LPARAM(lparam); + CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition; + } + } break; + case WM_KEYDOWN: HandleKey(wparam, lparam, 1); break; + case WM_KEYUP: HandleKey(wparam, lparam, 0); break; + case WM_LBUTTONDOWN: HandleMouseButton(MOUSE_BUTTON_LEFT, 1); break; + case WM_LBUTTONUP : HandleMouseButton(MOUSE_BUTTON_LEFT, 0); break; + case WM_RBUTTONDOWN: HandleMouseButton(MOUSE_BUTTON_RIGHT, 1); break; + 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: + { + switch (HIWORD(wparam)) + { + case XBUTTON1: HandleMouseButton(MOUSE_BUTTON_SIDE, 1); break; + case XBUTTON2: HandleMouseButton(MOUSE_BUTTON_EXTRA, 1); break; + default: TRACELOG(LOG_WARNING, "TODO: handle ex mouse button DOWN wparam=%u", HIWORD(wparam)); break; + } + } break; + case WM_XBUTTONUP: + { + switch (HIWORD(wparam)) + { + case XBUTTON1: HandleMouseButton(MOUSE_BUTTON_SIDE, 0); break; + case XBUTTON2: HandleMouseButton(MOUSE_BUTTON_EXTRA, 0); break; + default: TRACELOG(LOG_WARNING, "TODO: handle ex mouse button UP wparam=%u", HIWORD(wparam)); break; + } + } break; + case WM_MOUSEWHEEL: CORE.Input.Mouse.currentWheelMove.y = ((float)GET_WHEEL_DELTA_WPARAM(wparam))/WHEEL_DELTA; break; + case WM_MOUSEHWHEEL: CORE.Input.Mouse.currentWheelMove.x = ((float)GET_WHEEL_DELTA_WPARAM(wparam))/WHEEL_DELTA; break; + case WM_APP_UPDATE_WINDOW_SIZE: + { + UpdateWindowSize(UPDATE_WINDOW_NORMAL, hwnd, platform.appScreenWidth, platform.appScreenHeight, CORE.Window.flags); + } break; + + default: result = DefWindowProcW(hwnd, msg, wparam, lparam); // Message passed directly for execution (default behaviour) + } + //------------------------------------------------------------------------------------ + + // Sanity check + 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); + } + + 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); + } + + return result; +} + +static void HandleKey(WPARAM wparam, LPARAM lparam, char state) +{ + KeyboardKey key = KeyFromWparam(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; + + if ((key == KEY_ESCAPE) && (state == 1)) CORE.Window.shouldClose = 1; + } + else TRACELOG(LOG_WARNING, "INPUT: Unknown (or currently unhandled) virtual keycode %d (0x%x)", wparam, wparam); + + // TODO: Add key to the queue as well? +} + +static void HandleMouseButton(int button, char state) +{ + CORE.Input.Mouse.currentButtonState[button] = state; + CORE.Input.Touch.currentTouchState[button] = state; +} + +static void HandleRawInput(LPARAM lparam) +{ + RAWINPUT input = { 0 }; + + 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 (input.header.dwType != RIM_TYPEMOUSE) TRACELOG(LOG_ERROR, "Unexpected WM_INPUT type %lu", input.header.dwType); + + if (input.data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) TRACELOG(LOG_ERROR, "TODO: handle absolute mouse inputs!"); + + if (input.data.mouse.usFlags & MOUSE_VIRTUAL_DESKTOP) TRACELOG(LOG_ERROR, "TODO: handle virtual desktop mouse inputs!"); + + // Trick to keep the mouse position at 0,0 and instead move + // the previous position so we can still get a proper mouse delta + //CORE.Input.Mouse.previousPosition.x -= input.data.mouse.lLastX; + //CORE.Input.Mouse.previousPosition.y -= input.data.mouse.lLastY; + //if (CORE.Input.Mouse.currentPosition.x != 0) abort(); + //if (CORE.Input.Mouse.currentPosition.y != 0) abort(); +} + +static void HandleWindowResize(HWND hwnd, int *width, int *height) +{ + if (CORE.Window.flags & FLAG_WINDOW_MINIMIZED) return; + + SIZE clientSize = GetClientSize(hwnd); + + //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; + //glViewport(0, 0, clientSize.cx, clientSize.cy); + //SetupFramebuffer(0, 0); + + SetupViewport(clientSize.cx, clientSize.cy); + CORE.Window.resizedLastFrame = true; + float dpiScale = ((float)GetDpiForWindow(hwnd))/96.0f; + bool highdpi = !!(CORE.Window.flags & FLAG_WINDOW_HIGHDPI); + unsigned int screenWidth = highdpi? (unsigned int)(((float)clientSize.cx)/dpiScale) : clientSize.cx; + 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, "WINDOW: Updating app size to %ix%i from window resize", screenWidth, screenHeight); + *width = screenWidth; + *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); +} + +// Update window style +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); + 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)", + 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)); + if (currentMized != desiredMized) + { + switch (desiredMized) + { + case MIZED_NONE: ShowWindow(hwnd, SW_RESTORE); break; + case MIZED_MIN: ShowWindow(hwnd, SW_MINIMIZE); break; + case MIZED_MAX: ShowWindow(hwnd, SW_MAXIMIZE); break; + } + } +} + +// Sanitize flags +static unsigned SanitizeFlags(SanitizeFlagsKind kind, unsigned flags) +{ + if ((flags & FLAG_WINDOW_MAXIMIZED) && (flags & FLAG_BORDERLESS_WINDOWED_MODE)) + { + TRACELOG(LOG_INFO, "borderless windows mode is overriding maximized"); + flags &= ~FLAG_WINDOW_MAXIMIZED; + } + + switch (kind) + { + 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; + } + + return flags; +} + +// All window state changes from raylib flags go through this function. It performs +// whatever operations are needed to update the window state to match the desired flags +// In most cases this function should not update CORE.Window.flags directly, instead, +// the window itself should update CORE.Window.flags in response to actual state changes +// This means that CORE.Window.flags should always represent the actual state of the +// window. This function will continue to perform these update operations so long as +// the state continues to change +// +// This design takes care of many odd corner cases. For example, if you want to restore +// a window that was previously maximized AND minimized and you want to remove both these +// flags, you actually need to call ShowWindow with SW_RESTORE twice. Another example is +// if you have a maximized window, if the undecorated flag is modified then we'd need to +// update the window style, but updating the style would mean the window size would change +// causing the window to lose its Maximized state which would mean we'd need to update the +// window size and then update the window style a second time to restore that maximized +// state. This implementation is able to handle any/all of these special situations with a +// retry loop that continues until we either reach the desired state or the state stops changing +static void UpdateFlags(HWND hwnd, unsigned desiredFlags, int width, int height) +{ + // Flags that just apply immediately without needing any operations + 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) + { + (*wglSwapInterval)(vsync); + if (vsync) CORE.Window.flags |= FLAG_VSYNC_HINT; + else CORE.Window.flags &= ~FLAG_VSYNC_HINT; + } + + DWORD previousStyle; + for (unsigned attempt = 1; ; attempt++) + { + CheckFlags("UpdateFlags", hwnd, CORE.Window.flags, MakeWindowStyle(CORE.Window.flags), STYLE_MASK_ALL); + + bool windowSizeUpdated = false; + if (MakeWindowStyle(CORE.Window.flags) == MakeWindowStyle(desiredFlags)) + { + windowSizeUpdated = UpdateWindowSize(UPDATE_WINDOW_NORMAL, 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) + { + TRACELOG(LOG_ERROR, "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); + } + + previousStyle = MakeWindowStyle(CORE.Window.flags); + UpdateWindowStyle(hwnd, desiredFlags); } } From 070c7894c6901eb206c76534627858e5913826f5 Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 26 Sep 2025 23:35:28 +0200 Subject: [PATCH 036/167] REVIEWED: Some flags for window/context creation attributes --- src/platforms/rcore_desktop_win32.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/platforms/rcore_desktop_win32.c b/src/platforms/rcore_desktop_win32.c index 29669fd54..c7740ba2e 100644 --- a/src/platforms/rcore_desktop_win32.c +++ b/src/platforms/rcore_desktop_win32.c @@ -171,19 +171,25 @@ static PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL; #define WGL_DEPTH_BITS_ARB 0x2022 #define WGL_STENCIL_BITS_ARB 0x2023 #define WGL_TYPE_RGBA_ARB 0x202b + +// Context acceleration types #define WGL_NO_ACCELERATION_ARB 0x2025 // OpenGL 1.1 GDI software rasterizer #define WGL_GENERIC_ACCELERATION_ARB 0x2026 #define WGL_FULL_ACCELERATION_ARB 0x2027 // OpenGL hardware-accelerated, using GPU-drivers provided by vendor +// WGL_ARB_multisample extension supported +#define WGL_SAMPLE_BUFFERS_ARB 0x2041 // Multisampling: 1 if multisample buffers are supported +#define WGL_SAMPLES_ARB 0x2042 // Multisampling: Number of samples per pixel (4, 8, 16) + +// WGL_ARB_framebuffer_sRGB extension supported +#define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20a9 // GL_TRUE if the framebuffer can do sRGB conversion + #define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000 #define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 #define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 #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_SAMPLE_BUFFERS_ARB 0x2041 -#define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20a9 -#define WGL_TRANSPARENT_ARB 0x200A //---------------------------------------------------------------------------------- // Types and Structures Definition From 4cd131cf292bf4f5e06c7db89e9224fe36894330 Mon Sep 17 00:00:00 2001 From: Alexandre Almeida Date: Sun, 28 Sep 2025 13:53:40 -0300 Subject: [PATCH 037/167] Update miniaudio to v0.11.23 (#5208) --- src/external/miniaudio.h | 6087 ++++++++++++++++++++++++++------------ 1 file changed, 4134 insertions(+), 1953 deletions(-) diff --git a/src/external/miniaudio.h b/src/external/miniaudio.h index c74bebeb3..1e4e2c655 100644 --- a/src/external/miniaudio.h +++ b/src/external/miniaudio.h @@ -1,6 +1,6 @@ /* Audio playback and capture library. Choice of public domain or MIT-0. See license statements at the end of this file. -miniaudio - v0.11.22 - 2025-02-24 +miniaudio - v0.11.23 - 2025-09-11 David Reid - mackron@gmail.com @@ -12,18 +12,10 @@ GitHub: https://github.com/mackron/miniaudio /* 1. Introduction =============== -To use miniaudio, include "miniaudio.h": - - ```c - #include "miniaudio.h" - ``` - -The implementation is contained in "miniaudio.c". Just compile this like any other source file. You -can include miniaudio.c if you want to compile your project as a single translation unit: - - ```c - #include "miniaudio.c" - ``` +To use miniaudio, just include "miniaudio.h" like any other header and add "miniaudio.c" to your +source tree. If you don't want to add it to your source tree you can compile and link to it like +any other library. Note that ABI compatibility is not guaranteed between versions, even with bug +fix releases, so take care if compiling as a shared object. miniaudio includes both low level and high level APIs. The low level API is good for those who want to do all of their mixing themselves and only require a light weight interface to the underlying @@ -303,7 +295,7 @@ The engine encapsulates both the resource manager and the node graph to create a use high level API. The resource manager and node graph APIs are covered in more later sections of this manual. -The code below shows how you can initialize an engine using it's default configuration. +The code below shows how you can initialize an engine using its default configuration. ```c ma_result result; @@ -391,7 +383,7 @@ Sounds are not started by default. Start a sound with `ma_sound_start()` and sto `ma_sound_stop()`. When a sound is stopped, it is not rewound to the start. Use `ma_sound_seek_to_pcm_frame(&sound, 0)` to seek back to the start of a sound. By default, starting and stopping sounds happens immediately, but sometimes it might be convenient to schedule the sound -the be started and/or stopped at a specific time. This can be done with the following functions: +to be started and/or stopped at a specific time. This can be done with the following functions: ```c ma_sound_set_start_time_in_pcm_frames() @@ -463,6 +455,11 @@ is at the end, use `ma_sound_at_end()`. Looping of a sound can be controlled wit miniaudio should work cleanly out of the box without the need to download or install any dependencies. See below for platform-specific details. +This library has been designed to be added directly to your source tree which is the preferred way +of using it, but you can compile it as a normal library if that's your preference. Be careful if +compiling as a shared object because miniaudio is not ABI compatible between any release, including +bug fix releases. It's recommended you link statically. + Note that GCC and Clang require `-msse2`, `-mavx2`, etc. for SIMD optimizations. If you get errors about undefined references to `__sync_val_compare_and_swap_8`, `__atomic_load_8`, @@ -532,7 +529,7 @@ you'll need to disable run-time linking with `MA_NO_RUNTIME_LINKING` and link wi The Emscripten build emits Web Audio JavaScript directly and should compile cleanly out of the box. You cannot use `-std=c*` compiler flags, nor `-ansi`. -You can enable the use of AudioWorkets by defining `MA_ENABLE_AUDIO_WORKLETS` and then compiling +You can enable the use of AudioWorklets by defining `MA_ENABLE_AUDIO_WORKLETS` and then compiling with the following options: -sAUDIO_WORKLET=1 -sWASM_WORKERS=1 -sASYNCIFY @@ -881,7 +878,7 @@ read data within a certain range of the underlying data. To do this you can use This is useful if you have a sound bank where many sounds are stored in the same file and you want the data source to only play one of those sub-sounds. Note that once the range is set, everything -that takes a position, such as cursors and loop points, should always be relatvie to the start of +that takes a position, such as cursors and loop points, should always be relative to the start of the range. When the range is set, any previously defined loop point will be reset. Custom loop points can also be used with data sources. By default, data sources will loop after @@ -889,7 +886,7 @@ they reach the end of the data source, but if you need to loop at a specific loc the following: ```c - result = ma_data_set_loop_point_in_pcm_frames(pDataSource, loopBegInFrames, loopEndInFrames); + result = ma_data_source_set_loop_point_in_pcm_frames(pDataSource, loopBegInFrames, loopEndInFrames); if (result != MA_SUCCESS) { return result; // Failed to set the loop point. } @@ -3750,7 +3747,7 @@ extern "C" { #define MA_VERSION_MAJOR 0 #define MA_VERSION_MINOR 11 -#define MA_VERSION_REVISION 22 +#define MA_VERSION_REVISION 23 #define MA_VERSION_STRING MA_XSTRINGIFY(MA_VERSION_MAJOR) "." MA_XSTRINGIFY(MA_VERSION_MINOR) "." MA_XSTRINGIFY(MA_VERSION_REVISION) #if defined(_MSC_VER) && !defined(__clang__) @@ -3857,6 +3854,8 @@ typedef ma_uint16 wchar_t; #define MA_SIZE_MAX 0xFFFFFFFF /* When SIZE_MAX is not defined by the standard library just default to the maximum 32-bit unsigned integer. */ #endif +#define MA_UINT64_MAX (((ma_uint64)0xFFFFFFFF << 32) | (ma_uint64)0xFFFFFFFF) /* Weird shifting syntax is for VC6 compatibility. */ + /* Platform/backend detection. */ #if defined(_WIN32) || defined(__COSMOPOLITAN__) @@ -3865,29 +3864,55 @@ typedef ma_uint16 wchar_t; #define MA_WIN32_UWP #elif defined(WINAPI_FAMILY) && (defined(WINAPI_FAMILY_GAMES) && WINAPI_FAMILY == WINAPI_FAMILY_GAMES) #define MA_WIN32_GDK + #elif defined(NXDK) + #define MA_WIN32_NXDK #else #define MA_WIN32_DESKTOP #endif + + /* The original Xbox. */ + #if defined(NXDK) /* <-- Add other Xbox compiler toolchains here, and then add a toolchain-specific define in case we need to discriminate between them later. */ + #define MA_XBOX + + #if defined(NXDK) + #define MA_XBOX_NXDK + #endif + #endif #endif -#if !defined(_WIN32) /* If it's not Win32, assume POSIX. */ +#if defined(__MSDOS__) || defined(MSDOS) || defined(_MSDOS) || defined(__DOS__) + #define MA_DOS + + /* No threading allowed on DOS. */ + #ifndef MA_NO_THREADING + #define MA_NO_THREADING + #endif + + /* No runtime linking allowed on DOS. */ + #ifndef MA_NO_RUNTIME_LINKING + #define MA_NO_RUNTIME_LINKING + #endif +#endif +#if !defined(MA_WIN32) && !defined(MA_DOS) /* If it's not Win32, assume POSIX. */ #define MA_POSIX - /* - Use the MA_NO_PTHREAD_IN_HEADER option at your own risk. This is intentionally undocumented. - You can use this to avoid including pthread.h in the header section. The downside is that it - results in some fixed sized structures being declared for the various types that are used in - miniaudio. The risk here is that these types might be too small for a given platform. This - risk is yours to take and no support will be offered if you enable this option. - */ - #ifndef MA_NO_PTHREAD_IN_HEADER - #include /* Unfortunate #include, but needed for pthread_t, pthread_mutex_t and pthread_cond_t types. */ - typedef pthread_t ma_pthread_t; - typedef pthread_mutex_t ma_pthread_mutex_t; - typedef pthread_cond_t ma_pthread_cond_t; - #else - typedef ma_uintptr ma_pthread_t; - typedef union ma_pthread_mutex_t { char __data[40]; ma_uint64 __alignment; } ma_pthread_mutex_t; - typedef union ma_pthread_cond_t { char __data[48]; ma_uint64 __alignment; } ma_pthread_cond_t; + #if !defined(MA_NO_THREADING) + /* + Use the MA_NO_PTHREAD_IN_HEADER option at your own risk. This is intentionally undocumented. + You can use this to avoid including pthread.h in the header section. The downside is that it + results in some fixed sized structures being declared for the various types that are used in + miniaudio. The risk here is that these types might be too small for a given platform. This + risk is yours to take and no support will be offered if you enable this option. + */ + #ifndef MA_NO_PTHREAD_IN_HEADER + #include /* Unfortunate #include, but needed for pthread_t, pthread_mutex_t and pthread_cond_t types. */ + typedef pthread_t ma_pthread_t; + typedef pthread_mutex_t ma_pthread_mutex_t; + typedef pthread_cond_t ma_pthread_cond_t; + #else + typedef ma_uintptr ma_pthread_t; + typedef union ma_pthread_mutex_t { char __data[40]; ma_uint64 __alignment; } ma_pthread_mutex_t; + typedef union ma_pthread_cond_t { char __data[48]; ma_uint64 __alignment; } ma_pthread_cond_t; + #endif #endif #if defined(__unix__) @@ -3914,8 +3939,11 @@ typedef ma_uint16 wchar_t; #if defined(__PROSPERO__) #define MA_PROSPERO #endif - #if defined(__NX__) - #define MA_NX + #if defined(__3DS__) + #define MA_3DS + #endif + #if defined(__SWITCH__) || defined(__NX__) + #define MA_SWITCH #endif #if defined(__BEOS__) || defined(__HAIKU__) #define MA_BEOS @@ -3925,12 +3953,13 @@ typedef ma_uint16 wchar_t; #endif #endif -#if defined(__has_c_attribute) - #if __has_c_attribute(fallthrough) - #define MA_FALLTHROUGH [[fallthrough]] - #endif +#if !defined(MA_FALLTHROUGH) && defined(__cplusplus) && __cplusplus >= 201703L + #define MA_FALLTHROUGH [[fallthrough]] #endif -#if !defined(MA_FALLTHROUGH) && defined(__has_attribute) && (defined(__clang__) || defined(__GNUC__)) +#if !defined(MA_FALLTHROUGH) && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202000L + #define MA_FALLTHROUGH [[fallthrough]] +#endif +#if !defined(MA_FALLTHROUGH) && defined(__has_attribute) #if __has_attribute(fallthrough) #define MA_FALLTHROUGH __attribute__((fallthrough)) #endif @@ -3967,7 +3996,7 @@ typedef ma_uint16 wchar_t; #define MA_NO_INLINE __attribute__((noinline)) #else #define MA_INLINE MA_GNUC_INLINE_HINT - #define MA_NO_INLINE __attribute__((noinline)) + #define MA_NO_INLINE #endif #elif defined(__WATCOMC__) #define MA_INLINE __inline @@ -4350,7 +4379,7 @@ typedef struct typedef struct { - ma_int32 state; + ma_uint32 state; } ma_lcg; @@ -6569,7 +6598,7 @@ This section contains the APIs for device playback and capture. Here is where yo ************************************************************************************************************************************************************/ #ifndef MA_NO_DEVICE_IO /* Some backends are only supported on certain platforms. */ -#if defined(MA_WIN32) +#if defined(MA_WIN32) && !defined(MA_XBOX) #define MA_SUPPORT_WASAPI #if defined(MA_WIN32_DESKTOP) /* DirectSound and WinMM backends are only supported on desktops. */ @@ -7426,6 +7455,7 @@ struct ma_context ma_proc snd_pcm_hw_params_set_rate_resample; ma_proc snd_pcm_hw_params_set_rate; ma_proc snd_pcm_hw_params_set_rate_near; + ma_proc snd_pcm_hw_params_set_rate_minmax; ma_proc snd_pcm_hw_params_set_buffer_size_near; ma_proc snd_pcm_hw_params_set_periods_near; ma_proc snd_pcm_hw_params_set_access; @@ -7986,6 +8016,7 @@ struct ma_device /*AAudioStream**/ ma_ptr pStreamPlayback; /*AAudioStream**/ ma_ptr pStreamCapture; ma_mutex rerouteLock; + ma_atomic_bool32 isTearingDown; ma_aaudio_usage usage; ma_aaudio_content_type contentType; ma_aaudio_input_preset inputPreset; @@ -11255,7 +11286,7 @@ typedef struct ma_log* pLog; /* When set to NULL, will use the context's log. */ ma_uint32 listenerCount; /* Must be between 1 and MA_ENGINE_MAX_LISTENERS. */ ma_uint32 channels; /* The number of channels to use when mixing and spatializing. When set to 0, will use the native channel count of the device. */ - ma_uint32 sampleRate; /* The sample rate. When set to 0 will use the native channel count of the device. */ + ma_uint32 sampleRate; /* The sample rate. When set to 0 will use the native sample rate of the device. */ ma_uint32 periodSizeInFrames; /* If set to something other than 0, updates will always be exactly this size. The underlying device may be a different size, but from the perspective of the mixer that won't matter.*/ ma_uint32 periodSizeInMilliseconds; /* Used if periodSizeInFrames is unset. */ ma_uint32 gainSmoothTimeInFrames; /* The number of frames to interpolate the gain of spatialized sounds across. If set to 0, will use gainSmoothTimeInMilliseconds. */ @@ -11419,11 +11450,11 @@ MA_API ma_bool32 ma_sound_is_looping(const ma_sound* pSound); MA_API ma_bool32 ma_sound_at_end(const ma_sound* pSound); MA_API ma_result ma_sound_seek_to_pcm_frame(ma_sound* pSound, ma_uint64 frameIndex); /* Just a wrapper around ma_data_source_seek_to_pcm_frame(). */ MA_API ma_result ma_sound_seek_to_second(ma_sound* pSound, float seekPointInSeconds); /* Abstraction to ma_sound_seek_to_pcm_frame() */ -MA_API ma_result ma_sound_get_data_format(ma_sound* pSound, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap); -MA_API ma_result ma_sound_get_cursor_in_pcm_frames(ma_sound* pSound, ma_uint64* pCursor); -MA_API ma_result ma_sound_get_length_in_pcm_frames(ma_sound* pSound, ma_uint64* pLength); -MA_API ma_result ma_sound_get_cursor_in_seconds(ma_sound* pSound, float* pCursor); -MA_API ma_result ma_sound_get_length_in_seconds(ma_sound* pSound, float* pLength); +MA_API ma_result ma_sound_get_data_format(const ma_sound* pSound, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap); +MA_API ma_result ma_sound_get_cursor_in_pcm_frames(const ma_sound* pSound, ma_uint64* pCursor); +MA_API ma_result ma_sound_get_length_in_pcm_frames(const ma_sound* pSound, ma_uint64* pLength); +MA_API ma_result ma_sound_get_cursor_in_seconds(const ma_sound* pSound, float* pCursor); +MA_API ma_result ma_sound_get_length_in_seconds(const ma_sound* pSound, float* pLength); MA_API ma_result ma_sound_set_end_callback(ma_sound* pSound, ma_sound_end_proc callback, void* pUserData); MA_API ma_result ma_sound_group_init(ma_engine* pEngine, ma_uint32 flags, ma_sound_group* pParentGroup, ma_sound_group* pGroup); @@ -11544,17 +11575,23 @@ IMPLEMENTATION #endif #if !defined(MA_WIN32) -#include -#include /* select() (used for ma_sleep()). */ -#include + #if !defined(MA_NO_THREADING) + #include + #include /* For pthreads. */ + #endif + + #include /* select() (used for ma_sleep()). */ + #include /* For nanosleep() */ + #include #endif -#ifdef MA_NX -#include /* For nanosleep() */ +/* For fstat(), etc. */ +#if defined(MA_XBOX_NXDK) + #include /* Suggestion for NXDK: Add a sys/stat.h wrapper for compatibility. */ +#else + #include #endif -#include /* For fstat(), etc. */ - #ifdef MA_EMSCRIPTEN #include #endif @@ -11861,7 +11898,7 @@ static MA_INLINE ma_bool32 ma_has_neon(void) #endif #ifndef MA_RESTRICT - #if defined(__clang__) || defined(__GNUC__) || defined(_MSC_VER) + #if defined(__clang__) || defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95))) #define MA_RESTRICT __restrict #else #define MA_RESTRICT @@ -11955,7 +11992,7 @@ static void ma_sleep__posix(ma_uint32 milliseconds) (void)milliseconds; MA_ASSERT(MA_FALSE); /* The Emscripten build should never sleep. */ #else - #if (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309L) || defined(MA_NX) + #if (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309L) || defined(MA_SWITCH) struct timespec ts; ts.tv_sec = milliseconds / 1000; ts.tv_nsec = milliseconds % 1000 * 1000000; @@ -11997,7 +12034,7 @@ static MA_INLINE void ma_yield(void) #endif #endif #else - __asm__ __volatile__ ("pause"); + __asm__ __volatile__ ("rep; nop"); #endif #elif (defined(__arm__) && defined(__ARM_ARCH) && __ARM_ARCH >= 7) || defined(_M_ARM64) || (defined(_M_ARM) && _M_ARM >= 7) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6T2__) /* ARM */ @@ -12020,7 +12057,7 @@ static MA_INLINE unsigned int ma_disable_denormals(void) { unsigned int prevState; - #if defined(_MSC_VER) + #if defined(_MSC_VER) && !defined(MA_XBOX_NXDK) { /* Older versions of Visual Studio don't support the "safe" versions of _controlfp_s(). I don't @@ -12043,7 +12080,7 @@ static MA_INLINE unsigned int ma_disable_denormals(void) } #elif defined(MA_X86) || defined(MA_X64) { - #if defined(__SSE2__) && !(defined(__TINYC__) || defined(__WATCOMC__) || defined(__COSMOPOLITAN__)) /* <-- Add compilers that lack support for _mm_getcsr() and _mm_setcsr() to this list. */ + #if defined(MA_SUPPORT_SSE2) && defined(__SSE2__) && !(defined(__TINYC__) || defined(__WATCOMC__) || defined(__COSMOPOLITAN__)) /* <-- Add compilers that lack support for _mm_getcsr() and _mm_setcsr() to this list. */ { prevState = _mm_getcsr(); _mm_setcsr(prevState | MA_MM_DENORMALS_ZERO_MASK | MA_MM_FLUSH_ZERO_MASK); @@ -12067,7 +12104,7 @@ static MA_INLINE unsigned int ma_disable_denormals(void) static MA_INLINE void ma_restore_denormals(unsigned int prevState) { - #if defined(_MSC_VER) + #if defined(_MSC_VER) && !defined(MA_XBOX_NXDK) { /* Older versions of Visual Studio do not support _controlfp_s(). See ma_disable_denormals(). */ #if _MSC_VER <= 1200 @@ -12083,7 +12120,7 @@ static MA_INLINE void ma_restore_denormals(unsigned int prevState) } #elif defined(MA_X86) || defined(MA_X64) { - #if defined(__SSE2__) && !(defined(__TINYC__) || defined(__WATCOMC__) || defined(__COSMOPOLITAN__)) /* <-- Add compilers that lack support for _mm_getcsr() and _mm_setcsr() to this list. */ + #if defined(MA_SUPPORT_SSE2) && defined(__SSE2__) && !(defined(__TINYC__) || defined(__WATCOMC__) || defined(__COSMOPOLITAN__)) /* <-- Add compilers that lack support for _mm_getcsr() and _mm_setcsr() to this list. */ { _mm_setcsr(prevState); } @@ -12719,6 +12756,29 @@ MA_API MA_NO_INLINE int ma_strcmp(const char* str1, const char* str2) return ((unsigned char*)str1)[0] - ((unsigned char*)str2)[0]; } +MA_API MA_NO_INLINE int ma_wcscmp(const wchar_t* str1, const wchar_t* str2) +{ + if (str1 == str2) return 0; + + /* These checks differ from the standard implementation. It's not important, but I prefer it just for sanity. */ + if (str1 == NULL) return -1; + if (str2 == NULL) return 1; + + for (;;) { + if (str1[0] == L'\0') { + break; + } + if (str1[0] != str2[0]) { + break; + } + + str1 += 1; + str2 += 1; + } + + return ((unsigned short*)str1)[0] - ((unsigned short*)str2)[0]; +} + MA_API MA_NO_INLINE int ma_strappend(char* dst, size_t dstSize, const char* srcA, const char* srcB) { int result; @@ -12736,6 +12796,22 @@ MA_API MA_NO_INLINE int ma_strappend(char* dst, size_t dstSize, const char* srcA return result; } +MA_API MA_NO_INLINE size_t ma_wcslen(const wchar_t* str) +{ + const wchar_t* end; + + if (str == NULL) { + return 0; + } + + end = str; + while (end[0] != '\0') { + end += 1; + } + + return end - str; +} + MA_API MA_NO_INLINE char* ma_copy_string(const char* src, const ma_allocation_callbacks* pAllocationCallbacks) { size_t sz; @@ -12758,7 +12834,7 @@ MA_API MA_NO_INLINE char* ma_copy_string(const char* src, const ma_allocation_ca MA_API MA_NO_INLINE wchar_t* ma_copy_string_w(const wchar_t* src, const ma_allocation_callbacks* pAllocationCallbacks) { - size_t sz = wcslen(src)+1; + size_t sz = ma_wcslen(src)+1; wchar_t* dst = (wchar_t*)ma_malloc(sz * sizeof(*dst), pAllocationCallbacks); if (dst == NULL) { return NULL; @@ -13189,7 +13265,7 @@ MA_API ma_result ma_fopen(FILE** ppFile, const char* pFilePath, const char* pOpe return MA_INVALID_ARGS; } -#if defined(_MSC_VER) && _MSC_VER >= 1400 +#if (defined(_MSC_VER) && _MSC_VER >= 1400) && !defined(MA_XBOX_NXDK) err = fopen_s(ppFile, pFilePath, pOpenMode); if (err != 0) { return ma_result_from_errno(err); @@ -13231,7 +13307,7 @@ _wfopen() isn't always available in all compilation environments. This can be reviewed as compatibility issues arise. The preference is to use _wfopen_s() and _wfopen() as opposed to the wcsrtombs() fallback, so if you notice your compiler not detecting this properly I'm happy to look at adding support. */ -#if defined(_WIN32) +#if defined(_WIN32) && !defined(MA_XBOX_NXDK) #if defined(_MSC_VER) || defined(__MINGW64__) || (!defined(__STRICT_ANSI__) && !defined(_NO_EXT_KEYS)) #define MA_HAS_WFOPEN #endif @@ -13247,29 +13323,34 @@ MA_API ma_result ma_wfopen(FILE** ppFile, const wchar_t* pFilePath, const wchar_ return MA_INVALID_ARGS; } -#if defined(MA_HAS_WFOPEN) + #if defined(MA_HAS_WFOPEN) { /* Use _wfopen() on Windows. */ - #if defined(_MSC_VER) && _MSC_VER >= 1400 - errno_t err = _wfopen_s(ppFile, pFilePath, pOpenMode); - if (err != 0) { - return ma_result_from_errno(err); + #if defined(_MSC_VER) && _MSC_VER >= 1400 + { + errno_t err = _wfopen_s(ppFile, pFilePath, pOpenMode); + if (err != 0) { + return ma_result_from_errno(err); + } } - #else - *ppFile = _wfopen(pFilePath, pOpenMode); - if (*ppFile == NULL) { - return ma_result_from_errno(errno); + #else + { + *ppFile = _wfopen(pFilePath, pOpenMode); + if (*ppFile == NULL) { + return ma_result_from_errno(errno); + } } - #endif + #endif + (void)pAllocationCallbacks; } -#else - /* - Use fopen() on anything other than Windows. Requires a conversion. This is annoying because fopen() is locale specific. The only real way I can - think of to do this is with wcsrtombs(). Note that wcstombs() is apparently not thread-safe because it uses a static global mbstate_t object for - maintaining state. I've checked this with -std=c89 and it works, but if somebody get's a compiler error I'll look into improving compatibility. - */ + #elif !defined(MA_XBOX_NXDK) && !defined(MA_DOS) /* If your compiler does not support wcsrtombs(), add it here. */ { + /* + Use fopen() on anything other than Windows. Requires a conversion. This is annoying because fopen() is locale specific. The only real way I can + think of to do this is with wcsrtombs(). Note that wcstombs() is apparently not thread-safe because it uses a static global mbstate_t object for + maintaining state. I've checked this with -std=c89 and it works, but if somebody get's a compiler error I'll look into improving compatibility. + */ mbstate_t mbs; size_t lenMB; const wchar_t* pFilePathTemp = pFilePath; @@ -13310,11 +13391,16 @@ MA_API ma_result ma_wfopen(FILE** ppFile, const wchar_t* pFilePath, const wchar_ ma_free(pFilePathMB, pAllocationCallbacks); } + #else + { + /* Getting here means there is no way to open the file with a wide character string. */ + *ppFile = NULL; + } + #endif if (*ppFile == NULL) { return MA_ERROR; } -#endif return MA_SUCCESS; } @@ -13323,7 +13409,7 @@ MA_API ma_result ma_wfopen(FILE** ppFile, const wchar_t* pFilePath, const wchar_ static MA_INLINE void ma_copy_memory_64(void* dst, const void* src, ma_uint64 sizeInBytes) { -#if 0xFFFFFFFFFFFFFFFF <= MA_SIZE_MAX +#if MA_SIZE_MAX > 0xFFFFFFFF MA_COPY_MEMORY(dst, src, (size_t)sizeInBytes); #else while (sizeInBytes > 0) { @@ -13343,7 +13429,7 @@ static MA_INLINE void ma_copy_memory_64(void* dst, const void* src, ma_uint64 si static MA_INLINE void ma_zero_memory_64(void* dst, ma_uint64 sizeInBytes) { -#if 0xFFFFFFFFFFFFFFFF <= MA_SIZE_MAX +#if MA_SIZE_MAX > 0xFFFFFFFF MA_ZERO_MEMORY(dst, (size_t)sizeInBytes); #else while (sizeInBytes > 0) { @@ -13472,6 +13558,18 @@ static ma_result ma_allocation_callbacks_init_copy(ma_allocation_callbacks* pDst Logging **************************************************************************************************************************************************************/ +#ifndef ma_va_copy + #if !defined(_MSC_VER) || _MSC_VER >= 1800 + #if (defined(__GNUC__) && __GNUC__ < 3) + #define ma_va_copy(dst, src) ((dst) = (src)) /* This is untested. Not sure if this is correct for old GCC. */ + #else + #define ma_va_copy(dst, src) va_copy((dst), (src)) + #endif + #else + #define ma_va_copy(dst, src) ((dst) = (src)) + #endif +#endif + MA_API const char* ma_log_level_to_string(ma_uint32 logLevel) { switch (logLevel) @@ -13712,9 +13810,15 @@ MA_API ma_result ma_log_postv(ma_log* pLog, ma_uint32 level, const char* pFormat int length; char pFormattedMessageStack[1024]; char* pFormattedMessageHeap = NULL; + va_list args2; /* First try formatting into our fixed sized stack allocated buffer. If this is too small we'll fallback to a heap allocation. */ - length = vsnprintf(pFormattedMessageStack, sizeof(pFormattedMessageStack), pFormat, args); + ma_va_copy(args2, args); + { + length = vsnprintf(pFormattedMessageStack, sizeof(pFormattedMessageStack), pFormat, args2); + } + va_end(args2); + if (length < 0) { return MA_INVALID_OPERATION; /* An error occurred when trying to convert the buffer. */ } @@ -13755,17 +13859,10 @@ MA_API ma_result ma_log_postv(ma_log* pLog, ma_uint32 level, const char* pFormat char* pFormattedMessage = NULL; va_list args2; - #if _MSC_VER >= 1800 + ma_va_copy(args2, args); { - va_copy(args2, args); + formattedLen = ma_vscprintf(&pLog->allocationCallbacks, pFormat, args2); } - #else - { - args2 = args; - } - #endif - - formattedLen = ma_vscprintf(&pLog->allocationCallbacks, pFormat, args2); va_end(args2); if (formattedLen <= 0) { @@ -13964,7 +14061,7 @@ miniaudio's purposes. #define MA_LCG_A 48271 #define MA_LCG_C 0 -static ma_lcg g_maLCG = {MA_DEFAULT_LCG_SEED}; /* Non-zero initial seed. Use ma_seed() to use an explicit seed. */ +static ma_lcg g_maLCG = {MA_DEFAULT_LCG_SEED}; /* Non-zero initial seed. Use ma_lcg_seed() to use an explicit seed. */ static MA_INLINE void ma_lcg_seed(ma_lcg* pLCG, ma_int32 seed) { @@ -14013,7 +14110,7 @@ static MA_INLINE ma_int32 ma_lcg_rand_range_s32(ma_lcg* pLCG, ma_int32 lo, ma_in } - +#if 0 /* Currently unused. */ static MA_INLINE void ma_seed(ma_int32 seed) { ma_lcg_seed(&g_maLCG, seed); @@ -14038,6 +14135,7 @@ static MA_INLINE float ma_rand_f32(void) { return ma_lcg_rand_f32(&g_maLCG); } +#endif static MA_INLINE float ma_rand_range_f32(float lo, float hi) { @@ -14097,6 +14195,7 @@ Atomics **************************************************************************************************************************************************************/ /* c89atomic.h begin */ #ifndef ma_atomic_h +#define ma_atomic_h #if defined(__cplusplus) extern "C" { #endif @@ -14108,11 +14207,40 @@ extern "C" { #endif #endif typedef int ma_atomic_memory_order; -#define MA_ATOMIC_HAS_8 -#define MA_ATOMIC_HAS_16 -#define MA_ATOMIC_HAS_32 -#define MA_ATOMIC_HAS_64 -#if (defined(_MSC_VER) ) || defined(__WATCOMC__) || defined(__DMC__) +#if !defined(MA_ATOMIC_MODERN_MSVC) && \ + !defined(MA_ATOMIC_LEGACY_MSVC) && \ + !defined(MA_ATOMIC_LEGACY_MSVC_ASM) && \ + !defined(MA_ATOMIC_MODERN_GCC) && \ + !defined(MA_ATOMIC_LEGACY_GCC) && \ + !defined(MA_ATOMIC_LEGACY_GCC_ASM) + #if defined(_MSC_VER) || defined(__WATCOMC__) || defined(__DMC__) || defined(__BORLANDC__) + #if (defined(_MSC_VER) && _MSC_VER > 1600) + #define MA_ATOMIC_MODERN_MSVC + #else + #if defined(MA_X64) + #define MA_ATOMIC_LEGACY_MSVC + #else + #define MA_ATOMIC_LEGACY_MSVC_ASM + #endif + #endif + #elif (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))) || defined(__clang__) + #define MA_ATOMIC_MODERN_GCC + #else + #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) + #define MA_ATOMIC_LEGACY_GCC + #else + #define MA_ATOMIC_LEGACY_GCC_ASM + #endif + #endif +#endif +#if defined(MA_ATOMIC_MODERN_MSVC) || defined(MA_ATOMIC_LEGACY_MSVC) + #include + #define ma_atomic_memory_order_relaxed 1 + #define ma_atomic_memory_order_consume 2 + #define ma_atomic_memory_order_acquire 3 + #define ma_atomic_memory_order_release 4 + #define ma_atomic_memory_order_acq_rel 5 + #define ma_atomic_memory_order_seq_cst 6 #define MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, intrin, ma_atomicType, msvcType) \ ma_atomicType result; \ switch (order) \ @@ -14138,720 +14266,1501 @@ typedef int ma_atomic_memory_order; } break; \ } \ return result; - #define MA_ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, expected, desired, order, intrin, ma_atomicType, msvcType) \ + typedef ma_uint32 ma_atomic_flag; + static MA_INLINE ma_atomic_flag ma_atomic_flag_test_and_set_explicit(volatile ma_atomic_flag* dst, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, 1, order, _InterlockedExchange, ma_atomic_flag, long); + } + #else + { + (void)order; + return (ma_atomic_flag)_InterlockedExchange((volatile long*)dst, (long)1); + } + #endif + } + static MA_INLINE void ma_atomic_flag_clear_explicit(volatile ma_atomic_flag* dst, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, 0, order, _InterlockedExchange, ma_atomic_flag, long); + } + #else + { + (void)order; + _InterlockedExchange((volatile long*)dst, (long)0); + } + #endif + } + static MA_INLINE ma_atomic_flag ma_atomic_flag_load_explicit(volatile const ma_atomic_flag* dst, ma_atomic_memory_order order) + { + (void)order; + return (ma_uint32)_InterlockedCompareExchange((volatile long*)dst, 0, 0); + } +#endif +#if defined(MA_ATOMIC_LEGACY_MSVC_ASM) + #define ma_atomic_memory_order_relaxed 1 + #define ma_atomic_memory_order_consume 2 + #define ma_atomic_memory_order_acquire 3 + #define ma_atomic_memory_order_release 4 + #define ma_atomic_memory_order_acq_rel 5 + #define ma_atomic_memory_order_seq_cst 6 + typedef ma_uint32 ma_atomic_flag; + static MA_INLINE ma_atomic_flag ma_atomic_flag_test_and_set_explicit(volatile ma_atomic_flag* dst, ma_atomic_memory_order order) + { + ma_atomic_flag result = 0; + (void)order; + __asm { + mov ecx, dst + mov eax, 1 + xchg [ecx], eax + mov result, eax + } + return result; + } + static MA_INLINE void ma_atomic_flag_clear_explicit(volatile ma_atomic_flag* dst, ma_atomic_memory_order order) + { + if (order == ma_atomic_memory_order_relaxed) { + __asm { + mov esi, dst + mov dword ptr [esi], 0 + } + } else { + __asm { + mov esi, dst + mov eax, 0 + xchg [esi], eax + } + } + } + static MA_INLINE ma_atomic_flag ma_atomic_flag_load_explicit(volatile const ma_atomic_flag* dst, ma_atomic_memory_order order) + { + ma_atomic_flag result = 0; + if (order == ma_atomic_memory_order_relaxed) { + __asm { + mov esi, dst + mov eax, [esi] + mov result, eax + } + } else if (order <= ma_atomic_memory_order_release) { + __asm { + mov esi, dst + mov eax, [esi] + lock add dword ptr [esp], 0 + mov result, eax + } + } else { + __asm { + lock add dword ptr [esp], 0 + mov esi, dst + mov eax, [esi] + mov result, eax + lock add dword ptr [esp], 0 + } + } + return result; + } +#endif +#if defined(MA_ATOMIC_MODERN_GCC) + #define ma_atomic_memory_order_relaxed __ATOMIC_RELAXED + #define ma_atomic_memory_order_consume __ATOMIC_CONSUME + #define ma_atomic_memory_order_acquire __ATOMIC_ACQUIRE + #define ma_atomic_memory_order_release __ATOMIC_RELEASE + #define ma_atomic_memory_order_acq_rel __ATOMIC_ACQ_REL + #define ma_atomic_memory_order_seq_cst __ATOMIC_SEQ_CST + typedef ma_uint32 ma_atomic_flag; + #define ma_atomic_flag_test_and_set_explicit(dst, order) __atomic_exchange_n(dst, 1, order) + #define ma_atomic_flag_clear_explicit(dst, order) __atomic_store_n(dst, 0, order) + #define ma_atomic_flag_load_explicit(dst, order) __atomic_load_n(dst, order) +#endif +#if defined(MA_ATOMIC_LEGACY_GCC) + #define ma_atomic_memory_order_relaxed 1 + #define ma_atomic_memory_order_consume 2 + #define ma_atomic_memory_order_acquire 3 + #define ma_atomic_memory_order_release 4 + #define ma_atomic_memory_order_acq_rel 5 + #define ma_atomic_memory_order_seq_cst 6 + typedef ma_uint32 ma_atomic_flag; + static MA_INLINE ma_atomic_flag ma_atomic_flag_test_and_set_explicit(volatile ma_atomic_flag* dst, ma_atomic_memory_order order) + { + if (order > ma_atomic_memory_order_acquire) { + __sync_synchronize(); + } + return __sync_lock_test_and_set(dst, 1); + } + static MA_INLINE void ma_atomic_flag_clear_explicit(volatile ma_atomic_flag* dst, ma_atomic_memory_order order) + { + if (order > ma_atomic_memory_order_release) { + __sync_synchronize(); + } + __sync_lock_release(dst); + } + static MA_INLINE ma_atomic_flag ma_atomic_flag_load_explicit(volatile const ma_atomic_flag* dst, ma_atomic_memory_order order) + { + (void)order; + return __sync_val_compare_and_swap((ma_atomic_flag*)dst, 0, 0); + } +#endif +#if defined(MA_ATOMIC_LEGACY_GCC_ASM) + #define ma_atomic_memory_order_relaxed 1 + #define ma_atomic_memory_order_consume 2 + #define ma_atomic_memory_order_acquire 3 + #define ma_atomic_memory_order_release 4 + #define ma_atomic_memory_order_acq_rel 5 + #define ma_atomic_memory_order_seq_cst 6 + #if defined(MA_X86) + #define ma_atomic_thread_fence(order) __asm__ __volatile__("lock; addl $0, (%%esp)" ::: "memory") + #elif defined(MA_X64) + #define ma_atomic_thread_fence(order) __asm__ __volatile__("lock; addq $0, (%%rsp)" ::: "memory") + #else + #error Unsupported architecture. + #endif + #define MA_ATOMIC_XCHG_GCC_X86(instructionSizeSuffix, result, dst, src) \ + __asm__ __volatile__( \ + "xchg"instructionSizeSuffix" %0, %1" \ + : "=r"(result), \ + "=m"(*dst) \ + : "0"(src), \ + "m"(*dst) \ + : "memory" \ + ) + #define MA_ATOMIC_LOAD_RELAXED_GCC_X86(instructionSizeSuffix, result, dst) \ + __asm__ __volatile__( \ + "mov"instructionSizeSuffix" %1, %0" \ + : "=r"(result) \ + : "m"(*dst) \ + ) + #define MA_ATOMIC_LOAD_RELEASE_GCC_X86(instructionSizeSuffix, result, dst) \ + ma_atomic_thread_fence(ma_atomic_memory_order_release); \ + __asm__ __volatile__( \ + "mov"instructionSizeSuffix" %1, %0" \ + : "=r"(result) \ + : "m"(*dst) \ + : "memory" \ + ) + #define MA_ATOMIC_LOAD_SEQ_CST_GCC_X86(instructionSizeSuffix, result, dst) \ + ma_atomic_thread_fence(ma_atomic_memory_order_seq_cst); \ + __asm__ __volatile__( \ + "mov"instructionSizeSuffix" %1, %0" \ + : "=r"(result) \ + : "m"(*dst) \ + : "memory" \ + ); \ + ma_atomic_thread_fence(ma_atomic_memory_order_seq_cst) + typedef ma_uint32 ma_atomic_flag; + static MA_INLINE ma_atomic_flag ma_atomic_flag_test_and_set_explicit(volatile ma_atomic_flag* dst, ma_atomic_memory_order order) + { + ma_atomic_flag result; + #if defined(MA_X86) || defined(MA_X64) + { + (void)order; + MA_ATOMIC_XCHG_GCC_X86("l", result, dst, 1); + } + #else + { + #error Unsupported architecture. + } + #endif + return result; + } + static MA_INLINE void ma_atomic_flag_clear_explicit(volatile ma_atomic_flag* dst, ma_atomic_memory_order order) + { + #if defined(MA_X86) || defined(MA_X64) + { + if (order == ma_atomic_memory_order_relaxed) { + __asm__ __volatile__( + "movl $0, %0" + : "=m"(*dst) + ); + } else if (order == ma_atomic_memory_order_release) { + __asm__ __volatile__( + "movl $0, %0" + : "=m"(*dst) + : + : "memory" + ); + } else { + ma_atomic_flag tmp = 0; + __asm__ __volatile__( + "xchgl %0, %1" + : "=r"(tmp), + "=m"(*dst) + : "0"(tmp), + "m"(*dst) + : "memory" + ); + } + } + #else + { + #error Unsupported architecture. + } + #endif + } + static MA_INLINE ma_atomic_flag ma_atomic_flag_load_explicit(volatile const ma_atomic_flag* dst, ma_atomic_memory_order order) + { + #if defined(MA_X86) || defined(MA_X64) + { + ma_atomic_flag result; + if (order == ma_atomic_memory_order_relaxed) { + MA_ATOMIC_LOAD_RELAXED_GCC_X86("l", result, dst); + } else if (order <= ma_atomic_memory_order_release) { + MA_ATOMIC_LOAD_RELEASE_GCC_X86("l", result, dst); + } else { + MA_ATOMIC_LOAD_SEQ_CST_GCC_X86("l", result, dst); + } + return result; + } + #else + { + #error Unsupported architecture. + } + #endif + } +#endif +#define ma_atomic_flag_test_and_set(dst) ma_atomic_flag_test_and_set_explicit(dst, ma_atomic_memory_order_acquire) +#define ma_atomic_flag_clear(dst) ma_atomic_flag_clear_explicit(dst, ma_atomic_memory_order_release) +typedef ma_atomic_flag ma_atomic_spinlock; +static MA_INLINE void ma_atomic_spinlock_lock(volatile ma_atomic_spinlock* pSpinlock) +{ + for (;;) { + if (ma_atomic_flag_test_and_set_explicit(pSpinlock, ma_atomic_memory_order_acquire) == 0) { + break; + } + while (ma_atomic_flag_load_explicit(pSpinlock, ma_atomic_memory_order_relaxed) == 1) { + } + } +} +static MA_INLINE void ma_atomic_spinlock_unlock(volatile ma_atomic_spinlock* pSpinlock) +{ + ma_atomic_flag_clear_explicit(pSpinlock, ma_atomic_memory_order_release); +} +ma_atomic_spinlock ma_atomic_global_lock; +#if defined(MA_ATOMIC_MODERN_MSVC) || defined(MA_ATOMIC_LEGACY_MSVC) || defined(MA_ATOMIC_LEGACY_MSVC_ASM) || defined(MA_ATOMIC_LEGACY_GCC) || defined(MA_ATOMIC_LEGACY_GCC_ASM) + #if defined(MA_X64) || (defined(MA_X86) && ((defined(__GNUC__) && defined(__i486__)) || (defined(_M_IX86) && _M_IX86 >= 400))) + #if defined(MA_ATOMIC_LEGACY_MSVC) && defined(MA_X64) + #else + #define MA_ATOMIC_IS_LOCK_FREE_8 1 + #define MA_ATOMIC_IS_LOCK_FREE_16 1 + #endif + #define MA_ATOMIC_IS_LOCK_FREE_32 1 + #if defined(MA_X64) || (defined(MA_X86) && ((defined(__GNUC__) && defined(__i586__)) || (defined(_M_IX86) && _M_IX86 >= 500))) + #define MA_ATOMIC_IS_LOCK_FREE_64 1 + #else + #endif + #else + #endif + #if defined(MA_ARM32) || defined(MA_ARM64) + #define MA_ATOMIC_IS_LOCK_FREE_8 1 + #define MA_ATOMIC_IS_LOCK_FREE_16 1 + #define MA_ATOMIC_IS_LOCK_FREE_32 1 + #if defined(MA_ARM64) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) + #define MA_ATOMIC_IS_LOCK_FREE_64 1 + #endif + #endif + #if defined(MA_ATOMIC_PPC32) || defined(MA_ATOMIC_PPC64) + #if (defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 7))) && !defined(__clang__) + #else + #define MA_ATOMIC_IS_LOCK_FREE_8 1 + #define MA_ATOMIC_IS_LOCK_FREE_16 1 + #endif + #define MA_ATOMIC_IS_LOCK_FREE_32 1 + #if defined(MA_ATOMIC_PPC64) + #define MA_ATOMIC_IS_LOCK_FREE_64 1 + #endif + #endif + static MA_INLINE ma_bool32 ma_atomic_is_lock_free_8(volatile void* ptr) + { + (void)ptr; + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) + return 1; + #else + return 0; + #endif + } + static MA_INLINE ma_bool32 ma_atomic_is_lock_free_16(volatile void* ptr) + { + (void)ptr; + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) + return 1; + #else + return 0; + #endif + } + static MA_INLINE ma_bool32 ma_atomic_is_lock_free_32(volatile void* ptr) + { + (void)ptr; + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + return 1; + #else + return 0; + #endif + } + static MA_INLINE ma_bool32 ma_atomic_is_lock_free_64(volatile void* ptr) + { + (void)ptr; + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) + return 1; + #else + return 0; + #endif + } +#endif +#define MA_ATOMIC_COMPARE_AND_SWAP_LOCK(sizeInBits, dst, expected, replacement) \ + ma_uint##sizeInBits result; \ + ma_atomic_spinlock_lock(&ma_atomic_global_lock); \ + { \ + result = *dst; \ + if (result == expected) { \ + *dst = replacement; \ + } \ + } \ + ma_atomic_spinlock_unlock(&ma_atomic_global_lock); \ + return result +#define MA_ATOMIC_LOAD_EXPLICIT_LOCK(sizeInBits, ptr, order) \ + ma_uint##sizeInBits result; \ + ma_atomic_spinlock_lock(&ma_atomic_global_lock); \ + { \ + result = *ptr; \ + (void)order; \ + } \ + ma_atomic_spinlock_unlock(&ma_atomic_global_lock); \ + return result +#define MA_ATOMIC_STORE_EXPLICIT_LOCK(sizeInBits, dst, src, order) \ + ma_atomic_spinlock_lock(&ma_atomic_global_lock); \ + { \ + *dst = src; \ + (void)order; \ + } \ + ma_atomic_spinlock_unlock(&ma_atomic_global_lock) +#define MA_ATOMIC_STORE_EXPLICIT_CAS(sizeInBits, dst, src, order) \ + ma_uint##sizeInBits oldValue; \ + do { \ + oldValue = ma_atomic_load_explicit_##sizeInBits(dst, ma_atomic_memory_order_relaxed); \ + } while (ma_atomic_compare_and_swap_##sizeInBits(dst, oldValue, src) != oldValue); \ + (void)order +#define MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(sizeInBits, dst, src, order) \ + ma_uint##sizeInBits result; \ + ma_atomic_spinlock_lock(&ma_atomic_global_lock); \ + { \ + result = *dst; \ + *dst = src; \ + (void)order; \ + } \ + ma_atomic_spinlock_unlock(&ma_atomic_global_lock); \ + return result +#define MA_ATOMIC_EXCHANGE_EXPLICIT_CAS(sizeInBits, dst, src, order) \ + ma_uint##sizeInBits oldValue; \ + do { \ + oldValue = ma_atomic_load_explicit_##sizeInBits(dst, ma_atomic_memory_order_relaxed); \ + } while (ma_atomic_compare_and_swap_##sizeInBits(dst, oldValue, src) != oldValue); \ + (void)order; \ + return oldValue +#define MA_ATOMIC_FETCH_ADD_LOCK(sizeInBits, dst, src, order) \ + ma_uint##sizeInBits result; \ + ma_atomic_spinlock_lock(&ma_atomic_global_lock); \ + { \ + result = *dst; \ + *dst += src; \ + (void)order; \ + } \ + ma_atomic_spinlock_unlock(&ma_atomic_global_lock); \ + return result +#define MA_ATOMIC_FETCH_ADD_CAS(sizeInBits, dst, src, order) \ + ma_uint##sizeInBits oldValue; \ + ma_uint##sizeInBits newValue; \ + do { \ + oldValue = ma_atomic_load_explicit_##sizeInBits(dst, ma_atomic_memory_order_relaxed); \ + newValue = oldValue + src; \ + } while (ma_atomic_compare_and_swap_##sizeInBits(dst, oldValue, newValue) != oldValue); \ + (void)order; \ + return oldValue +#define MA_ATOMIC_FETCH_AND_CAS(sizeInBits, dst, src, order) \ + ma_uint##sizeInBits oldValue; \ + ma_uint##sizeInBits newValue; \ + do { \ + oldValue = ma_atomic_load_explicit_##sizeInBits(dst, ma_atomic_memory_order_relaxed); \ + newValue = (ma_uint##sizeInBits)(oldValue & src); \ + } while (ma_atomic_compare_and_swap_##sizeInBits(dst, oldValue, newValue) != oldValue); \ + (void)order; \ + return oldValue +#define MA_ATOMIC_FETCH_OR_CAS(sizeInBits, dst, src, order) \ + ma_uint##sizeInBits oldValue; \ + ma_uint##sizeInBits newValue; \ + do { \ + oldValue = ma_atomic_load_explicit_##sizeInBits(dst, ma_atomic_memory_order_relaxed); \ + newValue = (ma_uint##sizeInBits)(oldValue | src); \ + } while (ma_atomic_compare_and_swap_##sizeInBits(dst, oldValue, newValue) != oldValue); \ + (void)order; \ + return oldValue +#define MA_ATOMIC_FETCH_XOR_CAS(sizeInBits, dst, src, order) \ + ma_uint##sizeInBits oldValue; \ + ma_uint##sizeInBits newValue; \ + do { \ + oldValue = ma_atomic_load_explicit_##sizeInBits(dst, ma_atomic_memory_order_relaxed); \ + newValue = (ma_uint##sizeInBits)(oldValue ^ src); \ + } while (ma_atomic_compare_and_swap_##sizeInBits(dst, oldValue, newValue) != oldValue); \ + (void)order; \ + return oldValue +#if defined(MA_ATOMIC_MODERN_MSVC) || defined(MA_ATOMIC_LEGACY_MSVC) + #define MA_ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, expected, replacement, order, intrin, ma_atomicType, msvcType) \ ma_atomicType result; \ switch (order) \ { \ case ma_atomic_memory_order_relaxed: \ { \ - result = (ma_atomicType)intrin##_nf((volatile msvcType*)ptr, (msvcType)expected, (msvcType)desired); \ + result = (ma_atomicType)intrin##_nf((volatile msvcType*)ptr, (msvcType)expected, (msvcType)replacement); \ } break; \ case ma_atomic_memory_order_consume: \ case ma_atomic_memory_order_acquire: \ { \ - result = (ma_atomicType)intrin##_acq((volatile msvcType*)ptr, (msvcType)expected, (msvcType)desired); \ + result = (ma_atomicType)intrin##_acq((volatile msvcType*)ptr, (msvcType)expected, (msvcType)replacement); \ } break; \ case ma_atomic_memory_order_release: \ { \ - result = (ma_atomicType)intrin##_rel((volatile msvcType*)ptr, (msvcType)expected, (msvcType)desired); \ + result = (ma_atomicType)intrin##_rel((volatile msvcType*)ptr, (msvcType)expected, (msvcType)replacement); \ } break; \ case ma_atomic_memory_order_acq_rel: \ case ma_atomic_memory_order_seq_cst: \ default: \ { \ - result = (ma_atomicType)intrin((volatile msvcType*)ptr, (msvcType)expected, (msvcType)desired); \ + result = (ma_atomicType)intrin((volatile msvcType*)ptr, (msvcType)expected, (msvcType)replacement); \ } break; \ } \ return result; - #define ma_atomic_memory_order_relaxed 0 - #define ma_atomic_memory_order_consume 1 - #define ma_atomic_memory_order_acquire 2 - #define ma_atomic_memory_order_release 3 - #define ma_atomic_memory_order_acq_rel 4 - #define ma_atomic_memory_order_seq_cst 5 - #if _MSC_VER < 1600 && defined(MA_X86) - #define MA_ATOMIC_MSVC_USE_INLINED_ASSEMBLY - #endif - #if _MSC_VER < 1600 - #undef MA_ATOMIC_HAS_8 - #undef MA_ATOMIC_HAS_16 - #endif - #if !defined(MA_ATOMIC_MSVC_USE_INLINED_ASSEMBLY) - #include - #endif - #if defined(MA_ATOMIC_MSVC_USE_INLINED_ASSEMBLY) - #if defined(MA_ATOMIC_HAS_8) - static MA_INLINE ma_uint8 __stdcall ma_atomic_compare_and_swap_8(volatile ma_uint8* dst, ma_uint8 expected, ma_uint8 desired) - { - ma_uint8 result = 0; - __asm { - mov ecx, dst - mov al, expected - mov dl, desired - lock cmpxchg [ecx], dl - mov result, al - } - return result; - } - #endif - #if defined(MA_ATOMIC_HAS_16) - static MA_INLINE ma_uint16 __stdcall ma_atomic_compare_and_swap_16(volatile ma_uint16* dst, ma_uint16 expected, ma_uint16 desired) - { - ma_uint16 result = 0; - __asm { - mov ecx, dst - mov ax, expected - mov dx, desired - lock cmpxchg [ecx], dx - mov result, ax - } - return result; - } - #endif - #if defined(MA_ATOMIC_HAS_32) - static MA_INLINE ma_uint32 __stdcall ma_atomic_compare_and_swap_32(volatile ma_uint32* dst, ma_uint32 expected, ma_uint32 desired) - { - ma_uint32 result = 0; - __asm { - mov ecx, dst - mov eax, expected - mov edx, desired - lock cmpxchg [ecx], edx - mov result, eax - } - return result; - } - #endif - #if defined(MA_ATOMIC_HAS_64) - static MA_INLINE ma_uint64 __stdcall ma_atomic_compare_and_swap_64(volatile ma_uint64* dst, ma_uint64 expected, ma_uint64 desired) - { - ma_uint32 resultEAX = 0; - ma_uint32 resultEDX = 0; - __asm { - mov esi, dst - mov eax, dword ptr expected - mov edx, dword ptr expected + 4 - mov ebx, dword ptr desired - mov ecx, dword ptr desired + 4 - lock cmpxchg8b qword ptr [esi] - mov resultEAX, eax - mov resultEDX, edx - } - return ((ma_uint64)resultEDX << 32) | resultEAX; - } - #endif + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) + #define ma_atomic_compare_and_swap_8( dst, expected, replacement) (ma_uint8 )_InterlockedCompareExchange8((volatile char*)dst, (char)replacement, (char)expected) #else - #if defined(MA_ATOMIC_HAS_8) - #define ma_atomic_compare_and_swap_8( dst, expected, desired) (ma_uint8 )_InterlockedCompareExchange8((volatile char*)dst, (char)desired, (char)expected) - #endif - #if defined(MA_ATOMIC_HAS_16) - #define ma_atomic_compare_and_swap_16(dst, expected, desired) (ma_uint16)_InterlockedCompareExchange16((volatile short*)dst, (short)desired, (short)expected) - #endif - #if defined(MA_ATOMIC_HAS_32) - #define ma_atomic_compare_and_swap_32(dst, expected, desired) (ma_uint32)_InterlockedCompareExchange((volatile long*)dst, (long)desired, (long)expected) - #endif - #if defined(MA_ATOMIC_HAS_64) - #define ma_atomic_compare_and_swap_64(dst, expected, desired) (ma_uint64)_InterlockedCompareExchange64((volatile ma_int64*)dst, (ma_int64)desired, (ma_int64)expected) - #endif + static MA_INLINE ma_uint8 __stdcall ma_atomic_compare_and_swap_8(volatile ma_uint8* dst, ma_uint8 expected, ma_uint8 replacement) + { + MA_ATOMIC_COMPARE_AND_SWAP_LOCK(8, dst, expected, replacement); + } #endif - #if defined(MA_ATOMIC_MSVC_USE_INLINED_ASSEMBLY) - #if defined(MA_ATOMIC_HAS_8) - static MA_INLINE ma_uint8 __stdcall ma_atomic_exchange_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) - { - ma_uint8 result = 0; - (void)order; - __asm { - mov ecx, dst - mov al, src - lock xchg [ecx], al - mov result, al - } - return result; - } - #endif - #if defined(MA_ATOMIC_HAS_16) - static MA_INLINE ma_uint16 __stdcall ma_atomic_exchange_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) - { - ma_uint16 result = 0; - (void)order; - __asm { - mov ecx, dst - mov ax, src - lock xchg [ecx], ax - mov result, ax - } - return result; - } - #endif - #if defined(MA_ATOMIC_HAS_32) - static MA_INLINE ma_uint32 __stdcall ma_atomic_exchange_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) - { - ma_uint32 result = 0; - (void)order; - __asm { - mov ecx, dst - mov eax, src - lock xchg [ecx], eax - mov result, eax - } - return result; - } - #endif + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) + #define ma_atomic_compare_and_swap_16(dst, expected, replacement) (ma_uint16)_InterlockedCompareExchange16((volatile short*)dst, (short)replacement, (short)expected) #else - #if defined(MA_ATOMIC_HAS_8) - static MA_INLINE ma_uint8 __stdcall ma_atomic_exchange_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) - { + static MA_INLINE ma_uint16 __stdcall ma_atomic_compare_and_swap_16(volatile ma_uint16* dst, ma_uint16 expected, ma_uint16 replacement) + { + MA_ATOMIC_COMPARE_AND_SWAP_LOCK(16, dst, expected, replacement); + } + #endif + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + #define ma_atomic_compare_and_swap_32(dst, expected, replacement) (ma_uint32)_InterlockedCompareExchange((volatile long*)dst, (long)replacement, (long)expected) + #else + static MA_INLINE ma_uint32 __stdcall ma_atomic_compare_and_swap_32(volatile ma_uint32* dst, ma_uint32 expected, ma_uint32 replacement) + { + MA_ATOMIC_COMPARE_AND_SWAP_LOCK(32, dst, expected, replacement); + } + #endif + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + #define ma_atomic_compare_and_swap_64(dst, expected, replacement) (ma_uint64)_InterlockedCompareExchange64((volatile ma_int64*)dst, (ma_int64)replacement, (ma_int64)expected) + #else + static MA_INLINE ma_uint64 __stdcall ma_atomic_compare_and_swap_64(volatile ma_uint64* dst, ma_uint64 expected, ma_uint64 replacement) + { + MA_ATOMIC_COMPARE_AND_SWAP_LOCK(64, dst, expected, replacement); + } + #endif + static MA_INLINE ma_uint8 ma_atomic_load_explicit_8(volatile const ma_uint8* ptr, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) + { #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchange8, ma_uint8, char); + { + MA_ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, 0, 0, order, _InterlockedCompareExchange8, ma_uint8, char); + } #else + { + (void)order; + return ma_atomic_compare_and_swap_8((volatile ma_uint8*)ptr, 0, 0); + } + #endif + } + #else + { + MA_ATOMIC_LOAD_EXPLICIT_LOCK(8, ptr, order); + } + #endif + } + static MA_INLINE ma_uint16 ma_atomic_load_explicit_16(volatile const ma_uint16* ptr, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, 0, 0, order, _InterlockedCompareExchange16, ma_uint16, short); + } + #else + { + (void)order; + return ma_atomic_compare_and_swap_16((volatile ma_uint16*)ptr, 0, 0); + } + #endif + } + #else + { + MA_ATOMIC_LOAD_EXPLICIT_LOCK(16, ptr, order); + } + #endif + } + static MA_INLINE ma_uint32 ma_atomic_load_explicit_32(volatile const ma_uint32* ptr, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, 0, 0, order, _InterlockedCompareExchange, ma_uint32, long); + } + #else + { + (void)order; + return ma_atomic_compare_and_swap_32((volatile ma_uint32*)ptr, 0, 0); + } + #endif + } + #else + { + MA_ATOMIC_LOAD_EXPLICIT_LOCK(32, ptr, order); + } + #endif + } + static MA_INLINE ma_uint64 ma_atomic_load_explicit_64(volatile const ma_uint64* ptr, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, 0, 0, order, _InterlockedCompareExchange64, ma_uint64, long long); + } + #else + { + (void)order; + return ma_atomic_compare_and_swap_64((volatile ma_uint64*)ptr, 0, 0); + } + #endif + } + #else + { + MA_ATOMIC_LOAD_EXPLICIT_LOCK(64, ptr, order); + } + #endif + } + static MA_INLINE ma_uint8 __stdcall ma_atomic_exchange_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchange8, ma_uint8, char); + } + #else + { (void)order; return (ma_uint8)_InterlockedExchange8((volatile char*)dst, (char)src); - #endif } + #endif + } + #else + { + MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(8, dst, src, order); + } #endif - #if defined(MA_ATOMIC_HAS_16) - static MA_INLINE ma_uint16 __stdcall ma_atomic_exchange_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) - { + } + static MA_INLINE ma_uint16 __stdcall ma_atomic_exchange_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) + { #if defined(MA_ARM) + { MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchange16, ma_uint16, short); + } #else + { (void)order; return (ma_uint16)_InterlockedExchange16((volatile short*)dst, (short)src); - #endif } + #endif + } + #else + { + MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(16, dst, src, order); + } #endif - #if defined(MA_ATOMIC_HAS_32) - static MA_INLINE ma_uint32 __stdcall ma_atomic_exchange_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) - { + } + static MA_INLINE ma_uint32 __stdcall ma_atomic_exchange_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + { #if defined(MA_ARM) + { MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchange, ma_uint32, long); + } #else + { (void)order; return (ma_uint32)_InterlockedExchange((volatile long*)dst, (long)src); - #endif } - #endif - #if defined(MA_ATOMIC_HAS_64) && defined(MA_64BIT) - static MA_INLINE ma_uint64 __stdcall ma_atomic_exchange_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) - { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchange64, ma_uint64, long long); - #else - (void)order; - return (ma_uint64)_InterlockedExchange64((volatile long long*)dst, (long long)src); #endif - } - #else - #endif - #endif - #if defined(MA_ATOMIC_HAS_64) && !defined(MA_64BIT) - static MA_INLINE ma_uint64 __stdcall ma_atomic_exchange_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) - { - ma_uint64 oldValue; - do { - oldValue = *dst; - } while (ma_atomic_compare_and_swap_64(dst, oldValue, src) != oldValue); - (void)order; - return oldValue; } - #endif - #if defined(MA_ATOMIC_MSVC_USE_INLINED_ASSEMBLY) - #if defined(MA_ATOMIC_HAS_8) - static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_add_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) - { - ma_uint8 result = 0; - (void)order; - __asm { - mov ecx, dst - mov al, src - lock xadd [ecx], al - mov result, al - } - return result; - } + #else + { + MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(32, dst, src, order); + } #endif - #if defined(MA_ATOMIC_HAS_16) - static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_add_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + } + static MA_INLINE ma_uint64 __stdcall ma_atomic_exchange_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) + { + #if defined(MA_32BIT) { - ma_uint16 result = 0; - (void)order; - __asm { - mov ecx, dst - mov ax, src - lock xadd [ecx], ax - mov result, ax - } - return result; + MA_ATOMIC_EXCHANGE_EXPLICIT_CAS(64, dst, src, order); } - #endif - #if defined(MA_ATOMIC_HAS_32) - static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_add_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) - { - ma_uint32 result = 0; - (void)order; - __asm { - mov ecx, dst - mov eax, src - lock xadd [ecx], eax - mov result, eax - } - return result; - } - #endif - #else - #if defined(MA_ATOMIC_HAS_8) - static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_add_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) - { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchangeAdd8, ma_uint8, char); #else + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchange64, ma_uint64, long long); + } + #else + { + (void)order; + return (ma_uint64)_InterlockedExchange64((volatile long long*)dst, (long long)src); + } + #endif + } + #endif + } + #else + { + MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(64, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_add_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchangeAdd8, ma_uint8, char); + } + #else + { (void)order; return (ma_uint8)_InterlockedExchangeAdd8((volatile char*)dst, (char)src); - #endif } + #endif + } + #else + { + MA_ATOMIC_FETCH_ADD_LOCK(8, dst, src, order); + } #endif - #if defined(MA_ATOMIC_HAS_16) - static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_add_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) - { + } + static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_add_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) + { #if defined(MA_ARM) + { MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchangeAdd16, ma_uint16, short); + } #else + { (void)order; return (ma_uint16)_InterlockedExchangeAdd16((volatile short*)dst, (short)src); - #endif } + #endif + } + #else + { + MA_ATOMIC_FETCH_ADD_LOCK(16, dst, src, order); + } #endif - #if defined(MA_ATOMIC_HAS_32) - static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_add_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) - { + } + static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_add_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + { #if defined(MA_ARM) + { MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchangeAdd, ma_uint32, long); + } #else + { (void)order; return (ma_uint32)_InterlockedExchangeAdd((volatile long*)dst, (long)src); - #endif } - #endif - #if defined(MA_ATOMIC_HAS_64) && defined(MA_64BIT) - static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_add_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) - { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchangeAdd64, ma_uint64, long long); - #else - (void)order; - return (ma_uint64)_InterlockedExchangeAdd64((volatile long long*)dst, (long long)src); #endif - } + } #else - #endif - #endif - #if defined(MA_ATOMIC_HAS_64) && !defined(MA_64BIT) - static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_add_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) { - ma_uint64 oldValue; - ma_uint64 newValue; - do { - oldValue = *dst; - newValue = oldValue + src; - } while (ma_atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; + MA_ATOMIC_FETCH_ADD_LOCK(32, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_add_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) + { + #if defined(MA_32BIT) + { + MA_ATOMIC_FETCH_ADD_CAS(64, dst, src, order); + } + #else + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchangeAdd64, ma_uint64, long long); + } + #else + { + (void)order; + return (ma_uint64)_InterlockedExchangeAdd64((volatile long long*)dst, (long long)src); + } + #endif + } + #endif + } + #else + { + MA_ATOMIC_FETCH_ADD_LOCK(64, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_sub_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + return ma_atomic_fetch_add_explicit_8(dst, (ma_uint8)(-(ma_int8)src), order); + } + static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_sub_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + return ma_atomic_fetch_add_explicit_16(dst, (ma_uint16)(-(ma_int16)src), order); + } + static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_sub_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + return ma_atomic_fetch_add_explicit_32(dst, (ma_uint32)(-(ma_int32)src), order); + } + static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_sub_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + return ma_atomic_fetch_add_explicit_64(dst, (ma_uint64)(-(ma_int64)src), order); + } + static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_and_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedAnd8, ma_uint8, char); + } + #else + { + MA_ATOMIC_FETCH_AND_CAS(8, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_and_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedAnd16, ma_uint16, short); + } + #else + { + MA_ATOMIC_FETCH_AND_CAS(16, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_and_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedAnd, ma_uint32, long); + } + #else + { + MA_ATOMIC_FETCH_AND_CAS(32, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_and_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedAnd64, ma_uint64, long long); + } + #else + { + MA_ATOMIC_FETCH_AND_CAS(64, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_or_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedOr8, ma_uint8, char); + } + #else + { + MA_ATOMIC_FETCH_OR_CAS(8, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_or_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedOr16, ma_uint16, short); + } + #else + { + MA_ATOMIC_FETCH_OR_CAS(16, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_or_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedOr, ma_uint32, long); + } + #else + { + MA_ATOMIC_FETCH_OR_CAS(32, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_or_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedOr64, ma_uint64, long long); + } + #else + { + MA_ATOMIC_FETCH_OR_CAS(64, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_xor_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedXor8, ma_uint8, char); + } + #else + { + MA_ATOMIC_FETCH_XOR_CAS(8, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_xor_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedXor16, ma_uint16, short); + } + #else + { + MA_ATOMIC_FETCH_XOR_CAS(16, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_xor_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedXor, ma_uint32, long); + } + #else + { + MA_ATOMIC_FETCH_XOR_CAS(32, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_xor_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedXor64, ma_uint64, long long); + } + #else + { + MA_ATOMIC_FETCH_XOR_CAS(64, dst, src, order); + } + #endif + } + #define ma_atomic_store_explicit_8( dst, src, order) (void)ma_atomic_exchange_explicit_8 (dst, src, order) + #define ma_atomic_store_explicit_16(dst, src, order) (void)ma_atomic_exchange_explicit_16(dst, src, order) + #define ma_atomic_store_explicit_32(dst, src, order) (void)ma_atomic_exchange_explicit_32(dst, src, order) + #define ma_atomic_store_explicit_64(dst, src, order) (void)ma_atomic_exchange_explicit_64(dst, src, order) + #if defined(MA_X64) + #define ma_atomic_thread_fence(order) __faststorefence(), (void)order + #elif defined(MA_ARM64) + #define ma_atomic_thread_fence(order) __dmb(_ARM64_BARRIER_ISH), (void)order + #else + static MA_INLINE void ma_atomic_thread_fence(ma_atomic_memory_order order) + { + volatile ma_uint32 barrier = 0; + ma_atomic_fetch_add_explicit_32(&barrier, 0, order); } #endif - #if defined(MA_ATOMIC_MSVC_USE_INLINED_ASSEMBLY) - static MA_INLINE void __stdcall ma_atomic_thread_fence(ma_atomic_memory_order order) + #define ma_atomic_signal_fence(order) _ReadWriteBarrier(), (void)order +#endif +#if defined(MA_ATOMIC_LEGACY_MSVC_ASM) + static MA_INLINE ma_uint8 __stdcall ma_atomic_compare_and_swap_8(volatile ma_uint8* dst, ma_uint8 expected, ma_uint8 replacement) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) { + ma_uint8 result = 0; + __asm { + mov ecx, dst + mov al, expected + mov dl, replacement + lock cmpxchg [ecx], dl + mov result, al + } + return result; + } + #else + { + MA_ATOMIC_COMPARE_AND_SWAP_LOCK(8, dst, expected, replacement); + } + #endif + } + static MA_INLINE ma_uint16 __stdcall ma_atomic_compare_and_swap_16(volatile ma_uint16* dst, ma_uint16 expected, ma_uint16 replacement) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) + { + ma_uint16 result = 0; + __asm { + mov ecx, dst + mov ax, expected + mov dx, replacement + lock cmpxchg [ecx], dx + mov result, ax + } + return result; + } + #else + { + MA_ATOMIC_COMPARE_AND_SWAP_LOCK(16, dst, expected, replacement); + } + #endif + } + static MA_INLINE ma_uint32 __stdcall ma_atomic_compare_and_swap_32(volatile ma_uint32* dst, ma_uint32 expected, ma_uint32 replacement) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + { + ma_uint32 result = 0; + __asm { + mov ecx, dst + mov eax, expected + mov edx, replacement + lock cmpxchg [ecx], edx + mov result, eax + } + return result; + } + #else + { + MA_ATOMIC_COMPARE_AND_SWAP_LOCK(32, dst, expected, replacement); + } + #endif + } + static MA_INLINE ma_uint64 __stdcall ma_atomic_compare_and_swap_64(volatile ma_uint64* dst, ma_uint64 expected, ma_uint64 replacement) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) + { + ma_uint32 resultEAX = 0; + ma_uint32 resultEDX = 0; + __asm { + mov esi, dst + mov eax, dword ptr expected + mov edx, dword ptr expected + 4 + mov ebx, dword ptr replacement + mov ecx, dword ptr replacement + 4 + lock cmpxchg8b qword ptr [esi] + mov resultEAX, eax + mov resultEDX, edx + } + return ((ma_uint64)resultEDX << 32) | resultEAX; + } + #else + { + MA_ATOMIC_COMPARE_AND_SWAP_LOCK(64, dst, expected, replacement); + } + #endif + } + static MA_INLINE ma_uint8 ma_atomic_load_explicit_8(volatile const ma_uint8* dst, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) + { + ma_uint8 result = 0; + if (order == ma_atomic_memory_order_relaxed) { + __asm { + mov esi, dst + mov al, [esi] + mov result, al + } + } else if (order <= ma_atomic_memory_order_release) { + __asm { + mov esi, dst + mov al, [esi] + lock add dword ptr [esp], 0 + mov result, al + } + } else { + __asm { + lock add dword ptr [esp], 0 + mov esi, dst + mov al, [esi] + mov result, al + lock add dword ptr [esp], 0 + } + } + return result; + } + #else + { + MA_ATOMIC_LOAD_EXPLICIT_LOCK(8, dst, order); + } + #endif + } + static MA_INLINE ma_uint16 ma_atomic_load_explicit_16(volatile const ma_uint16* dst, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) + { + ma_uint16 result = 0; + if (order == ma_atomic_memory_order_relaxed) { + __asm { + mov esi, dst + mov ax, [esi] + mov result, ax + } + } else if (order <= ma_atomic_memory_order_release) { + __asm { + mov esi, dst + mov ax, [esi] + lock add dword ptr [esp], 0 + mov result, ax + } + } else { + __asm { + lock add dword ptr [esp], 0 + mov esi, dst + mov ax, [esi] + mov result, ax + lock add dword ptr [esp], 0 + } + } + return result; + } + #else + { + MA_ATOMIC_LOAD_EXPLICIT_LOCK(16, dst, order); + } + #endif + } + static MA_INLINE ma_uint32 ma_atomic_load_explicit_32(volatile const ma_uint32* dst, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + { + ma_uint32 result = 0; + if (order == ma_atomic_memory_order_relaxed) { + __asm { + mov esi, dst + mov eax, [esi] + mov result, eax + } + } else if (order <= ma_atomic_memory_order_release) { + __asm { + mov esi, dst + mov eax, [esi] + lock add dword ptr [esp], 0 + mov result, eax + } + } else { + __asm { + lock add dword ptr [esp], 0 + mov esi, dst + mov eax, [esi] + mov result, eax + lock add dword ptr [esp], 0 + } + } + return result; + } + #else + { + MA_ATOMIC_LOAD_EXPLICIT_LOCK(32, dst, order); + } + #endif + } + static MA_INLINE ma_uint64 ma_atomic_load_explicit_64(volatile const ma_uint64* dst, ma_atomic_memory_order order) + { + (void)order; + return ma_atomic_compare_and_swap_64((volatile ma_uint64*)dst, 0, 0); + } + static MA_INLINE void __stdcall ma_atomic_store_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + if (order == ma_atomic_memory_order_relaxed) { + __asm { + mov esi, dst + mov al, src + mov [esi], al + } + } else { + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) + { + __asm { + mov esi, dst + mov al, src + xchg [esi], al + } + } + #else + { + MA_ATOMIC_STORE_EXPLICIT_LOCK(8, dst, src, order); + } + #endif + } + } + static MA_INLINE void __stdcall ma_atomic_store_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + if (order == ma_atomic_memory_order_relaxed) { + __asm { + mov esi, dst + mov ax, src + mov [esi], ax + } + } else { + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) + { + __asm { + mov esi, dst + mov ax, src + xchg [esi], ax + } + } + #else + { + MA_ATOMIC_STORE_EXPLICIT_LOCK(16, dst, src, order); + } + #endif + } + } + static MA_INLINE void __stdcall ma_atomic_store_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + if (order == ma_atomic_memory_order_relaxed) { + __asm { + mov esi, dst + mov eax, src + mov [esi], eax + } + } else { + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + { + __asm { + mov esi, dst + mov eax, src + xchg [esi], eax + } + } + #else + { + MA_ATOMIC_STORE_EXPLICIT_LOCK(32, dst, src, order); + } + #endif + } + } + static MA_INLINE void __stdcall ma_atomic_store_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) + { + MA_ATOMIC_STORE_EXPLICIT_CAS(64, dst, src, order); + } + #else + { + MA_ATOMIC_STORE_EXPLICIT_LOCK(64, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint8 __stdcall ma_atomic_exchange_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) + { + ma_uint8 result = 0; (void)order; __asm { - lock add [esp], 0 + mov ecx, dst + mov al, src + lock xchg [ecx], al + mov result, al } + return result; } - #else - #if defined(MA_X64) - #define ma_atomic_thread_fence(order) __faststorefence(), (void)order - #elif defined(MA_ARM64) - #define ma_atomic_thread_fence(order) __dmb(_ARM64_BARRIER_ISH), (void)order #else - static MA_INLINE void ma_atomic_thread_fence(ma_atomic_memory_order order) - { - volatile ma_uint32 barrier = 0; - ma_atomic_fetch_add_explicit_32(&barrier, 0, order); + { + MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(8, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint16 __stdcall ma_atomic_exchange_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) + { + ma_uint16 result = 0; + (void)order; + __asm { + mov ecx, dst + mov ax, src + lock xchg [ecx], ax + mov result, ax } - #endif - #endif - #define ma_atomic_compiler_fence() ma_atomic_thread_fence(ma_atomic_memory_order_seq_cst) - #define ma_atomic_signal_fence(order) ma_atomic_thread_fence(order) - #if defined(MA_ATOMIC_HAS_8) - static MA_INLINE ma_uint8 ma_atomic_load_explicit_8(volatile const ma_uint8* ptr, ma_atomic_memory_order order) - { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, 0, 0, order, _InterlockedCompareExchange8, ma_uint8, char); + return result; + } #else - (void)order; - return ma_atomic_compare_and_swap_8((volatile ma_uint8*)ptr, 0, 0); - #endif - } - #endif - #if defined(MA_ATOMIC_HAS_16) - static MA_INLINE ma_uint16 ma_atomic_load_explicit_16(volatile const ma_uint16* ptr, ma_atomic_memory_order order) { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, 0, 0, order, _InterlockedCompareExchange16, ma_uint16, short); + MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(16, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint32 __stdcall ma_atomic_exchange_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + { + ma_uint32 result = 0; + (void)order; + __asm { + mov ecx, dst + mov eax, src + xchg [ecx], eax + mov result, eax + } + return result; + } #else - (void)order; - return ma_atomic_compare_and_swap_16((volatile ma_uint16*)ptr, 0, 0); - #endif - } - #endif - #if defined(MA_ATOMIC_HAS_32) - static MA_INLINE ma_uint32 ma_atomic_load_explicit_32(volatile const ma_uint32* ptr, ma_atomic_memory_order order) { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, 0, 0, order, _InterlockedCompareExchange, ma_uint32, long); + MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(32, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint64 __stdcall ma_atomic_exchange_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) + { + MA_ATOMIC_EXCHANGE_EXPLICIT_CAS(64, dst, src, order); + } #else - (void)order; - return ma_atomic_compare_and_swap_32((volatile ma_uint32*)ptr, 0, 0); - #endif - } - #endif - #if defined(MA_ATOMIC_HAS_64) - static MA_INLINE ma_uint64 ma_atomic_load_explicit_64(volatile const ma_uint64* ptr, ma_atomic_memory_order order) { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, 0, 0, order, _InterlockedCompareExchange64, ma_uint64, long long); + MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(64, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_add_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) + { + ma_uint8 result = 0; + (void)order; + __asm { + mov ecx, dst + mov al, src + lock xadd [ecx], al + mov result, al + } + return result; + } #else - (void)order; - return ma_atomic_compare_and_swap_64((volatile ma_uint64*)ptr, 0, 0); + { + MA_ATOMIC_FETCH_ADD_LOCK(8, dst, src, order); + } #endif - } - #endif - #if defined(MA_ATOMIC_HAS_8) - #define ma_atomic_store_explicit_8( dst, src, order) (void)ma_atomic_exchange_explicit_8 (dst, src, order) - #endif - #if defined(MA_ATOMIC_HAS_16) - #define ma_atomic_store_explicit_16(dst, src, order) (void)ma_atomic_exchange_explicit_16(dst, src, order) - #endif - #if defined(MA_ATOMIC_HAS_32) - #define ma_atomic_store_explicit_32(dst, src, order) (void)ma_atomic_exchange_explicit_32(dst, src, order) - #endif - #if defined(MA_ATOMIC_HAS_64) - #define ma_atomic_store_explicit_64(dst, src, order) (void)ma_atomic_exchange_explicit_64(dst, src, order) - #endif - #if defined(MA_ATOMIC_HAS_8) - static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_sub_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + } + static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_add_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) { - ma_uint8 oldValue; - ma_uint8 newValue; - do { - oldValue = *dst; - newValue = (ma_uint8)(oldValue - src); - } while (ma_atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); + ma_uint16 result = 0; (void)order; - return oldValue; + __asm { + mov ecx, dst + mov ax, src + lock xadd [ecx], ax + mov result, ax + } + return result; } - #endif - #if defined(MA_ATOMIC_HAS_16) - static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_sub_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) - { - ma_uint16 oldValue; - ma_uint16 newValue; - do { - oldValue = *dst; - newValue = (ma_uint16)(oldValue - src); - } while (ma_atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; - } - #endif - #if defined(MA_ATOMIC_HAS_32) - static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_sub_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) - { - ma_uint32 oldValue; - ma_uint32 newValue; - do { - oldValue = *dst; - newValue = oldValue - src; - } while (ma_atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; - } - #endif - #if defined(MA_ATOMIC_HAS_64) - static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_sub_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) - { - ma_uint64 oldValue; - ma_uint64 newValue; - do { - oldValue = *dst; - newValue = oldValue - src; - } while (ma_atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; - } - #endif - #if defined(MA_ATOMIC_HAS_8) - static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_and_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) - { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedAnd8, ma_uint8, char); #else - ma_uint8 oldValue; - ma_uint8 newValue; - do { - oldValue = *dst; - newValue = (ma_uint8)(oldValue & src); - } while (ma_atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; - #endif - } - #endif - #if defined(MA_ATOMIC_HAS_16) - static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_and_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedAnd16, ma_uint16, short); - #else - ma_uint16 oldValue; - ma_uint16 newValue; - do { - oldValue = *dst; - newValue = (ma_uint16)(oldValue & src); - } while (ma_atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; - #endif + MA_ATOMIC_FETCH_ADD_LOCK(16, dst, src, order); } - #endif - #if defined(MA_ATOMIC_HAS_32) - static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_and_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + #endif + } + static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_add_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedAnd, ma_uint32, long); - #else - ma_uint32 oldValue; - ma_uint32 newValue; - do { - oldValue = *dst; - newValue = oldValue & src; - } while (ma_atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); + ma_uint32 result = 0; (void)order; - return oldValue; - #endif + __asm { + mov ecx, dst + mov eax, src + lock xadd [ecx], eax + mov result, eax + } + return result; } - #endif - #if defined(MA_ATOMIC_HAS_64) - static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_and_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + #else { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedAnd64, ma_uint64, long long); - #else - ma_uint64 oldValue; - ma_uint64 newValue; - do { - oldValue = *dst; - newValue = oldValue & src; - } while (ma_atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; - #endif + MA_ATOMIC_FETCH_ADD_LOCK(32, dst, src, order); } - #endif - #if defined(MA_ATOMIC_HAS_8) - static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_xor_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + #endif + } + static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_add_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedXor8, ma_uint8, char); - #else - ma_uint8 oldValue; - ma_uint8 newValue; - do { - oldValue = *dst; - newValue = (ma_uint8)(oldValue ^ src); - } while (ma_atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; - #endif + MA_ATOMIC_FETCH_ADD_CAS(64, dst, src, order); } - #endif - #if defined(MA_ATOMIC_HAS_16) - static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_xor_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + #else { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedXor16, ma_uint16, short); - #else - ma_uint16 oldValue; - ma_uint16 newValue; - do { - oldValue = *dst; - newValue = (ma_uint16)(oldValue ^ src); - } while (ma_atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; - #endif + MA_ATOMIC_FETCH_ADD_LOCK(64, dst, src, order); } - #endif - #if defined(MA_ATOMIC_HAS_32) - static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_xor_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + #endif + } + static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_sub_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedXor, ma_uint32, long); - #else - ma_uint32 oldValue; - ma_uint32 newValue; - do { - oldValue = *dst; - newValue = oldValue ^ src; - } while (ma_atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); + ma_uint8 result = 0; (void)order; - return oldValue; - #endif + __asm { + mov ecx, dst + mov al, src + neg al + lock xadd [ecx], al + mov result, al + } + return result; } - #endif - #if defined(MA_ATOMIC_HAS_64) - static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_xor_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + #else { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedXor64, ma_uint64, long long); - #else - ma_uint64 oldValue; - ma_uint64 newValue; - do { - oldValue = *dst; - newValue = oldValue ^ src; - } while (ma_atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; - #endif + MA_ATOMIC_FETCH_ADD_LOCK(8, dst, (ma_uint8)(-(ma_int8)src), order); } - #endif - #if defined(MA_ATOMIC_HAS_8) - static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_or_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + #endif + } + static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_sub_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedOr8, ma_uint8, char); - #else - ma_uint8 oldValue; - ma_uint8 newValue; - do { - oldValue = *dst; - newValue = (ma_uint8)(oldValue | src); - } while (ma_atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); + ma_uint16 result = 0; (void)order; - return oldValue; - #endif + __asm { + mov ecx, dst + mov ax, src + neg ax + lock xadd [ecx], ax + mov result, ax + } + return result; } - #endif - #if defined(MA_ATOMIC_HAS_16) - static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_or_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + #else { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedOr16, ma_uint16, short); - #else - ma_uint16 oldValue; - ma_uint16 newValue; - do { - oldValue = *dst; - newValue = (ma_uint16)(oldValue | src); - } while (ma_atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; - #endif + MA_ATOMIC_FETCH_ADD_LOCK(16, dst, (ma_uint16)(-(ma_int16)src), order); } - #endif - #if defined(MA_ATOMIC_HAS_32) - static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_or_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + #endif + } + static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_sub_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedOr, ma_uint32, long); - #else - ma_uint32 oldValue; - ma_uint32 newValue; - do { - oldValue = *dst; - newValue = oldValue | src; - } while (ma_atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); + ma_uint32 result = 0; (void)order; - return oldValue; - #endif + __asm { + mov ecx, dst + mov eax, src + neg eax + lock xadd [ecx], eax + mov result, eax + } + return result; } - #endif - #if defined(MA_ATOMIC_HAS_64) - static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_or_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + #else { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedOr64, ma_uint64, long long); - #else - ma_uint64 oldValue; - ma_uint64 newValue; - do { - oldValue = *dst; - newValue = oldValue | src; - } while (ma_atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; - #endif + MA_ATOMIC_FETCH_ADD_LOCK(32, dst, (ma_uint32)(-(ma_int32)src), order); } - #endif - #if defined(MA_ATOMIC_HAS_8) - #define ma_atomic_test_and_set_explicit_8( dst, order) ma_atomic_exchange_explicit_8 (dst, 1, order) - #endif - #if defined(MA_ATOMIC_HAS_16) - #define ma_atomic_test_and_set_explicit_16(dst, order) ma_atomic_exchange_explicit_16(dst, 1, order) - #endif - #if defined(MA_ATOMIC_HAS_32) - #define ma_atomic_test_and_set_explicit_32(dst, order) ma_atomic_exchange_explicit_32(dst, 1, order) - #endif - #if defined(MA_ATOMIC_HAS_64) - #define ma_atomic_test_and_set_explicit_64(dst, order) ma_atomic_exchange_explicit_64(dst, 1, order) - #endif - #if defined(MA_ATOMIC_HAS_8) - #define ma_atomic_clear_explicit_8( dst, order) ma_atomic_store_explicit_8 (dst, 0, order) - #endif - #if defined(MA_ATOMIC_HAS_16) - #define ma_atomic_clear_explicit_16(dst, order) ma_atomic_store_explicit_16(dst, 0, order) - #endif - #if defined(MA_ATOMIC_HAS_32) - #define ma_atomic_clear_explicit_32(dst, order) ma_atomic_store_explicit_32(dst, 0, order) - #endif - #if defined(MA_ATOMIC_HAS_64) - #define ma_atomic_clear_explicit_64(dst, order) ma_atomic_store_explicit_64(dst, 0, order) - #endif - #if defined(MA_ATOMIC_HAS_8) - typedef ma_uint8 ma_atomic_flag; - #define ma_atomic_flag_test_and_set_explicit(ptr, order) (ma_bool32)ma_atomic_test_and_set_explicit_8(ptr, order) - #define ma_atomic_flag_clear_explicit(ptr, order) ma_atomic_clear_explicit_8(ptr, order) - #define ma_atomic_flag_load_explicit(ptr, order) ma_atomic_load_explicit_8(ptr, order) - #else - typedef ma_uint32 ma_atomic_flag; - #define ma_atomic_flag_test_and_set_explicit(ptr, order) (ma_bool32)ma_atomic_test_and_set_explicit_32(ptr, order) - #define ma_atomic_flag_clear_explicit(ptr, order) ma_atomic_clear_explicit_32(ptr, order) - #define ma_atomic_flag_load_explicit(ptr, order) ma_atomic_load_explicit_32(ptr, order) - #endif -#elif defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))) + #endif + } + static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_sub_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_ADD_CAS(64, dst, (ma_uint64)(-(ma_int64)src), order); + } + static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_and_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_AND_CAS(8, dst, src, order); + } + static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_and_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_AND_CAS(16, dst, src, order); + } + static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_and_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_AND_CAS(32, dst, src, order); + } + static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_and_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_AND_CAS(64, dst, src, order); + } + static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_or_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_OR_CAS(8, dst, src, order); + } + static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_or_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_OR_CAS(16, dst, src, order); + } + static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_or_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_OR_CAS(32, dst, src, order); + } + static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_or_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_OR_CAS(64, dst, src, order); + } + static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_xor_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_XOR_CAS(8, dst, src, order); + } + static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_xor_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_XOR_CAS(16, dst, src, order); + } + static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_xor_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_XOR_CAS(32, dst, src, order); + } + static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_xor_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_XOR_CAS(64, dst, src, order); + } + static MA_INLINE void __stdcall ma_atomic_thread_fence(ma_atomic_memory_order order) + { + (void)order; + __asm { + lock add dword ptr [esp], 0 + } + } + #define ma_atomic_signal_fence(order) __asm {}; (void)order +#endif +#if defined(MA_ATOMIC_MODERN_GCC) #define MA_ATOMIC_HAS_NATIVE_COMPARE_EXCHANGE - #define MA_ATOMIC_HAS_NATIVE_IS_LOCK_FREE - #define ma_atomic_memory_order_relaxed __ATOMIC_RELAXED - #define ma_atomic_memory_order_consume __ATOMIC_CONSUME - #define ma_atomic_memory_order_acquire __ATOMIC_ACQUIRE - #define ma_atomic_memory_order_release __ATOMIC_RELEASE - #define ma_atomic_memory_order_acq_rel __ATOMIC_ACQ_REL - #define ma_atomic_memory_order_seq_cst __ATOMIC_SEQ_CST - #define ma_atomic_compiler_fence() __asm__ __volatile__("":::"memory") #define ma_atomic_thread_fence(order) __atomic_thread_fence(order) #define ma_atomic_signal_fence(order) __atomic_signal_fence(order) #define ma_atomic_is_lock_free_8(ptr) __atomic_is_lock_free(1, ptr) #define ma_atomic_is_lock_free_16(ptr) __atomic_is_lock_free(2, ptr) #define ma_atomic_is_lock_free_32(ptr) __atomic_is_lock_free(4, ptr) #define ma_atomic_is_lock_free_64(ptr) __atomic_is_lock_free(8, ptr) - #define ma_atomic_test_and_set_explicit_8( dst, order) __atomic_exchange_n(dst, 1, order) - #define ma_atomic_test_and_set_explicit_16(dst, order) __atomic_exchange_n(dst, 1, order) - #define ma_atomic_test_and_set_explicit_32(dst, order) __atomic_exchange_n(dst, 1, order) - #define ma_atomic_test_and_set_explicit_64(dst, order) __atomic_exchange_n(dst, 1, order) - #define ma_atomic_clear_explicit_8( dst, order) __atomic_store_n(dst, 0, order) - #define ma_atomic_clear_explicit_16(dst, order) __atomic_store_n(dst, 0, order) - #define ma_atomic_clear_explicit_32(dst, order) __atomic_store_n(dst, 0, order) - #define ma_atomic_clear_explicit_64(dst, order) __atomic_store_n(dst, 0, order) #define ma_atomic_store_explicit_8( dst, src, order) __atomic_store_n(dst, src, order) #define ma_atomic_store_explicit_16(dst, src, order) __atomic_store_n(dst, src, order) #define ma_atomic_store_explicit_32(dst, src, order) __atomic_store_n(dst, src, order) @@ -14864,14 +15773,14 @@ typedef int ma_atomic_memory_order; #define ma_atomic_exchange_explicit_16(dst, src, order) __atomic_exchange_n(dst, src, order) #define ma_atomic_exchange_explicit_32(dst, src, order) __atomic_exchange_n(dst, src, order) #define ma_atomic_exchange_explicit_64(dst, src, order) __atomic_exchange_n(dst, src, order) - #define ma_atomic_compare_exchange_strong_explicit_8( dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 0, successOrder, failureOrder) - #define ma_atomic_compare_exchange_strong_explicit_16(dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 0, successOrder, failureOrder) - #define ma_atomic_compare_exchange_strong_explicit_32(dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 0, successOrder, failureOrder) - #define ma_atomic_compare_exchange_strong_explicit_64(dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 0, successOrder, failureOrder) - #define ma_atomic_compare_exchange_weak_explicit_8( dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 1, successOrder, failureOrder) - #define ma_atomic_compare_exchange_weak_explicit_16(dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 1, successOrder, failureOrder) - #define ma_atomic_compare_exchange_weak_explicit_32(dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 1, successOrder, failureOrder) - #define ma_atomic_compare_exchange_weak_explicit_64(dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 1, successOrder, failureOrder) + #define ma_atomic_compare_exchange_strong_explicit_8( dst, expected, replacement, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, replacement, 0, successOrder, failureOrder) + #define ma_atomic_compare_exchange_strong_explicit_16(dst, expected, replacement, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, replacement, 0, successOrder, failureOrder) + #define ma_atomic_compare_exchange_strong_explicit_32(dst, expected, replacement, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, replacement, 0, successOrder, failureOrder) + #define ma_atomic_compare_exchange_strong_explicit_64(dst, expected, replacement, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, replacement, 0, successOrder, failureOrder) + #define ma_atomic_compare_exchange_weak_explicit_8( dst, expected, replacement, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, replacement, 1, successOrder, failureOrder) + #define ma_atomic_compare_exchange_weak_explicit_16(dst, expected, replacement, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, replacement, 1, successOrder, failureOrder) + #define ma_atomic_compare_exchange_weak_explicit_32(dst, expected, replacement, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, replacement, 1, successOrder, failureOrder) + #define ma_atomic_compare_exchange_weak_explicit_64(dst, expected, replacement, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, replacement, 1, successOrder, failureOrder) #define ma_atomic_fetch_add_explicit_8( dst, src, order) __atomic_fetch_add(dst, src, order) #define ma_atomic_fetch_add_explicit_16(dst, src, order) __atomic_fetch_add(dst, src, order) #define ma_atomic_fetch_add_explicit_32(dst, src, order) __atomic_fetch_add(dst, src, order) @@ -14892,19 +15801,19 @@ typedef int ma_atomic_memory_order; #define ma_atomic_fetch_and_explicit_16(dst, src, order) __atomic_fetch_and(dst, src, order) #define ma_atomic_fetch_and_explicit_32(dst, src, order) __atomic_fetch_and(dst, src, order) #define ma_atomic_fetch_and_explicit_64(dst, src, order) __atomic_fetch_and(dst, src, order) - static MA_INLINE ma_uint8 ma_atomic_compare_and_swap_8(volatile ma_uint8* dst, ma_uint8 expected, ma_uint8 desired) + static MA_INLINE ma_uint8 ma_atomic_compare_and_swap_8(volatile ma_uint8* dst, ma_uint8 expected, ma_uint8 replacement) { - __atomic_compare_exchange_n(dst, &expected, desired, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); + __atomic_compare_exchange_n(dst, &expected, replacement, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); return expected; } - static MA_INLINE ma_uint16 ma_atomic_compare_and_swap_16(volatile ma_uint16* dst, ma_uint16 expected, ma_uint16 desired) + static MA_INLINE ma_uint16 ma_atomic_compare_and_swap_16(volatile ma_uint16* dst, ma_uint16 expected, ma_uint16 replacement) { - __atomic_compare_exchange_n(dst, &expected, desired, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); + __atomic_compare_exchange_n(dst, &expected, replacement, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); return expected; } - static MA_INLINE ma_uint32 ma_atomic_compare_and_swap_32(volatile ma_uint32* dst, ma_uint32 expected, ma_uint32 desired) + static MA_INLINE ma_uint32 ma_atomic_compare_and_swap_32(volatile ma_uint32* dst, ma_uint32 expected, ma_uint32 replacement) { - __atomic_compare_exchange_n(dst, &expected, desired, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); + __atomic_compare_exchange_n(dst, &expected, replacement, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); return expected; } #if defined(__clang__) @@ -14913,636 +15822,1134 @@ typedef int ma_atomic_memory_order; #pragma clang diagnostic ignored "-Watomic-alignment" #endif #endif - static MA_INLINE ma_uint64 ma_atomic_compare_and_swap_64(volatile ma_uint64* dst, ma_uint64 expected, ma_uint64 desired) + static MA_INLINE ma_uint64 ma_atomic_compare_and_swap_64(volatile ma_uint64* dst, ma_uint64 expected, ma_uint64 replacement) { - __atomic_compare_exchange_n(dst, &expected, desired, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); + __atomic_compare_exchange_n(dst, &expected, replacement, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); return expected; } #if defined(__clang__) #pragma clang diagnostic pop #endif - typedef ma_uint8 ma_atomic_flag; - #define ma_atomic_flag_test_and_set_explicit(dst, order) (ma_bool32)__atomic_test_and_set(dst, order) - #define ma_atomic_flag_clear_explicit(dst, order) __atomic_clear(dst, order) - #define ma_atomic_flag_load_explicit(ptr, order) ma_atomic_load_explicit_8(ptr, order) -#else - #define ma_atomic_memory_order_relaxed 1 - #define ma_atomic_memory_order_consume 2 - #define ma_atomic_memory_order_acquire 3 - #define ma_atomic_memory_order_release 4 - #define ma_atomic_memory_order_acq_rel 5 - #define ma_atomic_memory_order_seq_cst 6 - #define ma_atomic_compiler_fence() __asm__ __volatile__("":::"memory") - #if defined(__GNUC__) +#endif +#if defined(MA_ATOMIC_LEGACY_GCC) || defined(MA_ATOMIC_LEGACY_GCC_ASM) + #define ma_atomic_signal_fence(order) __asm__ __volatile__("":::"memory") + #if defined(MA_ATOMIC_LEGACY_GCC) #define ma_atomic_thread_fence(order) __sync_synchronize(), (void)order - static MA_INLINE ma_uint8 ma_atomic_exchange_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + static MA_INLINE ma_uint8 ma_atomic_compare_and_swap_8(volatile ma_uint8* dst, ma_uint8 expected, ma_uint8 replacement) { - if (order > ma_atomic_memory_order_acquire) { - __sync_synchronize(); + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) + { + return __sync_val_compare_and_swap(dst, expected, replacement); } - return __sync_lock_test_and_set(dst, src); + #else + { + MA_ATOMIC_COMPARE_AND_SWAP_LOCK(8, dst, expected, replacement); + } + #endif } - static MA_INLINE ma_uint16 ma_atomic_exchange_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + static MA_INLINE ma_uint16 ma_atomic_compare_and_swap_16(volatile ma_uint16* dst, ma_uint16 expected, ma_uint16 replacement) { - ma_uint16 oldValue; - do { - oldValue = *dst; - } while (__sync_val_compare_and_swap(dst, oldValue, src) != oldValue); - (void)order; - return oldValue; + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) + { + return __sync_val_compare_and_swap(dst, expected, replacement); + } + #else + { + MA_ATOMIC_COMPARE_AND_SWAP_LOCK(16, dst, expected, replacement); + } + #endif } - static MA_INLINE ma_uint32 ma_atomic_exchange_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + static MA_INLINE ma_uint32 ma_atomic_compare_and_swap_32(volatile ma_uint32* dst, ma_uint32 expected, ma_uint32 replacement) { - ma_uint32 oldValue; - do { - oldValue = *dst; - } while (__sync_val_compare_and_swap(dst, oldValue, src) != oldValue); - (void)order; - return oldValue; + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + { + return __sync_val_compare_and_swap(dst, expected, replacement); + } + #else + { + MA_ATOMIC_COMPARE_AND_SWAP_LOCK(32, dst, expected, replacement); + } + #endif } - static MA_INLINE ma_uint64 ma_atomic_exchange_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + static MA_INLINE ma_uint64 ma_atomic_compare_and_swap_64(volatile ma_uint64* dst, ma_uint64 expected, ma_uint64 replacement) { - ma_uint64 oldValue; - do { - oldValue = *dst; - } while (__sync_val_compare_and_swap(dst, oldValue, src) != oldValue); - (void)order; - return oldValue; + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) + { + return __sync_val_compare_and_swap(dst, expected, replacement); + } + #else + { + MA_ATOMIC_COMPARE_AND_SWAP_LOCK(64, dst, expected, replacement); + } + #endif } - static MA_INLINE ma_uint8 ma_atomic_fetch_add_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + static MA_INLINE ma_uint8 ma_atomic_load_explicit_8(volatile const ma_uint8* ptr, ma_atomic_memory_order order) { - (void)order; - return __sync_fetch_and_add(dst, src); + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) + { + (void)order; + return ma_atomic_compare_and_swap_8((ma_uint8*)ptr, 0, 0); + } + #else + { + MA_ATOMIC_LOAD_EXPLICIT_LOCK(8, ptr, order); + } + #endif } - static MA_INLINE ma_uint16 ma_atomic_fetch_add_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + static MA_INLINE ma_uint16 ma_atomic_load_explicit_16(volatile const ma_uint16* ptr, ma_atomic_memory_order order) { - (void)order; - return __sync_fetch_and_add(dst, src); + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) + { + (void)order; + return ma_atomic_compare_and_swap_16((ma_uint16*)ptr, 0, 0); + } + #else + { + MA_ATOMIC_LOAD_EXPLICIT_LOCK(16, ptr, order); + } + #endif } - static MA_INLINE ma_uint32 ma_atomic_fetch_add_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + static MA_INLINE ma_uint32 ma_atomic_load_explicit_32(volatile const ma_uint32* ptr, ma_atomic_memory_order order) { - (void)order; - return __sync_fetch_and_add(dst, src); + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + { + (void)order; + return ma_atomic_compare_and_swap_32((ma_uint32*)ptr, 0, 0); + } + #else + { + MA_ATOMIC_LOAD_EXPLICIT_LOCK(32, ptr, order); + } + #endif } - static MA_INLINE ma_uint64 ma_atomic_fetch_add_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + static MA_INLINE ma_uint64 ma_atomic_load_explicit_64(volatile const ma_uint64* ptr, ma_atomic_memory_order order) { - (void)order; - return __sync_fetch_and_add(dst, src); - } - static MA_INLINE ma_uint8 ma_atomic_fetch_sub_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) - { - (void)order; - return __sync_fetch_and_sub(dst, src); - } - static MA_INLINE ma_uint16 ma_atomic_fetch_sub_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) - { - (void)order; - return __sync_fetch_and_sub(dst, src); - } - static MA_INLINE ma_uint32 ma_atomic_fetch_sub_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) - { - (void)order; - return __sync_fetch_and_sub(dst, src); - } - static MA_INLINE ma_uint64 ma_atomic_fetch_sub_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) - { - (void)order; - return __sync_fetch_and_sub(dst, src); - } - static MA_INLINE ma_uint8 ma_atomic_fetch_or_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) - { - (void)order; - return __sync_fetch_and_or(dst, src); - } - static MA_INLINE ma_uint16 ma_atomic_fetch_or_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) - { - (void)order; - return __sync_fetch_and_or(dst, src); - } - static MA_INLINE ma_uint32 ma_atomic_fetch_or_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) - { - (void)order; - return __sync_fetch_and_or(dst, src); - } - static MA_INLINE ma_uint64 ma_atomic_fetch_or_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) - { - (void)order; - return __sync_fetch_and_or(dst, src); - } - static MA_INLINE ma_uint8 ma_atomic_fetch_xor_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) - { - (void)order; - return __sync_fetch_and_xor(dst, src); - } - static MA_INLINE ma_uint16 ma_atomic_fetch_xor_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) - { - (void)order; - return __sync_fetch_and_xor(dst, src); - } - static MA_INLINE ma_uint32 ma_atomic_fetch_xor_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) - { - (void)order; - return __sync_fetch_and_xor(dst, src); - } - static MA_INLINE ma_uint64 ma_atomic_fetch_xor_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) - { - (void)order; - return __sync_fetch_and_xor(dst, src); - } - static MA_INLINE ma_uint8 ma_atomic_fetch_and_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) - { - (void)order; - return __sync_fetch_and_and(dst, src); - } - static MA_INLINE ma_uint16 ma_atomic_fetch_and_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) - { - (void)order; - return __sync_fetch_and_and(dst, src); - } - static MA_INLINE ma_uint32 ma_atomic_fetch_and_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) - { - (void)order; - return __sync_fetch_and_and(dst, src); - } - static MA_INLINE ma_uint64 ma_atomic_fetch_and_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) - { - (void)order; - return __sync_fetch_and_and(dst, src); - } - #define ma_atomic_compare_and_swap_8( dst, expected, desired) __sync_val_compare_and_swap(dst, expected, desired) - #define ma_atomic_compare_and_swap_16(dst, expected, desired) __sync_val_compare_and_swap(dst, expected, desired) - #define ma_atomic_compare_and_swap_32(dst, expected, desired) __sync_val_compare_and_swap(dst, expected, desired) - #define ma_atomic_compare_and_swap_64(dst, expected, desired) __sync_val_compare_and_swap(dst, expected, desired) - #else - #if defined(MA_X86) - #define ma_atomic_thread_fence(order) __asm__ __volatile__("lock; addl $0, (%%esp)" ::: "memory", "cc") - #elif defined(MA_X64) - #define ma_atomic_thread_fence(order) __asm__ __volatile__("lock; addq $0, (%%rsp)" ::: "memory", "cc") - #else - #error Unsupported architecture. Please submit a feature request. - #endif - static MA_INLINE ma_uint8 ma_atomic_compare_and_swap_8(volatile ma_uint8* dst, ma_uint8 expected, ma_uint8 desired) - { - ma_uint8 result; - #if defined(MA_X86) || defined(MA_X64) - __asm__ __volatile__("lock; cmpxchg %3, %0" : "+m"(*dst), "=a"(result) : "a"(expected), "d"(desired) : "cc"); - #else - #error Unsupported architecture. Please submit a feature request. - #endif - return result; - } - static MA_INLINE ma_uint16 ma_atomic_compare_and_swap_16(volatile ma_uint16* dst, ma_uint16 expected, ma_uint16 desired) - { - ma_uint16 result; - #if defined(MA_X86) || defined(MA_X64) - __asm__ __volatile__("lock; cmpxchg %3, %0" : "+m"(*dst), "=a"(result) : "a"(expected), "d"(desired) : "cc"); - #else - #error Unsupported architecture. Please submit a feature request. - #endif - return result; - } - static MA_INLINE ma_uint32 ma_atomic_compare_and_swap_32(volatile ma_uint32* dst, ma_uint32 expected, ma_uint32 desired) - { - ma_uint32 result; - #if defined(MA_X86) || defined(MA_X64) - __asm__ __volatile__("lock; cmpxchg %3, %0" : "+m"(*dst), "=a"(result) : "a"(expected), "d"(desired) : "cc"); - #else - #error Unsupported architecture. Please submit a feature request. - #endif - return result; - } - static MA_INLINE ma_uint64 ma_atomic_compare_and_swap_64(volatile ma_uint64* dst, ma_uint64 expected, ma_uint64 desired) - { - volatile ma_uint64 result; - #if defined(MA_X86) - ma_uint32 resultEAX; - ma_uint32 resultEDX; - __asm__ __volatile__("push %%ebx; xchg %5, %%ebx; lock; cmpxchg8b %0; pop %%ebx" : "+m"(*dst), "=a"(resultEAX), "=d"(resultEDX) : "a"(expected & 0xFFFFFFFF), "d"(expected >> 32), "r"(desired & 0xFFFFFFFF), "c"(desired >> 32) : "cc"); - result = ((ma_uint64)resultEDX << 32) | resultEAX; - #elif defined(MA_X64) - __asm__ __volatile__("lock; cmpxchg %3, %0" : "+m"(*dst), "=a"(result) : "a"(expected), "d"(desired) : "cc"); - #else - #error Unsupported architecture. Please submit a feature request. - #endif - return result; + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) + { + (void)order; + return ma_atomic_compare_and_swap_64((ma_uint64*)ptr, 0, 0); + } + #else + { + MA_ATOMIC_LOAD_EXPLICIT_LOCK(64, ptr, order); + } + #endif } static MA_INLINE ma_uint8 ma_atomic_exchange_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) { - ma_uint8 result = 0; - (void)order; - #if defined(MA_X86) || defined(MA_X64) - __asm__ __volatile__("lock; xchg %1, %0" : "+m"(*dst), "=a"(result) : "a"(src)); - #else - #error Unsupported architecture. Please submit a feature request. - #endif - return result; + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) + { + if (order > ma_atomic_memory_order_acquire) { + __sync_synchronize(); + } + return __sync_lock_test_and_set(dst, src); + } + #else + { + MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(8, dst, src, order); + } + #endif } static MA_INLINE ma_uint16 ma_atomic_exchange_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) { - ma_uint16 result = 0; - (void)order; - #if defined(MA_X86) || defined(MA_X64) - __asm__ __volatile__("lock; xchg %1, %0" : "+m"(*dst), "=a"(result) : "a"(src)); - #else - #error Unsupported architecture. Please submit a feature request. - #endif - return result; + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) + { + if (order > ma_atomic_memory_order_acquire) { + __sync_synchronize(); + } + return __sync_lock_test_and_set(dst, src); + } + #else + { + MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(16, dst, src, order); + } + #endif } static MA_INLINE ma_uint32 ma_atomic_exchange_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) { - ma_uint32 result; - (void)order; - #if defined(MA_X86) || defined(MA_X64) - __asm__ __volatile__("lock; xchg %1, %0" : "+m"(*dst), "=a"(result) : "a"(src)); - #else - #error Unsupported architecture. Please submit a feature request. - #endif - return result; + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + { + if (order > ma_atomic_memory_order_acquire) { + __sync_synchronize(); + } + return __sync_lock_test_and_set(dst, src); + } + #else + { + MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(32, dst, src, order); + } + #endif } static MA_INLINE ma_uint64 ma_atomic_exchange_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) { - ma_uint64 result; - (void)order; - #if defined(MA_X86) - do { - result = *dst; - } while (ma_atomic_compare_and_swap_64(dst, result, src) != result); - #elif defined(MA_X64) - __asm__ __volatile__("lock; xchg %1, %0" : "+m"(*dst), "=a"(result) : "a"(src)); - #else - #error Unsupported architecture. Please submit a feature request. - #endif - return result; + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) + { + if (order > ma_atomic_memory_order_acquire) { + __sync_synchronize(); + } + return __sync_lock_test_and_set(dst, src); + } + #else + { + MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(64, dst, src, order); + } + #endif } + #define ma_atomic_store_explicit_8( dst, src, order) (void)ma_atomic_exchange_explicit_8 (dst, src, order) + #define ma_atomic_store_explicit_16(dst, src, order) (void)ma_atomic_exchange_explicit_16(dst, src, order) + #define ma_atomic_store_explicit_32(dst, src, order) (void)ma_atomic_exchange_explicit_32(dst, src, order) + #define ma_atomic_store_explicit_64(dst, src, order) (void)ma_atomic_exchange_explicit_64(dst, src, order) static MA_INLINE ma_uint8 ma_atomic_fetch_add_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) { - ma_uint8 result; - (void)order; - #if defined(MA_X86) || defined(MA_X64) - __asm__ __volatile__("lock; xadd %1, %0" : "+m"(*dst), "=a"(result) : "a"(src) : "cc"); - #else - #error Unsupported architecture. Please submit a feature request. - #endif - return result; + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) + { + (void)order; + return __sync_fetch_and_add(dst, src); + } + #else + { + MA_ATOMIC_FETCH_ADD_LOCK(8, dst, src, order); + } + #endif } static MA_INLINE ma_uint16 ma_atomic_fetch_add_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) { - ma_uint16 result; - (void)order; - #if defined(MA_X86) || defined(MA_X64) - __asm__ __volatile__("lock; xadd %1, %0" : "+m"(*dst), "=a"(result) : "a"(src) : "cc"); - #else - #error Unsupported architecture. Please submit a feature request. - #endif - return result; + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) + { + (void)order; + return __sync_fetch_and_add(dst, src); + } + #else + { + MA_ATOMIC_FETCH_ADD_LOCK(16, dst, src, order); + } + #endif } static MA_INLINE ma_uint32 ma_atomic_fetch_add_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) { - ma_uint32 result; - (void)order; - #if defined(MA_X86) || defined(MA_X64) - __asm__ __volatile__("lock; xadd %1, %0" : "+m"(*dst), "=a"(result) : "a"(src) : "cc"); - #else - #error Unsupported architecture. Please submit a feature request. - #endif - return result; + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + { + (void)order; + return __sync_fetch_and_add(dst, src); + } + #else + { + MA_ATOMIC_FETCH_ADD_LOCK(32, dst, src, order); + } + #endif } static MA_INLINE ma_uint64 ma_atomic_fetch_add_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) { - #if defined(MA_X86) - ma_uint64 oldValue; - ma_uint64 newValue; - (void)order; - do { - oldValue = *dst; - newValue = oldValue + src; - } while (ma_atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); - return oldValue; - #elif defined(MA_X64) - ma_uint64 result; - (void)order; - __asm__ __volatile__("lock; xadd %1, %0" : "+m"(*dst), "=a"(result) : "a"(src) : "cc"); - return result; - #endif + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) + { + (void)order; + return __sync_fetch_and_add(dst, src); + } + #else + { + MA_ATOMIC_FETCH_ADD_LOCK(64, dst, src, order); + } + #endif } static MA_INLINE ma_uint8 ma_atomic_fetch_sub_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) { - ma_uint8 oldValue; - ma_uint8 newValue; - do { - oldValue = *dst; - newValue = (ma_uint8)(oldValue - src); - } while (ma_atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) + { + (void)order; + return __sync_fetch_and_sub(dst, src); + } + #else + { + MA_ATOMIC_FETCH_ADD_LOCK(8, dst, (ma_uint8)(-(ma_int8)src), order); + } + #endif } static MA_INLINE ma_uint16 ma_atomic_fetch_sub_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) { - ma_uint16 oldValue; - ma_uint16 newValue; - do { - oldValue = *dst; - newValue = (ma_uint16)(oldValue - src); - } while (ma_atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) + { + (void)order; + return __sync_fetch_and_sub(dst, src); + } + #else + { + MA_ATOMIC_FETCH_ADD_LOCK(16, dst, (ma_uint16)(-(ma_int16)src), order); + } + #endif } static MA_INLINE ma_uint32 ma_atomic_fetch_sub_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) { - ma_uint32 oldValue; - ma_uint32 newValue; - do { - oldValue = *dst; - newValue = oldValue - src; - } while (ma_atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + { + (void)order; + return __sync_fetch_and_sub(dst, src); + } + #else + { + MA_ATOMIC_FETCH_ADD_LOCK(32, dst, (ma_uint32)(-(ma_int32)src), order); + } + #endif } static MA_INLINE ma_uint64 ma_atomic_fetch_sub_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) { - ma_uint64 oldValue; - ma_uint64 newValue; - do { - oldValue = *dst; - newValue = oldValue - src; - } while (ma_atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) + { + (void)order; + return __sync_fetch_and_sub(dst, src); + } + #else + { + MA_ATOMIC_FETCH_ADD_LOCK(64, dst, (ma_uint64)(-(ma_int64)src), order); + } + #endif } static MA_INLINE ma_uint8 ma_atomic_fetch_and_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) { - ma_uint8 oldValue; - ma_uint8 newValue; - do { - oldValue = *dst; - newValue = (ma_uint8)(oldValue & src); - } while (ma_atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) + { + (void)order; + return __sync_fetch_and_and(dst, src); + } + #else + { + MA_ATOMIC_FETCH_AND_CAS(8, dst, src, order); + } + #endif } static MA_INLINE ma_uint16 ma_atomic_fetch_and_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) { - ma_uint16 oldValue; - ma_uint16 newValue; - do { - oldValue = *dst; - newValue = (ma_uint16)(oldValue & src); - } while (ma_atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) + { + (void)order; + return __sync_fetch_and_and(dst, src); + } + #else + { + MA_ATOMIC_FETCH_AND_CAS(16, dst, src, order); + } + #endif } static MA_INLINE ma_uint32 ma_atomic_fetch_and_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) { - ma_uint32 oldValue; - ma_uint32 newValue; - do { - oldValue = *dst; - newValue = oldValue & src; - } while (ma_atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + { + (void)order; + return __sync_fetch_and_and(dst, src); + } + #else + { + MA_ATOMIC_FETCH_AND_CAS(32, dst, src, order); + } + #endif } static MA_INLINE ma_uint64 ma_atomic_fetch_and_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) { - ma_uint64 oldValue; - ma_uint64 newValue; - do { - oldValue = *dst; - newValue = oldValue & src; - } while (ma_atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; - } - static MA_INLINE ma_uint8 ma_atomic_fetch_xor_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) - { - ma_uint8 oldValue; - ma_uint8 newValue; - do { - oldValue = *dst; - newValue = (ma_uint8)(oldValue ^ src); - } while (ma_atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; - } - static MA_INLINE ma_uint16 ma_atomic_fetch_xor_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) - { - ma_uint16 oldValue; - ma_uint16 newValue; - do { - oldValue = *dst; - newValue = (ma_uint16)(oldValue ^ src); - } while (ma_atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; - } - static MA_INLINE ma_uint32 ma_atomic_fetch_xor_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) - { - ma_uint32 oldValue; - ma_uint32 newValue; - do { - oldValue = *dst; - newValue = oldValue ^ src; - } while (ma_atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; - } - static MA_INLINE ma_uint64 ma_atomic_fetch_xor_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) - { - ma_uint64 oldValue; - ma_uint64 newValue; - do { - oldValue = *dst; - newValue = oldValue ^ src; - } while (ma_atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) + { + (void)order; + return __sync_fetch_and_and(dst, src); + } + #else + { + MA_ATOMIC_FETCH_AND_CAS(64, dst, src, order); + } + #endif } static MA_INLINE ma_uint8 ma_atomic_fetch_or_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) { - ma_uint8 oldValue; - ma_uint8 newValue; - do { - oldValue = *dst; - newValue = (ma_uint8)(oldValue | src); - } while (ma_atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) + { + (void)order; + return __sync_fetch_and_or(dst, src); + } + #else + { + MA_ATOMIC_FETCH_OR_CAS(8, dst, src, order); + } + #endif } static MA_INLINE ma_uint16 ma_atomic_fetch_or_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) { - ma_uint16 oldValue; - ma_uint16 newValue; - do { - oldValue = *dst; - newValue = (ma_uint16)(oldValue | src); - } while (ma_atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) + { + (void)order; + return __sync_fetch_and_or(dst, src); + } + #else + { + MA_ATOMIC_FETCH_OR_CAS(16, dst, src, order); + } + #endif } static MA_INLINE ma_uint32 ma_atomic_fetch_or_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) { - ma_uint32 oldValue; - ma_uint32 newValue; - do { - oldValue = *dst; - newValue = oldValue | src; - } while (ma_atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + { + (void)order; + return __sync_fetch_and_or(dst, src); + } + #else + { + MA_ATOMIC_FETCH_OR_CAS(32, dst, src, order); + } + #endif } static MA_INLINE ma_uint64 ma_atomic_fetch_or_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) { - ma_uint64 oldValue; - ma_uint64 newValue; - do { - oldValue = *dst; - newValue = oldValue | src; - } while (ma_atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) + { + (void)order; + return __sync_fetch_and_or(dst, src); + } + #else + { + MA_ATOMIC_FETCH_OR_CAS(64, dst, src, order); + } + #endif } + static MA_INLINE ma_uint8 ma_atomic_fetch_xor_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) + { + (void)order; + return __sync_fetch_and_xor(dst, src); + } + #else + { + MA_ATOMIC_FETCH_XOR_CAS(8, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint16 ma_atomic_fetch_xor_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) + { + (void)order; + return __sync_fetch_and_xor(dst, src); + } + #else + { + MA_ATOMIC_FETCH_XOR_CAS(16, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint32 ma_atomic_fetch_xor_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + { + (void)order; + return __sync_fetch_and_xor(dst, src); + } + #else + { + MA_ATOMIC_FETCH_XOR_CAS(32, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint64 ma_atomic_fetch_xor_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) + { + (void)order; + return __sync_fetch_and_xor(dst, src); + } + #else + { + MA_ATOMIC_FETCH_XOR_CAS(64, dst, src, order); + } + #endif + } + #elif defined(MA_ATOMIC_LEGACY_GCC_ASM) + #define MA_ATOMIC_CMPXCHG_GCC_X86(instructionSizeSuffix, result, dst, expected, replacement) \ + __asm__ __volatile__( \ + "lock; cmpxchg"instructionSizeSuffix" %2, %1" \ + : "=a"(result), \ + "=m"(*dst) \ + : "r"(replacement), \ + "0"(expected), \ + "m"(*dst) \ + : "cc", "memory") + #define MA_ATOMIC_XADD_GCC_X86(instructionSizeSuffix, result, dst, src) \ + __asm__ __volatile__( \ + "lock; xadd"instructionSizeSuffix" %0, %1" \ + : "=a"(result), \ + "=m"(*dst) \ + : "0"(src), \ + "m"(*dst) \ + : "cc", "memory") + static MA_INLINE ma_uint8 ma_atomic_compare_and_swap_8(volatile ma_uint8* dst, ma_uint8 expected, ma_uint8 replacement) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) && (defined(MA_X86) || defined(MA_X64)) + { + ma_uint8 result; + #if defined(MA_X86) || defined(MA_X64) + { + MA_ATOMIC_CMPXCHG_GCC_X86("b", result, dst, expected, replacement); + } + #else + { + #error Unsupported architecture. + } + #endif + return result; + } + #else + { + MA_ATOMIC_COMPARE_AND_SWAP_LOCK(8, dst, expected, replacement); + } + #endif + } + static MA_INLINE ma_uint16 ma_atomic_compare_and_swap_16(volatile ma_uint16* dst, ma_uint16 expected, ma_uint16 replacement) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) && (defined(MA_X86) || defined(MA_X64)) + { + ma_uint16 result; + #if defined(MA_X86) || defined(MA_X64) + { + MA_ATOMIC_CMPXCHG_GCC_X86("w", result, dst, expected, replacement); + } + #else + { + #error Unsupported architecture. + } + #endif + return result; + } + #else + { + MA_ATOMIC_COMPARE_AND_SWAP_LOCK(16, dst, expected, replacement); + } + #endif + } + static MA_INLINE ma_uint32 ma_atomic_compare_and_swap_32(volatile ma_uint32* dst, ma_uint32 expected, ma_uint32 replacement) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) && (defined(MA_X86) || defined(MA_X64)) + { + ma_uint32 result; + #if defined(MA_X86) || defined(MA_X64) + { + MA_ATOMIC_CMPXCHG_GCC_X86("l", result, dst, expected, replacement); + } + #else + { + #error Unsupported architecture. + } + #endif + return result; + } + #else + { + MA_ATOMIC_COMPARE_AND_SWAP_LOCK(32, dst, expected, replacement); + } + #endif + } + static MA_INLINE ma_uint64 ma_atomic_compare_and_swap_64(volatile ma_uint64* dst, ma_uint64 expected, ma_uint64 replacement) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) && (defined(MA_X86) || defined(MA_X64)) + { + ma_uint64 result; + #if defined(MA_X86) + { + ma_uint32 resultEAX; + ma_uint32 resultEDX; + __asm__ __volatile__( + "pushl %%ebx\n" + "movl %4, %%ebx\n" + "lock cmpxchg8b (%%edi)\n" + "popl %%ebx\n" + : "=a"(resultEAX), + "=d"(resultEDX) + : "a"((ma_uint32)(expected & 0xFFFFFFFF)), + "d"((ma_uint32)(expected >> 32)), + "r"((ma_uint32)(replacement & 0xFFFFFFFF)), + "c"((ma_uint32)(replacement >> 32)), + "D"(dst) + : "memory", "cc"); + result = ((ma_uint64)resultEDX << 32) | resultEAX; + } + #elif defined(MA_X64) + { + MA_ATOMIC_CMPXCHG_GCC_X86("q", result, dst, expected, replacement); + } + #else + { + #error Unsupported architecture. + } + #endif + return result; + } + #else + { + MA_ATOMIC_COMPARE_AND_SWAP_LOCK(64, dst, expected, replacement); + } + #endif + } + static MA_INLINE ma_uint8 ma_atomic_load_explicit_8(volatile const ma_uint8* dst, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) && (defined(MA_X86) || defined(MA_X64)) + { + ma_uint8 result; + #if defined(MA_X86) || defined(MA_X64) + { + if (order == ma_atomic_memory_order_relaxed) { + MA_ATOMIC_LOAD_RELAXED_GCC_X86("b", result, dst); + } else if (order <= ma_atomic_memory_order_release) { + MA_ATOMIC_LOAD_RELEASE_GCC_X86("b", result, dst); + } else { + MA_ATOMIC_LOAD_SEQ_CST_GCC_X86("b", result, dst); + } + } + #else + { + #error Unsupported architecture. + } + #endif + return result; + } + #else + { + MA_ATOMIC_LOAD_EXPLICIT_LOCK(8, dst, order); + } + #endif + } + static MA_INLINE ma_uint16 ma_atomic_load_explicit_16(volatile const ma_uint16* dst, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) && (defined(MA_X86) || defined(MA_X64)) + { + ma_uint16 result; + #if defined(MA_X86) || defined(MA_X64) + { + if (order == ma_atomic_memory_order_relaxed) { + MA_ATOMIC_LOAD_RELAXED_GCC_X86("w", result, dst); + } else if (order <= ma_atomic_memory_order_release) { + MA_ATOMIC_LOAD_RELEASE_GCC_X86("w", result, dst); + } else { + MA_ATOMIC_LOAD_SEQ_CST_GCC_X86("w", result, dst); + } + } + #else + { + #error Unsupported architecture. + } + #endif + return result; + } + #else + { + MA_ATOMIC_LOAD_EXPLICIT_LOCK(16, dst, order); + } + #endif + } + static MA_INLINE ma_uint32 ma_atomic_load_explicit_32(volatile const ma_uint32* dst, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) && (defined(MA_X86) || defined(MA_X64)) + { + ma_uint32 result; + #if defined(MA_X86) || defined(MA_X64) + { + if (order == ma_atomic_memory_order_relaxed) { + MA_ATOMIC_LOAD_RELAXED_GCC_X86("l", result, dst); + } else if (order <= ma_atomic_memory_order_release) { + MA_ATOMIC_LOAD_RELEASE_GCC_X86("l", result, dst); + } else { + MA_ATOMIC_LOAD_SEQ_CST_GCC_X86("l", result, dst); + } + } + #else + { + #error Unsupported architecture. + } + #endif + return result; + } + #else + { + MA_ATOMIC_LOAD_EXPLICIT_LOCK(32, dst, order); + } + #endif + } + static MA_INLINE ma_uint64 ma_atomic_load_explicit_64(volatile const ma_uint64* dst, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) && (defined(MA_X86) || defined(MA_X64)) + { + ma_uint64 result; + #if defined(MA_X64) + { + if (order == ma_atomic_memory_order_relaxed) { + MA_ATOMIC_LOAD_RELAXED_GCC_X86("q", result, dst); + } else if (order <= ma_atomic_memory_order_release) { + MA_ATOMIC_LOAD_RELEASE_GCC_X86("q", result, dst); + } else { + MA_ATOMIC_LOAD_SEQ_CST_GCC_X86("q", result, dst); + } + } + #elif defined(MA_X86) + { + (void)order; + return ma_atomic_compare_and_swap_64((volatile ma_uint64*)dst, 0, 0); + } + #else + { + #error Unsupported architecture. + } + #endif + return result; + } + #else + { + MA_ATOMIC_LOAD_EXPLICIT_LOCK(64, dst, order); + } + #endif + } + static MA_INLINE ma_uint8 ma_atomic_exchange_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) && (defined(MA_X86) || defined(MA_X64)) + { + ma_uint8 result; + (void)order; + #if defined(MA_X86) || defined(MA_X64) + { + MA_ATOMIC_XCHG_GCC_X86("b", result, dst, src); + } + #else + { + #error Unsupported architecture. + } + #endif + return result; + } + #else + { + MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(8, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint16 ma_atomic_exchange_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) && (defined(MA_X86) || defined(MA_X64)) + { + ma_uint16 result; + (void)order; + #if defined(MA_X86) || defined(MA_X64) + { + MA_ATOMIC_XCHG_GCC_X86("w", result, dst, src); + } + #else + { + #error Unsupported architecture. + } + #endif + return result; + } + #else + { + MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(16, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint32 ma_atomic_exchange_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) && (defined(MA_X86) || defined(MA_X64)) + { + ma_uint32 result; + (void)order; + #if defined(MA_X86) || defined(MA_X64) + { + MA_ATOMIC_XCHG_GCC_X86("l", result, dst, src); + } + #else + { + #error Unsupported architecture. + } + #endif + return result; + } + #else + { + MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(32, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint64 ma_atomic_exchange_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) && (defined(MA_X86) || defined(MA_X64)) + { + ma_uint64 result; + (void)order; + #if defined(MA_X86) + { + MA_ATOMIC_EXCHANGE_EXPLICIT_CAS(64, dst, src, order); + } + #elif defined(MA_X64) + { + MA_ATOMIC_XCHG_GCC_X86("q", result, dst, src); + } + #else + { + #error Unsupported architecture. + } + #endif + return result; + } + #else + { + MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(64, dst, src, order); + } + #endif + } + static MA_INLINE void ma_atomic_store_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) && (defined(MA_X86) || defined(MA_X64)) + { + #if defined(MA_X86) || defined(MA_X64) + { + if (order == ma_atomic_memory_order_relaxed) { + __asm__ __volatile__ ( + "movb %1, %0" + : "=m"(*dst) + : "r"(src) + ); + } else { + __asm__ __volatile__ ( + "xchgb %1, %0" + : "=m"(*dst) + : "r"(src) + : "memory" + ); + } + } + #else + { + #error Unsupported architecture. + } + #endif + } + #else + { + MA_ATOMIC_STORE_EXPLICIT_LOCK(8, dst, src, order); + } + #endif + } + static MA_INLINE void ma_atomic_store_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) && (defined(MA_X86) || defined(MA_X64)) + { + #if defined(MA_X86) || defined(MA_X64) + { + if (order == ma_atomic_memory_order_relaxed) { + __asm__ __volatile__ ( + "movw %1, %0" + : "=m"(*dst) + : "r"(src) + ); + } else { + __asm__ __volatile__ ( + "xchgw %1, %0" + : "=m"(*dst) + : "r"(src) + : "memory" + ); + } + } + #else + { + #error Unsupported architecture. + } + #endif + } + #else + { + MA_ATOMIC_STORE_EXPLICIT_LOCK(16, dst, src, order); + } + #endif + } + static MA_INLINE void ma_atomic_store_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) && (defined(MA_X86) || defined(MA_X64)) + { + #if defined(MA_X86) || defined(MA_X64) + { + if (order == ma_atomic_memory_order_relaxed) { + __asm__ __volatile__ ( + "movl %1, %0" + : "=m"(*dst) + : "r"(src) + ); + } else { + __asm__ __volatile__ ( + "xchgl %1, %0" + : "=m"(*dst) + : "r"(src) + : "memory" + ); + } + } + #else + { + #error Unsupported architecture. + } + #endif + } + #else + { + MA_ATOMIC_STORE_EXPLICIT_LOCK(32, dst, src, order); + } + #endif + } + static MA_INLINE void ma_atomic_store_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) && (defined(MA_X86) || defined(MA_X64)) + { + #if defined(MA_X64) + { + if (order == ma_atomic_memory_order_relaxed) { + __asm__ __volatile__ ( + "movq %1, %0" + : "=m"(*dst) + : "r"(src) + ); + } else { + __asm__ __volatile__ ( + "xchgq %1, %0" + : "=m"(*dst) + : "r"(src) + : "memory" + ); + } + } + #else + { + MA_ATOMIC_STORE_EXPLICIT_CAS(64, dst, src, order); + } + #endif + } + #else + { + MA_ATOMIC_STORE_EXPLICIT_LOCK(64, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint8 ma_atomic_fetch_add_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) && (defined(MA_X86) || defined(MA_X64)) + { + #if defined(MA_X86) || defined(MA_X64) + { + ma_uint8 result; + (void)order; + MA_ATOMIC_XADD_GCC_X86("b", result, dst, src); + return result; + } + #else + { + #error Unsupported architecture. + } + #endif + } + #else + { + MA_ATOMIC_FETCH_ADD_LOCK(8, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint16 ma_atomic_fetch_add_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) && (defined(MA_X86) || defined(MA_X64)) + { + #if defined(MA_X86) || defined(MA_X64) + { + ma_uint16 result; + (void)order; + MA_ATOMIC_XADD_GCC_X86("w", result, dst, src); + return result; + } + #else + { + #error Unsupported architecture. + } + #endif + } + #else + { + MA_ATOMIC_FETCH_ADD_LOCK(16, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint32 ma_atomic_fetch_add_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) && (defined(MA_X86) || defined(MA_X64)) + { + #if defined(MA_X86) || defined(MA_X64) + { + ma_uint32 result; + (void)order; + MA_ATOMIC_XADD_GCC_X86("l", result, dst, src); + return result; + } + #else + { + #error Unsupported architecture. + } + #endif + } + #else + { + MA_ATOMIC_FETCH_ADD_LOCK(32, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint64 ma_atomic_fetch_add_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) && (defined(MA_X86) || defined(MA_X64)) + { + #if defined(MA_X86) + { + MA_ATOMIC_FETCH_ADD_CAS(64, dst, src, order); + } + #elif defined(MA_X64) + { + ma_uint64 result; + MA_ATOMIC_XADD_GCC_X86("q", result, dst, src); + (void)order; + return result; + } + #else + { + #error Unsupported architecture. + } + #endif + } + #else + { + MA_ATOMIC_FETCH_ADD_LOCK(64, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint8 ma_atomic_fetch_sub_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + return ma_atomic_fetch_add_explicit_8(dst, (ma_uint8)(-(ma_int8)src), order); + } + static MA_INLINE ma_uint16 ma_atomic_fetch_sub_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + return ma_atomic_fetch_add_explicit_16(dst, (ma_uint16)(-(ma_int16)src), order); + } + static MA_INLINE ma_uint32 ma_atomic_fetch_sub_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + return ma_atomic_fetch_add_explicit_32(dst, (ma_uint32)(-(ma_int32)src), order); + } + static MA_INLINE ma_uint64 ma_atomic_fetch_sub_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + return ma_atomic_fetch_add_explicit_64(dst, (ma_uint64)(-(ma_int64)src), order); + } + static MA_INLINE ma_uint8 ma_atomic_fetch_and_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_AND_CAS(8, dst, src, order); + } + static MA_INLINE ma_uint16 ma_atomic_fetch_and_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_AND_CAS(16, dst, src, order); + } + static MA_INLINE ma_uint32 ma_atomic_fetch_and_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_AND_CAS(32, dst, src, order); + } + static MA_INLINE ma_uint64 ma_atomic_fetch_and_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_AND_CAS(64, dst, src, order); + } + static MA_INLINE ma_uint8 ma_atomic_fetch_or_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_OR_CAS(8, dst, src, order); + } + static MA_INLINE ma_uint16 ma_atomic_fetch_or_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_OR_CAS(16, dst, src, order); + } + static MA_INLINE ma_uint32 ma_atomic_fetch_or_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_OR_CAS(32, dst, src, order); + } + static MA_INLINE ma_uint64 ma_atomic_fetch_or_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_OR_CAS(64, dst, src, order); + } + static MA_INLINE ma_uint8 ma_atomic_fetch_xor_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_XOR_CAS(8, dst, src, order); + } + static MA_INLINE ma_uint16 ma_atomic_fetch_xor_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_XOR_CAS(16, dst, src, order); + } + static MA_INLINE ma_uint32 ma_atomic_fetch_xor_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_XOR_CAS(32, dst, src, order); + } + static MA_INLINE ma_uint64 ma_atomic_fetch_xor_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_XOR_CAS(64, dst, src, order); + } + #else + #error Unsupported compiler. #endif - #define ma_atomic_signal_fence(order) ma_atomic_thread_fence(order) - static MA_INLINE ma_uint8 ma_atomic_load_explicit_8(volatile const ma_uint8* ptr, ma_atomic_memory_order order) - { - (void)order; - return ma_atomic_compare_and_swap_8((ma_uint8*)ptr, 0, 0); - } - static MA_INLINE ma_uint16 ma_atomic_load_explicit_16(volatile const ma_uint16* ptr, ma_atomic_memory_order order) - { - (void)order; - return ma_atomic_compare_and_swap_16((ma_uint16*)ptr, 0, 0); - } - static MA_INLINE ma_uint32 ma_atomic_load_explicit_32(volatile const ma_uint32* ptr, ma_atomic_memory_order order) - { - (void)order; - return ma_atomic_compare_and_swap_32((ma_uint32*)ptr, 0, 0); - } - static MA_INLINE ma_uint64 ma_atomic_load_explicit_64(volatile const ma_uint64* ptr, ma_atomic_memory_order order) - { - (void)order; - return ma_atomic_compare_and_swap_64((ma_uint64*)ptr, 0, 0); - } - #define ma_atomic_store_explicit_8( dst, src, order) (void)ma_atomic_exchange_explicit_8 (dst, src, order) - #define ma_atomic_store_explicit_16(dst, src, order) (void)ma_atomic_exchange_explicit_16(dst, src, order) - #define ma_atomic_store_explicit_32(dst, src, order) (void)ma_atomic_exchange_explicit_32(dst, src, order) - #define ma_atomic_store_explicit_64(dst, src, order) (void)ma_atomic_exchange_explicit_64(dst, src, order) - #define ma_atomic_test_and_set_explicit_8( dst, order) ma_atomic_exchange_explicit_8 (dst, 1, order) - #define ma_atomic_test_and_set_explicit_16(dst, order) ma_atomic_exchange_explicit_16(dst, 1, order) - #define ma_atomic_test_and_set_explicit_32(dst, order) ma_atomic_exchange_explicit_32(dst, 1, order) - #define ma_atomic_test_and_set_explicit_64(dst, order) ma_atomic_exchange_explicit_64(dst, 1, order) - #define ma_atomic_clear_explicit_8( dst, order) ma_atomic_store_explicit_8 (dst, 0, order) - #define ma_atomic_clear_explicit_16(dst, order) ma_atomic_store_explicit_16(dst, 0, order) - #define ma_atomic_clear_explicit_32(dst, order) ma_atomic_store_explicit_32(dst, 0, order) - #define ma_atomic_clear_explicit_64(dst, order) ma_atomic_store_explicit_64(dst, 0, order) - typedef ma_uint8 ma_atomic_flag; - #define ma_atomic_flag_test_and_set_explicit(ptr, order) (ma_bool32)ma_atomic_test_and_set_explicit_8(ptr, order) - #define ma_atomic_flag_clear_explicit(ptr, order) ma_atomic_clear_explicit_8(ptr, order) - #define ma_atomic_flag_load_explicit(ptr, order) ma_atomic_load_explicit_8(ptr, order) #endif #if !defined(MA_ATOMIC_HAS_NATIVE_COMPARE_EXCHANGE) - #if defined(MA_ATOMIC_HAS_8) - static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_8(volatile ma_uint8* dst, ma_uint8* expected, ma_uint8 desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) - { - ma_uint8 expectedValue; - ma_uint8 result; - (void)successOrder; - (void)failureOrder; - expectedValue = ma_atomic_load_explicit_8(expected, ma_atomic_memory_order_seq_cst); - result = ma_atomic_compare_and_swap_8(dst, expectedValue, desired); - if (result == expectedValue) { - return 1; - } else { - ma_atomic_store_explicit_8(expected, result, failureOrder); - return 0; - } - } - #endif - #if defined(MA_ATOMIC_HAS_16) - static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_16(volatile ma_uint16* dst, ma_uint16* expected, ma_uint16 desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) - { - ma_uint16 expectedValue; - ma_uint16 result; - (void)successOrder; - (void)failureOrder; - expectedValue = ma_atomic_load_explicit_16(expected, ma_atomic_memory_order_seq_cst); - result = ma_atomic_compare_and_swap_16(dst, expectedValue, desired); - if (result == expectedValue) { - return 1; - } else { - ma_atomic_store_explicit_16(expected, result, failureOrder); - return 0; - } - } - #endif - #if defined(MA_ATOMIC_HAS_32) - static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_32(volatile ma_uint32* dst, ma_uint32* expected, ma_uint32 desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) - { - ma_uint32 expectedValue; - ma_uint32 result; - (void)successOrder; - (void)failureOrder; - expectedValue = ma_atomic_load_explicit_32(expected, ma_atomic_memory_order_seq_cst); - result = ma_atomic_compare_and_swap_32(dst, expectedValue, desired); - if (result == expectedValue) { - return 1; - } else { - ma_atomic_store_explicit_32(expected, result, failureOrder); - return 0; - } - } - #endif - #if defined(MA_ATOMIC_HAS_64) - static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_64(volatile ma_uint64* dst, volatile ma_uint64* expected, ma_uint64 desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) - { - ma_uint64 expectedValue; - ma_uint64 result; - (void)successOrder; - (void)failureOrder; - expectedValue = ma_atomic_load_explicit_64(expected, ma_atomic_memory_order_seq_cst); - result = ma_atomic_compare_and_swap_64(dst, expectedValue, desired); - if (result == expectedValue) { - return 1; - } else { - ma_atomic_store_explicit_64(expected, result, failureOrder); - return 0; - } - } - #endif - #define ma_atomic_compare_exchange_weak_explicit_8( dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_8 (dst, expected, desired, successOrder, failureOrder) - #define ma_atomic_compare_exchange_weak_explicit_16(dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_16(dst, expected, desired, successOrder, failureOrder) - #define ma_atomic_compare_exchange_weak_explicit_32(dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_32(dst, expected, desired, successOrder, failureOrder) - #define ma_atomic_compare_exchange_weak_explicit_64(dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_64(dst, expected, desired, successOrder, failureOrder) -#endif -#if !defined(MA_ATOMIC_HAS_NATIVE_IS_LOCK_FREE) - static MA_INLINE ma_bool32 ma_atomic_is_lock_free_8(volatile void* ptr) + static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_8(volatile ma_uint8* dst, ma_uint8* expected, ma_uint8 replacement, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) { - (void)ptr; - return 1; - } - static MA_INLINE ma_bool32 ma_atomic_is_lock_free_16(volatile void* ptr) - { - (void)ptr; - return 1; - } - static MA_INLINE ma_bool32 ma_atomic_is_lock_free_32(volatile void* ptr) - { - (void)ptr; - return 1; - } - static MA_INLINE ma_bool32 ma_atomic_is_lock_free_64(volatile void* ptr) - { - (void)ptr; - #if defined(MA_64BIT) - return 1; - #else - #if defined(MA_X86) || defined(MA_X64) + ma_uint8 result; + (void)successOrder; + (void)failureOrder; + result = ma_atomic_compare_and_swap_8(dst, *expected, replacement); + if (result == *expected) { return 1; - #else + } else { + *expected = result; return 0; - #endif - #endif + } } + static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_16(volatile ma_uint16* dst, ma_uint16* expected, ma_uint16 replacement, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) + { + ma_uint16 result; + (void)successOrder; + (void)failureOrder; + result = ma_atomic_compare_and_swap_16(dst, *expected, replacement); + if (result == *expected) { + return 1; + } else { + *expected = result; + return 0; + } + } + static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_32(volatile ma_uint32* dst, ma_uint32* expected, ma_uint32 replacement, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) + { + ma_uint32 result; + (void)successOrder; + (void)failureOrder; + result = ma_atomic_compare_and_swap_32(dst, *expected, replacement); + if (result == *expected) { + return 1; + } else { + *expected = result; + return 0; + } + } + static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_64(volatile ma_uint64* dst, volatile ma_uint64* expected, ma_uint64 replacement, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) + { + ma_uint64 result; + (void)successOrder; + (void)failureOrder; + result = ma_atomic_compare_and_swap_64(dst, *expected, replacement); + if (result == *expected) { + return 1; + } else { + *expected = result; + return 0; + } + } + #define ma_atomic_compare_exchange_weak_explicit_8( dst, expected, replacement, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_8 (dst, expected, replacement, successOrder, failureOrder) + #define ma_atomic_compare_exchange_weak_explicit_16(dst, expected, replacement, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_16(dst, expected, replacement, successOrder, failureOrder) + #define ma_atomic_compare_exchange_weak_explicit_32(dst, expected, replacement, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_32(dst, expected, replacement, successOrder, failureOrder) + #define ma_atomic_compare_exchange_weak_explicit_64(dst, expected, replacement, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_64(dst, expected, replacement, successOrder, failureOrder) #endif #if defined(MA_64BIT) static MA_INLINE ma_bool32 ma_atomic_is_lock_free_ptr(volatile void** ptr) @@ -15561,17 +16968,17 @@ typedef int ma_atomic_memory_order; { return (void*)ma_atomic_exchange_explicit_64((volatile ma_uint64*)dst, (ma_uint64)src, order); } - static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_ptr(volatile void** dst, void** expected, void* desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) + static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_ptr(volatile void** dst, void** expected, void* replacement, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) { - return ma_atomic_compare_exchange_strong_explicit_64((volatile ma_uint64*)dst, (ma_uint64*)expected, (ma_uint64)desired, successOrder, failureOrder); + return ma_atomic_compare_exchange_strong_explicit_64((volatile ma_uint64*)dst, (ma_uint64*)expected, (ma_uint64)replacement, successOrder, failureOrder); } - static MA_INLINE ma_bool32 ma_atomic_compare_exchange_weak_explicit_ptr(volatile void** dst, void** expected, void* desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) + static MA_INLINE ma_bool32 ma_atomic_compare_exchange_weak_explicit_ptr(volatile void** dst, void** expected, void* replacement, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) { - return ma_atomic_compare_exchange_weak_explicit_64((volatile ma_uint64*)dst, (ma_uint64*)expected, (ma_uint64)desired, successOrder, failureOrder); + return ma_atomic_compare_exchange_weak_explicit_64((volatile ma_uint64*)dst, (ma_uint64*)expected, (ma_uint64)replacement, successOrder, failureOrder); } - static MA_INLINE void* ma_atomic_compare_and_swap_ptr(volatile void** dst, void* expected, void* desired) + static MA_INLINE void* ma_atomic_compare_and_swap_ptr(volatile void** dst, void* expected, void* replacement) { - return (void*)ma_atomic_compare_and_swap_64((volatile ma_uint64*)dst, (ma_uint64)expected, (ma_uint64)desired); + return (void*)ma_atomic_compare_and_swap_64((volatile ma_uint64*)dst, (ma_uint64)expected, (ma_uint64)replacement); } #elif defined(MA_32BIT) static MA_INLINE ma_bool32 ma_atomic_is_lock_free_ptr(volatile void** ptr) @@ -15590,36 +16997,26 @@ typedef int ma_atomic_memory_order; { return (void*)ma_atomic_exchange_explicit_32((volatile ma_uint32*)dst, (ma_uint32)src, order); } - static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_ptr(volatile void** dst, void** expected, void* desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) + static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_ptr(volatile void** dst, void** expected, void* replacement, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) { - return ma_atomic_compare_exchange_strong_explicit_32((volatile ma_uint32*)dst, (ma_uint32*)expected, (ma_uint32)desired, successOrder, failureOrder); + return ma_atomic_compare_exchange_strong_explicit_32((volatile ma_uint32*)dst, (ma_uint32*)expected, (ma_uint32)replacement, successOrder, failureOrder); } - static MA_INLINE ma_bool32 ma_atomic_compare_exchange_weak_explicit_ptr(volatile void** dst, void** expected, void* desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) + static MA_INLINE ma_bool32 ma_atomic_compare_exchange_weak_explicit_ptr(volatile void** dst, void** expected, void* replacement, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) { - return ma_atomic_compare_exchange_weak_explicit_32((volatile ma_uint32*)dst, (ma_uint32*)expected, (ma_uint32)desired, successOrder, failureOrder); + return ma_atomic_compare_exchange_weak_explicit_32((volatile ma_uint32*)dst, (ma_uint32*)expected, (ma_uint32)replacement, successOrder, failureOrder); } - static MA_INLINE void* ma_atomic_compare_and_swap_ptr(volatile void** dst, void* expected, void* desired) + static MA_INLINE void* ma_atomic_compare_and_swap_ptr(volatile void** dst, void* expected, void* replacement) { - return (void*)ma_atomic_compare_and_swap_32((volatile ma_uint32*)dst, (ma_uint32)expected, (ma_uint32)desired); + return (void*)ma_atomic_compare_and_swap_32((volatile ma_uint32*)dst, (ma_uint32)expected, (ma_uint32)replacement); } #else #error Unsupported architecture. #endif -#define ma_atomic_flag_test_and_set(ptr) ma_atomic_flag_test_and_set_explicit(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_flag_clear(ptr) ma_atomic_flag_clear_explicit(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_store_ptr(dst, src) ma_atomic_store_explicit_ptr((volatile void**)dst, (void*)src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_load_ptr(ptr) ma_atomic_load_explicit_ptr((volatile void**)ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_exchange_ptr(dst, src) ma_atomic_exchange_explicit_ptr((volatile void**)dst, (void*)src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_ptr(dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_ptr((volatile void**)dst, (void**)expected, (void*)desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_ptr(dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_ptr((volatile void**)dst, (void**)expected, (void*)desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_test_and_set_8( ptr) ma_atomic_test_and_set_explicit_8( ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_test_and_set_16(ptr) ma_atomic_test_and_set_explicit_16(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_test_and_set_32(ptr) ma_atomic_test_and_set_explicit_32(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_test_and_set_64(ptr) ma_atomic_test_and_set_explicit_64(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_clear_8( ptr) ma_atomic_clear_explicit_8( ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_clear_16(ptr) ma_atomic_clear_explicit_16(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_clear_32(ptr) ma_atomic_clear_explicit_32(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_clear_64(ptr) ma_atomic_clear_explicit_64(ptr, ma_atomic_memory_order_seq_cst) +#define ma_atomic_store_ptr(dst, src) ma_atomic_store_explicit_ptr((volatile void**)dst, (void*)src, ma_atomic_memory_order_seq_cst) +#define ma_atomic_load_ptr(ptr) ma_atomic_load_explicit_ptr((volatile void**)ptr, ma_atomic_memory_order_seq_cst) +#define ma_atomic_exchange_ptr(dst, src) ma_atomic_exchange_explicit_ptr((volatile void**)dst, (void*)src, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_strong_ptr(dst, expected, replacement) ma_atomic_compare_exchange_strong_explicit_ptr((volatile void**)dst, (void**)expected, (void*)replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_weak_ptr(dst, expected, replacement) ma_atomic_compare_exchange_weak_explicit_ptr((volatile void**)dst, (void**)expected, (void*)replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) #define ma_atomic_store_8( dst, src) ma_atomic_store_explicit_8( dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_store_16(dst, src) ma_atomic_store_explicit_16(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_store_32(dst, src) ma_atomic_store_explicit_32(dst, src, ma_atomic_memory_order_seq_cst) @@ -15632,14 +17029,14 @@ typedef int ma_atomic_memory_order; #define ma_atomic_exchange_16(dst, src) ma_atomic_exchange_explicit_16(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_exchange_32(dst, src) ma_atomic_exchange_explicit_32(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_exchange_64(dst, src) ma_atomic_exchange_explicit_64(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_8( dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_8( dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_16(dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_16(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_32(dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_32(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_64(dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_64(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_8( dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_8( dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_16( dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_16(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_32( dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_32(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_64( dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_64(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_strong_8( dst, expected, replacement) ma_atomic_compare_exchange_strong_explicit_8( dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_strong_16(dst, expected, replacement) ma_atomic_compare_exchange_strong_explicit_16(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_strong_32(dst, expected, replacement) ma_atomic_compare_exchange_strong_explicit_32(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_strong_64(dst, expected, replacement) ma_atomic_compare_exchange_strong_explicit_64(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_weak_8( dst, expected, replacement) ma_atomic_compare_exchange_weak_explicit_8( dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_weak_16( dst, expected, replacement) ma_atomic_compare_exchange_weak_explicit_16(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_weak_32( dst, expected, replacement) ma_atomic_compare_exchange_weak_explicit_32(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_weak_64( dst, expected, replacement) ma_atomic_compare_exchange_weak_explicit_64(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) #define ma_atomic_fetch_add_8( dst, src) ma_atomic_fetch_add_explicit_8( dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_fetch_add_16(dst, src) ma_atomic_fetch_add_explicit_16(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_fetch_add_32(dst, src) ma_atomic_fetch_add_explicit_32(dst, src, ma_atomic_memory_order_seq_cst) @@ -15660,14 +17057,6 @@ typedef int ma_atomic_memory_order; #define ma_atomic_fetch_and_16(dst, src) ma_atomic_fetch_and_explicit_16(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_fetch_and_32(dst, src) ma_atomic_fetch_and_explicit_32(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_fetch_and_64(dst, src) ma_atomic_fetch_and_explicit_64(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_test_and_set_explicit_i8( ptr, order) (ma_int8 )ma_atomic_test_and_set_explicit_8( (ma_uint8* )ptr, order) -#define ma_atomic_test_and_set_explicit_i16(ptr, order) (ma_int16)ma_atomic_test_and_set_explicit_16((ma_uint16*)ptr, order) -#define ma_atomic_test_and_set_explicit_i32(ptr, order) (ma_int32)ma_atomic_test_and_set_explicit_32((ma_uint32*)ptr, order) -#define ma_atomic_test_and_set_explicit_i64(ptr, order) (ma_int64)ma_atomic_test_and_set_explicit_64((ma_uint64*)ptr, order) -#define ma_atomic_clear_explicit_i8( ptr, order) ma_atomic_clear_explicit_8( (ma_uint8* )ptr, order) -#define ma_atomic_clear_explicit_i16(ptr, order) ma_atomic_clear_explicit_16((ma_uint16*)ptr, order) -#define ma_atomic_clear_explicit_i32(ptr, order) ma_atomic_clear_explicit_32((ma_uint32*)ptr, order) -#define ma_atomic_clear_explicit_i64(ptr, order) ma_atomic_clear_explicit_64((ma_uint64*)ptr, order) #define ma_atomic_store_explicit_i8( dst, src, order) ma_atomic_store_explicit_8( (ma_uint8* )dst, (ma_uint8 )src, order) #define ma_atomic_store_explicit_i16(dst, src, order) ma_atomic_store_explicit_16((ma_uint16*)dst, (ma_uint16)src, order) #define ma_atomic_store_explicit_i32(dst, src, order) ma_atomic_store_explicit_32((ma_uint32*)dst, (ma_uint32)src, order) @@ -15680,14 +17069,14 @@ typedef int ma_atomic_memory_order; #define ma_atomic_exchange_explicit_i16(dst, src, order) (ma_int16)ma_atomic_exchange_explicit_16((ma_uint16*)dst, (ma_uint16)src, order) #define ma_atomic_exchange_explicit_i32(dst, src, order) (ma_int32)ma_atomic_exchange_explicit_32((ma_uint32*)dst, (ma_uint32)src, order) #define ma_atomic_exchange_explicit_i64(dst, src, order) (ma_int64)ma_atomic_exchange_explicit_64((ma_uint64*)dst, (ma_uint64)src, order) -#define ma_atomic_compare_exchange_strong_explicit_i8( dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_8( (ma_uint8* )dst, (ma_uint8* )expected, (ma_uint8 )desired, successOrder, failureOrder) -#define ma_atomic_compare_exchange_strong_explicit_i16(dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_16((ma_uint16*)dst, (ma_uint16*)expected, (ma_uint16)desired, successOrder, failureOrder) -#define ma_atomic_compare_exchange_strong_explicit_i32(dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_32((ma_uint32*)dst, (ma_uint32*)expected, (ma_uint32)desired, successOrder, failureOrder) -#define ma_atomic_compare_exchange_strong_explicit_i64(dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_64((ma_uint64*)dst, (ma_uint64*)expected, (ma_uint64)desired, successOrder, failureOrder) -#define ma_atomic_compare_exchange_weak_explicit_i8( dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_weak_explicit_8( (ma_uint8* )dst, (ma_uint8* )expected, (ma_uint8 )desired, successOrder, failureOrder) -#define ma_atomic_compare_exchange_weak_explicit_i16(dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_weak_explicit_16((ma_uint16*)dst, (ma_uint16*)expected, (ma_uint16)desired, successOrder, failureOrder) -#define ma_atomic_compare_exchange_weak_explicit_i32(dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_weak_explicit_32((ma_uint32*)dst, (ma_uint32*)expected, (ma_uint32)desired, successOrder, failureOrder) -#define ma_atomic_compare_exchange_weak_explicit_i64(dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_weak_explicit_64((ma_uint64*)dst, (ma_uint64*)expected, (ma_uint64)desired, successOrder, failureOrder) +#define ma_atomic_compare_exchange_strong_explicit_i8( dst, expected, replacement, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_8( (ma_uint8* )dst, (ma_uint8* )expected, (ma_uint8 )replacement, successOrder, failureOrder) +#define ma_atomic_compare_exchange_strong_explicit_i16(dst, expected, replacement, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_16((ma_uint16*)dst, (ma_uint16*)expected, (ma_uint16)replacement, successOrder, failureOrder) +#define ma_atomic_compare_exchange_strong_explicit_i32(dst, expected, replacement, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_32((ma_uint32*)dst, (ma_uint32*)expected, (ma_uint32)replacement, successOrder, failureOrder) +#define ma_atomic_compare_exchange_strong_explicit_i64(dst, expected, replacement, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_64((ma_uint64*)dst, (ma_uint64*)expected, (ma_uint64)replacement, successOrder, failureOrder) +#define ma_atomic_compare_exchange_weak_explicit_i8( dst, expected, replacement, successOrder, failureOrder) ma_atomic_compare_exchange_weak_explicit_8( (ma_uint8* )dst, (ma_uint8* )expected, (ma_uint8 )replacement, successOrder, failureOrder) +#define ma_atomic_compare_exchange_weak_explicit_i16(dst, expected, replacement, successOrder, failureOrder) ma_atomic_compare_exchange_weak_explicit_16((ma_uint16*)dst, (ma_uint16*)expected, (ma_uint16)replacement, successOrder, failureOrder) +#define ma_atomic_compare_exchange_weak_explicit_i32(dst, expected, replacement, successOrder, failureOrder) ma_atomic_compare_exchange_weak_explicit_32((ma_uint32*)dst, (ma_uint32*)expected, (ma_uint32)replacement, successOrder, failureOrder) +#define ma_atomic_compare_exchange_weak_explicit_i64(dst, expected, replacement, successOrder, failureOrder) ma_atomic_compare_exchange_weak_explicit_64((ma_uint64*)dst, (ma_uint64*)expected, (ma_uint64)replacement, successOrder, failureOrder) #define ma_atomic_fetch_add_explicit_i8( dst, src, order) (ma_int8 )ma_atomic_fetch_add_explicit_8( (ma_uint8* )dst, (ma_uint8 )src, order) #define ma_atomic_fetch_add_explicit_i16(dst, src, order) (ma_int16)ma_atomic_fetch_add_explicit_16((ma_uint16*)dst, (ma_uint16)src, order) #define ma_atomic_fetch_add_explicit_i32(dst, src, order) (ma_int32)ma_atomic_fetch_add_explicit_32((ma_uint32*)dst, (ma_uint32)src, order) @@ -15708,14 +17097,6 @@ typedef int ma_atomic_memory_order; #define ma_atomic_fetch_and_explicit_i16(dst, src, order) (ma_int16)ma_atomic_fetch_and_explicit_16((ma_uint16*)dst, (ma_uint16)src, order) #define ma_atomic_fetch_and_explicit_i32(dst, src, order) (ma_int32)ma_atomic_fetch_and_explicit_32((ma_uint32*)dst, (ma_uint32)src, order) #define ma_atomic_fetch_and_explicit_i64(dst, src, order) (ma_int64)ma_atomic_fetch_and_explicit_64((ma_uint64*)dst, (ma_uint64)src, order) -#define ma_atomic_test_and_set_i8( ptr) ma_atomic_test_and_set_explicit_i8( ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_test_and_set_i16(ptr) ma_atomic_test_and_set_explicit_i16(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_test_and_set_i32(ptr) ma_atomic_test_and_set_explicit_i32(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_test_and_set_i64(ptr) ma_atomic_test_and_set_explicit_i64(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_clear_i8( ptr) ma_atomic_clear_explicit_i8( ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_clear_i16(ptr) ma_atomic_clear_explicit_i16(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_clear_i32(ptr) ma_atomic_clear_explicit_i32(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_clear_i64(ptr) ma_atomic_clear_explicit_i64(ptr, ma_atomic_memory_order_seq_cst) #define ma_atomic_store_i8( dst, src) ma_atomic_store_explicit_i8( dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_store_i16(dst, src) ma_atomic_store_explicit_i16(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_store_i32(dst, src) ma_atomic_store_explicit_i32(dst, src, ma_atomic_memory_order_seq_cst) @@ -15728,14 +17109,14 @@ typedef int ma_atomic_memory_order; #define ma_atomic_exchange_i16(dst, src) ma_atomic_exchange_explicit_i16(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_exchange_i32(dst, src) ma_atomic_exchange_explicit_i32(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_exchange_i64(dst, src) ma_atomic_exchange_explicit_i64(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_i8( dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_i8( dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_i16(dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_i16(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_i32(dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_i32(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_i64(dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_i64(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_i8( dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_i8( dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_i16(dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_i16(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_i32(dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_i32(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_i64(dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_i64(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_strong_i8( dst, expected, replacement) ma_atomic_compare_exchange_strong_explicit_i8( dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_strong_i16(dst, expected, replacement) ma_atomic_compare_exchange_strong_explicit_i16(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_strong_i32(dst, expected, replacement) ma_atomic_compare_exchange_strong_explicit_i32(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_strong_i64(dst, expected, replacement) ma_atomic_compare_exchange_strong_explicit_i64(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_weak_i8( dst, expected, replacement) ma_atomic_compare_exchange_weak_explicit_i8( dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_weak_i16(dst, expected, replacement) ma_atomic_compare_exchange_weak_explicit_i16(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_weak_i32(dst, expected, replacement) ma_atomic_compare_exchange_weak_explicit_i32(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_weak_i64(dst, expected, replacement) ma_atomic_compare_exchange_weak_explicit_i64(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) #define ma_atomic_fetch_add_i8( dst, src) ma_atomic_fetch_add_explicit_i8( dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_fetch_add_i16(dst, src) ma_atomic_fetch_add_explicit_i16(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_fetch_add_i32(dst, src) ma_atomic_fetch_add_explicit_i32(dst, src, ma_atomic_memory_order_seq_cst) @@ -15812,28 +17193,28 @@ static MA_INLINE double ma_atomic_exchange_explicit_f64(volatile double* dst, do r.i = ma_atomic_exchange_explicit_64((volatile ma_uint64*)dst, x.i, order); return r.f; } -static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_f32(volatile float* dst, float* expected, float desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) +static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_f32(volatile float* dst, float* expected, float replacement, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) { ma_atomic_if32 d; - d.f = desired; + d.f = replacement; return ma_atomic_compare_exchange_strong_explicit_32((volatile ma_uint32*)dst, (ma_uint32*)expected, d.i, successOrder, failureOrder); } -static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_f64(volatile double* dst, double* expected, double desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) +static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_f64(volatile double* dst, double* expected, double replacement, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) { ma_atomic_if64 d; - d.f = desired; + d.f = replacement; return ma_atomic_compare_exchange_strong_explicit_64((volatile ma_uint64*)dst, (ma_uint64*)expected, d.i, successOrder, failureOrder); } -static MA_INLINE ma_bool32 ma_atomic_compare_exchange_weak_explicit_f32(volatile float* dst, float* expected, float desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) +static MA_INLINE ma_bool32 ma_atomic_compare_exchange_weak_explicit_f32(volatile float* dst, float* expected, float replacement, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) { ma_atomic_if32 d; - d.f = desired; + d.f = replacement; return ma_atomic_compare_exchange_weak_explicit_32((volatile ma_uint32*)dst, (ma_uint32*)expected, d.i, successOrder, failureOrder); } -static MA_INLINE ma_bool32 ma_atomic_compare_exchange_weak_explicit_f64(volatile double* dst, double* expected, double desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) +static MA_INLINE ma_bool32 ma_atomic_compare_exchange_weak_explicit_f64(volatile double* dst, double* expected, double replacement, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) { ma_atomic_if64 d; - d.f = desired; + d.f = replacement; return ma_atomic_compare_exchange_weak_explicit_64((volatile ma_uint64*)dst, (ma_uint64*)expected, d.i, successOrder, failureOrder); } static MA_INLINE float ma_atomic_fetch_add_explicit_f32(volatile float* dst, float src, ma_atomic_memory_order order) @@ -15924,10 +17305,10 @@ static MA_INLINE double ma_atomic_fetch_and_explicit_f64(volatile double* dst, d #define ma_atomic_load_f64(ptr) (double)ma_atomic_load_explicit_f64(ptr, ma_atomic_memory_order_seq_cst) #define ma_atomic_exchange_f32(dst, src) (float )ma_atomic_exchange_explicit_f32(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_exchange_f64(dst, src) (double)ma_atomic_exchange_explicit_f64(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_f32(dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_f32(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_f64(dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_f64(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_f32(dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_f32(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_f64(dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_f64(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_strong_f32(dst, expected, replacement) ma_atomic_compare_exchange_strong_explicit_f32(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_strong_f64(dst, expected, replacement) ma_atomic_compare_exchange_strong_explicit_f64(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_weak_f32(dst, expected, replacement) ma_atomic_compare_exchange_weak_explicit_f32(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_weak_f64(dst, expected, replacement) ma_atomic_compare_exchange_weak_explicit_f64(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) #define ma_atomic_fetch_add_f32(dst, src) ma_atomic_fetch_add_explicit_f32(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_fetch_add_f64(dst, src) ma_atomic_fetch_add_explicit_f64(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_fetch_sub_f32(dst, src) ma_atomic_fetch_sub_explicit_f32(dst, src, ma_atomic_memory_order_seq_cst) @@ -15938,39 +17319,24 @@ static MA_INLINE double ma_atomic_fetch_and_explicit_f64(volatile double* dst, d #define ma_atomic_fetch_xor_f64(dst, src) ma_atomic_fetch_xor_explicit_f64(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_fetch_and_f32(dst, src) ma_atomic_fetch_and_explicit_f32(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_fetch_and_f64(dst, src) ma_atomic_fetch_and_explicit_f64(dst, src, ma_atomic_memory_order_seq_cst) -static MA_INLINE float ma_atomic_compare_and_swap_f32(volatile float* dst, float expected, float desired) +static MA_INLINE float ma_atomic_compare_and_swap_f32(volatile float* dst, float expected, float replacement) { ma_atomic_if32 r; ma_atomic_if32 e, d; e.f = expected; - d.f = desired; + d.f = replacement; r.i = ma_atomic_compare_and_swap_32((volatile ma_uint32*)dst, e.i, d.i); return r.f; } -static MA_INLINE double ma_atomic_compare_and_swap_f64(volatile double* dst, double expected, double desired) +static MA_INLINE double ma_atomic_compare_and_swap_f64(volatile double* dst, double expected, double replacement) { ma_atomic_if64 r; ma_atomic_if64 e, d; e.f = expected; - d.f = desired; + d.f = replacement; r.i = ma_atomic_compare_and_swap_64((volatile ma_uint64*)dst, e.i, d.i); return r.f; } -typedef ma_atomic_flag ma_atomic_spinlock; -static MA_INLINE void ma_atomic_spinlock_lock(volatile ma_atomic_spinlock* pSpinlock) -{ - for (;;) { - if (ma_atomic_flag_test_and_set_explicit(pSpinlock, ma_atomic_memory_order_acquire) == 0) { - break; - } - while (ma_atomic_flag_load_explicit(pSpinlock, ma_atomic_memory_order_relaxed) == 1) { - } - } -} -static MA_INLINE void ma_atomic_spinlock_unlock(volatile ma_atomic_spinlock* pSpinlock) -{ - ma_atomic_flag_clear_explicit(pSpinlock, ma_atomic_memory_order_release); -} #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) #pragma GCC diagnostic pop #endif @@ -16176,7 +17542,7 @@ static ma_result ma_thread_create__posix(ma_thread* pThread, ma_thread_priority int result; pthread_attr_t* pAttr = NULL; -#if !defined(__EMSCRIPTEN__) && !defined(__3DS__) +#if !defined(MA_EMSCRIPTEN) && !defined(MA_3DS) && !defined(MA_SWITCH) /* Try setting the thread priority. It's not critical if anything fails here. */ pthread_attr_t attr; if (pthread_attr_init(&attr) == 0) { @@ -16208,9 +17574,18 @@ static ma_result ma_thread_create__posix(ma_thread* pThread, ma_thread_priority } #endif - if (stackSize > 0) { - pthread_attr_setstacksize(&attr, stackSize); + #if defined(_POSIX_THREAD_ATTR_STACKSIZE) && _POSIX_THREAD_ATTR_STACKSIZE >= 0 + { + if (stackSize > 0) { + pthread_attr_setstacksize(&attr, stackSize); + } } + #else + { + (void)stackSize; /* Suppress unused parameter warning. */ + } + #endif + if (scheduler != -1) { int priorityMin = sched_get_priority_min(scheduler); @@ -16267,6 +17642,21 @@ static ma_result ma_thread_create__posix(ma_thread* pThread, ma_thread_priority } if (result != 0) { + /* + There have been reports that attempting to create a realtime thread can sometimes fail. In this case, + fall back to a normal priority thread. + + I'm including a compile-time option here to disable this functionality for those who have a hard + requirement on realtime threads and would rather an explicit failure. + */ + #ifndef MA_NO_PTHREAD_REALTIME_PRIORITY_FALLBACK + { + if(result == EPERM && priority == ma_thread_priority_realtime) { + return ma_thread_create__posix(pThread, ma_thread_priority_normal, stackSize, entryProc, pData); + } + } + #endif + return ma_result_from_errno(result); } @@ -16538,7 +17928,7 @@ static ma_result ma_event_signal__win32(ma_event* pEvent) static ma_result ma_semaphore_init__win32(int initialValue, ma_semaphore* pSemaphore) { - *pSemaphore = CreateSemaphoreW(NULL, (LONG)initialValue, LONG_MAX, NULL); + *pSemaphore = CreateSemaphore(NULL, (LONG)initialValue, LONG_MAX, NULL); if (*pSemaphore == NULL) { return ma_result_from_GetLastError(GetLastError()); } @@ -17432,10 +18822,12 @@ static MA_INLINE ma_uint16 ma_job_extract_slot(ma_uint64 toc) return (ma_uint16)(toc & 0x0000FFFF); } +#if 0 /* Currently unused, but might make use of this later. */ static MA_INLINE ma_uint16 ma_job_extract_code(ma_uint64 toc) { return (ma_uint16)((toc & 0xFFFF0000) >> 16); } +#endif static MA_INLINE ma_uint64 ma_job_toc_to_allocation(ma_uint64 toc) { @@ -17900,6 +19292,13 @@ MA_API ma_result ma_job_queue_next(ma_job_queue* pQueue, ma_job* pJob) Dynamic Linking *******************************************************************************/ +/* Disable run-time linking on certain backends and platforms. */ +#ifndef MA_NO_RUNTIME_LINKING + #if defined(MA_EMSCRIPTEN) || defined(MA_ORBIS) || defined(MA_PROSPERO) || defined(MA_SWITCH) || defined(MA_DOS) + #define MA_NO_RUNTIME_LINKING + #endif +#endif + #ifdef MA_POSIX /* No need for dlfcn.h if we're not using runtime linking. */ #ifndef MA_NO_RUNTIME_LINKING @@ -17909,104 +19308,124 @@ Dynamic Linking MA_API ma_handle ma_dlopen(ma_log* pLog, const char* filename) { -#ifndef MA_NO_RUNTIME_LINKING - ma_handle handle; + #ifndef MA_NO_RUNTIME_LINKING + { + ma_handle handle; - ma_log_postf(pLog, MA_LOG_LEVEL_DEBUG, "Loading library: %s\n", filename); + ma_log_postf(pLog, MA_LOG_LEVEL_DEBUG, "Loading library: %s\n", filename); - #ifdef MA_WIN32 - /* From MSDN: Desktop applications cannot use LoadPackagedLibrary; if a desktop application calls this function it fails with APPMODEL_ERROR_NO_PACKAGE.*/ - #if !defined(MA_WIN32_UWP) || !(defined(WINAPI_FAMILY) && ((defined(WINAPI_FAMILY_PHONE_APP) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP))) - handle = (ma_handle)LoadLibraryA(filename); + #ifdef MA_WIN32 + /* From MSDN: Desktop applications cannot use LoadPackagedLibrary; if a desktop application calls this function it fails with APPMODEL_ERROR_NO_PACKAGE.*/ + #if !defined(MA_WIN32_UWP) || !(defined(WINAPI_FAMILY) && ((defined(WINAPI_FAMILY_PHONE_APP) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP))) + handle = (ma_handle)LoadLibraryA(filename); + #else + /* *sigh* It appears there is no ANSI version of LoadPackagedLibrary()... */ + WCHAR filenameW[4096]; + if (MultiByteToWideChar(CP_UTF8, 0, filename, -1, filenameW, sizeof(filenameW)) == 0) { + handle = NULL; + } else { + handle = (ma_handle)LoadPackagedLibrary(filenameW, 0); + } + #endif #else - /* *sigh* It appears there is no ANSI version of LoadPackagedLibrary()... */ - WCHAR filenameW[4096]; - if (MultiByteToWideChar(CP_UTF8, 0, filename, -1, filenameW, sizeof(filenameW)) == 0) { - handle = NULL; - } else { - handle = (ma_handle)LoadPackagedLibrary(filenameW, 0); - } + handle = (ma_handle)dlopen(filename, RTLD_NOW); #endif - #else - handle = (ma_handle)dlopen(filename, RTLD_NOW); - #endif - /* - I'm not considering failure to load a library an error nor a warning because seamlessly falling through to a lower-priority - backend is a deliberate design choice. Instead I'm logging it as an informational message. - */ - if (handle == NULL) { - ma_log_postf(pLog, MA_LOG_LEVEL_INFO, "Failed to load library: %s\n", filename); + /* + I'm not considering failure to load a library an error nor a warning because seamlessly falling through to a lower-priority + backend is a deliberate design choice. Instead I'm logging it as an informational message. + */ + if (handle == NULL) { + ma_log_postf(pLog, MA_LOG_LEVEL_INFO, "Failed to load library: %s\n", filename); + } + + return handle; } - - return handle; -#else - /* Runtime linking is disabled. */ - (void)pLog; - (void)filename; - return NULL; -#endif + #else + { + /* Runtime linking is disabled. */ + (void)pLog; + (void)filename; + return NULL; + } + #endif } MA_API void ma_dlclose(ma_log* pLog, ma_handle handle) { -#ifndef MA_NO_RUNTIME_LINKING - #ifdef MA_WIN32 - FreeLibrary((HMODULE)handle); - #else - /* Hack for Android bug (see https://github.com/android/ndk/issues/360). Calling dlclose() pre-API 28 may segfault. */ - #if !defined(MA_ANDROID) || (defined(__ANDROID_API__) && __ANDROID_API__ >= 28) + #ifndef MA_NO_RUNTIME_LINKING + { + #ifdef MA_WIN32 { - dlclose((void*)handle); + FreeLibrary((HMODULE)handle); } #else { - (void)handle; + /* Hack for Android bug (see https://github.com/android/ndk/issues/360). Calling dlclose() pre-API 28 may segfault. */ + #if !defined(MA_ANDROID) || (defined(__ANDROID_API__) && __ANDROID_API__ >= 28) + { + dlclose((void*)handle); + } + #else + { + (void)handle; + } + #endif } #endif - #endif - (void)pLog; -#else - /* Runtime linking is disabled. */ - (void)pLog; - (void)handle; -#endif + (void)pLog; + } + #else + { + /* Runtime linking is disabled. */ + (void)pLog; + (void)handle; + } + #endif } MA_API ma_proc ma_dlsym(ma_log* pLog, ma_handle handle, const char* symbol) { -#ifndef MA_NO_RUNTIME_LINKING - ma_proc proc; + #ifndef MA_NO_RUNTIME_LINKING + { + ma_proc proc; - ma_log_postf(pLog, MA_LOG_LEVEL_DEBUG, "Loading symbol: %s\n", symbol); + ma_log_postf(pLog, MA_LOG_LEVEL_DEBUG, "Loading symbol: %s\n", symbol); -#ifdef _WIN32 - proc = (ma_proc)GetProcAddress((HMODULE)handle, symbol); -#else -#if (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) || defined(__clang__) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wpedantic" -#endif - proc = (ma_proc)dlsym((void*)handle, symbol); -#if (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) || defined(__clang__) - #pragma GCC diagnostic pop -#endif -#endif + #ifdef _WIN32 + { + proc = (ma_proc)GetProcAddress((HMODULE)handle, symbol); + } + #else + { + #if (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) || defined(__clang__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wpedantic" + #endif + proc = (ma_proc)dlsym((void*)handle, symbol); + #if (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) || defined(__clang__) + #pragma GCC diagnostic pop + #endif + } + #endif - if (proc == NULL) { - ma_log_postf(pLog, MA_LOG_LEVEL_WARNING, "Failed to load symbol: %s\n", symbol); + if (proc == NULL) { + ma_log_postf(pLog, MA_LOG_LEVEL_WARNING, "Failed to load symbol: %s\n", symbol); + } + + (void)pLog; /* It's possible for pContext to be unused. */ + return proc; } - - (void)pLog; /* It's possible for pContext to be unused. */ - return proc; -#else - /* Runtime linking is disabled. */ - (void)pLog; - (void)handle; - (void)symbol; - return NULL; -#endif + #else + { + /* Runtime linking is disabled. */ + (void)pLog; + (void)handle; + (void)symbol; + return NULL; + } + #endif } @@ -18020,13 +19439,6 @@ DEVICE I/O ************************************************************************************************************************************************************* ************************************************************************************************************************************************************/ -/* Disable run-time linking on certain backends and platforms. */ -#ifndef MA_NO_RUNTIME_LINKING - #if defined(MA_EMSCRIPTEN) || defined(MA_ORBIS) || defined(MA_PROSPERO) - #define MA_NO_RUNTIME_LINKING - #endif -#endif - #ifdef MA_APPLE #include #endif @@ -18039,12 +19451,6 @@ DEVICE I/O #ifdef MA_POSIX #include - #include - - /* No need for dlfcn.h if we're not using runtime linking. */ - #ifndef MA_NO_RUNTIME_LINKING - #include - #endif #endif /* This must be set to at least 26. */ @@ -18299,7 +19705,7 @@ MA_API ma_bool32 ma_is_loopback_supported(ma_backend backend) -#if defined(MA_WIN32) +#if defined(MA_WIN32) && !defined(MA_XBOX) /* WASAPI error codes. */ #define MA_AUDCLNT_E_NOT_INITIALIZED ((HRESULT)0x88890001) #define MA_AUDCLNT_E_ALREADY_INITIALIZED ((HRESULT)0x88890002) @@ -18514,6 +19920,11 @@ typedef LONG (WINAPI * MA_PFN_RegCloseKey)(HKEY hKey); typedef LONG (WINAPI * MA_PFN_RegQueryValueExA)(HKEY hKey, const char* lpValueName, DWORD* lpReserved, DWORD* lpType, BYTE* lpData, DWORD* lpcbData); #endif /* MA_WIN32_DESKTOP */ +static GUID MA_GUID_KSDATAFORMAT_SUBTYPE_PCM = {0x00000001, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; +static GUID MA_GUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = {0x00000003, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; +/*static GUID MA_GUID_KSDATAFORMAT_SUBTYPE_ALAW = {0x00000006, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};*/ +/*static GUID MA_GUID_KSDATAFORMAT_SUBTYPE_MULAW = {0x00000007, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};*/ + MA_API size_t ma_strlen_WCHAR(const WCHAR* str) { size_t len = 0; @@ -18577,7 +19988,7 @@ Timing *******************************************************************************/ #if defined(MA_WIN32) && !defined(MA_POSIX) static LARGE_INTEGER g_ma_TimerFrequency; /* <-- Initialized to zero since it's static. */ - static void ma_timer_init(ma_timer* pTimer) + static MA_INLINE void ma_timer_init(ma_timer* pTimer) { LARGE_INTEGER counter; @@ -18589,7 +20000,7 @@ Timing pTimer->counter = counter.QuadPart; } - static double ma_timer_get_time_in_seconds(ma_timer* pTimer) + static MA_INLINE double ma_timer_get_time_in_seconds(ma_timer* pTimer) { LARGE_INTEGER counter; if (!QueryPerformanceCounter(&counter)) { @@ -18600,7 +20011,7 @@ Timing } #elif defined(MA_APPLE) && (MAC_OS_X_VERSION_MIN_REQUIRED < 101200) static ma_uint64 g_ma_TimerFrequency = 0; - static void ma_timer_init(ma_timer* pTimer) + static MA_INLINE void ma_timer_init(ma_timer* pTimer) { mach_timebase_info_data_t baseTime; mach_timebase_info(&baseTime); @@ -18609,7 +20020,7 @@ Timing pTimer->counter = mach_absolute_time(); } - static double ma_timer_get_time_in_seconds(ma_timer* pTimer) + static MA_INLINE double ma_timer_get_time_in_seconds(ma_timer* pTimer) { ma_uint64 newTimeCounter = mach_absolute_time(); ma_uint64 oldTimeCounter = pTimer->counter; @@ -18634,7 +20045,7 @@ Timing #define MA_CLOCK_ID CLOCK_REALTIME #endif - static void ma_timer_init(ma_timer* pTimer) + static MA_INLINE void ma_timer_init(ma_timer* pTimer) { struct timespec newTime; clock_gettime(MA_CLOCK_ID, &newTime); @@ -18642,7 +20053,7 @@ Timing pTimer->counter = (newTime.tv_sec * 1000000000) + newTime.tv_nsec; } - static double ma_timer_get_time_in_seconds(ma_timer* pTimer) + static MA_INLINE double ma_timer_get_time_in_seconds(ma_timer* pTimer) { ma_uint64 newTimeCounter; ma_uint64 oldTimeCounter; @@ -18656,7 +20067,7 @@ Timing return (newTimeCounter - oldTimeCounter) / 1000000000.0; } #else - static void ma_timer_init(ma_timer* pTimer) + static MA_INLINE void ma_timer_init(ma_timer* pTimer) { struct timeval newTime; gettimeofday(&newTime, NULL); @@ -18664,7 +20075,7 @@ Timing pTimer->counter = (newTime.tv_sec * 1000000) + newTime.tv_usec; } - static double ma_timer_get_time_in_seconds(ma_timer* pTimer) + static MA_INLINE double ma_timer_get_time_in_seconds(ma_timer* pTimer) { ma_uint64 newTimeCounter; ma_uint64 oldTimeCounter; @@ -19248,14 +20659,6 @@ static MA_INLINE void ma_device__set_state(ma_device* pDevice, ma_device_state n } -#if defined(MA_WIN32) - static GUID MA_GUID_KSDATAFORMAT_SUBTYPE_PCM = {0x00000001, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; - static GUID MA_GUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = {0x00000003, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; - /*static GUID MA_GUID_KSDATAFORMAT_SUBTYPE_ALAW = {0x00000006, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};*/ - /*static GUID MA_GUID_KSDATAFORMAT_SUBTYPE_MULAW = {0x00000007, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};*/ -#endif - - MA_API ma_uint32 ma_get_format_priority_index(ma_format format) /* Lower = better. */ { @@ -19967,7 +21370,7 @@ static ma_result ma_context_init__null(ma_context* pContext, const ma_context_co WIN32 COMMON *******************************************************************************/ -#if defined(MA_WIN32) +#if defined(MA_WIN32) && !defined(MA_XBOX) #if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) #define ma_CoInitializeEx(pContext, pvReserved, dwCoInit) ((pContext->win32.CoInitializeEx) ? ((MA_PFN_CoInitializeEx)pContext->win32.CoInitializeEx)(pvReserved, dwCoInit) : ((MA_PFN_CoInitialize)pContext->win32.CoInitialize)(pvReserved)) #define ma_CoUninitialize(pContext) ((MA_PFN_CoUninitialize)pContext->win32.CoUninitialize)() @@ -19982,7 +21385,7 @@ WIN32 COMMON #define ma_PropVariantClear(pContext, pvar) PropVariantClear(pvar) #endif -#if !defined(MAXULONG_PTR) && !defined(__WATCOMC__) +#if !defined(MAXULONG_PTR) && !defined(__WATCOMC__) && !defined(MA_XBOX_NXDK) typedef size_t DWORD_PTR; #endif @@ -20409,11 +21812,21 @@ typedef enum MA_AudioCategory_Other = 0 /* <-- miniaudio is only caring about Other. */ } MA_AUDIO_STREAM_CATEGORY; +typedef enum +{ + MA_AUDCLNT_STREAMOPTIONS_NONE, + MA_AUDCLNT_STREAMOPTIONS_RAW, + MA_AUDCLNT_STREAMOPTIONS_MATCH_FORMAT, + MA_AUDCLNT_STREAMOPTIONS_AMBISONICS, + MA_AUDCLNT_STREAMOPTIONS_POST_VOLUME_LOOPBACK +} MA_AUDCLNT_STREAMOPTIONS; + typedef struct { ma_uint32 cbSize; BOOL bIsOffload; MA_AUDIO_STREAM_CATEGORY eCategory; + MA_AUDCLNT_STREAMOPTIONS Options; } ma_AudioClientProperties; /* IUnknown */ @@ -21588,6 +23001,7 @@ static ma_result ma_context_get_MMDevice__wasapi(ma_context* pContext, ma_device { ma_IMMDeviceEnumerator* pDeviceEnumerator; HRESULT hr; + HRESULT CoInitializeResult; MA_ASSERT(pContext != NULL); MA_ASSERT(ppMMDevice != NULL); @@ -21601,12 +23015,17 @@ static ma_result ma_context_get_MMDevice__wasapi(ma_context* pContext, ma_device The community has reported that this seems to fix the crash. There are future plans to move all WASAPI operation over to a single thread to make everything safer, but in the meantime while we wait for that to come online I'm happy enough to use this hack instead. + + CoUninitialize should only be called if we successfully initialized. S_OK and S_FALSE both mean that we need to + call CoUninitialize since the internal ref count was increased. RPC_E_CHANGED_MODE means that CoInitializeEx was + called with a different COINIT value, and we don't call CoUninitialize in that case. Other errors are possible, + so we check for S_OK and S_FALSE specifically. */ - ma_CoInitializeEx(pContext, NULL, MA_COINIT_VALUE); + CoInitializeResult = ma_CoInitializeEx(pContext, NULL, MA_COINIT_VALUE); { hr = ma_CoCreateInstance(pContext, &MA_CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, &MA_IID_IMMDeviceEnumerator, (void**)&pDeviceEnumerator); - } - ma_CoUninitialize(pContext); + } + if (CoInitializeResult == S_OK || CoInitializeResult == S_FALSE) { ma_CoUninitialize(pContext); } if (FAILED(hr)) { /* <-- This is checking the call above to ma_CoCreateInstance(). */ ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create IMMDeviceEnumerator.\n"); @@ -21950,7 +23369,7 @@ static ma_result ma_context_get_IAudioClient__wasapi(ma_context* pContext, ma_de pActivationParams = &activationParams; /* When requesting a specific device ID we need to use a special device ID. */ - MA_COPY_MEMORY(virtualDeviceID.wasapi, MA_VIRTUAL_AUDIO_DEVICE_PROCESS_LOOPBACK, (wcslen(MA_VIRTUAL_AUDIO_DEVICE_PROCESS_LOOPBACK) + 1) * sizeof(wchar_t)); /* +1 for the null terminator. */ + MA_COPY_MEMORY(virtualDeviceID.wasapi, MA_VIRTUAL_AUDIO_DEVICE_PROCESS_LOOPBACK, (ma_wcslen(MA_VIRTUAL_AUDIO_DEVICE_PROCESS_LOOPBACK) + 1) * sizeof(wchar_t)); /* +1 for the null terminator. */ pDeviceID = &virtualDeviceID; } else { pActivationParams = NULL; /* No activation parameters required. */ @@ -26679,6 +28098,9 @@ typedef snd_pcm_channel_area_t ma_snd_pcm_channel_area_t; typedef snd_pcm_chmap_t ma_snd_pcm_chmap_t; typedef snd_pcm_state_t ma_snd_pcm_state_t; +/* snd_pcm_state_t */ +#define MA_SND_PCM_STATE_XRUN SND_PCM_STATE_XRUN + /* snd_pcm_stream_t */ #define MA_SND_PCM_STREAM_PLAYBACK SND_PCM_STREAM_PLAYBACK #define MA_SND_PCM_STREAM_CAPTURE SND_PCM_STREAM_CAPTURE @@ -26874,6 +28296,7 @@ typedef int (* ma_snd_pcm_hw_params_set_channels_minmax_proc) ( typedef int (* ma_snd_pcm_hw_params_set_rate_resample_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, unsigned int val); typedef int (* ma_snd_pcm_hw_params_set_rate_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, unsigned int val, int dir); typedef int (* ma_snd_pcm_hw_params_set_rate_near_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +typedef int (* ma_snd_pcm_hw_params_set_rate_minmax_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, unsigned int *min, int *mindir, unsigned int *max, int *maxdir); typedef int (* ma_snd_pcm_hw_params_set_buffer_size_near_proc)(ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, ma_snd_pcm_uframes_t *val); typedef int (* ma_snd_pcm_hw_params_set_periods_near_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, unsigned int *val, int *dir); typedef int (* ma_snd_pcm_hw_params_set_access_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, ma_snd_pcm_access_t _access); @@ -28640,8 +30063,9 @@ static ma_result ma_context_init__alsa(ma_context* pContext, const ma_context_co ma_snd_pcm_hw_params_get_format_mask_proc _snd_pcm_hw_params_get_format_mask = snd_pcm_hw_params_get_format_mask; ma_snd_pcm_hw_params_set_channels_proc _snd_pcm_hw_params_set_channels = snd_pcm_hw_params_set_channels; ma_snd_pcm_hw_params_set_channels_near_proc _snd_pcm_hw_params_set_channels_near = snd_pcm_hw_params_set_channels_near; + ma_snd_pcm_hw_params_set_channels_minmax_proc _snd_pcm_hw_params_set_channels_minmax = snd_pcm_hw_params_set_channels_minmax; ma_snd_pcm_hw_params_set_rate_resample_proc _snd_pcm_hw_params_set_rate_resample = snd_pcm_hw_params_set_rate_resample; - ma_snd_pcm_hw_params_set_rate_near _snd_pcm_hw_params_set_rate = snd_pcm_hw_params_set_rate; + ma_snd_pcm_hw_params_set_rate_proc _snd_pcm_hw_params_set_rate = snd_pcm_hw_params_set_rate; ma_snd_pcm_hw_params_set_rate_near_proc _snd_pcm_hw_params_set_rate_near = snd_pcm_hw_params_set_rate_near; ma_snd_pcm_hw_params_set_rate_minmax_proc _snd_pcm_hw_params_set_rate_minmax = snd_pcm_hw_params_set_rate_minmax; ma_snd_pcm_hw_params_set_buffer_size_near_proc _snd_pcm_hw_params_set_buffer_size_near = snd_pcm_hw_params_set_buffer_size_near; @@ -28693,9 +30117,9 @@ static ma_result ma_context_init__alsa(ma_context* pContext, const ma_context_co ma_snd_pcm_info_proc _snd_pcm_info = snd_pcm_info; ma_snd_pcm_info_sizeof_proc _snd_pcm_info_sizeof = snd_pcm_info_sizeof; ma_snd_pcm_info_get_name_proc _snd_pcm_info_get_name = snd_pcm_info_get_name; - ma_snd_pcm_poll_descriptors _snd_pcm_poll_descriptors = snd_pcm_poll_descriptors; - ma_snd_pcm_poll_descriptors_count _snd_pcm_poll_descriptors_count = snd_pcm_poll_descriptors_count; - ma_snd_pcm_poll_descriptors_revents _snd_pcm_poll_descriptors_revents = snd_pcm_poll_descriptors_revents; + ma_snd_pcm_poll_descriptors_proc _snd_pcm_poll_descriptors = snd_pcm_poll_descriptors; + ma_snd_pcm_poll_descriptors_count_proc _snd_pcm_poll_descriptors_count = snd_pcm_poll_descriptors_count; + ma_snd_pcm_poll_descriptors_revents_proc _snd_pcm_poll_descriptors_revents = snd_pcm_poll_descriptors_revents; ma_snd_config_update_free_global_proc _snd_config_update_free_global = snd_config_update_free_global; pContext->alsa.snd_pcm_open = (ma_proc)_snd_pcm_open; @@ -28711,6 +30135,7 @@ static ma_result ma_context_init__alsa(ma_context* pContext, const ma_context_co pContext->alsa.snd_pcm_hw_params_set_rate_resample = (ma_proc)_snd_pcm_hw_params_set_rate_resample; pContext->alsa.snd_pcm_hw_params_set_rate = (ma_proc)_snd_pcm_hw_params_set_rate; pContext->alsa.snd_pcm_hw_params_set_rate_near = (ma_proc)_snd_pcm_hw_params_set_rate_near; + pContext->alsa.snd_pcm_hw_params_set_rate_minmax = (ma_proc)_snd_pcm_hw_params_set_rate_minmax; pContext->alsa.snd_pcm_hw_params_set_buffer_size_near = (ma_proc)_snd_pcm_hw_params_set_buffer_size_near; pContext->alsa.snd_pcm_hw_params_set_periods_near = (ma_proc)_snd_pcm_hw_params_set_periods_near; pContext->alsa.snd_pcm_hw_params_set_access = (ma_proc)_snd_pcm_hw_params_set_access; @@ -29436,7 +30861,7 @@ typedef void (* ma_pa_threaded_mainloop_unlock_proc) ( typedef void (* ma_pa_threaded_mainloop_wait_proc) (ma_pa_threaded_mainloop* m); typedef void (* ma_pa_threaded_mainloop_signal_proc) (ma_pa_threaded_mainloop* m, int wait_for_accept); typedef void (* ma_pa_threaded_mainloop_accept_proc) (ma_pa_threaded_mainloop* m); -typedef int (* ma_pa_threaded_mainloop_get_retval_proc) (ma_pa_threaded_mainloop* m); +typedef int (* ma_pa_threaded_mainloop_get_retval_proc) (const ma_pa_threaded_mainloop* m); typedef ma_pa_mainloop_api* (* ma_pa_threaded_mainloop_get_api_proc) (ma_pa_threaded_mainloop* m); typedef int (* ma_pa_threaded_mainloop_in_thread_proc) (ma_pa_threaded_mainloop* m); typedef void (* ma_pa_threaded_mainloop_set_name_proc) (ma_pa_threaded_mainloop* m, const char* name); @@ -29445,13 +30870,13 @@ typedef void (* ma_pa_context_unref_proc) ( typedef int (* ma_pa_context_connect_proc) (ma_pa_context* c, const char* server, ma_pa_context_flags_t flags, const ma_pa_spawn_api* api); typedef void (* ma_pa_context_disconnect_proc) (ma_pa_context* c); typedef void (* ma_pa_context_set_state_callback_proc) (ma_pa_context* c, ma_pa_context_notify_cb_t cb, void* userdata); -typedef ma_pa_context_state_t (* ma_pa_context_get_state_proc) (ma_pa_context* c); +typedef ma_pa_context_state_t (* ma_pa_context_get_state_proc) (const ma_pa_context* c); typedef ma_pa_operation* (* ma_pa_context_get_sink_info_list_proc) (ma_pa_context* c, ma_pa_sink_info_cb_t cb, void* userdata); typedef ma_pa_operation* (* ma_pa_context_get_source_info_list_proc) (ma_pa_context* c, ma_pa_source_info_cb_t cb, void* userdata); typedef ma_pa_operation* (* ma_pa_context_get_sink_info_by_name_proc) (ma_pa_context* c, const char* name, ma_pa_sink_info_cb_t cb, void* userdata); typedef ma_pa_operation* (* ma_pa_context_get_source_info_by_name_proc)(ma_pa_context* c, const char* name, ma_pa_source_info_cb_t cb, void* userdata); typedef void (* ma_pa_operation_unref_proc) (ma_pa_operation* o); -typedef ma_pa_operation_state_t (* ma_pa_operation_get_state_proc) (ma_pa_operation* o); +typedef ma_pa_operation_state_t (* ma_pa_operation_get_state_proc) (const ma_pa_operation* o); typedef ma_pa_channel_map* (* ma_pa_channel_map_init_extend_proc) (ma_pa_channel_map* m, unsigned channels, ma_pa_channel_map_def_t def); typedef int (* ma_pa_channel_map_valid_proc) (const ma_pa_channel_map* m); typedef int (* ma_pa_channel_map_compatible_proc) (const ma_pa_channel_map* m, const ma_pa_sample_spec* ss); @@ -29460,12 +30885,12 @@ typedef void (* ma_pa_stream_unref_proc) ( typedef int (* ma_pa_stream_connect_playback_proc) (ma_pa_stream* s, const char* dev, const ma_pa_buffer_attr* attr, ma_pa_stream_flags_t flags, const ma_pa_cvolume* volume, ma_pa_stream* sync_stream); typedef int (* ma_pa_stream_connect_record_proc) (ma_pa_stream* s, const char* dev, const ma_pa_buffer_attr* attr, ma_pa_stream_flags_t flags); typedef int (* ma_pa_stream_disconnect_proc) (ma_pa_stream* s); -typedef ma_pa_stream_state_t (* ma_pa_stream_get_state_proc) (ma_pa_stream* s); +typedef ma_pa_stream_state_t (* ma_pa_stream_get_state_proc) (const ma_pa_stream* s); typedef const ma_pa_sample_spec* (* ma_pa_stream_get_sample_spec_proc) (ma_pa_stream* s); typedef const ma_pa_channel_map* (* ma_pa_stream_get_channel_map_proc) (ma_pa_stream* s); typedef const ma_pa_buffer_attr* (* ma_pa_stream_get_buffer_attr_proc) (ma_pa_stream* s); typedef ma_pa_operation* (* ma_pa_stream_set_buffer_attr_proc) (ma_pa_stream* s, const ma_pa_buffer_attr* attr, ma_pa_stream_success_cb_t cb, void* userdata); -typedef const char* (* ma_pa_stream_get_device_name_proc) (ma_pa_stream* s); +typedef const char* (* ma_pa_stream_get_device_name_proc) (const ma_pa_stream* s); typedef void (* ma_pa_stream_set_write_callback_proc) (ma_pa_stream* s, ma_pa_stream_request_cb_t cb, void* userdata); typedef void (* ma_pa_stream_set_read_callback_proc) (ma_pa_stream* s, ma_pa_stream_request_cb_t cb, void* userdata); typedef void (* ma_pa_stream_set_suspended_callback_proc) (ma_pa_stream* s, ma_pa_stream_notify_cb_t cb, void* userdata); @@ -29473,15 +30898,15 @@ typedef void (* ma_pa_stream_set_moved_callback_proc) ( typedef int (* ma_pa_stream_is_suspended_proc) (const ma_pa_stream* s); typedef ma_pa_operation* (* ma_pa_stream_flush_proc) (ma_pa_stream* s, ma_pa_stream_success_cb_t cb, void* userdata); typedef ma_pa_operation* (* ma_pa_stream_drain_proc) (ma_pa_stream* s, ma_pa_stream_success_cb_t cb, void* userdata); -typedef int (* ma_pa_stream_is_corked_proc) (ma_pa_stream* s); +typedef int (* ma_pa_stream_is_corked_proc) (const ma_pa_stream* s); typedef ma_pa_operation* (* ma_pa_stream_cork_proc) (ma_pa_stream* s, int b, ma_pa_stream_success_cb_t cb, void* userdata); typedef ma_pa_operation* (* ma_pa_stream_trigger_proc) (ma_pa_stream* s, ma_pa_stream_success_cb_t cb, void* userdata); typedef int (* ma_pa_stream_begin_write_proc) (ma_pa_stream* s, void** data, size_t* nbytes); typedef int (* ma_pa_stream_write_proc) (ma_pa_stream* s, const void* data, size_t nbytes, ma_pa_free_cb_t free_cb, int64_t offset, ma_pa_seek_mode_t seek); typedef int (* ma_pa_stream_peek_proc) (ma_pa_stream* s, const void** data, size_t* nbytes); typedef int (* ma_pa_stream_drop_proc) (ma_pa_stream* s); -typedef size_t (* ma_pa_stream_writable_size_proc) (ma_pa_stream* s); -typedef size_t (* ma_pa_stream_readable_size_proc) (ma_pa_stream* s); +typedef size_t (* ma_pa_stream_writable_size_proc) (const ma_pa_stream* s); +typedef size_t (* ma_pa_stream_readable_size_proc) (const ma_pa_stream* s); typedef struct { @@ -29777,7 +31202,7 @@ static ma_result ma_init_pa_mainloop_and_pa_context__pulse(ma_context* pContext, } /* Now we need to connect to the context. Everything is asynchronous so we need to wait for it to connect before returning. */ - result = ma_result_from_pulse(((ma_pa_context_connect_proc)pContext->pulse.pa_context_connect)((ma_pa_context*)pPulseContext, pServerName, (tryAutoSpawn) ? 0 : MA_PA_CONTEXT_NOAUTOSPAWN, NULL)); + result = ma_result_from_pulse(((ma_pa_context_connect_proc)pContext->pulse.pa_context_connect)((ma_pa_context*)pPulseContext, pServerName, (tryAutoSpawn) ? MA_PA_CONTEXT_NOFLAGS : MA_PA_CONTEXT_NOAUTOSPAWN, NULL)); if (result != MA_SUCCESS) { ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to connect PulseAudio context."); ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)((ma_pa_mainloop*)(pMainLoop)); @@ -30510,7 +31935,7 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi const ma_pa_buffer_attr* pActualAttr = NULL; const ma_pa_channel_map* pActualChannelMap = NULL; ma_uint32 iChannel; - ma_pa_stream_flags_t streamFlags; + int streamFlags; MA_ASSERT(pDevice != NULL); MA_ZERO_OBJECT(&pDevice->pulse); @@ -30568,8 +31993,13 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi ss.channels = pDescriptorCapture->channels; } + /* PulseAudio has a maximum channel count of 32. We'll get a crash if this is exceeded. */ + if (ss.channels > 32) { + ss.channels = 32; + } + /* Use a default channel map. */ - ((ma_pa_channel_map_init_extend_proc)pDevice->pContext->pulse.pa_channel_map_init_extend)(&cmap, ss.channels, pConfig->pulse.channelMap); + ((ma_pa_channel_map_init_extend_proc)pDevice->pContext->pulse.pa_channel_map_init_extend)(&cmap, ss.channels, (ma_pa_channel_map_def_t)pConfig->pulse.channelMap); /* Use the requested sample rate if one was specified. */ if (pDescriptorCapture->sampleRate != 0) { @@ -30626,7 +32056,7 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi streamFlags |= MA_PA_STREAM_DONT_MOVE; } - error = ((ma_pa_stream_connect_record_proc)pDevice->pContext->pulse.pa_stream_connect_record)((ma_pa_stream*)pDevice->pulse.pStreamCapture, devCapture, &attr, streamFlags); + error = ((ma_pa_stream_connect_record_proc)pDevice->pContext->pulse.pa_stream_connect_record)((ma_pa_stream*)pDevice->pulse.pStreamCapture, devCapture, &attr, (ma_pa_stream_flags_t)streamFlags); if (error != MA_PA_OK) { ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to connect PulseAudio capture stream."); result = ma_result_from_pulse(error); @@ -30720,8 +32150,13 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi ss.channels = pDescriptorPlayback->channels; } + /* PulseAudio has a maximum channel count of 32. We'll get a crash if this is exceeded. */ + if (ss.channels > 32) { + ss.channels = 32; + } + /* Use a default channel map. */ - ((ma_pa_channel_map_init_extend_proc)pDevice->pContext->pulse.pa_channel_map_init_extend)(&cmap, ss.channels, pConfig->pulse.channelMap); + ((ma_pa_channel_map_init_extend_proc)pDevice->pContext->pulse.pa_channel_map_init_extend)(&cmap, ss.channels, (ma_pa_channel_map_def_t)pConfig->pulse.channelMap); /* Use the requested sample rate if one was specified. */ @@ -30783,7 +32218,7 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi streamFlags |= MA_PA_STREAM_DONT_MOVE; } - error = ((ma_pa_stream_connect_playback_proc)pDevice->pContext->pulse.pa_stream_connect_playback)((ma_pa_stream*)pDevice->pulse.pStreamPlayback, devPlayback, &attr, streamFlags, NULL, NULL); + error = ((ma_pa_stream_connect_playback_proc)pDevice->pContext->pulse.pa_stream_connect_playback)((ma_pa_stream*)pDevice->pulse.pStreamPlayback, devPlayback, &attr, (ma_pa_stream_flags_t)streamFlags, NULL, NULL); if (error != MA_PA_OK) { ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to connect PulseAudio playback stream."); result = ma_result_from_pulse(error); @@ -31338,6 +32773,7 @@ typedef JackProcessCallback ma_JackProcessCallback; typedef JackBufferSizeCallback ma_JackBufferSizeCallback; typedef JackShutdownCallback ma_JackShutdownCallback; #define MA_JACK_DEFAULT_AUDIO_TYPE JACK_DEFAULT_AUDIO_TYPE +#define ma_JackNullOption JackNullOption #define ma_JackNoStartServer JackNoStartServer #define ma_JackPortIsInput JackPortIsInput #define ma_JackPortIsOutput JackPortIsOutput @@ -31352,6 +32788,7 @@ typedef int (* ma_JackProcessCallback) (ma_jack_nframes_t nframes, void* arg) typedef int (* ma_JackBufferSizeCallback)(ma_jack_nframes_t nframes, void* arg); typedef void (* ma_JackShutdownCallback) (void* arg); #define MA_JACK_DEFAULT_AUDIO_TYPE "32 bit float mono audio" +#define ma_JackNullOption 0 #define ma_JackNoStartServer 1 #define ma_JackPortIsInput 1 #define ma_JackPortIsOutput 2 @@ -31392,7 +32829,7 @@ static ma_result ma_context_open_client__jack(ma_context* pContext, ma_jack_clie maxClientNameSize = ((ma_jack_client_name_size_proc)pContext->jack.jack_client_name_size)(); /* Includes null terminator. */ ma_strncpy_s(clientName, ma_min(sizeof(clientName), maxClientNameSize), (pContext->jack.pClientName != NULL) ? pContext->jack.pClientName : "miniaudio", (size_t)-1); - pClient = ((ma_jack_client_open_proc)pContext->jack.jack_client_open)(clientName, (pContext->jack.tryStartServer) ? 0 : ma_JackNoStartServer, &status, NULL); + pClient = ((ma_jack_client_open_proc)pContext->jack.jack_client_open)(clientName, (pContext->jack.tryStartServer) ? ma_JackNullOption : ma_JackNoStartServer, &status, NULL); if (pClient == NULL) { return MA_FAILED_TO_OPEN_BACKEND_DEVICE; } @@ -36994,7 +38431,7 @@ OSS Backend #define MA_OSS_DEFAULT_DEVICE_NAME "/dev/dsp" -static int ma_open_temp_device__oss() +static int ma_open_temp_device__oss(void) { /* The OSS sample code uses "/dev/mixer" as the device for getting system properties so I'm going to do the same. */ int fd = open("/dev/mixer", O_RDONLY, 0); @@ -37834,25 +39271,30 @@ static void ma_stream_error_callback__aaudio(ma_AAudioStream* pStream, void* pUs (void)error; ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[AAudio] ERROR CALLBACK: error=%d, AAudioStream_getState()=%d\n", error, ((MA_PFN_AAudioStream_getState)pDevice->pContext->aaudio.AAudioStream_getState)(pStream)); + /* When we get an error, we'll assume that the stream is in an erroneous state and needs to be restarted. From the documentation, we cannot do this from the error callback. Therefore we are going to use an event thread for the AAudio backend to do this cleanly and safely. */ - job = ma_job_init(MA_JOB_TYPE_DEVICE_AAUDIO_REROUTE); - job.data.device.aaudio.reroute.pDevice = pDevice; - - if (pStream == pDevice->aaudio.pStreamCapture) { - job.data.device.aaudio.reroute.deviceType = ma_device_type_capture; + if (ma_atomic_bool32_get(&pDevice->aaudio.isTearingDown)) { + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[AAudio] Device Disconnected. Tearing down device.\n"); } else { - job.data.device.aaudio.reroute.deviceType = ma_device_type_playback; - } - - result = ma_device_job_thread_post(&pDevice->pContext->aaudio.jobThread, &job); - if (result != MA_SUCCESS) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[AAudio] Device Disconnected. Failed to post job for rerouting.\n"); - return; + job = ma_job_init(MA_JOB_TYPE_DEVICE_AAUDIO_REROUTE); + job.data.device.aaudio.reroute.pDevice = pDevice; + + if (pStream == pDevice->aaudio.pStreamCapture) { + job.data.device.aaudio.reroute.deviceType = ma_device_type_capture; + } else { + job.data.device.aaudio.reroute.deviceType = ma_device_type_playback; + } + + result = ma_device_job_thread_post(&pDevice->pContext->aaudio.jobThread, &job); + if (result != MA_SUCCESS) { + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[AAudio] Device Disconnected. Failed to post job for rerouting.\n"); + return; + } } } @@ -38169,7 +39611,7 @@ static ma_result ma_close_streams__aaudio(ma_device* pDevice) { MA_ASSERT(pDevice != NULL); - /* When re-routing, streams may have been closed and never re-opened. Hence the extra checks below. */ + /* When rerouting, streams may have been closed and never re-opened. Hence the extra checks below. */ if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { ma_close_stream__aaudio(pDevice->pContext, (ma_AAudioStream*)pDevice->aaudio.pStreamCapture); pDevice->aaudio.pStreamCapture = NULL; @@ -38186,6 +39628,12 @@ static ma_result ma_device_uninit__aaudio(ma_device* pDevice) { MA_ASSERT(pDevice != NULL); + /* + Note: Closing the streams may cause a timeout error, which would then trigger rerouting in our error callback. + We must not schedule a reroute when device is getting destroyed. + */ + ma_atomic_bool32_set(&pDevice->aaudio.isTearingDown, MA_TRUE); + /* Wait for any rerouting to finish before attempting to close the streams. */ ma_mutex_lock(&pDevice->aaudio.rerouteLock); { @@ -38193,7 +39641,7 @@ static ma_result ma_device_uninit__aaudio(ma_device* pDevice) } ma_mutex_unlock(&pDevice->aaudio.rerouteLock); - /* Destroy re-routing lock. */ + /* Destroy rerouting lock. */ ma_mutex_uninit(&pDevice->aaudio.rerouteLock); return MA_SUCCESS; @@ -38429,17 +39877,22 @@ static ma_result ma_device_stop__aaudio(ma_device* pDevice) static ma_result ma_device_reinit__aaudio(ma_device* pDevice, ma_device_type deviceType) { + const ma_int32 maxAttempts = 4; /* Reasonable retry limit. */ + ma_result result; - int32_t retries = 0; + ma_int32 iAttempt; MA_ASSERT(pDevice != NULL); - /* - TODO: Stop retrying if main thread is about to uninit device. - */ - ma_mutex_lock(&pDevice->aaudio.rerouteLock); - { -error_disconnected: + /* We got disconnected! Retry a few times, until we find a connected device! */ + iAttempt = 0; + while (iAttempt++ < maxAttempts) { + /* Device tearing down? No need to reroute! */ + if (ma_atomic_bool32_get(&pDevice->aaudio.isTearingDown)) { + result = MA_SUCCESS; /* Caller should continue as normal. */ + break; + } + /* The first thing to do is close the streams. */ ma_close_streams__aaudio(pDevice); @@ -38495,14 +39948,16 @@ error_disconnected: result = ma_device_init_streams__aaudio(pDevice, &deviceConfig, &descriptorPlayback, &descriptorCapture); if (result != MA_SUCCESS) { ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_WARNING, "[AAudio] Failed to create stream after route change."); - goto done; + /* Reroute failed! */ + break; } result = ma_device_post_init(pDevice, deviceType, &descriptorPlayback, &descriptorCapture); if (result != MA_SUCCESS) { ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_WARNING, "[AAudio] Failed to initialize device after route change."); ma_close_streams__aaudio(pDevice); - goto done; + /* Reroute failed! */ + break; } /* We'll only ever do this in response to a reroute. */ @@ -38513,26 +39968,23 @@ error_disconnected: if (pDevice->aaudio.noAutoStartAfterReroute == MA_FALSE) { result = ma_device_start__aaudio(pDevice); if (result != MA_SUCCESS) { - /* We got disconnected! Retry a few times, until we find a connected device! */ - retries += 1; - if (retries <= 3) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[AAudio] Failed to start stream after route change, retrying(%d)", retries); - goto error_disconnected; + if (iAttempt < maxAttempts) { + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[AAudio] Failed to start stream after route change, retrying(%d)", iAttempt); + } else { + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[AAudio] Failed to start stream after route change, giving up."); } - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[AAudio] Failed to start stream after route change."); - goto done; } } else { - ma_device_stop(pDevice); /* Do a full device stop so we set internal state correctly. */ + ma_device_stop(pDevice); /* Do a full device stop so we set internal state correctly. */ } } - - result = MA_SUCCESS; - } -done: - /* Re-routing done */ - ma_mutex_unlock(&pDevice->aaudio.rerouteLock); + if (result == MA_SUCCESS) { + /* Reroute successful! */ + break; + } + } + return result; } @@ -38698,7 +40150,7 @@ static ma_result ma_context_init__aaudio(ma_context* pContext, const ma_context_ static ma_result ma_job_process__device__aaudio_reroute(ma_job* pJob) { - ma_result result; + ma_result result = MA_SUCCESS; ma_device* pDevice; MA_ASSERT(pJob != NULL); @@ -38706,19 +40158,22 @@ static ma_result ma_job_process__device__aaudio_reroute(ma_job* pJob) pDevice = (ma_device*)pJob->data.device.aaudio.reroute.pDevice; MA_ASSERT(pDevice != NULL); - /* Here is where we need to reroute the device. To do this we need to uninitialize the stream and reinitialize it. */ - result = ma_device_reinit__aaudio(pDevice, (ma_device_type)pJob->data.device.aaudio.reroute.deviceType); - if (result != MA_SUCCESS) { - /* - Getting here means we failed to reroute the device. The best thing I can think of here is to - just stop the device. - */ - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[AAudio] Stopping device due to reroute failure."); - ma_device_stop(pDevice); - return result; + ma_mutex_lock(&pDevice->aaudio.rerouteLock); + { + /* Here is where we need to reroute the device. To do this we need to uninitialize the stream and reinitialize it. */ + result = ma_device_reinit__aaudio(pDevice, (ma_device_type)pJob->data.device.aaudio.reroute.deviceType); + if (result != MA_SUCCESS) { + /* + Getting here means we failed to reroute the device. The best thing I can think of here is to + just stop the device. + */ + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[AAudio] Stopping device due to reroute failure."); + ma_device_stop(pDevice); + } } + ma_mutex_unlock(&pDevice->aaudio.rerouteLock); - return MA_SUCCESS; + return result; } #else /* Getting here means there is no AAudio backend so we need a no-op job implementation. */ @@ -41236,13 +42691,13 @@ MA_API ma_result ma_device_post_init(ma_device* pDevice, ma_device_type deviceTy static ma_thread_result MA_THREADCALL ma_worker_thread(void* pData) { ma_device* pDevice = (ma_device*)pData; -#ifdef MA_WIN32 +#if defined(MA_WIN32) && !defined(MA_XBOX) HRESULT CoInitializeResult; #endif MA_ASSERT(pDevice != NULL); -#ifdef MA_WIN32 +#if defined(MA_WIN32) && !defined(MA_XBOX) CoInitializeResult = ma_CoInitializeEx(pDevice->pContext, NULL, MA_COINIT_VALUE); #endif @@ -41333,8 +42788,8 @@ static ma_thread_result MA_THREADCALL ma_worker_thread(void* pData) ma_event_signal(&pDevice->stopEvent); } -#ifdef MA_WIN32 - if (CoInitializeResult == S_OK) { +#if defined(MA_WIN32) && !defined(MA_XBOX) + if (CoInitializeResult == S_OK || CoInitializeResult == S_FALSE) { ma_CoUninitialize(pDevice->pContext); } #endif @@ -41358,67 +42813,92 @@ static ma_bool32 ma_device__is_initialized(ma_device* pDevice) static ma_result ma_context_uninit_backend_apis__win32(ma_context* pContext) { /* For some reason UWP complains when CoUninitialize() is called. I'm just not going to call it on UWP. */ -#if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) - if (pContext->win32.CoInitializeResult == S_OK) { - ma_CoUninitialize(pContext); + #if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) + { + /* TODO: Remove this once the new single threaded backend system is in place in 0.12. */ + #if !defined(MA_XBOX) + { + if (pContext->win32.CoInitializeResult == S_OK || pContext->win32.CoInitializeResult == S_FALSE) { + ma_CoUninitialize(pContext); /* TODO: Remove this once the new single threaded backend system is in place in 0.12. */ + } + } + #endif + + #if defined(MA_WIN32_DESKTOP) + ma_dlclose(ma_context_get_log(pContext), pContext->win32.hUser32DLL); + ma_dlclose(ma_context_get_log(pContext), pContext->win32.hAdvapi32DLL); + #endif + + ma_dlclose(ma_context_get_log(pContext), pContext->win32.hOle32DLL); + } + #else + { + (void)pContext; } - - #if defined(MA_WIN32_DESKTOP) - ma_dlclose(ma_context_get_log(pContext), pContext->win32.hUser32DLL); - ma_dlclose(ma_context_get_log(pContext), pContext->win32.hAdvapi32DLL); #endif - ma_dlclose(ma_context_get_log(pContext), pContext->win32.hOle32DLL); -#else - (void)pContext; -#endif - return MA_SUCCESS; } static ma_result ma_context_init_backend_apis__win32(ma_context* pContext) { -#if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) - #if defined(MA_WIN32_DESKTOP) - /* User32.dll */ - pContext->win32.hUser32DLL = ma_dlopen(ma_context_get_log(pContext), "user32.dll"); - if (pContext->win32.hUser32DLL == NULL) { + /* + TODO: Reassess all of this stuff and move everything to the relevant backends. For example, I think + GetForegroundWindow() and GetDesktopWindow() are only used by the DirectSound backend. + */ + #if (defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK)) && !defined(MA_XBOX) + { + #if defined(MA_WIN32_DESKTOP) + { + /* User32.dll */ + pContext->win32.hUser32DLL = ma_dlopen(ma_context_get_log(pContext), "user32.dll"); + if (pContext->win32.hUser32DLL == NULL) { + return MA_FAILED_TO_INIT_BACKEND; + } + + pContext->win32.GetForegroundWindow = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hUser32DLL, "GetForegroundWindow"); + pContext->win32.GetDesktopWindow = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hUser32DLL, "GetDesktopWindow"); + + + /* Advapi32.dll */ + pContext->win32.hAdvapi32DLL = ma_dlopen(ma_context_get_log(pContext), "advapi32.dll"); + if (pContext->win32.hAdvapi32DLL == NULL) { + return MA_FAILED_TO_INIT_BACKEND; + } + + pContext->win32.RegOpenKeyExA = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hAdvapi32DLL, "RegOpenKeyExA"); + pContext->win32.RegCloseKey = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hAdvapi32DLL, "RegCloseKey"); + pContext->win32.RegQueryValueExA = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hAdvapi32DLL, "RegQueryValueExA"); + } + #endif + + /* Ole32.dll */ + pContext->win32.hOle32DLL = ma_dlopen(ma_context_get_log(pContext), "ole32.dll"); + if (pContext->win32.hOle32DLL == NULL) { return MA_FAILED_TO_INIT_BACKEND; } - pContext->win32.GetForegroundWindow = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hUser32DLL, "GetForegroundWindow"); - pContext->win32.GetDesktopWindow = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hUser32DLL, "GetDesktopWindow"); - - - /* Advapi32.dll */ - pContext->win32.hAdvapi32DLL = ma_dlopen(ma_context_get_log(pContext), "advapi32.dll"); - if (pContext->win32.hAdvapi32DLL == NULL) { - return MA_FAILED_TO_INIT_BACKEND; - } - - pContext->win32.RegOpenKeyExA = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hAdvapi32DLL, "RegOpenKeyExA"); - pContext->win32.RegCloseKey = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hAdvapi32DLL, "RegCloseKey"); - pContext->win32.RegQueryValueExA = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hAdvapi32DLL, "RegQueryValueExA"); + pContext->win32.CoInitialize = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "CoInitialize"); + pContext->win32.CoInitializeEx = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "CoInitializeEx"); + pContext->win32.CoUninitialize = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "CoUninitialize"); + pContext->win32.CoCreateInstance = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "CoCreateInstance"); + pContext->win32.CoTaskMemFree = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "CoTaskMemFree"); + pContext->win32.PropVariantClear = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "PropVariantClear"); + pContext->win32.StringFromGUID2 = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "StringFromGUID2"); + } + #else + { + (void)pContext; /* Unused. */ + } #endif - /* Ole32.dll */ - pContext->win32.hOle32DLL = ma_dlopen(ma_context_get_log(pContext), "ole32.dll"); - if (pContext->win32.hOle32DLL == NULL) { - return MA_FAILED_TO_INIT_BACKEND; + /* TODO: Remove this once the new single threaded backend system is in place in 0.12. */ + #if !defined(MA_XBOX) + { + pContext->win32.CoInitializeResult = ma_CoInitializeEx(pContext, NULL, MA_COINIT_VALUE); } + #endif - pContext->win32.CoInitialize = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "CoInitialize"); - pContext->win32.CoInitializeEx = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "CoInitializeEx"); - pContext->win32.CoUninitialize = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "CoUninitialize"); - pContext->win32.CoCreateInstance = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "CoCreateInstance"); - pContext->win32.CoTaskMemFree = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "CoTaskMemFree"); - pContext->win32.PropVariantClear = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "PropVariantClear"); - pContext->win32.StringFromGUID2 = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "StringFromGUID2"); -#else - (void)pContext; /* Unused. */ -#endif - - pContext->win32.CoInitializeResult = ma_CoInitializeEx(pContext, NULL, MA_COINIT_VALUE); return MA_SUCCESS; } #else @@ -44016,7 +45496,7 @@ static MA_INLINE void ma_pcm_s16_to_s32__reference(void* dst, const void* src, m ma_uint64 i; for (i = 0; i < count; i += 1) { - dst_s32[i] = src_s16[i] << 16; + dst_s32[i] = (ma_int32)src_s16[i] << 16; } (void)ditherMode; @@ -56408,8 +57888,12 @@ MA_API size_t ma_channel_map_to_string(const ma_channel* pChannelMap, ma_uint32 } /* Null terminate. Don't increment the length here. */ - if (pBufferOut != NULL && bufferCap > len + 1) { - pBufferOut[len] = '\0'; + if (pBufferOut != NULL) { + if (bufferCap > len) { + pBufferOut[len] = '\0'; + } else if (bufferCap > 0) { + pBufferOut[bufferCap - 1] = '\0'; + } } return len; @@ -56620,7 +58104,7 @@ MA_API ma_result ma_rb_init_ex(size_t subbufferSizeInBytes, size_t subbufferCoun Here is where we allocate our own buffer. We always want to align this to MA_SIMD_ALIGNMENT for future SIMD optimization opportunity. To do this we need to make sure the stride is a multiple of MA_SIMD_ALIGNMENT. */ - pRB->subbufferStrideInBytes = (pRB->subbufferSizeInBytes + (MA_SIMD_ALIGNMENT-1)) & ~MA_SIMD_ALIGNMENT; + pRB->subbufferStrideInBytes = ma_align(pRB->subbufferSizeInBytes, MA_SIMD_ALIGNMENT); bufferSizeInBytes = (size_t)pRB->subbufferCount*pRB->subbufferStrideInBytes; pRB->pBuffer = ma_aligned_malloc(bufferSizeInBytes, MA_SIMD_ALIGNMENT, &pRB->allocationCallbacks); @@ -59515,7 +60999,7 @@ MA_API ma_result ma_vfs_info(ma_vfs* pVFS, ma_vfs_file file, ma_file_info* pInfo } -#if !defined(MA_USE_WIN32_FILEIO) && (defined(MA_WIN32) && defined(MA_WIN32_DESKTOP) && !defined(MA_NO_WIN32_FILEIO) && !defined(MA_POSIX)) +#if !defined(MA_USE_WIN32_FILEIO) && (defined(MA_WIN32) && (defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_NXDK)) && !defined(MA_NO_WIN32_FILEIO) && !defined(MA_POSIX)) #define MA_USE_WIN32_FILEIO #endif @@ -59592,25 +61076,34 @@ static ma_result ma_default_vfs_open__win32(ma_vfs* pVFS, const char* pFilePath, static ma_result ma_default_vfs_open_w__win32(ma_vfs* pVFS, const wchar_t* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile) { - HANDLE hFile; - DWORD dwDesiredAccess; - DWORD dwShareMode; - DWORD dwCreationDisposition; + #if !defined(MA_XBOX_NXDK) + { + HANDLE hFile; + DWORD dwDesiredAccess; + DWORD dwShareMode; + DWORD dwCreationDisposition; - (void)pVFS; + (void)pVFS; - /* Load some Win32 symbols dynamically so we can dynamically check for the existence of SetFilePointerEx. */ - ma_win32_fileio_init(); + /* Load some Win32 symbols dynamically so we can dynamically check for the existence of SetFilePointerEx. */ + ma_win32_fileio_init(); - ma_default_vfs__get_open_settings_win32(openMode, &dwDesiredAccess, &dwShareMode, &dwCreationDisposition); + ma_default_vfs__get_open_settings_win32(openMode, &dwDesiredAccess, &dwShareMode, &dwCreationDisposition); - hFile = CreateFileW(pFilePath, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL); - if (hFile == INVALID_HANDLE_VALUE) { - return ma_result_from_GetLastError(GetLastError()); + hFile = CreateFileW(pFilePath, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) { + return ma_result_from_GetLastError(GetLastError()); + } + + *pFile = hFile; + return MA_SUCCESS; } - - *pFile = hFile; - return MA_SUCCESS; + #else + { + /* No CreateFileW() available. */ + return MA_NOT_IMPLEMENTED; + } + #endif } static ma_result ma_default_vfs_close__win32(ma_vfs* pVFS, ma_vfs_file file) @@ -59781,19 +61274,28 @@ static ma_result ma_default_vfs_tell__win32(ma_vfs* pVFS, ma_vfs_file file, ma_i static ma_result ma_default_vfs_info__win32(ma_vfs* pVFS, ma_vfs_file file, ma_file_info* pInfo) { - BY_HANDLE_FILE_INFORMATION fi; - BOOL result; - (void)pVFS; - result = GetFileInformationByHandle((HANDLE)file, &fi); - if (result == 0) { - return ma_result_from_GetLastError(GetLastError()); + #if !defined(MA_XBOX_NXDK) + { + BY_HANDLE_FILE_INFORMATION fi; + BOOL result; + + result = GetFileInformationByHandle((HANDLE)file, &fi); + if (result == 0) { + return ma_result_from_GetLastError(GetLastError()); + } + + pInfo->sizeInBytes = ((ma_uint64)fi.nFileSizeHigh << 32) | ((ma_uint64)fi.nFileSizeLow); + + return MA_SUCCESS; } - - pInfo->sizeInBytes = ((ma_uint64)fi.nFileSizeHigh << 32) | ((ma_uint64)fi.nFileSizeLow); - - return MA_SUCCESS; + #else + { + /* GetFileInformationByHandle() is unavailable. */ + return MA_NOT_IMPLEMENTED; + } + #endif } #else static ma_result ma_default_vfs_open__stdio(ma_vfs* pVFS, const char* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile) @@ -60131,6 +61633,8 @@ static ma_result ma_default_vfs_tell(ma_vfs* pVFS, ma_vfs_file file, ma_int64* p static ma_result ma_default_vfs_info(ma_vfs* pVFS, ma_vfs_file file, ma_file_info* pInfo) { + ma_result result; + if (pInfo == NULL) { return MA_INVALID_ARGS; } @@ -60142,10 +61646,43 @@ static ma_result ma_default_vfs_info(ma_vfs* pVFS, ma_vfs_file file, ma_file_inf } #if defined(MA_USE_WIN32_FILEIO) - return ma_default_vfs_info__win32(pVFS, file, pInfo); + result = ma_default_vfs_info__win32(pVFS, file, pInfo); #else - return ma_default_vfs_info__stdio(pVFS, file, pInfo); + result = ma_default_vfs_info__stdio(pVFS, file, pInfo); #endif + + if (result == MA_NOT_IMPLEMENTED) { + /* Not implemented. Fall back to seek/tell/seek. */ + ma_result result; + ma_int64 cursor; + ma_int64 sizeInBytes; + + result = ma_default_vfs_tell(pVFS, file, &cursor); + if (result != MA_SUCCESS) { + return result; + } + + result = ma_default_vfs_seek(pVFS, file, 0, ma_seek_origin_end); + if (result != MA_SUCCESS) { + return result; + } + + result = ma_default_vfs_tell(pVFS, file, &sizeInBytes); + if (result != MA_SUCCESS) { + return result; + } + + pInfo->sizeInBytes = sizeInBytes; + + result = ma_default_vfs_seek(pVFS, file, cursor, ma_seek_origin_start); + if (result != MA_SUCCESS) { + return result; + } + + MA_ASSERT(result == MA_SUCCESS); + } + + return result; } @@ -60333,8 +61870,8 @@ extern "C" { #define MA_DR_WAV_STRINGIFY(x) #x #define MA_DR_WAV_XSTRINGIFY(x) MA_DR_WAV_STRINGIFY(x) #define MA_DR_WAV_VERSION_MAJOR 0 -#define MA_DR_WAV_VERSION_MINOR 13 -#define MA_DR_WAV_VERSION_REVISION 18 +#define MA_DR_WAV_VERSION_MINOR 14 +#define MA_DR_WAV_VERSION_REVISION 1 #define MA_DR_WAV_VERSION_STRING MA_DR_WAV_XSTRINGIFY(MA_DR_WAV_VERSION_MAJOR) "." MA_DR_WAV_XSTRINGIFY(MA_DR_WAV_VERSION_MINOR) "." MA_DR_WAV_XSTRINGIFY(MA_DR_WAV_VERSION_REVISION) #include #define MA_DR_WAVE_FORMAT_PCM 0x1 @@ -60350,8 +61887,9 @@ MA_API void ma_dr_wav_version(ma_uint32* pMajor, ma_uint32* pMinor, ma_uint32* p MA_API const char* ma_dr_wav_version_string(void); typedef enum { - ma_dr_wav_seek_origin_start, - ma_dr_wav_seek_origin_current + MA_DR_WAV_SEEK_SET, + MA_DR_WAV_SEEK_CUR, + MA_DR_WAV_SEEK_END } ma_dr_wav_seek_origin; typedef enum { @@ -60388,6 +61926,7 @@ MA_API ma_uint16 ma_dr_wav_fmt_get_format(const ma_dr_wav_fmt* pFMT); typedef size_t (* ma_dr_wav_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead); typedef size_t (* ma_dr_wav_write_proc)(void* pUserData, const void* pData, size_t bytesToWrite); typedef ma_bool32 (* ma_dr_wav_seek_proc)(void* pUserData, int offset, ma_dr_wav_seek_origin origin); +typedef ma_bool32 (* ma_dr_wav_tell_proc)(void* pUserData, ma_int64* pCursor); typedef ma_uint64 (* ma_dr_wav_chunk_proc)(void* pChunkUserData, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pReadSeekUserData, const ma_dr_wav_chunk_header* pChunkHeader, ma_dr_wav_container container, const ma_dr_wav_fmt* pFMT); typedef struct { @@ -60432,6 +61971,11 @@ typedef enum ma_dr_wav_metadata_type_list_info_genre = 1 << 15, ma_dr_wav_metadata_type_list_info_album = 1 << 16, ma_dr_wav_metadata_type_list_info_tracknumber = 1 << 17, + ma_dr_wav_metadata_type_list_info_location = 1 << 18, + ma_dr_wav_metadata_type_list_info_organization = 1 << 19, + ma_dr_wav_metadata_type_list_info_keywords = 1 << 20, + ma_dr_wav_metadata_type_list_info_medium = 1 << 21, + ma_dr_wav_metadata_type_list_info_description = 1 << 22, ma_dr_wav_metadata_type_list_all_info_strings = ma_dr_wav_metadata_type_list_info_software | ma_dr_wav_metadata_type_list_info_copyright | ma_dr_wav_metadata_type_list_info_title @@ -60440,7 +61984,12 @@ typedef enum | ma_dr_wav_metadata_type_list_info_date | ma_dr_wav_metadata_type_list_info_genre | ma_dr_wav_metadata_type_list_info_album - | ma_dr_wav_metadata_type_list_info_tracknumber, + | ma_dr_wav_metadata_type_list_info_tracknumber + | ma_dr_wav_metadata_type_list_info_location + | ma_dr_wav_metadata_type_list_info_organization + | ma_dr_wav_metadata_type_list_info_keywords + | ma_dr_wav_metadata_type_list_info_medium + | ma_dr_wav_metadata_type_list_info_description, ma_dr_wav_metadata_type_list_all_adtl = ma_dr_wav_metadata_type_list_label | ma_dr_wav_metadata_type_list_note | ma_dr_wav_metadata_type_list_labelled_cue_region, @@ -60457,8 +62006,8 @@ typedef struct { ma_uint32 cuePointId; ma_uint32 type; - ma_uint32 firstSampleByteOffset; - ma_uint32 lastSampleByteOffset; + ma_uint32 firstSampleOffset; + ma_uint32 lastSampleOffset; ma_uint32 sampleFraction; ma_uint32 playCount; } ma_dr_wav_smpl_loop; @@ -60493,7 +62042,7 @@ typedef struct ma_uint8 dataChunkId[4]; ma_uint32 chunkStart; ma_uint32 blockStart; - ma_uint32 sampleByteOffset; + ma_uint32 sampleOffset; } ma_dr_wav_cue_point; typedef struct { @@ -60595,6 +62144,7 @@ typedef struct ma_dr_wav_read_proc onRead; ma_dr_wav_write_proc onWrite; ma_dr_wav_seek_proc onSeek; + ma_dr_wav_tell_proc onTell; void* pUserData; ma_allocation_callbacks allocationCallbacks; ma_dr_wav_container container; @@ -60637,9 +62187,9 @@ typedef struct ma_bool8 isUnsigned; } aiff; } ma_dr_wav; -MA_API ma_bool32 ma_dr_wav_init(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_bool32 ma_dr_wav_init_ex(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_chunk_proc onChunk, void* pReadSeekUserData, void* pChunkUserData, ma_uint32 flags, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_bool32 ma_dr_wav_init_with_metadata(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pUserData, ma_uint32 flags, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_bool32 ma_dr_wav_init(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_tell_proc onTell, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_bool32 ma_dr_wav_init_ex(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_tell_proc onTell, ma_dr_wav_chunk_proc onChunk, void* pReadSeekTellUserData, void* pChunkUserData, ma_uint32 flags, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_bool32 ma_dr_wav_init_with_metadata(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_tell_proc onTell, void* pUserData, ma_uint32 flags, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_bool32 ma_dr_wav_init_write(ma_dr_wav* pWav, const ma_dr_wav_data_format* pFormat, ma_dr_wav_write_proc onWrite, ma_dr_wav_seek_proc onSeek, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_bool32 ma_dr_wav_init_write_sequential(ma_dr_wav* pWav, const ma_dr_wav_data_format* pFormat, ma_uint64 totalSampleCount, ma_dr_wav_write_proc onWrite, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_bool32 ma_dr_wav_init_write_sequential_pcm_frames(ma_dr_wav* pWav, const ma_dr_wav_data_format* pFormat, ma_uint64 totalPCMFrameCount, ma_dr_wav_write_proc onWrite, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); @@ -60711,9 +62261,9 @@ MA_API ma_bool32 ma_dr_wav_init_memory_write(ma_dr_wav* pWav, void** ppData, siz MA_API ma_bool32 ma_dr_wav_init_memory_write_sequential(ma_dr_wav* pWav, void** ppData, size_t* pDataSize, const ma_dr_wav_data_format* pFormat, ma_uint64 totalSampleCount, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_bool32 ma_dr_wav_init_memory_write_sequential_pcm_frames(ma_dr_wav* pWav, void** ppData, size_t* pDataSize, const ma_dr_wav_data_format* pFormat, ma_uint64 totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); #ifndef MA_DR_WAV_NO_CONVERSION_API -MA_API ma_int16* ma_dr_wav_open_and_read_pcm_frames_s16(ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API float* ma_dr_wav_open_and_read_pcm_frames_f32(ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_int32* ma_dr_wav_open_and_read_pcm_frames_s32(ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_int16* ma_dr_wav_open_and_read_pcm_frames_s16(ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API float* ma_dr_wav_open_and_read_pcm_frames_f32(ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_int32* ma_dr_wav_open_and_read_pcm_frames_s32(ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks); #ifndef MA_DR_WAV_NO_STDIO MA_API ma_int16* ma_dr_wav_open_file_and_read_pcm_frames_s16(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks); MA_API float* ma_dr_wav_open_file_and_read_pcm_frames_f32(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks); @@ -60753,8 +62303,8 @@ extern "C" { #define MA_DR_FLAC_STRINGIFY(x) #x #define MA_DR_FLAC_XSTRINGIFY(x) MA_DR_FLAC_STRINGIFY(x) #define MA_DR_FLAC_VERSION_MAJOR 0 -#define MA_DR_FLAC_VERSION_MINOR 12 -#define MA_DR_FLAC_VERSION_REVISION 43 +#define MA_DR_FLAC_VERSION_MINOR 13 +#define MA_DR_FLAC_VERSION_REVISION 1 #define MA_DR_FLAC_VERSION_STRING MA_DR_FLAC_XSTRINGIFY(MA_DR_FLAC_VERSION_MAJOR) "." MA_DR_FLAC_XSTRINGIFY(MA_DR_FLAC_VERSION_MINOR) "." MA_DR_FLAC_XSTRINGIFY(MA_DR_FLAC_VERSION_REVISION) #include #if defined(_MSC_VER) && _MSC_VER >= 1700 @@ -60817,8 +62367,9 @@ typedef enum } ma_dr_flac_container; typedef enum { - ma_dr_flac_seek_origin_start, - ma_dr_flac_seek_origin_current + MA_DR_FLAC_SEEK_SET, + MA_DR_FLAC_SEEK_CUR, + MA_DR_FLAC_SEEK_END } ma_dr_flac_seek_origin; typedef struct { @@ -60894,6 +62445,7 @@ typedef struct } ma_dr_flac_metadata; typedef size_t (* ma_dr_flac_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead); typedef ma_bool32 (* ma_dr_flac_seek_proc)(void* pUserData, int offset, ma_dr_flac_seek_origin origin); +typedef ma_bool32 (* ma_dr_flac_tell_proc)(void* pUserData, ma_int64* pCursor); typedef void (* ma_dr_flac_meta_proc)(void* pUserData, ma_dr_flac_metadata* pMetadata); typedef struct { @@ -60905,6 +62457,7 @@ typedef struct { ma_dr_flac_read_proc onRead; ma_dr_flac_seek_proc onSeek; + ma_dr_flac_tell_proc onTell; void* pUserData; size_t unalignedByteCount; ma_dr_flac_cache_t unalignedCache; @@ -60964,10 +62517,10 @@ typedef struct ma_dr_flac_bs bs; ma_uint8 pExtraData[1]; } ma_dr_flac; -MA_API ma_dr_flac* ma_dr_flac_open(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_dr_flac* ma_dr_flac_open_relaxed(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_container container, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_dr_flac* ma_dr_flac_open_with_metadata(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_meta_proc onMeta, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_dr_flac* ma_dr_flac_open_with_metadata_relaxed(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_meta_proc onMeta, ma_dr_flac_container container, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_dr_flac* ma_dr_flac_open(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_dr_flac* ma_dr_flac_open_relaxed(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, ma_dr_flac_container container, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_dr_flac* ma_dr_flac_open_with_metadata(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, ma_dr_flac_meta_proc onMeta, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_dr_flac* ma_dr_flac_open_with_metadata_relaxed(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, ma_dr_flac_meta_proc onMeta, ma_dr_flac_container container, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); MA_API void ma_dr_flac_close(ma_dr_flac* pFlac); MA_API ma_uint64 ma_dr_flac_read_pcm_frames_s32(ma_dr_flac* pFlac, ma_uint64 framesToRead, ma_int32* pBufferOut); MA_API ma_uint64 ma_dr_flac_read_pcm_frames_s16(ma_dr_flac* pFlac, ma_uint64 framesToRead, ma_int16* pBufferOut); @@ -60981,9 +62534,9 @@ MA_API ma_dr_flac* ma_dr_flac_open_file_with_metadata_w(const wchar_t* pFileName #endif MA_API ma_dr_flac* ma_dr_flac_open_memory(const void* pData, size_t dataSize, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_dr_flac* ma_dr_flac_open_memory_with_metadata(const void* pData, size_t dataSize, ma_dr_flac_meta_proc onMeta, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_int32* ma_dr_flac_open_and_read_pcm_frames_s32(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, ma_uint64* totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_int16* ma_dr_flac_open_and_read_pcm_frames_s16(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, ma_uint64* totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API float* ma_dr_flac_open_and_read_pcm_frames_f32(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, ma_uint64* totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_int32* ma_dr_flac_open_and_read_pcm_frames_s32(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, void* pUserData, unsigned int* channels, unsigned int* sampleRate, ma_uint64* totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_int16* ma_dr_flac_open_and_read_pcm_frames_s16(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, void* pUserData, unsigned int* channels, unsigned int* sampleRate, ma_uint64* totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API float* ma_dr_flac_open_and_read_pcm_frames_f32(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, void* pUserData, unsigned int* channels, unsigned int* sampleRate, ma_uint64* totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); #ifndef MA_DR_FLAC_NO_STDIO MA_API ma_int32* ma_dr_flac_open_file_and_read_pcm_frames_s32(const char* filename, unsigned int* channels, unsigned int* sampleRate, ma_uint64* totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_int16* ma_dr_flac_open_file_and_read_pcm_frames_s16(const char* filename, unsigned int* channels, unsigned int* sampleRate, ma_uint64* totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); @@ -61031,6 +62584,12 @@ MA_API ma_bool32 ma_dr_flac_next_cuesheet_track(ma_dr_flac_cuesheet_track_iterat #endif /* MA_NO_FLAC */ #if !defined(MA_NO_MP3) && !defined(MA_NO_DECODING) +#ifndef MA_DR_MP3_NO_SIMD + #if (defined(MA_NO_NEON) && defined(MA_ARM)) || (defined(MA_NO_SSE2) && (defined(MA_X86) || defined(MA_X64))) + #define MA_DR_MP3_NO_SIMD + #endif +#endif + /* dr_mp3_h begin */ #ifndef ma_dr_mp3_h #define ma_dr_mp3_h @@ -61040,8 +62599,8 @@ extern "C" { #define MA_DR_MP3_STRINGIFY(x) #x #define MA_DR_MP3_XSTRINGIFY(x) MA_DR_MP3_STRINGIFY(x) #define MA_DR_MP3_VERSION_MAJOR 0 -#define MA_DR_MP3_VERSION_MINOR 6 -#define MA_DR_MP3_VERSION_REVISION 40 +#define MA_DR_MP3_VERSION_MINOR 7 +#define MA_DR_MP3_VERSION_REVISION 1 #define MA_DR_MP3_VERSION_STRING MA_DR_MP3_XSTRINGIFY(MA_DR_MP3_VERSION_MAJOR) "." MA_DR_MP3_XSTRINGIFY(MA_DR_MP3_VERSION_MINOR) "." MA_DR_MP3_XSTRINGIFY(MA_DR_MP3_VERSION_REVISION) #include #define MA_DR_MP3_MAX_PCM_FRAMES_PER_MP3_FRAME 1152 @@ -61050,7 +62609,7 @@ MA_API void ma_dr_mp3_version(ma_uint32* pMajor, ma_uint32* pMinor, ma_uint32* p MA_API const char* ma_dr_mp3_version_string(void); typedef struct { - int frame_bytes, channels, hz, layer, bitrate_kbps; + int frame_bytes, channels, sample_rate, layer, bitrate_kbps; } ma_dr_mp3dec_frame_info; typedef struct { @@ -61063,8 +62622,9 @@ MA_API int ma_dr_mp3dec_decode_frame(ma_dr_mp3dec *dec, const ma_uint8 *mp3, int MA_API void ma_dr_mp3dec_f32_to_s16(const float *in, ma_int16 *out, size_t num_samples); typedef enum { - ma_dr_mp3_seek_origin_start, - ma_dr_mp3_seek_origin_current + MA_DR_MP3_SEEK_SET, + MA_DR_MP3_SEEK_CUR, + MA_DR_MP3_SEEK_END } ma_dr_mp3_seek_origin; typedef struct { @@ -61073,8 +62633,24 @@ typedef struct ma_uint16 mp3FramesToDiscard; ma_uint16 pcmFramesToDiscard; } ma_dr_mp3_seek_point; +typedef enum +{ + MA_DR_MP3_METADATA_TYPE_ID3V1, + MA_DR_MP3_METADATA_TYPE_ID3V2, + MA_DR_MP3_METADATA_TYPE_APE, + MA_DR_MP3_METADATA_TYPE_XING, + MA_DR_MP3_METADATA_TYPE_VBRI +} ma_dr_mp3_metadata_type; +typedef struct +{ + ma_dr_mp3_metadata_type type; + const void* pRawData; + size_t rawDataSize; +} ma_dr_mp3_metadata; typedef size_t (* ma_dr_mp3_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead); typedef ma_bool32 (* ma_dr_mp3_seek_proc)(void* pUserData, int offset, ma_dr_mp3_seek_origin origin); +typedef ma_bool32 (* ma_dr_mp3_tell_proc)(void* pUserData, ma_int64* pCursor); +typedef void (* ma_dr_mp3_meta_proc)(void* pUserData, const ma_dr_mp3_metadata* pMetadata); typedef struct { ma_uint32 channels; @@ -61087,7 +62663,9 @@ typedef struct ma_uint32 sampleRate; ma_dr_mp3_read_proc onRead; ma_dr_mp3_seek_proc onSeek; + ma_dr_mp3_meta_proc onMeta; void* pUserData; + void* pUserDataMeta; ma_allocation_callbacks allocationCallbacks; ma_uint32 mp3FrameChannels; ma_uint32 mp3FrameSampleRate; @@ -61096,13 +62674,20 @@ typedef struct ma_uint8 pcmFrames[sizeof(float)*MA_DR_MP3_MAX_SAMPLES_PER_FRAME]; ma_uint64 currentPCMFrame; ma_uint64 streamCursor; + ma_uint64 streamLength; + ma_uint64 streamStartOffset; ma_dr_mp3_seek_point* pSeekPoints; ma_uint32 seekPointCount; + ma_uint32 delayInPCMFrames; + ma_uint32 paddingInPCMFrames; + ma_uint64 totalPCMFrameCount; + ma_bool32 isVBR; + ma_bool32 isCBR; size_t dataSize; size_t dataCapacity; size_t dataConsumed; ma_uint8* pData; - ma_bool32 atEnd : 1; + ma_bool32 atEnd; struct { const ma_uint8* pData; @@ -61110,9 +62695,12 @@ typedef struct size_t currentReadPos; } memory; } ma_dr_mp3; -MA_API ma_bool32 ma_dr_mp3_init(ma_dr_mp3* pMP3, ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_bool32 ma_dr_mp3_init(ma_dr_mp3* pMP3, ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, ma_dr_mp3_tell_proc onTell, ma_dr_mp3_meta_proc onMeta, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_bool32 ma_dr_mp3_init_memory_with_metadata(ma_dr_mp3* pMP3, const void* pData, size_t dataSize, ma_dr_mp3_meta_proc onMeta, void* pUserDataMeta, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_bool32 ma_dr_mp3_init_memory(ma_dr_mp3* pMP3, const void* pData, size_t dataSize, const ma_allocation_callbacks* pAllocationCallbacks); #ifndef MA_DR_MP3_NO_STDIO +MA_API ma_bool32 ma_dr_mp3_init_file_with_metadata(ma_dr_mp3* pMP3, const char* pFilePath, ma_dr_mp3_meta_proc onMeta, void* pUserDataMeta, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_bool32 ma_dr_mp3_init_file_with_metadata_w(ma_dr_mp3* pMP3, const wchar_t* pFilePath, ma_dr_mp3_meta_proc onMeta, void* pUserDataMeta, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_bool32 ma_dr_mp3_init_file(ma_dr_mp3* pMP3, const char* pFilePath, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_bool32 ma_dr_mp3_init_file_w(ma_dr_mp3* pMP3, const wchar_t* pFilePath, const ma_allocation_callbacks* pAllocationCallbacks); #endif @@ -61125,8 +62713,8 @@ MA_API ma_uint64 ma_dr_mp3_get_mp3_frame_count(ma_dr_mp3* pMP3); MA_API ma_bool32 ma_dr_mp3_get_mp3_and_pcm_frame_count(ma_dr_mp3* pMP3, ma_uint64* pMP3FrameCount, ma_uint64* pPCMFrameCount); MA_API ma_bool32 ma_dr_mp3_calculate_seek_points(ma_dr_mp3* pMP3, ma_uint32* pSeekPointCount, ma_dr_mp3_seek_point* pSeekPoints); MA_API ma_bool32 ma_dr_mp3_bind_seek_table(ma_dr_mp3* pMP3, ma_uint32 seekPointCount, ma_dr_mp3_seek_point* pSeekPoints); -MA_API float* ma_dr_mp3_open_and_read_pcm_frames_f32(ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, void* pUserData, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_int16* ma_dr_mp3_open_and_read_pcm_frames_s16(ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, void* pUserData, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API float* ma_dr_mp3_open_and_read_pcm_frames_f32(ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, ma_dr_mp3_tell_proc onTell, void* pUserData, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_int16* ma_dr_mp3_open_and_read_pcm_frames_s16(ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, ma_dr_mp3_tell_proc onTell, void* pUserData, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); MA_API float* ma_dr_mp3_open_memory_and_read_pcm_frames_f32(const void* pData, size_t dataSize, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_int16* ma_dr_mp3_open_memory_and_read_pcm_frames_s16(const void* pData, size_t dataSize, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); #ifndef MA_DR_MP3_NO_STDIO @@ -61679,8 +63267,10 @@ static ma_bool32 ma_wav_dr_callback__seek(void* pUserData, int offset, ma_dr_wav MA_ASSERT(pWav != NULL); maSeekOrigin = ma_seek_origin_start; - if (origin == ma_dr_wav_seek_origin_current) { - maSeekOrigin = ma_seek_origin_current; + if (origin == MA_DR_WAV_SEEK_CUR) { + maSeekOrigin = ma_seek_origin_current; + } else if (origin == MA_DR_WAV_SEEK_END) { + maSeekOrigin = ma_seek_origin_end; } result = pWav->onSeek(pWav->pReadSeekTellUserData, offset, maSeekOrigin); @@ -61690,6 +63280,26 @@ static ma_bool32 ma_wav_dr_callback__seek(void* pUserData, int offset, ma_dr_wav return MA_TRUE; } + +static ma_bool32 ma_wav_dr_callback__tell(void* pUserData, ma_int64* pCursor) +{ + ma_wav* pWav = (ma_wav*)pUserData; + ma_result result; + + MA_ASSERT(pWav != NULL); + MA_ASSERT(pCursor != NULL); + + if (pWav->onTell == NULL) { + return MA_FALSE; /* Not implemented. */ + } + + result = pWav->onTell(pWav->pReadSeekTellUserData, pCursor); + if (result != MA_SUCCESS) { + return MA_FALSE; /* Failed to tell. */ + } + + return MA_TRUE; +} #endif static ma_result ma_wav_init_internal(const ma_decoding_backend_config* pConfig, ma_wav* pWav) @@ -61784,7 +63394,7 @@ MA_API ma_result ma_wav_init(ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_p { ma_bool32 wavResult; - wavResult = ma_dr_wav_init(&pWav->dr, ma_wav_dr_callback__read, ma_wav_dr_callback__seek, pWav, pAllocationCallbacks); + wavResult = ma_dr_wav_init(&pWav->dr, ma_wav_dr_callback__read, ma_wav_dr_callback__seek, ma_wav_dr_callback__tell, pWav, pAllocationCallbacks); if (wavResult != MA_TRUE) { return MA_INVALID_FILE; } @@ -62363,8 +63973,10 @@ static ma_bool32 ma_flac_dr_callback__seek(void* pUserData, int offset, ma_dr_fl MA_ASSERT(pFlac != NULL); maSeekOrigin = ma_seek_origin_start; - if (origin == ma_dr_flac_seek_origin_current) { - maSeekOrigin = ma_seek_origin_current; + if (origin == MA_DR_FLAC_SEEK_CUR) { + maSeekOrigin = ma_seek_origin_current; + } else if (origin == MA_DR_FLAC_SEEK_END) { + maSeekOrigin = ma_seek_origin_end; } result = pFlac->onSeek(pFlac->pReadSeekTellUserData, offset, maSeekOrigin); @@ -62374,6 +63986,26 @@ static ma_bool32 ma_flac_dr_callback__seek(void* pUserData, int offset, ma_dr_fl return MA_TRUE; } + +static ma_bool32 ma_flac_dr_callback__tell(void* pUserData, ma_int64* pCursor) +{ + ma_flac* pFlac = (ma_flac*)pUserData; + ma_result result; + + MA_ASSERT(pFlac != NULL); + MA_ASSERT(pCursor != NULL); + + if (pFlac->onTell == NULL) { + return MA_FALSE; /* Not implemented. */ + } + + result = pFlac->onTell(pFlac->pReadSeekTellUserData, pCursor); + if (result != MA_SUCCESS) { + return MA_FALSE; /* Failed to tell. */ + } + + return MA_TRUE; +} #endif static ma_result ma_flac_init_internal(const ma_decoding_backend_config* pConfig, ma_flac* pFlac) @@ -62425,7 +64057,7 @@ MA_API ma_result ma_flac_init(ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_ #if !defined(MA_NO_FLAC) { - pFlac->dr = ma_dr_flac_open(ma_flac_dr_callback__read, ma_flac_dr_callback__seek, pFlac, pAllocationCallbacks); + pFlac->dr = ma_dr_flac_open(ma_flac_dr_callback__read, ma_flac_dr_callback__seek, ma_flac_dr_callback__tell, pFlac, pAllocationCallbacks); if (pFlac->dr == NULL) { return MA_INVALID_FILE; } @@ -62986,9 +64618,12 @@ static ma_bool32 ma_mp3_dr_callback__seek(void* pUserData, int offset, ma_dr_mp3 MA_ASSERT(pMP3 != NULL); - maSeekOrigin = ma_seek_origin_start; - if (origin == ma_dr_mp3_seek_origin_current) { - maSeekOrigin = ma_seek_origin_current; + if (origin == MA_DR_MP3_SEEK_SET) { + maSeekOrigin = ma_seek_origin_start; + } else if (origin == MA_DR_MP3_SEEK_END) { + maSeekOrigin = ma_seek_origin_end; + } else { + maSeekOrigin = ma_seek_origin_current; } result = pMP3->onSeek(pMP3->pReadSeekTellUserData, offset, maSeekOrigin); @@ -62998,6 +64633,21 @@ static ma_bool32 ma_mp3_dr_callback__seek(void* pUserData, int offset, ma_dr_mp3 return MA_TRUE; } + +static ma_bool32 ma_mp3_dr_callback__tell(void* pUserData, ma_int64* pCursor) +{ + ma_mp3* pMP3 = (ma_mp3*)pUserData; + ma_result result; + + MA_ASSERT(pMP3 != NULL); + + result = pMP3->onTell(pMP3->pReadSeekTellUserData, pCursor); + if (result != MA_SUCCESS) { + return MA_FALSE; + } + + return MA_TRUE; +} #endif static ma_result ma_mp3_init_internal(const ma_decoding_backend_config* pConfig, ma_mp3* pMP3) @@ -63098,7 +64748,7 @@ MA_API ma_result ma_mp3_init(ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_p { ma_bool32 mp3Result; - mp3Result = ma_dr_mp3_init(&pMP3->dr, ma_mp3_dr_callback__read, ma_mp3_dr_callback__seek, pMP3, pAllocationCallbacks); + mp3Result = ma_dr_mp3_init(&pMP3->dr, ma_mp3_dr_callback__read, ma_mp3_dr_callback__seek, ma_mp3_dr_callback__tell, NULL, pMP3, pAllocationCallbacks); if (mp3Result != MA_TRUE) { return MA_INVALID_FILE; } @@ -64997,14 +66647,16 @@ static ma_bool32 ma_path_extension_equal_w(const wchar_t* path, const wchar_t* e ext1 = extension; ext2 = ma_path_extension_w(path); -#if defined(_MSC_VER) || defined(__WATCOMC__) || defined(__DMC__) - return _wcsicmp(ext1, ext2) == 0; -#else - /* - I'm not aware of a wide character version of strcasecmp(). I'm therefore converting the extensions to multibyte strings and comparing those. This - isn't the most efficient way to do it, but it should work OK. - */ + #if (defined(_MSC_VER) || defined(__WATCOMC__) || defined(__DMC__)) && !defined(MA_XBOX_NXDK) { + return _wcsicmp(ext1, ext2) == 0; + } + #elif !defined(MA_XBOX_NXDK) && !defined(MA_DOS) + { + /* + I'm not aware of a wide character version of strcasecmp(). I'm therefore converting the extensions to multibyte strings and comparing those. This + isn't the most efficient way to do it, but it should work OK. + */ char ext1MB[4096]; char ext2MB[4096]; const wchar_t* pext1 = ext1; @@ -65024,7 +66676,13 @@ static ma_bool32 ma_path_extension_equal_w(const wchar_t* path, const wchar_t* e return strcasecmp(ext1MB, ext2MB) == 0; } -#endif + #else + { + /* Getting here means we don't have a way to do a case-sensitive comparison for wide strings. Fall back to a simple case-sensitive comparison. */ + /* TODO: Implement our own wchar_t-to-char conversion routine and then use the char* version for comparing. */ + return ma_wcscmp(ext1, ext2) == 0; + } + #endif } #endif /* MA_HAS_PATH_API */ @@ -66119,10 +67777,18 @@ static ma_bool32 ma_encoder__internal_on_seek_wav(void* pUserData, int offset, m { ma_encoder* pEncoder = (ma_encoder*)pUserData; ma_result result; + ma_seek_origin maSeekOrigin; MA_ASSERT(pEncoder != NULL); - result = pEncoder->onSeek(pEncoder, offset, (origin == ma_dr_wav_seek_origin_start) ? ma_seek_origin_start : ma_seek_origin_current); + maSeekOrigin = ma_seek_origin_start; + if (origin == MA_DR_WAV_SEEK_CUR) { + maSeekOrigin = ma_seek_origin_current; + } else if (origin == MA_DR_WAV_SEEK_END) { + maSeekOrigin = ma_seek_origin_end; + } + + result = pEncoder->onSeek(pEncoder, offset, maSeekOrigin); if (result != MA_SUCCESS) { return MA_FALSE; } else { @@ -67644,7 +69310,7 @@ static MA_INLINE ma_uint32 ma_hash_getblock(const ma_uint32* blocks, int i) ma_uint32 block; /* Try silencing a sanitization warning about unaligned access by doing a memcpy() instead of assignment. */ - MA_COPY_MEMORY(&block, ma_offset_ptr(blocks, i * sizeof(block)), sizeof(block)); + MA_COPY_MEMORY(&block, ma_offset_ptr(blocks, i * (int) sizeof(block)), sizeof(block)); if (ma_is_little_endian()) { return block; @@ -67720,7 +69386,7 @@ static ma_uint32 ma_hash_string_32(const char* str) static ma_uint32 ma_hash_string_w_32(const wchar_t* str) { - return ma_hash_32(str, (int)wcslen(str) * sizeof(*str), MA_DEFAULT_HASH_SEED); + return ma_hash_32(str, (int)ma_wcslen(str) * sizeof(*str), MA_DEFAULT_HASH_SEED); } @@ -67880,6 +69546,7 @@ static MA_INLINE ma_resource_manager_data_buffer_node* ma_resource_manager_data_ return ma_resource_manager_data_buffer_node_find_min(pDataBufferNode->pChildHi); } +#if 0 /* Currently unused, but might make use of this later. */ static MA_INLINE ma_resource_manager_data_buffer_node* ma_resource_manager_data_buffer_node_find_inorder_predecessor(ma_resource_manager_data_buffer_node* pDataBufferNode) { MA_ASSERT(pDataBufferNode != NULL); @@ -67887,6 +69554,7 @@ static MA_INLINE ma_resource_manager_data_buffer_node* ma_resource_manager_data_ return ma_resource_manager_data_buffer_node_find_max(pDataBufferNode->pChildLo); } +#endif static ma_result ma_resource_manager_data_buffer_node_remove(ma_resource_manager* pResourceManager, ma_resource_manager_data_buffer_node* pDataBufferNode) { @@ -69009,16 +70677,19 @@ static ma_result ma_resource_manager_data_buffer_node_acquire_critical_section(m /* Failed to post job. Probably ran out of memory. */ ma_log_postf(ma_resource_manager_get_log(pResourceManager), MA_LOG_LEVEL_ERROR, "Failed to post MA_JOB_TYPE_RESOURCE_MANAGER_LOAD_DATA_BUFFER_NODE job. %s.\n", ma_result_description(result)); - /* - Fences were acquired before posting the job, but since the job was not able to - be posted, we need to make sure we release them so nothing gets stuck waiting. - */ - if (pInitFence != NULL) { ma_fence_release(pInitFence); } - if (pDoneFence != NULL) { ma_fence_release(pDoneFence); } - if ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT) != 0) { ma_resource_manager_inline_notification_uninit(pInitNotification); } else { + /* + Fences were acquired before posting the job, but since the job was not able to + be posted, we need to make sure we release them so nothing gets stuck waiting. + + In the WAIT_INIT case, these will have already been released in ma_job_process() + so we should only release fences in this branch. + */ + if (pInitFence != NULL) { ma_fence_release(pInitFence); } + if (pDoneFence != NULL) { ma_fence_release(pDoneFence); } + /* These will have been freed by the job thread, but with WAIT_INIT they will already have happened since the job has already been handled. */ ma_free(pFilePathCopy, &pResourceManager->config.allocationCallbacks); ma_free(pFilePathWCopy, &pResourceManager->config.allocationCallbacks); @@ -76674,7 +78345,7 @@ static ma_result ma_sound_init_from_data_source_internal(ma_engine* pEngine, con } if (pConfig->loopPointBegInPCMFrames != 0 || pConfig->loopPointEndInPCMFrames != ~((ma_uint64)0)) { - ma_data_source_set_range_in_pcm_frames(ma_sound_get_data_source(pSound), pConfig->loopPointBegInPCMFrames, pConfig->loopPointEndInPCMFrames); + ma_data_source_set_loop_point_in_pcm_frames(ma_sound_get_data_source(pSound), pConfig->loopPointBegInPCMFrames, pConfig->loopPointEndInPCMFrames); } ma_sound_set_looping(pSound, pConfig->isLooping || ((pConfig->flags & MA_SOUND_FLAG_LOOPING) != 0)); @@ -76736,6 +78407,7 @@ MA_API ma_result ma_sound_init_from_file_internal(ma_engine* pEngine, const ma_s result = ma_resource_manager_data_source_init_ex(pEngine->pResourceManager, &resourceManagerDataSourceConfig, pSound->pResourceManagerDataSource); if (result != MA_SUCCESS) { + ma_free(pSound->pResourceManagerDataSource, &pEngine->allocationCallbacks); goto done; } @@ -77541,7 +79213,12 @@ MA_API ma_uint64 ma_sound_get_time_in_pcm_frames(const ma_sound* pSound) MA_API ma_uint64 ma_sound_get_time_in_milliseconds(const ma_sound* pSound) { - return ma_sound_get_time_in_pcm_frames(pSound) * 1000 / ma_engine_get_sample_rate(ma_sound_get_engine(pSound)); + ma_uint32 sampleRate = ma_engine_get_sample_rate(ma_sound_get_engine(pSound)); + if (sampleRate == 0) { + return 0; /* Prevent a division by zero. */ + } + + return ma_sound_get_time_in_pcm_frames(pSound) * 1000 / sampleRate; } MA_API void ma_sound_set_looping(ma_sound* pSound, ma_bool32 isLooping) @@ -77625,7 +79302,7 @@ MA_API ma_result ma_sound_seek_to_second(ma_sound* pSound, float seekPointInSeco return ma_sound_seek_to_pcm_frame(pSound, frameIndex); } -MA_API ma_result ma_sound_get_data_format(ma_sound* pSound, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) +MA_API ma_result ma_sound_get_data_format(const ma_sound* pSound, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) { if (pSound == NULL) { return MA_INVALID_ARGS; @@ -77658,7 +79335,7 @@ MA_API ma_result ma_sound_get_data_format(ma_sound* pSound, ma_format* pFormat, } } -MA_API ma_result ma_sound_get_cursor_in_pcm_frames(ma_sound* pSound, ma_uint64* pCursor) +MA_API ma_result ma_sound_get_cursor_in_pcm_frames(const ma_sound* pSound, ma_uint64* pCursor) { ma_uint64 seekTarget; @@ -77680,7 +79357,7 @@ MA_API ma_result ma_sound_get_cursor_in_pcm_frames(ma_sound* pSound, ma_uint64* } } -MA_API ma_result ma_sound_get_length_in_pcm_frames(ma_sound* pSound, ma_uint64* pLength) +MA_API ma_result ma_sound_get_length_in_pcm_frames(const ma_sound* pSound, ma_uint64* pLength) { if (pSound == NULL) { return MA_INVALID_ARGS; @@ -77694,7 +79371,7 @@ MA_API ma_result ma_sound_get_length_in_pcm_frames(ma_sound* pSound, ma_uint64* return ma_data_source_get_length_in_pcm_frames(pSound->pDataSource, pLength); } -MA_API ma_result ma_sound_get_cursor_in_seconds(ma_sound* pSound, float* pCursor) +MA_API ma_result ma_sound_get_cursor_in_seconds(const ma_sound* pSound, float* pCursor) { ma_result result; ma_uint64 cursorInPCMFrames; @@ -77720,7 +79397,7 @@ MA_API ma_result ma_sound_get_cursor_in_seconds(ma_sound* pSound, float* pCursor return MA_SUCCESS; } -MA_API ma_result ma_sound_get_length_in_seconds(ma_sound* pSound, float* pLength) +MA_API ma_result ma_sound_get_length_in_seconds(const ma_sound* pSound, float* pLength) { if (pSound == NULL) { return MA_INVALID_ARGS; @@ -78539,12 +80216,12 @@ MA_PRIVATE ma_bool32 ma_dr_wav__seek_forward(ma_dr_wav_seek_proc onSeek, ma_uint ma_uint64 bytesRemainingToSeek = offset; while (bytesRemainingToSeek > 0) { if (bytesRemainingToSeek > 0x7FFFFFFF) { - if (!onSeek(pUserData, 0x7FFFFFFF, ma_dr_wav_seek_origin_current)) { + if (!onSeek(pUserData, 0x7FFFFFFF, MA_DR_WAV_SEEK_CUR)) { return MA_FALSE; } bytesRemainingToSeek -= 0x7FFFFFFF; } else { - if (!onSeek(pUserData, (int)bytesRemainingToSeek, ma_dr_wav_seek_origin_current)) { + if (!onSeek(pUserData, (int)bytesRemainingToSeek, MA_DR_WAV_SEEK_CUR)) { return MA_FALSE; } bytesRemainingToSeek = 0; @@ -78555,17 +80232,17 @@ MA_PRIVATE ma_bool32 ma_dr_wav__seek_forward(ma_dr_wav_seek_proc onSeek, ma_uint MA_PRIVATE ma_bool32 ma_dr_wav__seek_from_start(ma_dr_wav_seek_proc onSeek, ma_uint64 offset, void* pUserData) { if (offset <= 0x7FFFFFFF) { - return onSeek(pUserData, (int)offset, ma_dr_wav_seek_origin_start); + return onSeek(pUserData, (int)offset, MA_DR_WAV_SEEK_SET); } - if (!onSeek(pUserData, 0x7FFFFFFF, ma_dr_wav_seek_origin_start)) { + if (!onSeek(pUserData, 0x7FFFFFFF, MA_DR_WAV_SEEK_SET)) { return MA_FALSE; } offset -= 0x7FFFFFFF; for (;;) { if (offset <= 0x7FFFFFFF) { - return onSeek(pUserData, (int)offset, ma_dr_wav_seek_origin_current); + return onSeek(pUserData, (int)offset, MA_DR_WAV_SEEK_CUR); } - if (!onSeek(pUserData, 0x7FFFFFFF, ma_dr_wav_seek_origin_current)) { + if (!onSeek(pUserData, 0x7FFFFFFF, MA_DR_WAV_SEEK_CUR)) { return MA_FALSE; } offset -= 0x7FFFFFFF; @@ -78588,7 +80265,7 @@ MA_PRIVATE ma_bool32 ma_dr_wav__on_seek(ma_dr_wav_seek_proc onSeek, void* pUserD if (!onSeek(pUserData, offset, origin)) { return MA_FALSE; } - if (origin == ma_dr_wav_seek_origin_start) { + if (origin == MA_DR_WAV_SEEK_SET) { *pCursor = offset; } else { *pCursor += offset; @@ -78707,12 +80384,12 @@ MA_PRIVATE ma_uint64 ma_dr_wav__read_smpl_to_metadata_obj(ma_dr_wav__metadata_pa ma_uint8 smplLoopData[MA_DR_WAV_SMPL_LOOP_BYTES]; bytesJustRead = ma_dr_wav__metadata_parser_read(pParser, smplLoopData, sizeof(smplLoopData), &totalBytesRead); if (bytesJustRead == sizeof(smplLoopData)) { - pMetadata->data.smpl.pLoops[iSampleLoop].cuePointId = ma_dr_wav_bytes_to_u32(smplLoopData + 0); - pMetadata->data.smpl.pLoops[iSampleLoop].type = ma_dr_wav_bytes_to_u32(smplLoopData + 4); - pMetadata->data.smpl.pLoops[iSampleLoop].firstSampleByteOffset = ma_dr_wav_bytes_to_u32(smplLoopData + 8); - pMetadata->data.smpl.pLoops[iSampleLoop].lastSampleByteOffset = ma_dr_wav_bytes_to_u32(smplLoopData + 12); - pMetadata->data.smpl.pLoops[iSampleLoop].sampleFraction = ma_dr_wav_bytes_to_u32(smplLoopData + 16); - pMetadata->data.smpl.pLoops[iSampleLoop].playCount = ma_dr_wav_bytes_to_u32(smplLoopData + 20); + pMetadata->data.smpl.pLoops[iSampleLoop].cuePointId = ma_dr_wav_bytes_to_u32(smplLoopData + 0); + pMetadata->data.smpl.pLoops[iSampleLoop].type = ma_dr_wav_bytes_to_u32(smplLoopData + 4); + pMetadata->data.smpl.pLoops[iSampleLoop].firstSampleOffset = ma_dr_wav_bytes_to_u32(smplLoopData + 8); + pMetadata->data.smpl.pLoops[iSampleLoop].lastSampleOffset = ma_dr_wav_bytes_to_u32(smplLoopData + 12); + pMetadata->data.smpl.pLoops[iSampleLoop].sampleFraction = ma_dr_wav_bytes_to_u32(smplLoopData + 16); + pMetadata->data.smpl.pLoops[iSampleLoop].playCount = ma_dr_wav_bytes_to_u32(smplLoopData + 20); } else { break; } @@ -78756,7 +80433,7 @@ MA_PRIVATE ma_uint64 ma_dr_wav__read_cue_to_metadata_obj(ma_dr_wav__metadata_par pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[3] = cuePointData[11]; pMetadata->data.cue.pCuePoints[iCuePoint].chunkStart = ma_dr_wav_bytes_to_u32(cuePointData + 12); pMetadata->data.cue.pCuePoints[iCuePoint].blockStart = ma_dr_wav_bytes_to_u32(cuePointData + 16); - pMetadata->data.cue.pCuePoints[iCuePoint].sampleByteOffset = ma_dr_wav_bytes_to_u32(cuePointData + 20); + pMetadata->data.cue.pCuePoints[iCuePoint].sampleOffset = ma_dr_wav_bytes_to_u32(cuePointData + 20); } else { break; } @@ -79096,7 +80773,7 @@ MA_PRIVATE ma_uint64 ma_dr_wav__metadata_process_chunk(ma_dr_wav__metadata_parse if (pParser->stage == ma_dr_wav__metadata_parser_stage_count) { ma_uint8 buffer[4]; size_t bytesJustRead; - if (!pParser->onSeek(pParser->pReadSeekUserData, 28, ma_dr_wav_seek_origin_current)) { + if (!pParser->onSeek(pParser->pReadSeekUserData, 28, MA_DR_WAV_SEEK_CUR)) { return bytesRead; } bytesRead += 28; @@ -79191,7 +80868,7 @@ MA_PRIVATE ma_uint64 ma_dr_wav__metadata_process_chunk(ma_dr_wav__metadata_parse return bytesRead; } allocSizeNeeded += ma_dr_wav__strlen(buffer) + 1; - allocSizeNeeded += (size_t)pChunkHeader->sizeInBytes - MA_DR_WAV_BEXT_BYTES; + allocSizeNeeded += (size_t)pChunkHeader->sizeInBytes - MA_DR_WAV_BEXT_BYTES + 1; ma_dr_wav__metadata_request_extra_memory_for_stage_2(pParser, allocSizeNeeded, 1); pParser->metadataCount += 1; } else { @@ -79274,6 +80951,16 @@ MA_PRIVATE ma_uint64 ma_dr_wav__metadata_process_chunk(ma_dr_wav__metadata_parse subchunkBytesRead = ma_dr_wav__metadata_process_info_text_chunk(pParser, subchunkDataSize, ma_dr_wav_metadata_type_list_info_album); } else if (ma_dr_wav__chunk_matches(allowedMetadataTypes, subchunkId, ma_dr_wav_metadata_type_list_info_tracknumber, "ITRK")) { subchunkBytesRead = ma_dr_wav__metadata_process_info_text_chunk(pParser, subchunkDataSize, ma_dr_wav_metadata_type_list_info_tracknumber); + } else if (ma_dr_wav__chunk_matches(allowedMetadataTypes, subchunkId, ma_dr_wav_metadata_type_list_info_location, "IARL")) { + subchunkBytesRead = ma_dr_wav__metadata_process_info_text_chunk(pParser, subchunkDataSize, ma_dr_wav_metadata_type_list_info_location); + } else if (ma_dr_wav__chunk_matches(allowedMetadataTypes, subchunkId, ma_dr_wav_metadata_type_list_info_organization, "ICMS")) { + subchunkBytesRead = ma_dr_wav__metadata_process_info_text_chunk(pParser, subchunkDataSize, ma_dr_wav_metadata_type_list_info_organization); + } else if (ma_dr_wav__chunk_matches(allowedMetadataTypes, subchunkId, ma_dr_wav_metadata_type_list_info_keywords, "IKEY")) { + subchunkBytesRead = ma_dr_wav__metadata_process_info_text_chunk(pParser, subchunkDataSize, ma_dr_wav_metadata_type_list_info_keywords); + } else if (ma_dr_wav__chunk_matches(allowedMetadataTypes, subchunkId, ma_dr_wav_metadata_type_list_info_medium, "IMED")) { + subchunkBytesRead = ma_dr_wav__metadata_process_info_text_chunk(pParser, subchunkDataSize, ma_dr_wav_metadata_type_list_info_medium); + } else if (ma_dr_wav__chunk_matches(allowedMetadataTypes, subchunkId, ma_dr_wav_metadata_type_list_info_description, "ISBJ")) { + subchunkBytesRead = ma_dr_wav__metadata_process_info_text_chunk(pParser, subchunkDataSize, ma_dr_wav_metadata_type_list_info_description); } else if ((allowedMetadataTypes & ma_dr_wav_metadata_type_unknown) != 0) { subchunkBytesRead = ma_dr_wav__metadata_process_unknown_chunk(pParser, subchunkId, subchunkDataSize, listType); } @@ -79281,13 +80968,13 @@ MA_PRIVATE ma_uint64 ma_dr_wav__metadata_process_chunk(ma_dr_wav__metadata_parse MA_DR_WAV_ASSERT(subchunkBytesRead <= subchunkDataSize); if (subchunkBytesRead < subchunkDataSize) { ma_uint64 bytesToSeek = subchunkDataSize - subchunkBytesRead; - if (!pParser->onSeek(pParser->pReadSeekUserData, (int)bytesToSeek, ma_dr_wav_seek_origin_current)) { + if (!pParser->onSeek(pParser->pReadSeekUserData, (int)bytesToSeek, MA_DR_WAV_SEEK_CUR)) { break; } bytesRead += bytesToSeek; } if ((subchunkDataSize % 2) == 1) { - if (!pParser->onSeek(pParser->pReadSeekUserData, 1, ma_dr_wav_seek_origin_current)) { + if (!pParser->onSeek(pParser->pReadSeekUserData, 1, MA_DR_WAV_SEEK_CUR)) { break; } bytesRead += 1; @@ -79324,7 +81011,7 @@ MA_API ma_uint16 ma_dr_wav_fmt_get_format(const ma_dr_wav_fmt* pFMT) return ma_dr_wav_bytes_to_u16(pFMT->subFormat); } } -MA_PRIVATE ma_bool32 ma_dr_wav_preinit(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pReadSeekUserData, const ma_allocation_callbacks* pAllocationCallbacks) +MA_PRIVATE ma_bool32 ma_dr_wav_preinit(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_tell_proc onTell, void* pReadSeekTellUserData, const ma_allocation_callbacks* pAllocationCallbacks) { if (pWav == NULL || onRead == NULL || onSeek == NULL) { return MA_FALSE; @@ -79332,7 +81019,8 @@ MA_PRIVATE ma_bool32 ma_dr_wav_preinit(ma_dr_wav* pWav, ma_dr_wav_read_proc onRe MA_DR_WAV_ZERO_MEMORY(pWav, sizeof(*pWav)); pWav->onRead = onRead; pWav->onSeek = onSeek; - pWav->pUserData = pReadSeekUserData; + pWav->onTell = onTell; + pWav->pUserData = pReadSeekTellUserData; pWav->allocationCallbacks = ma_dr_wav_copy_allocation_callbacks_or_defaults(pAllocationCallbacks); if (pWav->allocationCallbacks.onFree == NULL || (pWav->allocationCallbacks.onMalloc == NULL && pWav->allocationCallbacks.onRealloc == NULL)) { return MA_FALSE; @@ -79546,14 +81234,14 @@ MA_PRIVATE ma_bool32 ma_dr_wav_init__internal(ma_dr_wav* pWav, ma_dr_wav_chunk_p fmt.channelMask = ma_dr_wav_bytes_to_u32_ex(fmtext + 2, pWav->container); ma_dr_wav_bytes_to_guid(fmtext + 6, fmt.subFormat); } else { - if (pWav->onSeek(pWav->pUserData, fmt.extendedSize, ma_dr_wav_seek_origin_current) == MA_FALSE) { + if (pWav->onSeek(pWav->pUserData, fmt.extendedSize, MA_DR_WAV_SEEK_CUR) == MA_FALSE) { return MA_FALSE; } } cursor += fmt.extendedSize; bytesReadSoFar += fmt.extendedSize; } - if (pWav->onSeek(pWav->pUserData, (int)(header.sizeInBytes - bytesReadSoFar), ma_dr_wav_seek_origin_current) == MA_FALSE) { + if (pWav->onSeek(pWav->pUserData, (int)(header.sizeInBytes - bytesReadSoFar), MA_DR_WAV_SEEK_CUR) == MA_FALSE) { return MA_FALSE; } cursor += (header.sizeInBytes - bytesReadSoFar); @@ -79704,15 +81392,26 @@ MA_PRIVATE ma_bool32 ma_dr_wav_init__internal(ma_dr_wav* pWav, ma_dr_wav_chunk_p return MA_FALSE; } offset = ma_dr_wav_bytes_to_u32_ex(offsetAndBlockSizeData + 0, pWav->container); - if (ma_dr_wav__seek_forward(pWav->onSeek, offset, pWav->pUserData) == MA_FALSE) { - return MA_FALSE; - } - cursor += offset; - pWav->dataChunkDataPos = cursor; + pWav->dataChunkDataPos = cursor + offset; dataChunkSize = chunkSize; - if (sequential || !isProcessingMetadata) { - break; + if (dataChunkSize > offset) { + dataChunkSize -= offset; } else { + dataChunkSize = 0; + } + if (sequential) { + if (foundChunk_fmt) { + if (ma_dr_wav__seek_forward(pWav->onSeek, offset, pWav->pUserData) == MA_FALSE) { + return MA_FALSE; + } + cursor += offset; + break; + } else { + return MA_FALSE; + } + } else { + chunkSize += header.paddingSize; + chunkSize -= sizeof(offsetAndBlockSizeData); if (ma_dr_wav__seek_forward(pWav->onSeek, chunkSize, pWav->pUserData) == MA_FALSE) { break; } @@ -79776,6 +81475,17 @@ MA_PRIVATE ma_bool32 ma_dr_wav_init__internal(ma_dr_wav* pWav, ma_dr_wav_chunk_p pWav->pMetadata = metadataParser.pMetadata; pWav->metadataCount = metadataParser.metadataCount; } + if (pWav->onTell != NULL && pWav->onSeek != NULL) { + if (pWav->onSeek(pWav->pUserData, 0, MA_DR_WAV_SEEK_END) == MA_TRUE) { + ma_int64 fileSize; + if (pWav->onTell(pWav->pUserData, &fileSize)) { + if (dataChunkSize + pWav->dataChunkDataPos > (ma_uint64)fileSize) { + dataChunkSize = (ma_uint64)fileSize - pWav->dataChunkDataPos; + } + } + } else { + } + } if (dataChunkSize == 0xFFFFFFFF && (pWav->container == ma_dr_wav_container_riff || pWav->container == ma_dr_wav_container_rifx) && pWav->isSequentialWrite == MA_FALSE) { dataChunkSize = 0; for (;;) { @@ -79795,8 +81505,14 @@ MA_PRIVATE ma_bool32 ma_dr_wav_init__internal(ma_dr_wav* pWav, ma_dr_wav_chunk_p pWav->sampleRate = fmt.sampleRate; pWav->channels = fmt.channels; pWav->bitsPerSample = fmt.bitsPerSample; - pWav->bytesRemaining = dataChunkSize; pWav->translatedFormatTag = translatedFormatTag; + if (!ma_dr_wav__is_compressed_format_tag(translatedFormatTag)) { + ma_uint32 bytesPerFrame = ma_dr_wav_get_bytes_per_pcm_frame(pWav); + if (bytesPerFrame > 0) { + dataChunkSize -= (dataChunkSize % bytesPerFrame); + } + } + pWav->bytesRemaining = dataChunkSize; pWav->dataChunkDataSize = dataChunkSize; if (sampleCountFromFactChunk != 0) { pWav->totalPCMFrameCount = sampleCountFromFactChunk; @@ -79851,20 +81567,20 @@ MA_PRIVATE ma_bool32 ma_dr_wav_init__internal(ma_dr_wav* pWav, ma_dr_wav_chunk_p #endif return MA_TRUE; } -MA_API ma_bool32 ma_dr_wav_init(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_bool32 ma_dr_wav_init(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_tell_proc onTell, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) { - return ma_dr_wav_init_ex(pWav, onRead, onSeek, NULL, pUserData, NULL, 0, pAllocationCallbacks); + return ma_dr_wav_init_ex(pWav, onRead, onSeek, onTell, NULL, pUserData, NULL, 0, pAllocationCallbacks); } -MA_API ma_bool32 ma_dr_wav_init_ex(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_chunk_proc onChunk, void* pReadSeekUserData, void* pChunkUserData, ma_uint32 flags, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_bool32 ma_dr_wav_init_ex(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_tell_proc onTell, ma_dr_wav_chunk_proc onChunk, void* pReadSeekTellUserData, void* pChunkUserData, ma_uint32 flags, const ma_allocation_callbacks* pAllocationCallbacks) { - if (!ma_dr_wav_preinit(pWav, onRead, onSeek, pReadSeekUserData, pAllocationCallbacks)) { + if (!ma_dr_wav_preinit(pWav, onRead, onSeek, onTell, pReadSeekTellUserData, pAllocationCallbacks)) { return MA_FALSE; } return ma_dr_wav_init__internal(pWav, onChunk, pChunkUserData, flags); } -MA_API ma_bool32 ma_dr_wav_init_with_metadata(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pUserData, ma_uint32 flags, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_bool32 ma_dr_wav_init_with_metadata(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_tell_proc onTell, void* pUserData, ma_uint32 flags, const ma_allocation_callbacks* pAllocationCallbacks) { - if (!ma_dr_wav_preinit(pWav, onRead, onSeek, pUserData, pAllocationCallbacks)) { + if (!ma_dr_wav_preinit(pWav, onRead, onSeek, onTell, pUserData, pAllocationCallbacks)) { return MA_FALSE; } return ma_dr_wav_init__internal(pWav, NULL, NULL, flags | MA_DR_WAV_WITH_METADATA); @@ -80026,8 +81742,8 @@ MA_PRIVATE size_t ma_dr_wav__write_or_count_metadata(ma_dr_wav* pWav, ma_dr_wav_ for (iLoop = 0; iLoop < pMetadata->data.smpl.sampleLoopCount; ++iLoop) { bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].cuePointId); bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].type); - bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].firstSampleByteOffset); - bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].lastSampleByteOffset); + bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].firstSampleOffset); + bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].lastSampleOffset); bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].sampleFraction); bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].playCount); } @@ -80061,7 +81777,7 @@ MA_PRIVATE size_t ma_dr_wav__write_or_count_metadata(ma_dr_wav* pWav, ma_dr_wav_ bytesWritten += ma_dr_wav__write_or_count(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId, 4); bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].chunkStart); bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].blockStart); - bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].sampleByteOffset); + bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].sampleOffset); } } break; case ma_dr_wav_metadata_type_acid: @@ -80147,15 +81863,20 @@ MA_PRIVATE size_t ma_dr_wav__write_or_count_metadata(ma_dr_wav* pWav, ma_dr_wav_ if (pMetadata->type & ma_dr_wav_metadata_type_list_all_info_strings) { const char* pID = NULL; switch (pMetadata->type) { - case ma_dr_wav_metadata_type_list_info_software: pID = "ISFT"; break; - case ma_dr_wav_metadata_type_list_info_copyright: pID = "ICOP"; break; - case ma_dr_wav_metadata_type_list_info_title: pID = "INAM"; break; - case ma_dr_wav_metadata_type_list_info_artist: pID = "IART"; break; - case ma_dr_wav_metadata_type_list_info_comment: pID = "ICMT"; break; - case ma_dr_wav_metadata_type_list_info_date: pID = "ICRD"; break; - case ma_dr_wav_metadata_type_list_info_genre: pID = "IGNR"; break; - case ma_dr_wav_metadata_type_list_info_album: pID = "IPRD"; break; - case ma_dr_wav_metadata_type_list_info_tracknumber: pID = "ITRK"; break; + case ma_dr_wav_metadata_type_list_info_software: pID = "ISFT"; break; + case ma_dr_wav_metadata_type_list_info_copyright: pID = "ICOP"; break; + case ma_dr_wav_metadata_type_list_info_title: pID = "INAM"; break; + case ma_dr_wav_metadata_type_list_info_artist: pID = "IART"; break; + case ma_dr_wav_metadata_type_list_info_comment: pID = "ICMT"; break; + case ma_dr_wav_metadata_type_list_info_date: pID = "ICRD"; break; + case ma_dr_wav_metadata_type_list_info_genre: pID = "IGNR"; break; + case ma_dr_wav_metadata_type_list_info_album: pID = "IPRD"; break; + case ma_dr_wav_metadata_type_list_info_tracknumber: pID = "ITRK"; break; + case ma_dr_wav_metadata_type_list_info_location: pID = "IARL"; break; + case ma_dr_wav_metadata_type_list_info_organization: pID = "ICMS"; break; + case ma_dr_wav_metadata_type_list_info_keywords: pID = "IKEY"; break; + case ma_dr_wav_metadata_type_list_info_medium: pID = "IMED"; break; + case ma_dr_wav_metadata_type_list_info_description: pID = "ISBJ"; break; default: break; } MA_DR_WAV_ASSERT(pID != NULL); @@ -80370,7 +82091,7 @@ MA_PRIVATE ma_bool32 ma_dr_wav_init_write__internal(ma_dr_wav* pWav, const ma_dr } pWav->dataChunkDataSizeTargetWrite = initialDataChunkSize; if (pFormat->container == ma_dr_wav_container_riff) { - ma_uint32 chunkSizeRIFF = 28 + (ma_uint32)initialDataChunkSize; + ma_uint32 chunkSizeRIFF = 36 + (ma_uint32)initialDataChunkSize; runningPos += ma_dr_wav__write(pWav, "RIFF", 4); runningPos += ma_dr_wav__write_u32ne_to_le(pWav, chunkSizeRIFF); runningPos += ma_dr_wav__write(pWav, "WAVE", 4); @@ -80493,7 +82214,31 @@ MA_PRIVATE size_t ma_dr_wav__on_write_stdio(void* pUserData, const void* pData, } MA_PRIVATE ma_bool32 ma_dr_wav__on_seek_stdio(void* pUserData, int offset, ma_dr_wav_seek_origin origin) { - return fseek((FILE*)pUserData, offset, (origin == ma_dr_wav_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0; + int whence = SEEK_SET; + if (origin == MA_DR_WAV_SEEK_CUR) { + whence = SEEK_CUR; + } else if (origin == MA_DR_WAV_SEEK_END) { + whence = SEEK_END; + } + return fseek((FILE*)pUserData, offset, whence) == 0; +} +MA_PRIVATE ma_bool32 ma_dr_wav__on_tell_stdio(void* pUserData, ma_int64* pCursor) +{ + FILE* pFileStdio = (FILE*)pUserData; + ma_int64 result; + MA_DR_WAV_ASSERT(pFileStdio != NULL); + MA_DR_WAV_ASSERT(pCursor != NULL); +#if defined(_WIN32) && !defined(NXDK) + #if defined(_MSC_VER) && _MSC_VER > 1200 + result = _ftelli64(pFileStdio); + #else + result = ftell(pFileStdio); + #endif +#else + result = ftell(pFileStdio); +#endif + *pCursor = result; + return MA_TRUE; } MA_API ma_bool32 ma_dr_wav_init_file(ma_dr_wav* pWav, const char* filename, const ma_allocation_callbacks* pAllocationCallbacks) { @@ -80502,7 +82247,7 @@ MA_API ma_bool32 ma_dr_wav_init_file(ma_dr_wav* pWav, const char* filename, cons MA_PRIVATE ma_bool32 ma_dr_wav_init_file__internal_FILE(ma_dr_wav* pWav, FILE* pFile, ma_dr_wav_chunk_proc onChunk, void* pChunkUserData, ma_uint32 flags, const ma_allocation_callbacks* pAllocationCallbacks) { ma_bool32 result; - result = ma_dr_wav_preinit(pWav, ma_dr_wav__on_read_stdio, ma_dr_wav__on_seek_stdio, (void*)pFile, pAllocationCallbacks); + result = ma_dr_wav_preinit(pWav, ma_dr_wav__on_read_stdio, ma_dr_wav__on_seek_stdio, ma_dr_wav__on_tell_stdio, (void*)pFile, pAllocationCallbacks); if (result != MA_TRUE) { fclose(pFile); return result; @@ -80639,25 +82384,27 @@ MA_PRIVATE size_t ma_dr_wav__on_read_memory(void* pUserData, void* pBufferOut, s MA_PRIVATE ma_bool32 ma_dr_wav__on_seek_memory(void* pUserData, int offset, ma_dr_wav_seek_origin origin) { ma_dr_wav* pWav = (ma_dr_wav*)pUserData; + ma_int64 newCursor; MA_DR_WAV_ASSERT(pWav != NULL); - if (origin == ma_dr_wav_seek_origin_current) { - if (offset > 0) { - if (pWav->memoryStream.currentReadPos + offset > pWav->memoryStream.dataSize) { - return MA_FALSE; - } - } else { - if (pWav->memoryStream.currentReadPos < (size_t)-offset) { - return MA_FALSE; - } - } - pWav->memoryStream.currentReadPos += offset; + newCursor = pWav->memoryStream.currentReadPos; + if (origin == MA_DR_WAV_SEEK_SET) { + newCursor = 0; + } else if (origin == MA_DR_WAV_SEEK_CUR) { + newCursor = (ma_int64)pWav->memoryStream.currentReadPos; + } else if (origin == MA_DR_WAV_SEEK_END) { + newCursor = (ma_int64)pWav->memoryStream.dataSize; } else { - if ((ma_uint32)offset <= pWav->memoryStream.dataSize) { - pWav->memoryStream.currentReadPos = offset; - } else { - return MA_FALSE; - } + MA_DR_WAV_ASSERT(!"Invalid seek origin"); + return MA_FALSE; } + newCursor += offset; + if (newCursor < 0) { + return MA_FALSE; + } + if ((size_t)newCursor > pWav->memoryStream.dataSize) { + return MA_FALSE; + } + pWav->memoryStream.currentReadPos = (size_t)newCursor; return MA_TRUE; } MA_PRIVATE size_t ma_dr_wav__on_write_memory(void* pUserData, const void* pDataIn, size_t bytesToWrite) @@ -80691,25 +82438,35 @@ MA_PRIVATE size_t ma_dr_wav__on_write_memory(void* pUserData, const void* pDataI MA_PRIVATE ma_bool32 ma_dr_wav__on_seek_memory_write(void* pUserData, int offset, ma_dr_wav_seek_origin origin) { ma_dr_wav* pWav = (ma_dr_wav*)pUserData; + ma_int64 newCursor; MA_DR_WAV_ASSERT(pWav != NULL); - if (origin == ma_dr_wav_seek_origin_current) { - if (offset > 0) { - if (pWav->memoryStreamWrite.currentWritePos + offset > pWav->memoryStreamWrite.dataSize) { - offset = (int)(pWav->memoryStreamWrite.dataSize - pWav->memoryStreamWrite.currentWritePos); - } - } else { - if (pWav->memoryStreamWrite.currentWritePos < (size_t)-offset) { - offset = -(int)pWav->memoryStreamWrite.currentWritePos; - } - } - pWav->memoryStreamWrite.currentWritePos += offset; + newCursor = pWav->memoryStreamWrite.currentWritePos; + if (origin == MA_DR_WAV_SEEK_SET) { + newCursor = 0; + } else if (origin == MA_DR_WAV_SEEK_CUR) { + newCursor = (ma_int64)pWav->memoryStreamWrite.currentWritePos; + } else if (origin == MA_DR_WAV_SEEK_END) { + newCursor = (ma_int64)pWav->memoryStreamWrite.dataSize; } else { - if ((ma_uint32)offset <= pWav->memoryStreamWrite.dataSize) { - pWav->memoryStreamWrite.currentWritePos = offset; - } else { - pWav->memoryStreamWrite.currentWritePos = pWav->memoryStreamWrite.dataSize; - } + MA_DR_WAV_ASSERT(!"Invalid seek origin"); + return MA_INVALID_ARGS; } + newCursor += offset; + if (newCursor < 0) { + return MA_FALSE; + } + if ((size_t)newCursor > pWav->memoryStreamWrite.dataSize) { + return MA_FALSE; + } + pWav->memoryStreamWrite.currentWritePos = (size_t)newCursor; + return MA_TRUE; +} +MA_PRIVATE ma_bool32 ma_dr_wav__on_tell_memory(void* pUserData, ma_int64* pCursor) +{ + ma_dr_wav* pWav = (ma_dr_wav*)pUserData; + MA_DR_WAV_ASSERT(pWav != NULL); + MA_DR_WAV_ASSERT(pCursor != NULL); + *pCursor = (ma_int64)pWav->memoryStream.currentReadPos; return MA_TRUE; } MA_API ma_bool32 ma_dr_wav_init_memory(ma_dr_wav* pWav, const void* data, size_t dataSize, const ma_allocation_callbacks* pAllocationCallbacks) @@ -80721,7 +82478,7 @@ MA_API ma_bool32 ma_dr_wav_init_memory_ex(ma_dr_wav* pWav, const void* data, siz if (data == NULL || dataSize == 0) { return MA_FALSE; } - if (!ma_dr_wav_preinit(pWav, ma_dr_wav__on_read_memory, ma_dr_wav__on_seek_memory, pWav, pAllocationCallbacks)) { + if (!ma_dr_wav_preinit(pWav, ma_dr_wav__on_read_memory, ma_dr_wav__on_seek_memory, ma_dr_wav__on_tell_memory, pWav, pAllocationCallbacks)) { return MA_FALSE; } pWav->memoryStream.data = (const ma_uint8*)data; @@ -80734,7 +82491,7 @@ MA_API ma_bool32 ma_dr_wav_init_memory_with_metadata(ma_dr_wav* pWav, const void if (data == NULL || dataSize == 0) { return MA_FALSE; } - if (!ma_dr_wav_preinit(pWav, ma_dr_wav__on_read_memory, ma_dr_wav__on_seek_memory, pWav, pAllocationCallbacks)) { + if (!ma_dr_wav_preinit(pWav, ma_dr_wav__on_read_memory, ma_dr_wav__on_seek_memory, ma_dr_wav__on_tell_memory, pWav, pAllocationCallbacks)) { return MA_FALSE; } pWav->memoryStream.data = (const ma_uint8*)data; @@ -80793,30 +82550,30 @@ MA_API ma_result ma_dr_wav_uninit(ma_dr_wav* pWav) } if (pWav->onSeek && !pWav->isSequentialWrite) { if (pWav->container == ma_dr_wav_container_riff) { - if (pWav->onSeek(pWav->pUserData, 4, ma_dr_wav_seek_origin_start)) { + if (pWav->onSeek(pWav->pUserData, 4, MA_DR_WAV_SEEK_SET)) { ma_uint32 riffChunkSize = ma_dr_wav__riff_chunk_size_riff(pWav->dataChunkDataSize, pWav->pMetadata, pWav->metadataCount); ma_dr_wav__write_u32ne_to_le(pWav, riffChunkSize); } - if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos - 4, ma_dr_wav_seek_origin_start)) { + if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos - 4, MA_DR_WAV_SEEK_SET)) { ma_uint32 dataChunkSize = ma_dr_wav__data_chunk_size_riff(pWav->dataChunkDataSize); ma_dr_wav__write_u32ne_to_le(pWav, dataChunkSize); } } else if (pWav->container == ma_dr_wav_container_w64) { - if (pWav->onSeek(pWav->pUserData, 16, ma_dr_wav_seek_origin_start)) { + if (pWav->onSeek(pWav->pUserData, 16, MA_DR_WAV_SEEK_SET)) { ma_uint64 riffChunkSize = ma_dr_wav__riff_chunk_size_w64(pWav->dataChunkDataSize); ma_dr_wav__write_u64ne_to_le(pWav, riffChunkSize); } - if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos - 8, ma_dr_wav_seek_origin_start)) { + if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos - 8, MA_DR_WAV_SEEK_SET)) { ma_uint64 dataChunkSize = ma_dr_wav__data_chunk_size_w64(pWav->dataChunkDataSize); ma_dr_wav__write_u64ne_to_le(pWav, dataChunkSize); } } else if (pWav->container == ma_dr_wav_container_rf64) { int ds64BodyPos = 12 + 8; - if (pWav->onSeek(pWav->pUserData, ds64BodyPos + 0, ma_dr_wav_seek_origin_start)) { + if (pWav->onSeek(pWav->pUserData, ds64BodyPos + 0, MA_DR_WAV_SEEK_SET)) { ma_uint64 riffChunkSize = ma_dr_wav__riff_chunk_size_rf64(pWav->dataChunkDataSize, pWav->pMetadata, pWav->metadataCount); ma_dr_wav__write_u64ne_to_le(pWav, riffChunkSize); } - if (pWav->onSeek(pWav->pUserData, ds64BodyPos + 8, ma_dr_wav_seek_origin_start)) { + if (pWav->onSeek(pWav->pUserData, ds64BodyPos + 8, MA_DR_WAV_SEEK_SET)) { ma_uint64 dataChunkSize = ma_dr_wav__data_chunk_size_rf64(pWav->dataChunkDataSize); ma_dr_wav__write_u64ne_to_le(pWav, dataChunkSize); } @@ -80863,7 +82620,7 @@ MA_API size_t ma_dr_wav_read_raw(ma_dr_wav* pWav, size_t bytesToRead, void* pBuf if (bytesToSeek > 0x7FFFFFFF) { bytesToSeek = 0x7FFFFFFF; } - if (pWav->onSeek(pWav->pUserData, (int)bytesToSeek, ma_dr_wav_seek_origin_current) == MA_FALSE) { + if (pWav->onSeek(pWav->pUserData, (int)bytesToSeek, MA_DR_WAV_SEEK_CUR) == MA_FALSE) { break; } bytesRead += bytesToSeek; @@ -80962,7 +82719,7 @@ MA_PRIVATE ma_bool32 ma_dr_wav_seek_to_first_pcm_frame(ma_dr_wav* pWav) if (pWav->onWrite != NULL) { return MA_FALSE; } - if (!pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos, ma_dr_wav_seek_origin_start)) { + if (!pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos, MA_DR_WAV_SEEK_SET)) { return MA_FALSE; } if (ma_dr_wav__is_compressed_format_tag(pWav->translatedFormatTag)) { @@ -81043,7 +82800,7 @@ MA_API ma_bool32 ma_dr_wav_seek_to_pcm_frame(ma_dr_wav* pWav, ma_uint64 targetFr } while (offset > 0) { int offset32 = ((offset > INT_MAX) ? INT_MAX : (int)offset); - if (!pWav->onSeek(pWav->pUserData, offset32, ma_dr_wav_seek_origin_current)) { + if (!pWav->onSeek(pWav->pUserData, offset32, MA_DR_WAV_SEEK_CUR)) { return MA_FALSE; } pWav->readCursorInPCMFrames += offset32 / bytesPerFrame; @@ -81169,12 +82926,12 @@ MA_API ma_uint64 ma_dr_wav_write_pcm_frames(ma_dr_wav* pWav, ma_uint64 framesToW MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_s16__msadpcm(ma_dr_wav* pWav, ma_uint64 framesToRead, ma_int16* pBufferOut) { ma_uint64 totalFramesRead = 0; - static ma_int32 adaptationTable[] = { + static const ma_int32 adaptationTable[] = { 230, 230, 230, 230, 307, 409, 512, 614, 768, 614, 512, 409, 307, 230, 230, 230 }; - static ma_int32 coeff1Table[] = { 256, 512, 0, 192, 240, 460, 392 }; - static ma_int32 coeff2Table[] = { 0, -256, 0, 64, 0, -208, -232 }; + static const ma_int32 coeff1Table[] = { 256, 512, 0, 192, 240, 460, 392 }; + static const ma_int32 coeff2Table[] = { 0, -256, 0, 64, 0, -208, -232 }; MA_DR_WAV_ASSERT(pWav != NULL); MA_DR_WAV_ASSERT(framesToRead > 0); while (pWav->readCursorInPCMFrames < pWav->totalPCMFrameCount) { @@ -81307,11 +83064,11 @@ MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_s16__ima(ma_dr_wav* pWav, ma_uint { ma_uint64 totalFramesRead = 0; ma_uint32 iChannel; - static ma_int32 indexTable[16] = { + static const ma_int32 indexTable[16] = { -1, -1, -1, -1, 2, 4, 6, 8, -1, -1, -1, -1, 2, 4, 6, 8 }; - static ma_int32 stepTable[89] = { + static const ma_int32 stepTable[89] = { 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, @@ -81334,7 +83091,7 @@ MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_s16__ima(ma_dr_wav* pWav, ma_uint } pWav->ima.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header); if (header[2] >= ma_dr_wav_countof(stepTable)) { - pWav->onSeek(pWav->pUserData, pWav->ima.bytesRemainingInBlock, ma_dr_wav_seek_origin_current); + pWav->onSeek(pWav->pUserData, pWav->ima.bytesRemainingInBlock, MA_DR_WAV_SEEK_CUR); pWav->ima.bytesRemainingInBlock = 0; return totalFramesRead; } @@ -81349,7 +83106,7 @@ MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_s16__ima(ma_dr_wav* pWav, ma_uint } pWav->ima.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header); if (header[2] >= ma_dr_wav_countof(stepTable) || header[6] >= ma_dr_wav_countof(stepTable)) { - pWav->onSeek(pWav->pUserData, pWav->ima.bytesRemainingInBlock, ma_dr_wav_seek_origin_current); + pWav->onSeek(pWav->pUserData, pWav->ima.bytesRemainingInBlock, MA_DR_WAV_SEEK_CUR); pWav->ima.bytesRemainingInBlock = 0; return totalFramesRead; } @@ -81424,7 +83181,7 @@ MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_s16__ima(ma_dr_wav* pWav, ma_uint return totalFramesRead; } #ifndef MA_DR_WAV_NO_CONVERSION_API -static unsigned short g_ma_dr_wavAlawTable[256] = { +static const unsigned short ma_dr_wav_gAlawTable[256] = { 0xEA80, 0xEB80, 0xE880, 0xE980, 0xEE80, 0xEF80, 0xEC80, 0xED80, 0xE280, 0xE380, 0xE080, 0xE180, 0xE680, 0xE780, 0xE480, 0xE580, 0xF540, 0xF5C0, 0xF440, 0xF4C0, 0xF740, 0xF7C0, 0xF640, 0xF6C0, 0xF140, 0xF1C0, 0xF040, 0xF0C0, 0xF340, 0xF3C0, 0xF240, 0xF2C0, 0xAA00, 0xAE00, 0xA200, 0xA600, 0xBA00, 0xBE00, 0xB200, 0xB600, 0x8A00, 0x8E00, 0x8200, 0x8600, 0x9A00, 0x9E00, 0x9200, 0x9600, @@ -81442,7 +83199,7 @@ static unsigned short g_ma_dr_wavAlawTable[256] = { 0x0560, 0x0520, 0x05E0, 0x05A0, 0x0460, 0x0420, 0x04E0, 0x04A0, 0x0760, 0x0720, 0x07E0, 0x07A0, 0x0660, 0x0620, 0x06E0, 0x06A0, 0x02B0, 0x0290, 0x02F0, 0x02D0, 0x0230, 0x0210, 0x0270, 0x0250, 0x03B0, 0x0390, 0x03F0, 0x03D0, 0x0330, 0x0310, 0x0370, 0x0350 }; -static unsigned short g_ma_dr_wavMulawTable[256] = { +static const unsigned short ma_dr_wav_gMulawTable[256] = { 0x8284, 0x8684, 0x8A84, 0x8E84, 0x9284, 0x9684, 0x9A84, 0x9E84, 0xA284, 0xA684, 0xAA84, 0xAE84, 0xB284, 0xB684, 0xBA84, 0xBE84, 0xC184, 0xC384, 0xC584, 0xC784, 0xC984, 0xCB84, 0xCD84, 0xCF84, 0xD184, 0xD384, 0xD584, 0xD784, 0xD984, 0xDB84, 0xDD84, 0xDF84, 0xE104, 0xE204, 0xE304, 0xE404, 0xE504, 0xE604, 0xE704, 0xE804, 0xE904, 0xEA04, 0xEB04, 0xEC04, 0xED04, 0xEE04, 0xEF04, 0xF004, @@ -81462,11 +83219,11 @@ static unsigned short g_ma_dr_wavMulawTable[256] = { }; static MA_INLINE ma_int16 ma_dr_wav__alaw_to_s16(ma_uint8 sampleIn) { - return (short)g_ma_dr_wavAlawTable[sampleIn]; + return (short)ma_dr_wav_gAlawTable[sampleIn]; } static MA_INLINE ma_int16 ma_dr_wav__mulaw_to_s16(ma_uint8 sampleIn) { - return (short)g_ma_dr_wavMulawTable[sampleIn]; + return (short)ma_dr_wav_gMulawTable[sampleIn]; } MA_PRIVATE void ma_dr_wav__pcm_to_s16(ma_int16* pOut, const ma_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample) { @@ -82625,7 +84382,7 @@ MA_PRIVATE ma_int32* ma_dr_wav__read_pcm_frames_and_close_s32(ma_dr_wav* pWav, u } return pSampleData; } -MA_API ma_int16* ma_dr_wav_open_and_read_pcm_frames_s16(ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_int16* ma_dr_wav_open_and_read_pcm_frames_s16(ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) { ma_dr_wav wav; if (channelsOut) { @@ -82637,12 +84394,12 @@ MA_API ma_int16* ma_dr_wav_open_and_read_pcm_frames_s16(ma_dr_wav_read_proc onRe if (totalFrameCountOut) { *totalFrameCountOut = 0; } - if (!ma_dr_wav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) { + if (!ma_dr_wav_init(&wav, onRead, onSeek, onTell, pUserData, pAllocationCallbacks)) { return NULL; } return ma_dr_wav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut); } -MA_API float* ma_dr_wav_open_and_read_pcm_frames_f32(ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API float* ma_dr_wav_open_and_read_pcm_frames_f32(ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) { ma_dr_wav wav; if (channelsOut) { @@ -82654,12 +84411,12 @@ MA_API float* ma_dr_wav_open_and_read_pcm_frames_f32(ma_dr_wav_read_proc onRead, if (totalFrameCountOut) { *totalFrameCountOut = 0; } - if (!ma_dr_wav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) { + if (!ma_dr_wav_init(&wav, onRead, onSeek, onTell, pUserData, pAllocationCallbacks)) { return NULL; } return ma_dr_wav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); } -MA_API ma_int32* ma_dr_wav_open_and_read_pcm_frames_s32(ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_int32* ma_dr_wav_open_and_read_pcm_frames_s32(ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) { ma_dr_wav wav; if (channelsOut) { @@ -82671,7 +84428,7 @@ MA_API ma_int32* ma_dr_wav_open_and_read_pcm_frames_s32(ma_dr_wav_read_proc onRe if (totalFrameCountOut) { *totalFrameCountOut = 0; } - if (!ma_dr_wav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) { + if (!ma_dr_wav_init(&wav, onRead, onSeek, onTell, pUserData, pAllocationCallbacks)) { return NULL; } return ma_dr_wav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); @@ -84106,23 +85863,23 @@ static ma_bool32 ma_dr_flac__seek_to_byte(ma_dr_flac_bs* bs, ma_uint64 offsetFro MA_DR_FLAC_ASSERT(offsetFromStart > 0); if (offsetFromStart > 0x7FFFFFFF) { ma_uint64 bytesRemaining = offsetFromStart; - if (!bs->onSeek(bs->pUserData, 0x7FFFFFFF, ma_dr_flac_seek_origin_start)) { + if (!bs->onSeek(bs->pUserData, 0x7FFFFFFF, MA_DR_FLAC_SEEK_SET)) { return MA_FALSE; } bytesRemaining -= 0x7FFFFFFF; while (bytesRemaining > 0x7FFFFFFF) { - if (!bs->onSeek(bs->pUserData, 0x7FFFFFFF, ma_dr_flac_seek_origin_current)) { + if (!bs->onSeek(bs->pUserData, 0x7FFFFFFF, MA_DR_FLAC_SEEK_CUR)) { return MA_FALSE; } bytesRemaining -= 0x7FFFFFFF; } if (bytesRemaining > 0) { - if (!bs->onSeek(bs->pUserData, (int)bytesRemaining, ma_dr_flac_seek_origin_current)) { + if (!bs->onSeek(bs->pUserData, (int)bytesRemaining, MA_DR_FLAC_SEEK_CUR)) { return MA_FALSE; } } } else { - if (!bs->onSeek(bs->pUserData, (int)offsetFromStart, ma_dr_flac_seek_origin_start)) { + if (!bs->onSeek(bs->pUserData, (int)offsetFromStart, MA_DR_FLAC_SEEK_SET)) { return MA_FALSE; } } @@ -86600,6 +88357,7 @@ typedef struct { ma_dr_flac_read_proc onRead; ma_dr_flac_seek_proc onSeek; + ma_dr_flac_tell_proc onTell; ma_dr_flac_meta_proc onMeta; ma_dr_flac_container container; void* pUserData; @@ -86728,11 +88486,12 @@ static void ma_dr_flac__free_from_callbacks(void* p, const ma_allocation_callbac pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData); } } -static ma_bool32 ma_dr_flac__read_and_decode_metadata(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_meta_proc onMeta, void* pUserData, void* pUserDataMD, ma_uint64* pFirstFramePos, ma_uint64* pSeektablePos, ma_uint32* pSeekpointCount, ma_allocation_callbacks* pAllocationCallbacks) +static ma_bool32 ma_dr_flac__read_and_decode_metadata(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, ma_dr_flac_meta_proc onMeta, void* pUserData, void* pUserDataMD, ma_uint64* pFirstFramePos, ma_uint64* pSeektablePos, ma_uint32* pSeekpointCount, ma_allocation_callbacks* pAllocationCallbacks) { ma_uint64 runningFilePos = 42; ma_uint64 seektablePos = 0; ma_uint32 seektableSize = 0; + (void)onTell; for (;;) { ma_dr_flac_metadata metadata; ma_uint8 isLastBlock = 0; @@ -86990,7 +88749,7 @@ static ma_bool32 ma_dr_flac__read_and_decode_metadata(ma_dr_flac_read_proc onRea { if (onMeta) { metadata.data.padding.unused = 0; - if (!onSeek(pUserData, blockSize, ma_dr_flac_seek_origin_current)) { + if (!onSeek(pUserData, blockSize, MA_DR_FLAC_SEEK_CUR)) { isLastBlock = MA_TRUE; } else { onMeta(pUserDataMD, &metadata); @@ -87000,7 +88759,7 @@ static ma_bool32 ma_dr_flac__read_and_decode_metadata(ma_dr_flac_read_proc onRea case MA_DR_FLAC_METADATA_BLOCK_TYPE_INVALID: { if (onMeta) { - if (!onSeek(pUserData, blockSize, ma_dr_flac_seek_origin_current)) { + if (!onSeek(pUserData, blockSize, MA_DR_FLAC_SEEK_CUR)) { isLastBlock = MA_TRUE; } } @@ -87024,7 +88783,7 @@ static ma_bool32 ma_dr_flac__read_and_decode_metadata(ma_dr_flac_read_proc onRea } break; } if (onMeta == NULL && blockSize > 0) { - if (!onSeek(pUserData, blockSize, ma_dr_flac_seek_origin_current)) { + if (!onSeek(pUserData, blockSize, MA_DR_FLAC_SEEK_CUR)) { isLastBlock = MA_TRUE; } } @@ -87288,6 +89047,7 @@ typedef struct { ma_dr_flac_read_proc onRead; ma_dr_flac_seek_proc onSeek; + ma_dr_flac_tell_proc onTell; void* pUserData; ma_uint64 currentBytePos; ma_uint64 firstBytePos; @@ -87306,29 +89066,29 @@ static size_t ma_dr_flac_oggbs__read_physical(ma_dr_flac_oggbs* oggbs, void* buf } static ma_bool32 ma_dr_flac_oggbs__seek_physical(ma_dr_flac_oggbs* oggbs, ma_uint64 offset, ma_dr_flac_seek_origin origin) { - if (origin == ma_dr_flac_seek_origin_start) { + if (origin == MA_DR_FLAC_SEEK_SET) { if (offset <= 0x7FFFFFFF) { - if (!oggbs->onSeek(oggbs->pUserData, (int)offset, ma_dr_flac_seek_origin_start)) { + if (!oggbs->onSeek(oggbs->pUserData, (int)offset, MA_DR_FLAC_SEEK_SET)) { return MA_FALSE; } oggbs->currentBytePos = offset; return MA_TRUE; } else { - if (!oggbs->onSeek(oggbs->pUserData, 0x7FFFFFFF, ma_dr_flac_seek_origin_start)) { + if (!oggbs->onSeek(oggbs->pUserData, 0x7FFFFFFF, MA_DR_FLAC_SEEK_SET)) { return MA_FALSE; } oggbs->currentBytePos = offset; - return ma_dr_flac_oggbs__seek_physical(oggbs, offset - 0x7FFFFFFF, ma_dr_flac_seek_origin_current); + return ma_dr_flac_oggbs__seek_physical(oggbs, offset - 0x7FFFFFFF, MA_DR_FLAC_SEEK_CUR); } } else { while (offset > 0x7FFFFFFF) { - if (!oggbs->onSeek(oggbs->pUserData, 0x7FFFFFFF, ma_dr_flac_seek_origin_current)) { + if (!oggbs->onSeek(oggbs->pUserData, 0x7FFFFFFF, MA_DR_FLAC_SEEK_CUR)) { return MA_FALSE; } oggbs->currentBytePos += 0x7FFFFFFF; offset -= 0x7FFFFFFF; } - if (!oggbs->onSeek(oggbs->pUserData, (int)offset, ma_dr_flac_seek_origin_current)) { + if (!oggbs->onSeek(oggbs->pUserData, (int)offset, MA_DR_FLAC_SEEK_CUR)) { return MA_FALSE; } oggbs->currentBytePos += offset; @@ -87354,7 +89114,7 @@ static ma_bool32 ma_dr_flac_oggbs__goto_next_page(ma_dr_flac_oggbs* oggbs, ma_dr continue; } if (header.serialNumber != oggbs->serialNumber) { - if (pageBodySize > 0 && !ma_dr_flac_oggbs__seek_physical(oggbs, pageBodySize, ma_dr_flac_seek_origin_current)) { + if (pageBodySize > 0 && !ma_dr_flac_oggbs__seek_physical(oggbs, pageBodySize, MA_DR_FLAC_SEEK_CUR)) { return MA_FALSE; } continue; @@ -87416,7 +89176,7 @@ static ma_bool32 ma_dr_flac_oggbs__seek_to_next_packet(ma_dr_flac_oggbs* oggbs) } bytesToEndOfPacketOrPage += segmentSize; } - ma_dr_flac_oggbs__seek_physical(oggbs, bytesToEndOfPacketOrPage, ma_dr_flac_seek_origin_current); + ma_dr_flac_oggbs__seek_physical(oggbs, bytesToEndOfPacketOrPage, MA_DR_FLAC_SEEK_CUR); oggbs->bytesRemainingInPage -= bytesToEndOfPacketOrPage; if (atEndOfPage) { if (!ma_dr_flac_oggbs__goto_next_page(oggbs)) { @@ -87469,36 +89229,44 @@ static ma_bool32 ma_dr_flac__on_seek_ogg(void* pUserData, int offset, ma_dr_flac int bytesSeeked = 0; MA_DR_FLAC_ASSERT(oggbs != NULL); MA_DR_FLAC_ASSERT(offset >= 0); - if (origin == ma_dr_flac_seek_origin_start) { - if (!ma_dr_flac_oggbs__seek_physical(oggbs, (int)oggbs->firstBytePos, ma_dr_flac_seek_origin_start)) { + if (origin == MA_DR_FLAC_SEEK_SET) { + if (!ma_dr_flac_oggbs__seek_physical(oggbs, (int)oggbs->firstBytePos, MA_DR_FLAC_SEEK_SET)) { return MA_FALSE; } if (!ma_dr_flac_oggbs__goto_next_page(oggbs, ma_dr_flac_ogg_fail_on_crc_mismatch)) { return MA_FALSE; } - return ma_dr_flac__on_seek_ogg(pUserData, offset, ma_dr_flac_seek_origin_current); - } - MA_DR_FLAC_ASSERT(origin == ma_dr_flac_seek_origin_current); - while (bytesSeeked < offset) { - int bytesRemainingToSeek = offset - bytesSeeked; - MA_DR_FLAC_ASSERT(bytesRemainingToSeek >= 0); - if (oggbs->bytesRemainingInPage >= (size_t)bytesRemainingToSeek) { - bytesSeeked += bytesRemainingToSeek; - (void)bytesSeeked; - oggbs->bytesRemainingInPage -= bytesRemainingToSeek; - break; - } - if (oggbs->bytesRemainingInPage > 0) { - bytesSeeked += (int)oggbs->bytesRemainingInPage; - oggbs->bytesRemainingInPage = 0; - } - MA_DR_FLAC_ASSERT(bytesRemainingToSeek > 0); - if (!ma_dr_flac_oggbs__goto_next_page(oggbs, ma_dr_flac_ogg_fail_on_crc_mismatch)) { - return MA_FALSE; + return ma_dr_flac__on_seek_ogg(pUserData, offset, MA_DR_FLAC_SEEK_CUR); + } else if (origin == MA_DR_FLAC_SEEK_CUR) { + while (bytesSeeked < offset) { + int bytesRemainingToSeek = offset - bytesSeeked; + MA_DR_FLAC_ASSERT(bytesRemainingToSeek >= 0); + if (oggbs->bytesRemainingInPage >= (size_t)bytesRemainingToSeek) { + bytesSeeked += bytesRemainingToSeek; + (void)bytesSeeked; + oggbs->bytesRemainingInPage -= bytesRemainingToSeek; + break; + } + if (oggbs->bytesRemainingInPage > 0) { + bytesSeeked += (int)oggbs->bytesRemainingInPage; + oggbs->bytesRemainingInPage = 0; + } + MA_DR_FLAC_ASSERT(bytesRemainingToSeek > 0); + if (!ma_dr_flac_oggbs__goto_next_page(oggbs, ma_dr_flac_ogg_fail_on_crc_mismatch)) { + return MA_FALSE; + } } + } else if (origin == MA_DR_FLAC_SEEK_END) { + return MA_FALSE; } return MA_TRUE; } +static ma_bool32 ma_dr_flac__on_tell_ogg(void* pUserData, ma_int64* pCursor) +{ + (void)pUserData; + (void)pCursor; + return MA_FALSE; +} static ma_bool32 ma_dr_flac_ogg__seek_to_pcm_frame(ma_dr_flac* pFlac, ma_uint64 pcmFrameIndex) { ma_dr_flac_oggbs* oggbs = (ma_dr_flac_oggbs*)pFlac->_oggbs; @@ -87515,7 +89283,7 @@ static ma_bool32 ma_dr_flac_ogg__seek_to_pcm_frame(ma_dr_flac* pFlac, ma_uint64 runningGranulePosition = 0; for (;;) { if (!ma_dr_flac_oggbs__goto_next_page(oggbs, ma_dr_flac_ogg_recover_on_crc_mismatch)) { - ma_dr_flac_oggbs__seek_physical(oggbs, originalBytePos, ma_dr_flac_seek_origin_start); + ma_dr_flac_oggbs__seek_physical(oggbs, originalBytePos, MA_DR_FLAC_SEEK_SET); return MA_FALSE; } runningFrameBytePos = oggbs->currentBytePos - ma_dr_flac_ogg__get_page_header_size(&oggbs->currentPageHeader) - oggbs->pageDataSize; @@ -87534,7 +89302,7 @@ static ma_bool32 ma_dr_flac_ogg__seek_to_pcm_frame(ma_dr_flac* pFlac, ma_uint64 } } } - if (!ma_dr_flac_oggbs__seek_physical(oggbs, runningFrameBytePos, ma_dr_flac_seek_origin_start)) { + if (!ma_dr_flac_oggbs__seek_physical(oggbs, runningFrameBytePos, MA_DR_FLAC_SEEK_SET)) { return MA_FALSE; } if (!ma_dr_flac_oggbs__goto_next_page(oggbs, ma_dr_flac_ogg_recover_on_crc_mismatch)) { @@ -87629,7 +89397,7 @@ static ma_bool32 ma_dr_flac__init_private__ogg(ma_dr_flac_init_info* pInit, ma_d if (mappingVersion[0] != 1) { return MA_FALSE; } - if (!onSeek(pUserData, 2, ma_dr_flac_seek_origin_current)) { + if (!onSeek(pUserData, 2, MA_DR_FLAC_SEEK_CUR)) { return MA_FALSE; } if (onRead(pUserData, sig, 4) != 4) { @@ -87674,17 +89442,17 @@ static ma_bool32 ma_dr_flac__init_private__ogg(ma_dr_flac_init_info* pInit, ma_d return MA_FALSE; } } else { - if (!onSeek(pUserData, bytesRemainingInPage, ma_dr_flac_seek_origin_current)) { + if (!onSeek(pUserData, bytesRemainingInPage, MA_DR_FLAC_SEEK_CUR)) { return MA_FALSE; } } } else { - if (!onSeek(pUserData, bytesRemainingInPage, ma_dr_flac_seek_origin_current)) { + if (!onSeek(pUserData, bytesRemainingInPage, MA_DR_FLAC_SEEK_CUR)) { return MA_FALSE; } } } else { - if (!onSeek(pUserData, pageBodySize, ma_dr_flac_seek_origin_current)) { + if (!onSeek(pUserData, pageBodySize, MA_DR_FLAC_SEEK_CUR)) { return MA_FALSE; } } @@ -87698,7 +89466,7 @@ static ma_bool32 ma_dr_flac__init_private__ogg(ma_dr_flac_init_info* pInit, ma_d return MA_TRUE; } #endif -static ma_bool32 ma_dr_flac__init_private(ma_dr_flac_init_info* pInit, ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_meta_proc onMeta, ma_dr_flac_container container, void* pUserData, void* pUserDataMD) +static ma_bool32 ma_dr_flac__init_private(ma_dr_flac_init_info* pInit, ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, ma_dr_flac_meta_proc onMeta, ma_dr_flac_container container, void* pUserData, void* pUserDataMD) { ma_bool32 relaxed; ma_uint8 id[4]; @@ -87708,12 +89476,14 @@ static ma_bool32 ma_dr_flac__init_private(ma_dr_flac_init_info* pInit, ma_dr_fla MA_DR_FLAC_ZERO_MEMORY(pInit, sizeof(*pInit)); pInit->onRead = onRead; pInit->onSeek = onSeek; + pInit->onTell = onTell; pInit->onMeta = onMeta; pInit->container = container; pInit->pUserData = pUserData; pInit->pUserDataMD = pUserDataMD; pInit->bs.onRead = onRead; pInit->bs.onSeek = onSeek; + pInit->bs.onTell = onTell; pInit->bs.pUserData = pUserData; ma_dr_flac__reset_cache(&pInit->bs); relaxed = container != ma_dr_flac_container_unknown; @@ -87736,7 +89506,7 @@ static ma_bool32 ma_dr_flac__init_private(ma_dr_flac_init_info* pInit, ma_dr_fla if (flags & 0x10) { headerSize += 10; } - if (!onSeek(pUserData, headerSize, ma_dr_flac_seek_origin_current)) { + if (!onSeek(pUserData, headerSize, MA_DR_FLAC_SEEK_CUR)) { return MA_FALSE; } pInit->runningFilePos += headerSize; @@ -87779,7 +89549,7 @@ static void ma_dr_flac__init_from_info(ma_dr_flac* pFlac, const ma_dr_flac_init_ pFlac->totalPCMFrameCount = pInit->totalPCMFrameCount; pFlac->container = pInit->container; } -static ma_dr_flac* ma_dr_flac_open_with_metadata_private(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_meta_proc onMeta, ma_dr_flac_container container, void* pUserData, void* pUserDataMD, const ma_allocation_callbacks* pAllocationCallbacks) +static ma_dr_flac* ma_dr_flac_open_with_metadata_private(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, ma_dr_flac_meta_proc onMeta, ma_dr_flac_container container, void* pUserData, void* pUserDataMD, const ma_allocation_callbacks* pAllocationCallbacks) { ma_dr_flac_init_info init; ma_uint32 allocationSize; @@ -87794,7 +89564,7 @@ static ma_dr_flac* ma_dr_flac_open_with_metadata_private(ma_dr_flac_read_proc on ma_allocation_callbacks allocationCallbacks; ma_dr_flac* pFlac; ma_dr_flac__init_cpu_caps(); - if (!ma_dr_flac__init_private(&init, onRead, onSeek, onMeta, container, pUserData, pUserDataMD)) { + if (!ma_dr_flac__init_private(&init, onRead, onSeek, onTell, onMeta, container, pUserData, pUserDataMD)) { return NULL; } if (pAllocationCallbacks != NULL) { @@ -87827,6 +89597,7 @@ static ma_dr_flac* ma_dr_flac_open_with_metadata_private(ma_dr_flac_read_proc on MA_DR_FLAC_ZERO_MEMORY(pOggbs, sizeof(*pOggbs)); pOggbs->onRead = onRead; pOggbs->onSeek = onSeek; + pOggbs->onTell = onTell; pOggbs->pUserData = pUserData; pOggbs->currentBytePos = init.oggFirstBytePos; pOggbs->firstBytePos = init.oggFirstBytePos; @@ -87841,15 +89612,17 @@ static ma_dr_flac* ma_dr_flac_open_with_metadata_private(ma_dr_flac_read_proc on if (init.hasMetadataBlocks) { ma_dr_flac_read_proc onReadOverride = onRead; ma_dr_flac_seek_proc onSeekOverride = onSeek; + ma_dr_flac_tell_proc onTellOverride = onTell; void* pUserDataOverride = pUserData; #ifndef MA_DR_FLAC_NO_OGG if (init.container == ma_dr_flac_container_ogg) { onReadOverride = ma_dr_flac__on_read_ogg; onSeekOverride = ma_dr_flac__on_seek_ogg; + onTellOverride = ma_dr_flac__on_tell_ogg; pUserDataOverride = (void*)pOggbs; } #endif - if (!ma_dr_flac__read_and_decode_metadata(onReadOverride, onSeekOverride, onMeta, pUserDataOverride, pUserDataMD, &firstFramePos, &seektablePos, &seekpointCount, &allocationCallbacks)) { + if (!ma_dr_flac__read_and_decode_metadata(onReadOverride, onSeekOverride, onTellOverride, onMeta, pUserDataOverride, pUserDataMD, &firstFramePos, &seektablePos, &seekpointCount, &allocationCallbacks)) { #ifndef MA_DR_FLAC_NO_OGG ma_dr_flac__free_from_callbacks(pOggbs, &allocationCallbacks); #endif @@ -87875,6 +89648,7 @@ static ma_dr_flac* ma_dr_flac_open_with_metadata_private(ma_dr_flac_read_proc on pOggbs = NULL; pFlac->bs.onRead = ma_dr_flac__on_read_ogg; pFlac->bs.onSeek = ma_dr_flac__on_seek_ogg; + pFlac->bs.onTell = ma_dr_flac__on_tell_ogg; pFlac->bs.pUserData = (void*)pInternalOggbs; pFlac->_oggbs = (void*)pInternalOggbs; } @@ -87894,7 +89668,7 @@ static ma_dr_flac* ma_dr_flac_open_with_metadata_private(ma_dr_flac_read_proc on pFlac->pSeekpoints = (ma_dr_flac_seekpoint*)((ma_uint8*)pFlac->pDecodedSamples + decodedSamplesAllocationSize); MA_DR_FLAC_ASSERT(pFlac->bs.onSeek != NULL); MA_DR_FLAC_ASSERT(pFlac->bs.onRead != NULL); - if (pFlac->bs.onSeek(pFlac->bs.pUserData, (int)seektablePos, ma_dr_flac_seek_origin_start)) { + if (pFlac->bs.onSeek(pFlac->bs.pUserData, (int)seektablePos, MA_DR_FLAC_SEEK_SET)) { ma_uint32 iSeekpoint; for (iSeekpoint = 0; iSeekpoint < seekpointCount; iSeekpoint += 1) { if (pFlac->bs.onRead(pFlac->bs.pUserData, pFlac->pSeekpoints + iSeekpoint, MA_DR_FLAC_SEEKPOINT_SIZE_IN_BYTES) == MA_DR_FLAC_SEEKPOINT_SIZE_IN_BYTES) { @@ -87907,7 +89681,7 @@ static ma_dr_flac* ma_dr_flac_open_with_metadata_private(ma_dr_flac_read_proc on break; } } - if (!pFlac->bs.onSeek(pFlac->bs.pUserData, (int)pFlac->firstFLACFramePosInBytes, ma_dr_flac_seek_origin_start)) { + if (!pFlac->bs.onSeek(pFlac->bs.pUserData, (int)pFlac->firstFLACFramePosInBytes, MA_DR_FLAC_SEEK_SET)) { ma_dr_flac__free_from_callbacks(pFlac, &allocationCallbacks); return NULL; } @@ -87950,8 +89724,31 @@ static size_t ma_dr_flac__on_read_stdio(void* pUserData, void* bufferOut, size_t } static ma_bool32 ma_dr_flac__on_seek_stdio(void* pUserData, int offset, ma_dr_flac_seek_origin origin) { - MA_DR_FLAC_ASSERT(offset >= 0); - return fseek((FILE*)pUserData, offset, (origin == ma_dr_flac_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0; + int whence = SEEK_SET; + if (origin == MA_DR_FLAC_SEEK_CUR) { + whence = SEEK_CUR; + } else if (origin == MA_DR_FLAC_SEEK_END) { + whence = SEEK_END; + } + return fseek((FILE*)pUserData, offset, whence) == 0; +} +static ma_bool32 ma_dr_flac__on_tell_stdio(void* pUserData, ma_int64* pCursor) +{ + FILE* pFileStdio = (FILE*)pUserData; + ma_int64 result; + MA_DR_FLAC_ASSERT(pFileStdio != NULL); + MA_DR_FLAC_ASSERT(pCursor != NULL); +#if defined(_WIN32) && !defined(NXDK) + #if defined(_MSC_VER) && _MSC_VER > 1200 + result = _ftelli64(pFileStdio); + #else + result = ftell(pFileStdio); + #endif +#else + result = ftell(pFileStdio); +#endif + *pCursor = result; + return MA_TRUE; } MA_API ma_dr_flac* ma_dr_flac_open_file(const char* pFileName, const ma_allocation_callbacks* pAllocationCallbacks) { @@ -87960,7 +89757,7 @@ MA_API ma_dr_flac* ma_dr_flac_open_file(const char* pFileName, const ma_allocati if (ma_fopen(&pFile, pFileName, "rb") != MA_SUCCESS) { return NULL; } - pFlac = ma_dr_flac_open(ma_dr_flac__on_read_stdio, ma_dr_flac__on_seek_stdio, (void*)pFile, pAllocationCallbacks); + pFlac = ma_dr_flac_open(ma_dr_flac__on_read_stdio, ma_dr_flac__on_seek_stdio, ma_dr_flac__on_tell_stdio, (void*)pFile, pAllocationCallbacks); if (pFlac == NULL) { fclose(pFile); return NULL; @@ -87975,7 +89772,7 @@ MA_API ma_dr_flac* ma_dr_flac_open_file_w(const wchar_t* pFileName, const ma_all if (ma_wfopen(&pFile, pFileName, L"rb", pAllocationCallbacks) != MA_SUCCESS) { return NULL; } - pFlac = ma_dr_flac_open(ma_dr_flac__on_read_stdio, ma_dr_flac__on_seek_stdio, (void*)pFile, pAllocationCallbacks); + pFlac = ma_dr_flac_open(ma_dr_flac__on_read_stdio, ma_dr_flac__on_seek_stdio, ma_dr_flac__on_tell_stdio, (void*)pFile, pAllocationCallbacks); if (pFlac == NULL) { fclose(pFile); return NULL; @@ -87990,7 +89787,7 @@ MA_API ma_dr_flac* ma_dr_flac_open_file_with_metadata(const char* pFileName, ma_ if (ma_fopen(&pFile, pFileName, "rb") != MA_SUCCESS) { return NULL; } - pFlac = ma_dr_flac_open_with_metadata_private(ma_dr_flac__on_read_stdio, ma_dr_flac__on_seek_stdio, onMeta, ma_dr_flac_container_unknown, (void*)pFile, pUserData, pAllocationCallbacks); + pFlac = ma_dr_flac_open_with_metadata_private(ma_dr_flac__on_read_stdio, ma_dr_flac__on_seek_stdio, ma_dr_flac__on_tell_stdio, onMeta, ma_dr_flac_container_unknown, (void*)pFile, pUserData, pAllocationCallbacks); if (pFlac == NULL) { fclose(pFile); return pFlac; @@ -88005,7 +89802,7 @@ MA_API ma_dr_flac* ma_dr_flac_open_file_with_metadata_w(const wchar_t* pFileName if (ma_wfopen(&pFile, pFileName, L"rb", pAllocationCallbacks) != MA_SUCCESS) { return NULL; } - pFlac = ma_dr_flac_open_with_metadata_private(ma_dr_flac__on_read_stdio, ma_dr_flac__on_seek_stdio, onMeta, ma_dr_flac_container_unknown, (void*)pFile, pUserData, pAllocationCallbacks); + pFlac = ma_dr_flac_open_with_metadata_private(ma_dr_flac__on_read_stdio, ma_dr_flac__on_seek_stdio, ma_dr_flac__on_tell_stdio, onMeta, ma_dr_flac_container_unknown, (void*)pFile, pUserData, pAllocationCallbacks); if (pFlac == NULL) { fclose(pFile); return pFlac; @@ -88033,24 +89830,35 @@ static size_t ma_dr_flac__on_read_memory(void* pUserData, void* bufferOut, size_ static ma_bool32 ma_dr_flac__on_seek_memory(void* pUserData, int offset, ma_dr_flac_seek_origin origin) { ma_dr_flac__memory_stream* memoryStream = (ma_dr_flac__memory_stream*)pUserData; + ma_int64 newCursor; MA_DR_FLAC_ASSERT(memoryStream != NULL); - MA_DR_FLAC_ASSERT(offset >= 0); - if (offset > (ma_int64)memoryStream->dataSize) { + newCursor = memoryStream->currentReadPos; + if (origin == MA_DR_FLAC_SEEK_SET) { + newCursor = 0; + } else if (origin == MA_DR_FLAC_SEEK_CUR) { + newCursor = (ma_int64)memoryStream->currentReadPos; + } else if (origin == MA_DR_FLAC_SEEK_END) { + newCursor = (ma_int64)memoryStream->dataSize; + } else { + MA_DR_FLAC_ASSERT(!"Invalid seek origin"); return MA_FALSE; } - if (origin == ma_dr_flac_seek_origin_current) { - if (memoryStream->currentReadPos + offset <= memoryStream->dataSize) { - memoryStream->currentReadPos += offset; - } else { - return MA_FALSE; - } - } else { - if ((ma_uint32)offset <= memoryStream->dataSize) { - memoryStream->currentReadPos = offset; - } else { - return MA_FALSE; - } + newCursor += offset; + if (newCursor < 0) { + return MA_FALSE; } + if ((size_t)newCursor > memoryStream->dataSize) { + return MA_FALSE; + } + memoryStream->currentReadPos = (size_t)newCursor; + return MA_TRUE; +} +static ma_bool32 ma_dr_flac__on_tell_memory(void* pUserData, ma_int64* pCursor) +{ + ma_dr_flac__memory_stream* memoryStream = (ma_dr_flac__memory_stream*)pUserData; + MA_DR_FLAC_ASSERT(memoryStream != NULL); + MA_DR_FLAC_ASSERT(pCursor != NULL); + *pCursor = (ma_int64)memoryStream->currentReadPos; return MA_TRUE; } MA_API ma_dr_flac* ma_dr_flac_open_memory(const void* pData, size_t dataSize, const ma_allocation_callbacks* pAllocationCallbacks) @@ -88060,7 +89868,7 @@ MA_API ma_dr_flac* ma_dr_flac_open_memory(const void* pData, size_t dataSize, co memoryStream.data = (const ma_uint8*)pData; memoryStream.dataSize = dataSize; memoryStream.currentReadPos = 0; - pFlac = ma_dr_flac_open(ma_dr_flac__on_read_memory, ma_dr_flac__on_seek_memory, &memoryStream, pAllocationCallbacks); + pFlac = ma_dr_flac_open(ma_dr_flac__on_read_memory, ma_dr_flac__on_seek_memory, ma_dr_flac__on_tell_memory, &memoryStream, pAllocationCallbacks); if (pFlac == NULL) { return NULL; } @@ -88085,7 +89893,7 @@ MA_API ma_dr_flac* ma_dr_flac_open_memory_with_metadata(const void* pData, size_ memoryStream.data = (const ma_uint8*)pData; memoryStream.dataSize = dataSize; memoryStream.currentReadPos = 0; - pFlac = ma_dr_flac_open_with_metadata_private(ma_dr_flac__on_read_memory, ma_dr_flac__on_seek_memory, onMeta, ma_dr_flac_container_unknown, &memoryStream, pUserData, pAllocationCallbacks); + pFlac = ma_dr_flac_open_with_metadata_private(ma_dr_flac__on_read_memory, ma_dr_flac__on_seek_memory, ma_dr_flac__on_tell_memory, onMeta, ma_dr_flac_container_unknown, &memoryStream, pUserData, pAllocationCallbacks); if (pFlac == NULL) { return NULL; } @@ -88103,21 +89911,21 @@ MA_API ma_dr_flac* ma_dr_flac_open_memory_with_metadata(const void* pData, size_ } return pFlac; } -MA_API ma_dr_flac* ma_dr_flac_open(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_dr_flac* ma_dr_flac_open(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) { - return ma_dr_flac_open_with_metadata_private(onRead, onSeek, NULL, ma_dr_flac_container_unknown, pUserData, pUserData, pAllocationCallbacks); + return ma_dr_flac_open_with_metadata_private(onRead, onSeek, onTell, NULL, ma_dr_flac_container_unknown, pUserData, pUserData, pAllocationCallbacks); } -MA_API ma_dr_flac* ma_dr_flac_open_relaxed(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_container container, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_dr_flac* ma_dr_flac_open_relaxed(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, ma_dr_flac_container container, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) { - return ma_dr_flac_open_with_metadata_private(onRead, onSeek, NULL, container, pUserData, pUserData, pAllocationCallbacks); + return ma_dr_flac_open_with_metadata_private(onRead, onSeek, onTell, NULL, container, pUserData, pUserData, pAllocationCallbacks); } -MA_API ma_dr_flac* ma_dr_flac_open_with_metadata(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_meta_proc onMeta, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_dr_flac* ma_dr_flac_open_with_metadata(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, ma_dr_flac_meta_proc onMeta, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) { - return ma_dr_flac_open_with_metadata_private(onRead, onSeek, onMeta, ma_dr_flac_container_unknown, pUserData, pUserData, pAllocationCallbacks); + return ma_dr_flac_open_with_metadata_private(onRead, onSeek, onTell, onMeta, ma_dr_flac_container_unknown, pUserData, pUserData, pAllocationCallbacks); } -MA_API ma_dr_flac* ma_dr_flac_open_with_metadata_relaxed(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_meta_proc onMeta, ma_dr_flac_container container, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_dr_flac* ma_dr_flac_open_with_metadata_relaxed(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, ma_dr_flac_meta_proc onMeta, ma_dr_flac_container container, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) { - return ma_dr_flac_open_with_metadata_private(onRead, onSeek, onMeta, container, pUserData, pUserData, pAllocationCallbacks); + return ma_dr_flac_open_with_metadata_private(onRead, onSeek, onTell, onMeta, container, pUserData, pUserData, pAllocationCallbacks); } MA_API void ma_dr_flac_close(ma_dr_flac* pFlac) { @@ -90410,7 +92218,7 @@ on_error: MA_DR_FLAC_DEFINE_FULL_READ_AND_CLOSE(s32, ma_int32) MA_DR_FLAC_DEFINE_FULL_READ_AND_CLOSE(s16, ma_int16) MA_DR_FLAC_DEFINE_FULL_READ_AND_CLOSE(f32, float) -MA_API ma_int32* ma_dr_flac_open_and_read_pcm_frames_s32(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalPCMFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_int32* ma_dr_flac_open_and_read_pcm_frames_s32(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalPCMFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) { ma_dr_flac* pFlac; if (channelsOut) { @@ -90422,13 +92230,13 @@ MA_API ma_int32* ma_dr_flac_open_and_read_pcm_frames_s32(ma_dr_flac_read_proc on if (totalPCMFrameCountOut) { *totalPCMFrameCountOut = 0; } - pFlac = ma_dr_flac_open(onRead, onSeek, pUserData, pAllocationCallbacks); + pFlac = ma_dr_flac_open(onRead, onSeek, onTell, pUserData, pAllocationCallbacks); if (pFlac == NULL) { return NULL; } return ma_dr_flac__full_read_and_close_s32(pFlac, channelsOut, sampleRateOut, totalPCMFrameCountOut); } -MA_API ma_int16* ma_dr_flac_open_and_read_pcm_frames_s16(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalPCMFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_int16* ma_dr_flac_open_and_read_pcm_frames_s16(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalPCMFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) { ma_dr_flac* pFlac; if (channelsOut) { @@ -90440,13 +92248,13 @@ MA_API ma_int16* ma_dr_flac_open_and_read_pcm_frames_s16(ma_dr_flac_read_proc on if (totalPCMFrameCountOut) { *totalPCMFrameCountOut = 0; } - pFlac = ma_dr_flac_open(onRead, onSeek, pUserData, pAllocationCallbacks); + pFlac = ma_dr_flac_open(onRead, onSeek, onTell, pUserData, pAllocationCallbacks); if (pFlac == NULL) { return NULL; } return ma_dr_flac__full_read_and_close_s16(pFlac, channelsOut, sampleRateOut, totalPCMFrameCountOut); } -MA_API float* ma_dr_flac_open_and_read_pcm_frames_f32(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalPCMFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API float* ma_dr_flac_open_and_read_pcm_frames_f32(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalPCMFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) { ma_dr_flac* pFlac; if (channelsOut) { @@ -90458,7 +92266,7 @@ MA_API float* ma_dr_flac_open_and_read_pcm_frames_f32(ma_dr_flac_read_proc onRea if (totalPCMFrameCountOut) { *totalPCMFrameCountOut = 0; } - pFlac = ma_dr_flac_open(onRead, onSeek, pUserData, pAllocationCallbacks); + pFlac = ma_dr_flac_open(onRead, onSeek, onTell, pUserData, pAllocationCallbacks); if (pFlac == NULL) { return NULL; } @@ -91262,6 +93070,10 @@ static float ma_dr_mp3_L3_ldexp_q2(float y, int exp_q2) } while ((exp_q2 -= e) > 0); return y; } +#if (defined(__GNUC__) && (__GNUC__ >= 14)) && !defined(__clang__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wstringop-overflow" +#endif static void ma_dr_mp3_L3_decode_scalefactors(const ma_uint8 *hdr, ma_uint8 *ist_pos, ma_dr_mp3_bs *bs, const ma_dr_mp3_L3_gr_info *gr, float *scf, int ch) { static const ma_uint8 g_scf_partitions[3][28] = { @@ -91320,7 +93132,10 @@ static void ma_dr_mp3_L3_decode_scalefactors(const ma_uint8 *hdr, ma_uint8 *ist_ scf[i] = ma_dr_mp3_L3_ldexp_q2(gain, iscf[i] << scf_shift); } } -static const float g_ma_dr_mp3_pow43[129 + 16] = { +#if (defined(__GNUC__) && (__GNUC__ >= 14)) && !defined(__clang__) + #pragma GCC diagnostic pop +#endif +static const float ma_dr_mp3_g_pow43[129 + 16] = { 0,-1,-2.519842f,-4.326749f,-6.349604f,-8.549880f,-10.902724f,-13.390518f,-16.000000f,-18.720754f,-21.544347f,-24.463781f,-27.473142f,-30.567351f,-33.741992f,-36.993181f, 0,1,2.519842f,4.326749f,6.349604f,8.549880f,10.902724f,13.390518f,16.000000f,18.720754f,21.544347f,24.463781f,27.473142f,30.567351f,33.741992f,36.993181f,40.317474f,43.711787f,47.173345f,50.699631f,54.288352f,57.937408f,61.644865f,65.408941f,69.227979f,73.100443f,77.024898f,81.000000f,85.024491f,89.097188f,93.216975f,97.382800f,101.593667f,105.848633f,110.146801f,114.487321f,118.869381f,123.292209f,127.755065f,132.257246f,136.798076f,141.376907f,145.993119f,150.646117f,155.335327f,160.060199f,164.820202f,169.614826f,174.443577f,179.305980f,184.201575f,189.129918f,194.090580f,199.083145f,204.107210f,209.162385f,214.248292f,219.364564f,224.510845f,229.686789f,234.892058f,240.126328f,245.389280f,250.680604f,256.000000f,261.347174f,266.721841f,272.123723f,277.552547f,283.008049f,288.489971f,293.998060f,299.532071f,305.091761f,310.676898f,316.287249f,321.922592f,327.582707f,333.267377f,338.976394f,344.709550f,350.466646f,356.247482f,362.051866f,367.879608f,373.730522f,379.604427f,385.501143f,391.420496f,397.362314f,403.326427f,409.312672f,415.320884f,421.350905f,427.402579f,433.475750f,439.570269f,445.685987f,451.822757f,457.980436f,464.158883f,470.357960f,476.577530f,482.817459f,489.077615f,495.357868f,501.658090f,507.978156f,514.317941f,520.677324f,527.056184f,533.454404f,539.871867f,546.308458f,552.764065f,559.238575f,565.731879f,572.243870f,578.774440f,585.323483f,591.890898f,598.476581f,605.080431f,611.702349f,618.342238f,625.000000f,631.675540f,638.368763f,645.079578f }; @@ -91330,7 +93145,7 @@ static float ma_dr_mp3_L3_pow_43(int x) int sign, mult = 256; if (x < 129) { - return g_ma_dr_mp3_pow43[16 + x]; + return ma_dr_mp3_g_pow43[16 + x]; } if (x < 1024) { @@ -91339,7 +93154,7 @@ static float ma_dr_mp3_L3_pow_43(int x) } sign = 2*x & 64; frac = (float)((x & 63) - sign) / ((x & ~63) + sign); - return g_ma_dr_mp3_pow43[16 + ((x + sign) >> 6)]*(1.f + frac*((4.f/3) + frac*(2.f/9)))*mult; + return ma_dr_mp3_g_pow43[16 + ((x + sign) >> 6)]*(1.f + frac*((4.f/3) + frac*(2.f/9)))*mult; } static void ma_dr_mp3_L3_huffman(float *dst, ma_dr_mp3_bs *bs, const ma_dr_mp3_L3_gr_info *gr_info, const float *scf, int layer3gr_limit) { @@ -91409,7 +93224,7 @@ static void ma_dr_mp3_L3_huffman(float *dst, ma_dr_mp3_bs *bs, const ma_dr_mp3_L *dst = one*ma_dr_mp3_L3_pow_43(lsb)*((ma_int32)bs_cache < 0 ? -1: 1); } else { - *dst = g_ma_dr_mp3_pow43[16 + lsb - 16*(bs_cache >> 31)]*one; + *dst = ma_dr_mp3_g_pow43[16 + lsb - 16*(bs_cache >> 31)]*one; } MA_DR_MP3_FLUSH_BITS(lsb ? 1 : 0); } @@ -91437,7 +93252,7 @@ static void ma_dr_mp3_L3_huffman(float *dst, ma_dr_mp3_bs *bs, const ma_dr_mp3_L for (j = 0; j < 2; j++, dst++, leaf >>= 4) { int lsb = leaf & 0x0F; - *dst = g_ma_dr_mp3_pow43[16 + lsb - 16*(bs_cache >> 31)]*one; + *dst = ma_dr_mp3_g_pow43[16 + lsb - 16*(bs_cache >> 31)]*one; MA_DR_MP3_FLUSH_BITS(lsb ? 1 : 0); } MA_DR_MP3_CHECK_BITS; @@ -92268,7 +94083,7 @@ MA_API int ma_dr_mp3dec_decode_frame(ma_dr_mp3dec *dec, const ma_uint8 *mp3, int MA_DR_MP3_COPY_MEMORY(dec->header, hdr, MA_DR_MP3_HDR_SIZE); info->frame_bytes = i + frame_size; info->channels = MA_DR_MP3_HDR_IS_MONO(hdr) ? 1 : 2; - info->hz = ma_dr_mp3_hdr_sample_rate_hz(hdr); + info->sample_rate = ma_dr_mp3_hdr_sample_rate_hz(hdr); info->layer = 4 - MA_DR_MP3_HDR_GET_LAYER(hdr); info->bitrate_kbps = ma_dr_mp3_hdr_bitrate_kbps(hdr); ma_dr_mp3_bs_init(bs_frame, hdr + MA_DR_MP3_HDR_SIZE, frame_size - MA_DR_MP3_HDR_SIZE); @@ -92491,19 +94306,41 @@ static ma_allocation_callbacks ma_dr_mp3_copy_allocation_callbacks_or_defaults(c } static size_t ma_dr_mp3__on_read(ma_dr_mp3* pMP3, void* pBufferOut, size_t bytesToRead) { - size_t bytesRead = pMP3->onRead(pMP3->pUserData, pBufferOut, bytesToRead); + size_t bytesRead; + MA_DR_MP3_ASSERT(pMP3 != NULL); + MA_DR_MP3_ASSERT(pMP3->onRead != NULL); + if (bytesToRead == 0) { + return 0; + } + bytesRead = pMP3->onRead(pMP3->pUserData, pBufferOut, bytesToRead); pMP3->streamCursor += bytesRead; return bytesRead; } +static size_t ma_dr_mp3__on_read_clamped(ma_dr_mp3* pMP3, void* pBufferOut, size_t bytesToRead) +{ + MA_DR_MP3_ASSERT(pMP3 != NULL); + MA_DR_MP3_ASSERT(pMP3->onRead != NULL); + if (pMP3->streamLength == MA_UINT64_MAX) { + return ma_dr_mp3__on_read(pMP3, pBufferOut, bytesToRead); + } else { + ma_uint64 bytesRemaining; + bytesRemaining = (pMP3->streamLength - pMP3->streamCursor); + if (bytesToRead > bytesRemaining) { + bytesToRead = (size_t)bytesRemaining; + } + return ma_dr_mp3__on_read(pMP3, pBufferOut, bytesToRead); + } +} static ma_bool32 ma_dr_mp3__on_seek(ma_dr_mp3* pMP3, int offset, ma_dr_mp3_seek_origin origin) { MA_DR_MP3_ASSERT(offset >= 0); + MA_DR_MP3_ASSERT(origin == MA_DR_MP3_SEEK_SET || origin == MA_DR_MP3_SEEK_CUR); if (!pMP3->onSeek(pMP3->pUserData, offset, origin)) { return MA_FALSE; } - if (origin == ma_dr_mp3_seek_origin_start) { + if (origin == MA_DR_MP3_SEEK_SET) { pMP3->streamCursor = (ma_uint64)offset; - } else { + } else{ pMP3->streamCursor += offset; } return MA_TRUE; @@ -92513,18 +94350,18 @@ static ma_bool32 ma_dr_mp3__on_seek_64(ma_dr_mp3* pMP3, ma_uint64 offset, ma_dr_ if (offset <= 0x7FFFFFFF) { return ma_dr_mp3__on_seek(pMP3, (int)offset, origin); } - if (!ma_dr_mp3__on_seek(pMP3, 0x7FFFFFFF, ma_dr_mp3_seek_origin_start)) { + if (!ma_dr_mp3__on_seek(pMP3, 0x7FFFFFFF, MA_DR_MP3_SEEK_SET)) { return MA_FALSE; } offset -= 0x7FFFFFFF; while (offset > 0) { if (offset <= 0x7FFFFFFF) { - if (!ma_dr_mp3__on_seek(pMP3, (int)offset, ma_dr_mp3_seek_origin_current)) { + if (!ma_dr_mp3__on_seek(pMP3, (int)offset, MA_DR_MP3_SEEK_CUR)) { return MA_FALSE; } offset = 0; } else { - if (!ma_dr_mp3__on_seek(pMP3, 0x7FFFFFFF, ma_dr_mp3_seek_origin_current)) { + if (!ma_dr_mp3__on_seek(pMP3, 0x7FFFFFFF, MA_DR_MP3_SEEK_CUR)) { return MA_FALSE; } offset -= 0x7FFFFFFF; @@ -92532,7 +94369,18 @@ static ma_bool32 ma_dr_mp3__on_seek_64(ma_dr_mp3* pMP3, ma_uint64 offset, ma_dr_ } return MA_TRUE; } -static ma_uint32 ma_dr_mp3_decode_next_frame_ex__callbacks(ma_dr_mp3* pMP3, ma_dr_mp3d_sample_t* pPCMFrames) +static void ma_dr_mp3__on_meta(ma_dr_mp3* pMP3, ma_dr_mp3_metadata_type type, const void* pRawData, size_t rawDataSize) +{ + if (pMP3->onMeta) { + ma_dr_mp3_metadata metadata; + MA_DR_MP3_ZERO_OBJECT(&metadata); + metadata.type = type; + metadata.pRawData = pRawData; + metadata.rawDataSize = rawDataSize; + pMP3->onMeta(pMP3->pUserDataMeta, &metadata); + } +} +static ma_uint32 ma_dr_mp3_decode_next_frame_ex__callbacks(ma_dr_mp3* pMP3, ma_dr_mp3d_sample_t* pPCMFrames, ma_dr_mp3dec_frame_info* pMP3FrameInfo, const ma_uint8** ppMP3FrameData) { ma_uint32 pcmFramesRead = 0; MA_DR_MP3_ASSERT(pMP3 != NULL); @@ -92559,7 +94407,7 @@ static ma_uint32 ma_dr_mp3_decode_next_frame_ex__callbacks(ma_dr_mp3* pMP3, ma_d pMP3->pData = pNewData; pMP3->dataCapacity = newDataCap; } - bytesRead = ma_dr_mp3__on_read(pMP3, pMP3->pData + pMP3->dataSize, (pMP3->dataCapacity - pMP3->dataSize)); + bytesRead = ma_dr_mp3__on_read_clamped(pMP3, pMP3->pData + pMP3->dataSize, (pMP3->dataCapacity - pMP3->dataSize)); if (bytesRead == 0) { if (pMP3->dataSize == 0) { pMP3->atEnd = MA_TRUE; @@ -92578,16 +94426,20 @@ static ma_uint32 ma_dr_mp3_decode_next_frame_ex__callbacks(ma_dr_mp3* pMP3, ma_d return 0; } pcmFramesRead = ma_dr_mp3dec_decode_frame(&pMP3->decoder, pMP3->pData + pMP3->dataConsumed, (int)pMP3->dataSize, pPCMFrames, &info); - if (info.frame_bytes > 0) { - pMP3->dataConsumed += (size_t)info.frame_bytes; - pMP3->dataSize -= (size_t)info.frame_bytes; - } + pMP3->dataConsumed += (size_t)info.frame_bytes; + pMP3->dataSize -= (size_t)info.frame_bytes; if (pcmFramesRead > 0) { pcmFramesRead = ma_dr_mp3_hdr_frame_samples(pMP3->decoder.header); pMP3->pcmFramesConsumedInMP3Frame = 0; pMP3->pcmFramesRemainingInMP3Frame = pcmFramesRead; pMP3->mp3FrameChannels = info.channels; - pMP3->mp3FrameSampleRate = info.hz; + pMP3->mp3FrameSampleRate = info.sample_rate; + if (pMP3FrameInfo != NULL) { + *pMP3FrameInfo = info; + } + if (ppMP3FrameData != NULL) { + *ppMP3FrameData = pMP3->pData + pMP3->dataConsumed - (size_t)info.frame_bytes; + } break; } else if (info.frame_bytes == 0) { size_t bytesRead; @@ -92604,7 +94456,7 @@ static ma_uint32 ma_dr_mp3_decode_next_frame_ex__callbacks(ma_dr_mp3* pMP3, ma_d pMP3->pData = pNewData; pMP3->dataCapacity = newDataCap; } - bytesRead = ma_dr_mp3__on_read(pMP3, pMP3->pData + pMP3->dataSize, (pMP3->dataCapacity - pMP3->dataSize)); + bytesRead = ma_dr_mp3__on_read_clamped(pMP3, pMP3->pData + pMP3->dataSize, (pMP3->dataCapacity - pMP3->dataSize)); if (bytesRead == 0) { pMP3->atEnd = MA_TRUE; return 0; @@ -92614,7 +94466,7 @@ static ma_uint32 ma_dr_mp3_decode_next_frame_ex__callbacks(ma_dr_mp3* pMP3, ma_d }; return pcmFramesRead; } -static ma_uint32 ma_dr_mp3_decode_next_frame_ex__memory(ma_dr_mp3* pMP3, ma_dr_mp3d_sample_t* pPCMFrames) +static ma_uint32 ma_dr_mp3_decode_next_frame_ex__memory(ma_dr_mp3* pMP3, ma_dr_mp3d_sample_t* pPCMFrames, ma_dr_mp3dec_frame_info* pMP3FrameInfo, const ma_uint8** ppMP3FrameData) { ma_uint32 pcmFramesRead = 0; ma_dr_mp3dec_frame_info info; @@ -92630,36 +94482,44 @@ static ma_uint32 ma_dr_mp3_decode_next_frame_ex__memory(ma_dr_mp3* pMP3, ma_dr_m pMP3->pcmFramesConsumedInMP3Frame = 0; pMP3->pcmFramesRemainingInMP3Frame = pcmFramesRead; pMP3->mp3FrameChannels = info.channels; - pMP3->mp3FrameSampleRate = info.hz; + pMP3->mp3FrameSampleRate = info.sample_rate; + if (pMP3FrameInfo != NULL) { + *pMP3FrameInfo = info; + } + if (ppMP3FrameData != NULL) { + *ppMP3FrameData = pMP3->memory.pData + pMP3->memory.currentReadPos; + } break; } else if (info.frame_bytes > 0) { pMP3->memory.currentReadPos += (size_t)info.frame_bytes; + pMP3->streamCursor += (size_t)info.frame_bytes; } else { break; } } pMP3->memory.currentReadPos += (size_t)info.frame_bytes; + pMP3->streamCursor += (size_t)info.frame_bytes; return pcmFramesRead; } -static ma_uint32 ma_dr_mp3_decode_next_frame_ex(ma_dr_mp3* pMP3, ma_dr_mp3d_sample_t* pPCMFrames) +static ma_uint32 ma_dr_mp3_decode_next_frame_ex(ma_dr_mp3* pMP3, ma_dr_mp3d_sample_t* pPCMFrames, ma_dr_mp3dec_frame_info* pMP3FrameInfo, const ma_uint8** ppMP3FrameData) { if (pMP3->memory.pData != NULL && pMP3->memory.dataSize > 0) { - return ma_dr_mp3_decode_next_frame_ex__memory(pMP3, pPCMFrames); + return ma_dr_mp3_decode_next_frame_ex__memory(pMP3, pPCMFrames, pMP3FrameInfo, ppMP3FrameData); } else { - return ma_dr_mp3_decode_next_frame_ex__callbacks(pMP3, pPCMFrames); + return ma_dr_mp3_decode_next_frame_ex__callbacks(pMP3, pPCMFrames, pMP3FrameInfo, ppMP3FrameData); } } static ma_uint32 ma_dr_mp3_decode_next_frame(ma_dr_mp3* pMP3) { MA_DR_MP3_ASSERT(pMP3 != NULL); - return ma_dr_mp3_decode_next_frame_ex(pMP3, (ma_dr_mp3d_sample_t*)pMP3->pcmFrames); + return ma_dr_mp3_decode_next_frame_ex(pMP3, (ma_dr_mp3d_sample_t*)pMP3->pcmFrames, NULL, NULL); } #if 0 static ma_uint32 ma_dr_mp3_seek_next_frame(ma_dr_mp3* pMP3) { ma_uint32 pcmFrameCount; MA_DR_MP3_ASSERT(pMP3 != NULL); - pcmFrameCount = ma_dr_mp3_decode_next_frame_ex(pMP3, NULL); + pcmFrameCount = ma_dr_mp3_decode_next_frame_ex(pMP3, NULL, NULL, NULL); if (pcmFrameCount == 0) { return 0; } @@ -92669,33 +94529,249 @@ static ma_uint32 ma_dr_mp3_seek_next_frame(ma_dr_mp3* pMP3) return pcmFrameCount; } #endif -static ma_bool32 ma_dr_mp3_init_internal(ma_dr_mp3* pMP3, ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) +static ma_bool32 ma_dr_mp3_init_internal(ma_dr_mp3* pMP3, ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, ma_dr_mp3_tell_proc onTell, ma_dr_mp3_meta_proc onMeta, void* pUserData, void* pUserDataMeta, const ma_allocation_callbacks* pAllocationCallbacks) { + ma_dr_mp3dec_frame_info firstFrameInfo; + const ma_uint8* pFirstFrameData; + ma_uint32 firstFramePCMFrameCount; + ma_uint32 detectedMP3FrameCount = 0xFFFFFFFF; MA_DR_MP3_ASSERT(pMP3 != NULL); MA_DR_MP3_ASSERT(onRead != NULL); ma_dr_mp3dec_init(&pMP3->decoder); pMP3->onRead = onRead; pMP3->onSeek = onSeek; + pMP3->onMeta = onMeta; pMP3->pUserData = pUserData; + pMP3->pUserDataMeta = pUserDataMeta; pMP3->allocationCallbacks = ma_dr_mp3_copy_allocation_callbacks_or_defaults(pAllocationCallbacks); if (pMP3->allocationCallbacks.onFree == NULL || (pMP3->allocationCallbacks.onMalloc == NULL && pMP3->allocationCallbacks.onRealloc == NULL)) { return MA_FALSE; } - if (ma_dr_mp3_decode_next_frame(pMP3) == 0) { + pMP3->streamCursor = 0; + pMP3->streamLength = MA_UINT64_MAX; + pMP3->streamStartOffset = 0; + pMP3->delayInPCMFrames = 0; + pMP3->paddingInPCMFrames = 0; + pMP3->totalPCMFrameCount = MA_UINT64_MAX; + #if 1 + if (onSeek != NULL && onTell != NULL) { + if (onSeek(pUserData, 0, MA_DR_MP3_SEEK_END)) { + ma_int64 streamLen; + int streamEndOffset = 0; + if (onTell(pUserData, &streamLen)) { + if (streamLen > 128) { + char id3[3]; + if (onSeek(pUserData, streamEndOffset - 128, MA_DR_MP3_SEEK_END)) { + if (onRead(pUserData, id3, 3) == 3 && id3[0] == 'T' && id3[1] == 'A' && id3[2] == 'G') { + streamEndOffset -= 128; + streamLen -= 128; + if (onMeta != NULL) { + ma_uint8 tag[128]; + tag[0] = 'T'; tag[1] = 'A'; tag[2] = 'G'; + if (onRead(pUserData, tag + 3, 125) == 125) { + ma_dr_mp3__on_meta(pMP3, MA_DR_MP3_METADATA_TYPE_ID3V1, tag, 128); + } + } + } else { + } + } else { + } + } else { + } + if (streamLen > 32) { + char ape[32]; + if (onSeek(pUserData, streamEndOffset - 32, MA_DR_MP3_SEEK_END)) { + if (onRead(pUserData, ape, 32) == 32 && ape[0] == 'A' && ape[1] == 'P' && ape[2] == 'E' && ape[3] == 'T' && ape[4] == 'A' && ape[5] == 'G' && ape[6] == 'E' && ape[7] == 'X') { + ma_uint32 tagSize = + ((ma_uint32)ape[24] << 0) | + ((ma_uint32)ape[25] << 8) | + ((ma_uint32)ape[26] << 16) | + ((ma_uint32)ape[27] << 24); + streamEndOffset -= 32 + tagSize; + streamLen -= 32 + tagSize; + if (onMeta != NULL) { + if (onSeek(pUserData, streamEndOffset, MA_DR_MP3_SEEK_END)) { + size_t apeTagSize = (size_t)tagSize + 32; + ma_uint8* pTagData = (ma_uint8*)ma_dr_mp3_malloc(apeTagSize, pAllocationCallbacks); + if (pTagData != NULL) { + if (onRead(pUserData, pTagData, apeTagSize) == apeTagSize) { + ma_dr_mp3__on_meta(pMP3, MA_DR_MP3_METADATA_TYPE_APE, pTagData, apeTagSize); + } + ma_dr_mp3_free(pTagData, pAllocationCallbacks); + } + } + } + } + } + } else { + } + if (!onSeek(pUserData, 0, MA_DR_MP3_SEEK_SET)) { + return MA_FALSE; + } + pMP3->streamLength = (ma_uint64)streamLen; + if (pMP3->memory.pData != NULL) { + pMP3->memory.dataSize = (size_t)pMP3->streamLength; + } + } else { + if (!onSeek(pUserData, 0, MA_DR_MP3_SEEK_SET)) { + return MA_FALSE; + } + } + } else { + } + } else { + } + #endif + #if 1 + { + char header[10]; + if (onRead(pUserData, header, 10) == 10) { + if (header[0] == 'I' && header[1] == 'D' && header[2] == '3') { + ma_uint32 tagSize = + (((ma_uint32)header[6] & 0x7F) << 21) | + (((ma_uint32)header[7] & 0x7F) << 14) | + (((ma_uint32)header[8] & 0x7F) << 7) | + (((ma_uint32)header[9] & 0x7F) << 0); + if (header[5] & 0x10) { + tagSize += 10; + } + if (onMeta != NULL) { + size_t tagSizeWithHeader = 10 + tagSize; + ma_uint8* pTagData = (ma_uint8*)ma_dr_mp3_malloc(tagSizeWithHeader, pAllocationCallbacks); + if (pTagData != NULL) { + MA_DR_MP3_COPY_MEMORY(pTagData, header, 10); + if (onRead(pUserData, pTagData + 10, tagSize) == tagSize) { + ma_dr_mp3__on_meta(pMP3, MA_DR_MP3_METADATA_TYPE_ID3V2, pTagData, tagSizeWithHeader); + } + ma_dr_mp3_free(pTagData, pAllocationCallbacks); + } + } else { + if (onSeek != NULL) { + if (!onSeek(pUserData, tagSize, MA_DR_MP3_SEEK_CUR)) { + return MA_FALSE; + } + } else { + char discard[1024]; + while (tagSize > 0) { + size_t bytesToRead = tagSize; + if (bytesToRead > sizeof(discard)) { + bytesToRead = sizeof(discard); + } + if (onRead(pUserData, discard, bytesToRead) != bytesToRead) { + return MA_FALSE; + } + tagSize -= (ma_uint32)bytesToRead; + } + } + } + pMP3->streamStartOffset += 10 + tagSize; + pMP3->streamCursor = pMP3->streamStartOffset; + } else { + if (onSeek != NULL) { + if (!onSeek(pUserData, 0, MA_DR_MP3_SEEK_SET)) { + return MA_FALSE; + } + } else { + } + } + } else { + return MA_FALSE; + } + } + #endif + firstFramePCMFrameCount = ma_dr_mp3_decode_next_frame_ex(pMP3, (ma_dr_mp3d_sample_t*)pMP3->pcmFrames, &firstFrameInfo, &pFirstFrameData); + if (firstFramePCMFrameCount > 0) { + MA_DR_MP3_ASSERT(pFirstFrameData != NULL); + #if 1 + MA_DR_MP3_ASSERT(firstFrameInfo.frame_bytes > 0); + { + ma_dr_mp3_bs bs; + ma_dr_mp3_L3_gr_info grInfo[4]; + const ma_uint8* pTagData = pFirstFrameData; + ma_dr_mp3_bs_init(&bs, pFirstFrameData + MA_DR_MP3_HDR_SIZE, firstFrameInfo.frame_bytes - MA_DR_MP3_HDR_SIZE); + if (MA_DR_MP3_HDR_IS_CRC(pFirstFrameData)) { + ma_dr_mp3_bs_get_bits(&bs, 16); + } + if (ma_dr_mp3_L3_read_side_info(&bs, grInfo, pFirstFrameData) >= 0) { + ma_bool32 isXing = MA_FALSE; + ma_bool32 isInfo = MA_FALSE; + const ma_uint8* pTagDataBeg; + pTagDataBeg = pFirstFrameData + MA_DR_MP3_HDR_SIZE + (bs.pos/8); + pTagData = pTagDataBeg; + isXing = (pTagData[0] == 'X' && pTagData[1] == 'i' && pTagData[2] == 'n' && pTagData[3] == 'g'); + isInfo = (pTagData[0] == 'I' && pTagData[1] == 'n' && pTagData[2] == 'f' && pTagData[3] == 'o'); + if (isXing || isInfo) { + ma_uint32 bytes = 0; + ma_uint32 flags = pTagData[7]; + pTagData += 8; + if (flags & 0x01) { + detectedMP3FrameCount = (ma_uint32)pTagData[0] << 24 | (ma_uint32)pTagData[1] << 16 | (ma_uint32)pTagData[2] << 8 | (ma_uint32)pTagData[3]; + pTagData += 4; + } + if (flags & 0x02) { + bytes = (ma_uint32)pTagData[0] << 24 | (ma_uint32)pTagData[1] << 16 | (ma_uint32)pTagData[2] << 8 | (ma_uint32)pTagData[3]; + (void)bytes; + pTagData += 4; + } + if (flags & 0x04) { + pTagData += 100; + } + if (flags & 0x08) { + pTagData += 4; + } + if (pTagData[0]) { + pTagData += 21; + if (pTagData - pFirstFrameData + 14 < firstFrameInfo.frame_bytes) { + int delayInPCMFrames; + int paddingInPCMFrames; + delayInPCMFrames = (( (ma_uint32)pTagData[0] << 4) | ((ma_uint32)pTagData[1] >> 4)) + (528 + 1); + paddingInPCMFrames = ((((ma_uint32)pTagData[1] & 0xF) << 8) | ((ma_uint32)pTagData[2] )) - (528 + 1); + if (paddingInPCMFrames < 0) { + paddingInPCMFrames = 0; + } + pMP3->delayInPCMFrames = (ma_uint32)delayInPCMFrames; + pMP3->paddingInPCMFrames = (ma_uint32)paddingInPCMFrames; + } + } + if (isXing) { + pMP3->isVBR = MA_TRUE; + } else if (isInfo) { + pMP3->isCBR = MA_TRUE; + } + if (onMeta != NULL) { + ma_dr_mp3_metadata_type metadataType = isXing ? MA_DR_MP3_METADATA_TYPE_XING : MA_DR_MP3_METADATA_TYPE_VBRI; + size_t tagDataSize; + tagDataSize = (size_t)firstFrameInfo.frame_bytes; + tagDataSize -= (size_t)(pTagDataBeg - pFirstFrameData); + ma_dr_mp3__on_meta(pMP3, metadataType, pTagDataBeg, tagDataSize); + } + pMP3->pcmFramesRemainingInMP3Frame = 0; + pMP3->streamStartOffset += (ma_uint32)(firstFrameInfo.frame_bytes); + pMP3->streamCursor = pMP3->streamStartOffset; + ma_dr_mp3dec_init(&pMP3->decoder); + } + } else { + } + } + #endif + } else { ma_dr_mp3__free_from_callbacks(pMP3->pData, &pMP3->allocationCallbacks); return MA_FALSE; } + if (detectedMP3FrameCount != 0xFFFFFFFF) { + pMP3->totalPCMFrameCount = detectedMP3FrameCount * firstFramePCMFrameCount; + } pMP3->channels = pMP3->mp3FrameChannels; pMP3->sampleRate = pMP3->mp3FrameSampleRate; return MA_TRUE; } -MA_API ma_bool32 ma_dr_mp3_init(ma_dr_mp3* pMP3, ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_bool32 ma_dr_mp3_init(ma_dr_mp3* pMP3, ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, ma_dr_mp3_tell_proc onTell, ma_dr_mp3_meta_proc onMeta, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) { if (pMP3 == NULL || onRead == NULL) { return MA_FALSE; } MA_DR_MP3_ZERO_OBJECT(pMP3); - return ma_dr_mp3_init_internal(pMP3, onRead, onSeek, pUserData, pAllocationCallbacks); + return ma_dr_mp3_init_internal(pMP3, onRead, onSeek, onTell, onMeta, pUserData, pUserData, pAllocationCallbacks); } static size_t ma_dr_mp3__on_read_memory(void* pUserData, void* pBufferOut, size_t bytesToRead) { @@ -92716,29 +94792,40 @@ static size_t ma_dr_mp3__on_read_memory(void* pUserData, void* pBufferOut, size_ static ma_bool32 ma_dr_mp3__on_seek_memory(void* pUserData, int byteOffset, ma_dr_mp3_seek_origin origin) { ma_dr_mp3* pMP3 = (ma_dr_mp3*)pUserData; + ma_int64 newCursor; MA_DR_MP3_ASSERT(pMP3 != NULL); - if (origin == ma_dr_mp3_seek_origin_current) { - if (byteOffset > 0) { - if (pMP3->memory.currentReadPos + byteOffset > pMP3->memory.dataSize) { - byteOffset = (int)(pMP3->memory.dataSize - pMP3->memory.currentReadPos); - } - } else { - if (pMP3->memory.currentReadPos < (size_t)-byteOffset) { - byteOffset = -(int)pMP3->memory.currentReadPos; - } - } - pMP3->memory.currentReadPos += byteOffset; + newCursor = pMP3->memory.currentReadPos; + if (origin == MA_DR_MP3_SEEK_SET) { + newCursor = 0; + } else if (origin == MA_DR_MP3_SEEK_CUR) { + newCursor = (ma_int64)pMP3->memory.currentReadPos; + } else if (origin == MA_DR_MP3_SEEK_END) { + newCursor = (ma_int64)pMP3->memory.dataSize; } else { - if ((ma_uint32)byteOffset <= pMP3->memory.dataSize) { - pMP3->memory.currentReadPos = byteOffset; - } else { - pMP3->memory.currentReadPos = pMP3->memory.dataSize; - } + MA_DR_MP3_ASSERT(!"Invalid seek origin"); + return MA_FALSE; } + newCursor += byteOffset; + if (newCursor < 0) { + return MA_FALSE; + } + if ((size_t)newCursor > pMP3->memory.dataSize) { + return MA_FALSE; + } + pMP3->memory.currentReadPos = (size_t)newCursor; return MA_TRUE; } -MA_API ma_bool32 ma_dr_mp3_init_memory(ma_dr_mp3* pMP3, const void* pData, size_t dataSize, const ma_allocation_callbacks* pAllocationCallbacks) +static ma_bool32 ma_dr_mp3__on_tell_memory(void* pUserData, ma_int64* pCursor) { + ma_dr_mp3* pMP3 = (ma_dr_mp3*)pUserData; + MA_DR_MP3_ASSERT(pMP3 != NULL); + MA_DR_MP3_ASSERT(pCursor != NULL); + *pCursor = (ma_int64)pMP3->memory.currentReadPos; + return MA_TRUE; +} +MA_API ma_bool32 ma_dr_mp3_init_memory_with_metadata(ma_dr_mp3* pMP3, const void* pData, size_t dataSize, ma_dr_mp3_meta_proc onMeta, void* pUserDataMeta, const ma_allocation_callbacks* pAllocationCallbacks) +{ + ma_bool32 result; if (pMP3 == NULL) { return MA_FALSE; } @@ -92749,7 +94836,21 @@ MA_API ma_bool32 ma_dr_mp3_init_memory(ma_dr_mp3* pMP3, const void* pData, size_ pMP3->memory.pData = (const ma_uint8*)pData; pMP3->memory.dataSize = dataSize; pMP3->memory.currentReadPos = 0; - return ma_dr_mp3_init_internal(pMP3, ma_dr_mp3__on_read_memory, ma_dr_mp3__on_seek_memory, pMP3, pAllocationCallbacks); + result = ma_dr_mp3_init_internal(pMP3, ma_dr_mp3__on_read_memory, ma_dr_mp3__on_seek_memory, ma_dr_mp3__on_tell_memory, onMeta, pMP3, pUserDataMeta, pAllocationCallbacks); + if (result == MA_FALSE) { + return MA_FALSE; + } + if (pMP3->streamLength <= (ma_uint64)MA_SIZE_MAX) { + pMP3->memory.dataSize = (size_t)pMP3->streamLength; + } + if (pMP3->streamStartOffset > (ma_uint64)MA_SIZE_MAX) { + return MA_FALSE; + } + return MA_TRUE; +} +MA_API ma_bool32 ma_dr_mp3_init_memory(ma_dr_mp3* pMP3, const void* pData, size_t dataSize, const ma_allocation_callbacks* pAllocationCallbacks) +{ + return ma_dr_mp3_init_memory_with_metadata(pMP3, pData, dataSize, NULL, NULL, pAllocationCallbacks); } #ifndef MA_DR_MP3_NO_STDIO #include @@ -92760,36 +94861,76 @@ static size_t ma_dr_mp3__on_read_stdio(void* pUserData, void* pBufferOut, size_t } static ma_bool32 ma_dr_mp3__on_seek_stdio(void* pUserData, int offset, ma_dr_mp3_seek_origin origin) { - return fseek((FILE*)pUserData, offset, (origin == ma_dr_mp3_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0; + int whence = SEEK_SET; + if (origin == MA_DR_MP3_SEEK_CUR) { + whence = SEEK_CUR; + } else if (origin == MA_DR_MP3_SEEK_END) { + whence = SEEK_END; + } + return fseek((FILE*)pUserData, offset, whence) == 0; } -MA_API ma_bool32 ma_dr_mp3_init_file(ma_dr_mp3* pMP3, const char* pFilePath, const ma_allocation_callbacks* pAllocationCallbacks) +static ma_bool32 ma_dr_mp3__on_tell_stdio(void* pUserData, ma_int64* pCursor) +{ + FILE* pFileStdio = (FILE*)pUserData; + ma_int64 result; + MA_DR_MP3_ASSERT(pFileStdio != NULL); + MA_DR_MP3_ASSERT(pCursor != NULL); +#if defined(_WIN32) && !defined(NXDK) + #if defined(_MSC_VER) && _MSC_VER > 1200 + result = _ftelli64(pFileStdio); + #else + result = ftell(pFileStdio); + #endif +#else + result = ftell(pFileStdio); +#endif + *pCursor = result; + return MA_TRUE; +} +MA_API ma_bool32 ma_dr_mp3_init_file_with_metadata(ma_dr_mp3* pMP3, const char* pFilePath, ma_dr_mp3_meta_proc onMeta, void* pUserDataMeta, const ma_allocation_callbacks* pAllocationCallbacks) { ma_bool32 result; FILE* pFile; + if (pMP3 == NULL) { + return MA_FALSE; + } + MA_DR_MP3_ZERO_OBJECT(pMP3); if (ma_fopen(&pFile, pFilePath, "rb") != MA_SUCCESS) { return MA_FALSE; } - result = ma_dr_mp3_init(pMP3, ma_dr_mp3__on_read_stdio, ma_dr_mp3__on_seek_stdio, (void*)pFile, pAllocationCallbacks); + result = ma_dr_mp3_init_internal(pMP3, ma_dr_mp3__on_read_stdio, ma_dr_mp3__on_seek_stdio, ma_dr_mp3__on_tell_stdio, onMeta, (void*)pFile, pUserDataMeta, pAllocationCallbacks); if (result != MA_TRUE) { fclose(pFile); return result; } return MA_TRUE; } -MA_API ma_bool32 ma_dr_mp3_init_file_w(ma_dr_mp3* pMP3, const wchar_t* pFilePath, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_bool32 ma_dr_mp3_init_file_with_metadata_w(ma_dr_mp3* pMP3, const wchar_t* pFilePath, ma_dr_mp3_meta_proc onMeta, void* pUserDataMeta, const ma_allocation_callbacks* pAllocationCallbacks) { ma_bool32 result; FILE* pFile; + if (pMP3 == NULL) { + return MA_FALSE; + } + MA_DR_MP3_ZERO_OBJECT(pMP3); if (ma_wfopen(&pFile, pFilePath, L"rb", pAllocationCallbacks) != MA_SUCCESS) { return MA_FALSE; } - result = ma_dr_mp3_init(pMP3, ma_dr_mp3__on_read_stdio, ma_dr_mp3__on_seek_stdio, (void*)pFile, pAllocationCallbacks); + result = ma_dr_mp3_init_internal(pMP3, ma_dr_mp3__on_read_stdio, ma_dr_mp3__on_seek_stdio, ma_dr_mp3__on_tell_stdio, onMeta, (void*)pFile, pUserDataMeta, pAllocationCallbacks); if (result != MA_TRUE) { fclose(pFile); return result; } return MA_TRUE; } +MA_API ma_bool32 ma_dr_mp3_init_file(ma_dr_mp3* pMP3, const char* pFilePath, const ma_allocation_callbacks* pAllocationCallbacks) +{ + return ma_dr_mp3_init_file_with_metadata(pMP3, pFilePath, NULL, NULL, pAllocationCallbacks); +} +MA_API ma_bool32 ma_dr_mp3_init_file_w(ma_dr_mp3* pMP3, const wchar_t* pFilePath, const ma_allocation_callbacks* pAllocationCallbacks) +{ + return ma_dr_mp3_init_file_with_metadata_w(pMP3, pFilePath, NULL, NULL, pAllocationCallbacks); +} #endif MA_API void ma_dr_mp3_uninit(ma_dr_mp3* pMP3) { @@ -92859,17 +95000,38 @@ static ma_uint64 ma_dr_mp3_read_pcm_frames_raw(ma_dr_mp3* pMP3, ma_uint64 frames MA_DR_MP3_ASSERT(pMP3 != NULL); MA_DR_MP3_ASSERT(pMP3->onRead != NULL); while (framesToRead > 0) { - ma_uint32 framesToConsume = (ma_uint32)MA_DR_MP3_MIN(pMP3->pcmFramesRemainingInMP3Frame, framesToRead); + ma_uint32 framesToConsume; + if (pMP3->currentPCMFrame < pMP3->delayInPCMFrames) { + ma_uint32 framesToSkip = (ma_uint32)MA_DR_MP3_MIN(pMP3->pcmFramesRemainingInMP3Frame, pMP3->delayInPCMFrames - pMP3->currentPCMFrame); + pMP3->currentPCMFrame += framesToSkip; + pMP3->pcmFramesConsumedInMP3Frame += framesToSkip; + pMP3->pcmFramesRemainingInMP3Frame -= framesToSkip; + } + framesToConsume = (ma_uint32)MA_DR_MP3_MIN(pMP3->pcmFramesRemainingInMP3Frame, framesToRead); + if (pMP3->totalPCMFrameCount != MA_UINT64_MAX && pMP3->totalPCMFrameCount > pMP3->paddingInPCMFrames) { + if (pMP3->currentPCMFrame < (pMP3->totalPCMFrameCount - pMP3->paddingInPCMFrames)) { + ma_uint64 framesRemainigToPadding = (pMP3->totalPCMFrameCount - pMP3->paddingInPCMFrames) - pMP3->currentPCMFrame; + if (framesToConsume > framesRemainigToPadding) { + framesToConsume = (ma_uint32)framesRemainigToPadding; + } + } else { + break; + } + } if (pBufferOut != NULL) { - #if defined(MA_DR_MP3_FLOAT_OUTPUT) - float* pFramesOutF32 = (float*)MA_DR_MP3_OFFSET_PTR(pBufferOut, sizeof(float) * totalFramesRead * pMP3->channels); - float* pFramesInF32 = (float*)MA_DR_MP3_OFFSET_PTR(&pMP3->pcmFrames[0], sizeof(float) * pMP3->pcmFramesConsumedInMP3Frame * pMP3->mp3FrameChannels); - MA_DR_MP3_COPY_MEMORY(pFramesOutF32, pFramesInF32, sizeof(float) * framesToConsume * pMP3->channels); - #else - ma_int16* pFramesOutS16 = (ma_int16*)MA_DR_MP3_OFFSET_PTR(pBufferOut, sizeof(ma_int16) * totalFramesRead * pMP3->channels); - ma_int16* pFramesInS16 = (ma_int16*)MA_DR_MP3_OFFSET_PTR(&pMP3->pcmFrames[0], sizeof(ma_int16) * pMP3->pcmFramesConsumedInMP3Frame * pMP3->mp3FrameChannels); - MA_DR_MP3_COPY_MEMORY(pFramesOutS16, pFramesInS16, sizeof(ma_int16) * framesToConsume * pMP3->channels); - #endif + #if defined(MA_DR_MP3_FLOAT_OUTPUT) + { + float* pFramesOutF32 = (float*)MA_DR_MP3_OFFSET_PTR(pBufferOut, sizeof(float) * totalFramesRead * pMP3->channels); + float* pFramesInF32 = (float*)MA_DR_MP3_OFFSET_PTR(&pMP3->pcmFrames[0], sizeof(float) * pMP3->pcmFramesConsumedInMP3Frame * pMP3->mp3FrameChannels); + MA_DR_MP3_COPY_MEMORY(pFramesOutF32, pFramesInF32, sizeof(float) * framesToConsume * pMP3->channels); + } + #else + { + ma_int16* pFramesOutS16 = (ma_int16*)MA_DR_MP3_OFFSET_PTR(pBufferOut, sizeof(ma_int16) * totalFramesRead * pMP3->channels); + ma_int16* pFramesInS16 = (ma_int16*)MA_DR_MP3_OFFSET_PTR(&pMP3->pcmFrames[0], sizeof(ma_int16) * pMP3->pcmFramesConsumedInMP3Frame * pMP3->mp3FrameChannels); + MA_DR_MP3_COPY_MEMORY(pFramesOutS16, pFramesInS16, sizeof(ma_int16) * framesToConsume * pMP3->channels); + } + #endif } pMP3->currentPCMFrame += framesToConsume; pMP3->pcmFramesConsumedInMP3Frame += framesToConsume; @@ -92879,6 +95041,9 @@ static ma_uint64 ma_dr_mp3_read_pcm_frames_raw(ma_dr_mp3* pMP3, ma_uint64 frames if (framesToRead == 0) { break; } + if (pMP3->totalPCMFrameCount != MA_UINT64_MAX && pMP3->totalPCMFrameCount > pMP3->paddingInPCMFrames && pMP3->currentPCMFrame >= (pMP3->totalPCMFrameCount - pMP3->paddingInPCMFrames)) { + break; + } MA_DR_MP3_ASSERT(pMP3->pcmFramesRemainingInMP3Frame == 0); if (ma_dr_mp3_decode_next_frame(pMP3) == 0) { break; @@ -92958,7 +95123,7 @@ static ma_bool32 ma_dr_mp3_seek_to_start_of_stream(ma_dr_mp3* pMP3) { MA_DR_MP3_ASSERT(pMP3 != NULL); MA_DR_MP3_ASSERT(pMP3->onSeek != NULL); - if (!ma_dr_mp3__on_seek(pMP3, 0, ma_dr_mp3_seek_origin_start)) { + if (!ma_dr_mp3__on_seek_64(pMP3, pMP3->streamStartOffset, MA_DR_MP3_SEEK_SET)) { return MA_FALSE; } ma_dr_mp3_reset(pMP3); @@ -93024,7 +95189,7 @@ static ma_bool32 ma_dr_mp3_seek_to_pcm_frame__seek_table(ma_dr_mp3* pMP3, ma_uin seekPoint.mp3FramesToDiscard = 0; seekPoint.pcmFramesToDiscard = 0; } - if (!ma_dr_mp3__on_seek_64(pMP3, seekPoint.seekPosInBytes, ma_dr_mp3_seek_origin_start)) { + if (!ma_dr_mp3__on_seek_64(pMP3, seekPoint.seekPosInBytes, MA_DR_MP3_SEEK_SET)) { return MA_FALSE; } ma_dr_mp3_reset(pMP3); @@ -93035,7 +95200,7 @@ static ma_bool32 ma_dr_mp3_seek_to_pcm_frame__seek_table(ma_dr_mp3* pMP3, ma_uin if (iMP3Frame == seekPoint.mp3FramesToDiscard-1) { pPCMFrames = (ma_dr_mp3d_sample_t*)pMP3->pcmFrames; } - pcmFramesRead = ma_dr_mp3_decode_next_frame_ex(pMP3, pPCMFrames); + pcmFramesRead = ma_dr_mp3_decode_next_frame_ex(pMP3, pPCMFrames, NULL, NULL); if (pcmFramesRead == 0) { return MA_FALSE; } @@ -93077,7 +95242,7 @@ MA_API ma_bool32 ma_dr_mp3_get_mp3_and_pcm_frame_count(ma_dr_mp3* pMP3, ma_uint6 totalMP3FrameCount = 0; for (;;) { ma_uint32 pcmFramesInCurrentMP3Frame; - pcmFramesInCurrentMP3Frame = ma_dr_mp3_decode_next_frame_ex(pMP3, NULL); + pcmFramesInCurrentMP3Frame = ma_dr_mp3_decode_next_frame_ex(pMP3, NULL, NULL, NULL); if (pcmFramesInCurrentMP3Frame == 0) { break; } @@ -93101,10 +95266,26 @@ MA_API ma_bool32 ma_dr_mp3_get_mp3_and_pcm_frame_count(ma_dr_mp3* pMP3, ma_uint6 MA_API ma_uint64 ma_dr_mp3_get_pcm_frame_count(ma_dr_mp3* pMP3) { ma_uint64 totalPCMFrameCount; - if (!ma_dr_mp3_get_mp3_and_pcm_frame_count(pMP3, NULL, &totalPCMFrameCount)) { + if (pMP3 == NULL) { return 0; } - return totalPCMFrameCount; + if (pMP3->totalPCMFrameCount != MA_UINT64_MAX) { + totalPCMFrameCount = pMP3->totalPCMFrameCount; + if (totalPCMFrameCount >= pMP3->delayInPCMFrames) { + totalPCMFrameCount -= pMP3->delayInPCMFrames; + } else { + } + if (totalPCMFrameCount >= pMP3->paddingInPCMFrames) { + totalPCMFrameCount -= pMP3->paddingInPCMFrames; + } else { + } + return totalPCMFrameCount; + } else { + if (!ma_dr_mp3_get_mp3_and_pcm_frame_count(pMP3, NULL, &totalPCMFrameCount)) { + return 0; + } + return totalPCMFrameCount; + } } MA_API ma_uint64 ma_dr_mp3_get_mp3_frame_count(ma_dr_mp3* pMP3) { @@ -93174,7 +95355,7 @@ MA_API ma_bool32 ma_dr_mp3_calculate_seek_points(ma_dr_mp3* pMP3, ma_uint32* pSe MA_DR_MP3_ASSERT(pMP3->streamCursor >= pMP3->dataSize); mp3FrameInfo[iMP3Frame].bytePos = pMP3->streamCursor - pMP3->dataSize; mp3FrameInfo[iMP3Frame].pcmFrameIndex = runningPCMFrameCount; - pcmFramesInCurrentMP3FrameIn = ma_dr_mp3_decode_next_frame_ex(pMP3, NULL); + pcmFramesInCurrentMP3FrameIn = ma_dr_mp3_decode_next_frame_ex(pMP3, NULL, NULL, NULL); if (pcmFramesInCurrentMP3FrameIn == 0) { return MA_FALSE; } @@ -93198,7 +95379,7 @@ MA_API ma_bool32 ma_dr_mp3_calculate_seek_points(ma_dr_mp3* pMP3, ma_uint32* pSe } mp3FrameInfo[MA_DR_MP3_COUNTOF(mp3FrameInfo)-1].bytePos = pMP3->streamCursor - pMP3->dataSize; mp3FrameInfo[MA_DR_MP3_COUNTOF(mp3FrameInfo)-1].pcmFrameIndex = runningPCMFrameCount; - pcmFramesInCurrentMP3FrameIn = ma_dr_mp3_decode_next_frame_ex(pMP3, NULL); + pcmFramesInCurrentMP3FrameIn = ma_dr_mp3_decode_next_frame_ex(pMP3, NULL, NULL, NULL); if (pcmFramesInCurrentMP3FrameIn == 0) { pSeekPoints[iSeekPoint].seekPosInBytes = mp3FrameInfo[0].bytePos; pSeekPoints[iSeekPoint].pcmFrameIndex = nextTargetPCMFrame; @@ -93336,18 +95517,18 @@ static ma_int16* ma_dr_mp3__full_read_and_close_s16(ma_dr_mp3* pMP3, ma_dr_mp3_c } return pFrames; } -MA_API float* ma_dr_mp3_open_and_read_pcm_frames_f32(ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, void* pUserData, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API float* ma_dr_mp3_open_and_read_pcm_frames_f32(ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, ma_dr_mp3_tell_proc onTell, void* pUserData, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount, const ma_allocation_callbacks* pAllocationCallbacks) { ma_dr_mp3 mp3; - if (!ma_dr_mp3_init(&mp3, onRead, onSeek, pUserData, pAllocationCallbacks)) { + if (!ma_dr_mp3_init(&mp3, onRead, onSeek, onTell, NULL, pUserData, pAllocationCallbacks)) { return NULL; } return ma_dr_mp3__full_read_and_close_f32(&mp3, pConfig, pTotalFrameCount); } -MA_API ma_int16* ma_dr_mp3_open_and_read_pcm_frames_s16(ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, void* pUserData, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_int16* ma_dr_mp3_open_and_read_pcm_frames_s16(ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, ma_dr_mp3_tell_proc onTell, void* pUserData, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount, const ma_allocation_callbacks* pAllocationCallbacks) { ma_dr_mp3 mp3; - if (!ma_dr_mp3_init(&mp3, onRead, onSeek, pUserData, pAllocationCallbacks)) { + if (!ma_dr_mp3_init(&mp3, onRead, onSeek, onTell, NULL, pUserData, pAllocationCallbacks)) { return NULL; } return ma_dr_mp3__full_read_and_close_s16(&mp3, pConfig, pTotalFrameCount); From f36c8ddc56fa177b055e0fef44fe531fe59535d1 Mon Sep 17 00:00:00 2001 From: iann Date: Mon, 29 Sep 2025 02:34:38 +0900 Subject: [PATCH 038/167] [rlgl] Allow tint colors in GL_LINE (wires) and GL_POINT (points) draw modes on OpenGL 1.1 clean (#5207) * gate with OPENGL_11 prototype and definition for rlSetPointSize and rlGetPointSize * gate with OPENGL_11 prototype and definition for rlSetPointSize and rlGetPointSize * more coverage for fixing expected texcoords, normals, and colors * fix guard styling * fix guard issue, and remove fallback unneccessary else clause (default shader ill work) * opengl3.3 and es2 need the color array allocated in order to allow for updates later (unlike opengl11) --- src/rlgl.h | 29 +++++++++++++++++++++++++---- src/rmodels.c | 44 +++++++++++++++++++++++++++++++++----------- 2 files changed, 58 insertions(+), 15 deletions(-) diff --git a/src/rlgl.h b/src/rlgl.h index 7db05251d..2a1a5d5f8 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -644,10 +644,8 @@ RLAPI void rlEnableVertexBufferElement(unsigned int id); // Enable vertex buffer RLAPI void rlDisableVertexBufferElement(void); // Disable vertex buffer element (VBO element) RLAPI void rlEnableVertexAttribute(unsigned int index); // Enable vertex attribute index RLAPI void rlDisableVertexAttribute(unsigned int index); // Disable vertex attribute index -#if defined(GRAPHICS_API_OPENGL_11) RLAPI void rlEnableStatePointer(int vertexAttribType, void *buffer); // Enable attribute state pointer RLAPI void rlDisableStatePointer(int vertexAttribType); // Disable attribute state pointer -#endif // Textures state RLAPI void rlActiveTextureSlot(int slot); // Select and active a texture slot @@ -686,6 +684,8 @@ RLAPI void rlDisableScissorTest(void); // Disable scissor test RLAPI void rlScissor(int x, int y, int width, int height); // Scissor test RLAPI void rlEnablePointMode(void); // Enable point mode RLAPI void rlDisablePointMode(void); // Disable point mode +RLAPI void rlSetPointSize(float size); // Set the point drawing size +RLAPI float rlGetPointSize(void); // Get the point drawing size RLAPI void rlEnableWireMode(void); // Enable wire mode RLAPI void rlDisableWireMode(void); // Disable wire mode RLAPI void rlSetLineWidth(float width); // Set the line drawing width @@ -2016,6 +2016,25 @@ float rlGetLineWidth(void) return width; } +// Set the point drawing size +void rlSetPointSize(float size) +{ +#if defined(GRAPHICS_API_OPENGL_11) + glPointSize(size); +#endif +} + +// Get the point drawing size +float rlGetPointSize(void) +{ + float size = 1; +#if defined(GRAPHICS_API_OPENGL_11) + glGetFloatv(GL_POINT_SIZE, &size); +#endif + return size; + +} + // Enable line aliasing void rlEnableSmoothLines(void) { @@ -4003,10 +4022,10 @@ void rlDrawVertexArrayElementsInstanced(int offset, int count, const void *buffe #endif } -#if defined(GRAPHICS_API_OPENGL_11) // Enable vertex state pointer void rlEnableStatePointer(int vertexAttribType, void *buffer) { +#if defined(GRAPHICS_API_OPENGL_11) if (buffer != NULL) glEnableClientState(vertexAttribType); switch (vertexAttribType) { @@ -4017,14 +4036,16 @@ void rlEnableStatePointer(int vertexAttribType, void *buffer) //case GL_INDEX_ARRAY: if (buffer != NULL) glIndexPointer(GL_SHORT, 0, buffer); break; // Indexed colors default: break; } +#endif } // Disable vertex state pointer void rlDisableStatePointer(int vertexAttribType) { +#if defined(GRAPHICS_API_OPENGL_11) glDisableClientState(vertexAttribType); -} #endif +} // Load vertex array object (VAO) unsigned int rlLoadVertexArray(void) diff --git a/src/rmodels.c b/src/rmodels.c index 9aca37a24..01e85475c 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -1293,10 +1293,19 @@ void UploadMesh(Mesh *mesh, bool dynamic) rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION); // Enable vertex attributes: texcoords (shader-location = 1) - mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD] = rlLoadVertexBuffer(mesh->texcoords, mesh->vertexCount*2*sizeof(float), dynamic); - rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD, 2, RL_FLOAT, 0, 0, 0); - rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD); + if (mesh->texcoords != NULL) + { + mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD] = rlLoadVertexBuffer(mesh->texcoords, mesh->vertexCount*2*sizeof(float), dynamic); + rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD, 2, RL_FLOAT, 0, 0, 0); + rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD); + } + else + { + float value[2] = { 0.0f, 0.0f }; + rlSetVertexAttributeDefault(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD, value, SHADER_ATTRIB_VEC2, 2); + rlDisableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD); + } // WARNING: When setting default vertex attribute values, the values for each generic vertex attribute // is part of current state, and it is maintained even if a different program object is used @@ -1431,12 +1440,12 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform) if (mesh.animVertices) rlEnableStatePointer(GL_VERTEX_ARRAY, mesh.animVertices); else rlEnableStatePointer(GL_VERTEX_ARRAY, mesh.vertices); - rlEnableStatePointer(GL_TEXTURE_COORD_ARRAY, mesh.texcoords); + if (mesh.texcoords) rlEnableStatePointer(GL_TEXTURE_COORD_ARRAY, mesh.texcoords); if (mesh.animNormals) rlEnableStatePointer(GL_NORMAL_ARRAY, mesh.animNormals); - else rlEnableStatePointer(GL_NORMAL_ARRAY, mesh.normals); + else if (mesh.normals) rlEnableStatePointer(GL_NORMAL_ARRAY, mesh.normals); - rlEnableStatePointer(GL_COLOR_ARRAY, mesh.colors); + if (mesh.colors) rlEnableStatePointer(GL_COLOR_ARRAY, mesh.colors); rlPushMatrix(); rlMultMatrixf(MatrixToFloat(transform)); @@ -3836,6 +3845,7 @@ void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float // Draw a model points // WARNING: OpenGL ES 2.0 does not support point mode drawing +// TODO: gate these properly for non es 2.0 versions only void DrawModelPoints(Model model, Vector3 position, float scale, Color tint) { rlEnablePointMode(); @@ -4420,7 +4430,11 @@ static Model LoadOBJ(const char *fileName) model.meshes[i].vertices = (float *)MemAlloc(sizeof(float)*vertexCount*3); model.meshes[i].normals = (float *)MemAlloc(sizeof(float)*vertexCount*3); model.meshes[i].texcoords = (float *)MemAlloc(sizeof(float)*vertexCount*2); + #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) model.meshes[i].colors = (unsigned char *)MemAlloc(sizeof(unsigned char)*vertexCount*4); + #else + model.meshes[i].colors = NULL; + #endif } MemFree(localMeshVertexCounts); @@ -4474,7 +4488,17 @@ static Model LoadOBJ(const char *fileName) for (int i = 0; i < 3; i++) model.meshes[meshIndex].vertices[localMeshVertexCount*3 + i] = objAttributes.vertices[vertIndex*3 + i]; - for (int i = 0; i < 2; i++) model.meshes[meshIndex].texcoords[localMeshVertexCount*2 + i] = objAttributes.texcoords[texcordIndex*2 + i]; + if (objAttributes.texcoords != NULL && texcordIndex != TINYOBJ_INVALID_INDEX && texcordIndex >= 0) + { + for (int i = 0; i < 2; i++) model.meshes[meshIndex].texcoords[localMeshVertexCount*2 + i] = objAttributes.texcoords[texcordIndex*2 + i]; + model.meshes[meshIndex].texcoords[localMeshVertexCount*2 + 1] = 1.0f - model.meshes[meshIndex].texcoords[localMeshVertexCount*2 + 1]; + } + else + { + model.meshes[meshIndex].texcoords[localMeshVertexCount*2 + 0] = 0.0f; + model.meshes[meshIndex].texcoords[localMeshVertexCount*2 + 1] = 0.0f; + } + if (objAttributes.normals != NULL && normalIndex != TINYOBJ_INVALID_INDEX && normalIndex >= 0) { for (int i = 0; i < 3; i++) model.meshes[meshIndex].normals[localMeshVertexCount*3 + i] = objAttributes.normals[normalIndex*3 + i]; @@ -4485,11 +4509,9 @@ static Model LoadOBJ(const char *fileName) model.meshes[meshIndex].normals[localMeshVertexCount*3 + 1] = 1.0f; model.meshes[meshIndex].normals[localMeshVertexCount*3 + 2] = 0.0f; } - - model.meshes[meshIndex].texcoords[localMeshVertexCount*2 + 1] = 1.0f - model.meshes[meshIndex].texcoords[localMeshVertexCount*2 + 1]; - + #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) for (int i = 0; i < 4; i++) model.meshes[meshIndex].colors[localMeshVertexCount*4 + i] = 255; - + #endif faceVertIndex++; localMeshVertexCount++; } From 4767841b7119396f129eceeab0c7e90e8198e48d Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 28 Sep 2025 19:45:52 +0200 Subject: [PATCH 039/167] Code format review --- src/rmodels.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rmodels.c b/src/rmodels.c index 01e85475c..c54ef03fa 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -4488,7 +4488,7 @@ static Model LoadOBJ(const char *fileName) for (int i = 0; i < 3; i++) model.meshes[meshIndex].vertices[localMeshVertexCount*3 + i] = objAttributes.vertices[vertIndex*3 + i]; - if (objAttributes.texcoords != NULL && texcordIndex != TINYOBJ_INVALID_INDEX && texcordIndex >= 0) + if ((objAttributes.texcoords != NULL) && (texcordIndex != TINYOBJ_INVALID_INDEX) && (texcordIndex >= 0)) { for (int i = 0; i < 2; i++) model.meshes[meshIndex].texcoords[localMeshVertexCount*2 + i] = objAttributes.texcoords[texcordIndex*2 + i]; model.meshes[meshIndex].texcoords[localMeshVertexCount*2 + 1] = 1.0f - model.meshes[meshIndex].texcoords[localMeshVertexCount*2 + 1]; @@ -4499,7 +4499,7 @@ static Model LoadOBJ(const char *fileName) model.meshes[meshIndex].texcoords[localMeshVertexCount*2 + 1] = 0.0f; } - if (objAttributes.normals != NULL && normalIndex != TINYOBJ_INVALID_INDEX && normalIndex >= 0) + if ((objAttributes.normals != NULL) && (normalIndex != TINYOBJ_INVALID_INDEX) && (normalIndex >= 0)) { for (int i = 0; i < 3; i++) model.meshes[meshIndex].normals[localMeshVertexCount*3 + i] = objAttributes.normals[normalIndex*3 + i]; } From a2a22e5e4873111d45c0b9a09d482407d22a89ce Mon Sep 17 00:00:00 2001 From: Jett <30197659+JettMonstersGoBoom@users.noreply.github.com> Date: Sun, 28 Sep 2025 17:02:53 -0400 Subject: [PATCH 040/167] ADDED: example: `core_input_actions` (#5211) * adding core_input_actions action based input API vs direct input, allows remapping of buttons or keys to an action. * adjusted formatting. * updates for struct name and fixed a typo --- examples/Makefile | 1 + examples/core/core_input_actions.c | 174 +++++++++++++++++++++++++++++ 2 files changed, 175 insertions(+) create mode 100644 examples/core/core_input_actions.c diff --git a/examples/Makefile b/examples/Makefile index ee17bb350..6d409b511 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -524,6 +524,7 @@ CORE = \ core/core_input_mouse_wheel \ core/core_input_multitouch \ core/core_input_virtual_controls \ + core/core_input_actions \ core/core_random_sequence \ core/core_random_values \ core/core_render_texture \ diff --git a/examples/core/core_input_actions.c b/examples/core/core_input_actions.c new file mode 100644 index 000000000..b8266a8f4 --- /dev/null +++ b/examples/core/core_input_actions.c @@ -0,0 +1,174 @@ + +/******************************************************************************************* +* +* raylib [core_inputactionInputs] example - presents a simple API for remapping input to actions +* +* Example complexity rating: [★☆☆☆] 1/4 +* +* Example originally created with raylib 5.5, last time updated with raylib 5.6 +* +* Example contributed by MonstersGoBoom 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 MonstersGoBoom +* +********************************************************************************************/ + +/* + Simple example for decoding input as actions, allowing remapping of input to different keys or gamepad buttons. + for example instead of + IsKeyDown(KEY_LEFT) + you'd use + IsActionDown(ACTION_LEFT) + which can be reassigned to e.g. KEY_A and also assigned to a gamepad button. the action will trigger with either gamepad or keys + */ + + +#include +#include +#include +#include "raylib.h" + +// add your own action types here + +typedef enum ActionType +{ + NO_ACTION, + ACTION_UP, + ACTION_DOWN, + ACTION_LEFT, + ACTION_RIGHT, + ACTION_FIRE, + MAX_ACTION +} ActionType; + +// struct for key and button inputs +typedef struct ActionInput +{ + int key; + int button; +} ActionInput; + +// gamepad index, change this if you have multiple gamepads. +int gamepadIndex = 0; +static ActionInput actionInputs[MAX_ACTION] = {0}; + +// combines IsKeyPressed and IsGameButtonPressed to one action +bool isActionPressed(int action) +{ + if (action Date: Sun, 28 Sep 2025 23:31:07 +0200 Subject: [PATCH 041/167] REVIEWED: New example format and requirements: `core_input_actions` #5211 --- examples/Makefile | 2 +- examples/Makefile.Web | 4 + examples/README.md | 5 +- examples/core/core_input_actions.c | 243 ++++---- examples/core/core_input_actions.png | Bin 0 -> 15477 bytes examples/examples_list.txt | 1 + .../examples/core_input_actions.vcxproj | 569 ++++++++++++++++++ projects/VS2022/raylib.sln | 27 + 8 files changed, 738 insertions(+), 113 deletions(-) create mode 100644 examples/core/core_input_actions.png create mode 100644 projects/VS2022/examples/core_input_actions.vcxproj diff --git a/examples/Makefile b/examples/Makefile index 6d409b511..8fb92ac2b 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -516,6 +516,7 @@ CORE = \ core/core_custom_logging \ core/core_drop_files \ core/core_high_dpi \ + core/core_input_actions \ core/core_input_gamepad \ core/core_input_gestures \ core/core_input_gestures_testbed \ @@ -524,7 +525,6 @@ CORE = \ core/core_input_mouse_wheel \ core/core_input_multitouch \ core/core_input_virtual_controls \ - core/core_input_actions \ core/core_random_sequence \ core/core_random_values \ core/core_render_texture \ diff --git a/examples/Makefile.Web b/examples/Makefile.Web index a16d57853..87c2866c6 100644 --- a/examples/Makefile.Web +++ b/examples/Makefile.Web @@ -516,6 +516,7 @@ CORE = \ core/core_custom_logging \ core/core_drop_files \ core/core_high_dpi \ + core/core_input_actions \ core/core_input_gamepad \ core/core_input_gestures \ core/core_input_gestures_testbed \ @@ -732,6 +733,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_input_actions: core/core_input_actions.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) + core/core_input_gamepad: core/core_input_gamepad.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \ --preload-file core/resources/ps3.png@resources/ps3.png \ diff --git a/examples/README.md b/examples/README.md index 1753a31bc..d7f56d8d4 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: 163] +## EXAMPLES COLLECTION [TOTAL: 164] -### category: core [37] +### category: core [38] Examples using raylib[core](../src/rcore.c) platform functionality like window creation, inputs, drawing modes and system functionality. @@ -62,6 +62,7 @@ Examples using raylib[core](../src/rcore.c) platform functionality like window c | [core_high_dpi](core/core_high_dpi.c) | core_high_dpi | ⭐⭐☆☆ | 5.0 | 5.5 | [Jonathan Marler](https://github.com/marler8997) | | [core_render_texture](core/core_render_texture.c) | core_render_texture | ⭐☆☆☆ | 5.6-dev | 5.6-dev | [Ramon Santamaria](https://github.com/raysan5) | | [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) | ### category: shapes [20] diff --git a/examples/core/core_input_actions.c b/examples/core/core_input_actions.c index b8266a8f4..aff356087 100644 --- a/examples/core/core_input_actions.c +++ b/examples/core/core_input_actions.c @@ -1,41 +1,31 @@ - /******************************************************************************************* * -* raylib [core_inputactionInputs] example - presents a simple API for remapping input to actions +* raylib [core] example - input actions * -* Example complexity rating: [★☆☆☆] 1/4 +* Example complexity rating: [★★☆☆] 2/4 * * Example originally created with raylib 5.5, last time updated with raylib 5.6 * -* Example contributed by MonstersGoBoom and reviewed by Ramon Santamaria (@raysan5) +* Example contributed by Jett (@JettMonstersGoBoom) 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 MonstersGoBoom +* Copyright (c) 2025 Jett (@JettMonstersGoBoom) * ********************************************************************************************/ -/* - Simple example for decoding input as actions, allowing remapping of input to different keys or gamepad buttons. - for example instead of - IsKeyDown(KEY_LEFT) - you'd use - IsActionDown(ACTION_LEFT) - which can be reassigned to e.g. KEY_A and also assigned to a gamepad button. the action will trigger with either gamepad or keys - */ +// Simple example for decoding input as actions, allowing remapping of input to different keys or gamepad buttons +// For example instead of using `IsKeyDown(KEY_LEFT)`, you can use `IsActionDown(ACTION_LEFT)` +// which can be reassigned to e.g. KEY_A and also assigned to a gamepad button. the action will trigger with either gamepad or keys - -#include -#include -#include #include "raylib.h" -// add your own action types here - -typedef enum ActionType -{ - NO_ACTION, +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- +typedef enum ActionType { + NO_ACTION = 0, ACTION_UP, ACTION_DOWN, ACTION_LEFT, @@ -44,42 +34,137 @@ typedef enum ActionType MAX_ACTION } ActionType; -// struct for key and button inputs -typedef struct ActionInput -{ +// Key and button inputs +typedef struct ActionInput { int key; int button; } ActionInput; -// gamepad index, change this if you have multiple gamepads. -int gamepadIndex = 0; -static ActionInput actionInputs[MAX_ACTION] = {0}; +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +static int gamepadIndex = 0; // Gamepad default index +static ActionInput actionInputs[MAX_ACTION] = { 0 }; -// combines IsKeyPressed and IsGameButtonPressed to one action -bool isActionPressed(int action) +//---------------------------------------------------------------------------------- +// Module Functions Declaration +//---------------------------------------------------------------------------------- +static bool IsActionPressed(int action); // Check action key/button pressed +static bool IsActionReleased(int action); // Check action key/button released +static bool IsActionDown(int action); // Check action key/button down + +static void SetActionsDefault(void); // Set the "default" keyset +static void SetActionsCursor(void); // Set the "alternate" keyset + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main(void) { - if (actionGfQUFriv`U>e1VacN@3H##CB#u%cv2~yIG8ILhD?f1{@buYV` zzha?fw>*9zd!>9@qknjByKIJEmkqU*ZF$ba7H?k1s2H4o{B6U3+2&@)fxX_QJa_3!~IgDQjV;V(D|&bd8tIRpZjeh z)*WcxtH>vOlOf0BiaXbr`s0vnwqccQc19sXM25zP*~F#ghh{Z&WOdi&el>`D_}&G~z8} zT@X5iH%x=3^&%B z92k6Tk>A*rEffb#$>hLBaeX4WFO6q?HTTftqrTRpNYhhK@yF$OUK`r@O3mYt&=-1z z10e-JIhHsn#*Z^PPuz|Ny(kmka!_gCCE$8R{L2?=_q=uox zY%5(FuFYu7xg^8#Zo9BLqYGp4*gXDHGMhbUdC^6rb`1~dk05K>Q=K`y=U)O zR=+y*h1ux=zTZG@+L?`bheNO8rJD&ITNf8aUC3O*#cvk{C#nO_H&@1N7x6C05n6&{ zF2_OZ>(}Bp9$ryPHIIHfuJW}HrP67av`iX5+m-R+>u3^<=gN*XOu4g_?0-MIrEOmG z^JgrFqm25@zqu4duiv$)LIq_fp}4&mZ+$JuV-`9oz{6d#;fn(NucbyeYWAfv>N~~z zHors6KcK3^cQus%?qet*s18rN!Dq#qIM2yt#}@U{4%@}_RPmEJ_p`>~I?7rry01|6 z7Z>#(%&aQCJ~rdBO_c>T7G0 zCt@sdE*jHA#dVUrdHuqKN8GzsNmvV?NKt2q8Ya<0d8_nVs~x$4KokY9zIMD!m6y3lF=^C;aL7O1bU8e<^~zgh?dJ2rTjYP= z{{RH|{};dlU}4ytfEIujfELts6}Y3S%LaS__yX_+;0q&r?!Xs-F92TvzVK=Kg1u;s zMuWFqK&yLR6z_ab<{6Xf)vfNN5yvY#Y3t^JcJOdEzuyo0B-+7o@MJd7N?S)-IoBO+ zq^mmDHZ=5u`e5(J2cLu6R&d)L%tpk%8mWWq1VU|PFdO+4W+NY+4ECbE&PdB^7gXMf6J;vUo(_^Mm;Vk|Vd)IA3J1SU}c0$l9?3xI{;CwhPufEIuj)DH## zcT_za1AGDa0`LXk3nL%y1HJ%!0r&#&1>g(AkFNqP04)G5z*P~j09erVI{ + + + + 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_input_actions + 10.0 + core_input_actions + + + + 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 fe2241434..faca55fa0 100644 --- a/projects/VS2022/raylib.sln +++ b/projects/VS2022/raylib.sln @@ -345,6 +345,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "text_inline_styling", "exam EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_undo_redo", "examples\core_undo_redo.vcxproj", "{3B27F358-2679-4F38-B297-17B536F580BB}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_input_actions", "examples\core_input_actions.vcxproj", "{6B1A933E-71B8-4C1F-9E79-02D98830E671}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug.DLL|ARM64 = Debug.DLL|ARM64 @@ -4247,6 +4249,30 @@ Global {3B27F358-2679-4F38-B297-17B536F580BB}.Release|x64.Build.0 = Release|x64 {3B27F358-2679-4F38-B297-17B536F580BB}.Release|x86.ActiveCfg = Release|Win32 {3B27F358-2679-4F38-B297-17B536F580BB}.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 @@ -4421,6 +4447,7 @@ Global {49C67F03-1A56-4F96-B278-39B66EC93678} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} {D496308F-3C3C-40B3-A3ED-EA327D244B3E} = {8D3C83B7-F1E0-4C2E-9E34-EE5F6AB2502A} {3B27F358-2679-4F38-B297-17B536F580BB} = {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 c551fb7118268193414f427da2b478cf2141fb2c Mon Sep 17 00:00:00 2001 From: Tim Little Date: Sun, 28 Sep 2025 22:40:09 +0100 Subject: [PATCH 042/167] Add models_basic_voxel example (#5212) --- examples/Makefile | 1 + examples/Makefile.Web | 4 + examples/README.md | 3 +- examples/examples_list.txt | 1 + examples/models/models_basic_voxel.c | 152 +++++++++++++++++++++++++ examples/models/models_basic_voxel.png | Bin 0 -> 349583 bytes 6 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 examples/models/models_basic_voxel.c create mode 100644 examples/models/models_basic_voxel.png diff --git a/examples/Makefile b/examples/Makefile index 8fb92ac2b..36faed3b3 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -607,6 +607,7 @@ TEXT = \ MODELS = \ models/models_animation_gpu_skinning \ models/models_animation_playing \ + models/models_basic_voxel \ models/models_billboard_rendering \ models/models_bone_socket \ models/models_box_collisions \ diff --git a/examples/Makefile.Web b/examples/Makefile.Web index 87c2866c6..b1b1f0779 100644 --- a/examples/Makefile.Web +++ b/examples/Makefile.Web @@ -607,6 +607,7 @@ TEXT = \ MODELS = \ models/models_animation_gpu_skinning \ models/models_animation_playing \ + models/models_basic_voxel \ models/models_billboard_rendering \ models/models_bone_socket \ models/models_box_collisions \ @@ -1049,6 +1050,9 @@ models/models_animation_playing: models/models_animation_playing.c --preload-file models/resources/models/iqm/guytex.png@resources/models/iqm/guytex.png \ --preload-file models/resources/models/iqm/guyanim.iqm@resources/models/iqm/guyanim.iqm +models/models_basic_voxel: models/models_basic_voxel.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) + models/models_billboard_rendering: models/models_billboard_rendering.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \ --preload-file models/resources/billboard.png@resources/billboard.png diff --git a/examples/README.md b/examples/README.md index d7f56d8d4..48e83c852 100644 --- a/examples/README.md +++ b/examples/README.md @@ -145,7 +145,7 @@ Examples using raylib text functionality, including sprite fonts loading/generat | [text_codepoints_loading](text/text_codepoints_loading.c) | text_codepoints_loading | ⭐⭐⭐☆ | 4.2 | 4.2 | [Ramon Santamaria](https://github.com/raysan5) | | [text_inline_styling](text/text_inline_styling.c) | text_inline_styling | ⭐⭐⭐☆ | 5.6-dev | 5.6-dev | [Wagner Barongello](https://github.com/SultansOfCode) | -### category: models [23] +### category: models [24] Examples using raylib models functionality, including models loading/generation and drawing, provided by raylib [models](../src/rmodels.c) module. @@ -174,6 +174,7 @@ Examples using raylib models functionality, including models loading/generation | [models_animation_gpu_skinning](models/models_animation_gpu_skinning.c) | models_animation_gpu_skinning | ⭐⭐⭐☆ | 4.5 | 4.5 | [Daniel Holden](https://github.com/orangeduck) | | [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) | ### category: shaders [29] diff --git a/examples/examples_list.txt b/examples/examples_list.txt index adaa12390..b5682123f 100644 --- a/examples/examples_list.txt +++ b/examples/examples_list.txt @@ -128,6 +128,7 @@ models;models_textured_cube;★★☆☆;4.5;4.5;2022;2025;"Ramon Santamaria";@r models;models_animation_gpu_skinning;★★★☆;4.5;4.5;2024;2025;"Daniel Holden";@orangeduck 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 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 shaders;shaders_shapes_textures;★★☆☆;1.7;3.7;2015;2025;"Ramon Santamaria";@raysan5 diff --git a/examples/models/models_basic_voxel.c b/examples/models/models_basic_voxel.c new file mode 100644 index 000000000..8df15d73d --- /dev/null +++ b/examples/models/models_basic_voxel.c @@ -0,0 +1,152 @@ +/******************************************************************************************* +* +* raylib [models] example - basic voxel +* +* Example complexity rating: [★★☆☆] 2/4 +* +* Example originally created with raylib 5.5, last time updated with raylib 5.5 +* +* Example contributed by Tim Little (@timlittle) 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 Tim Little (@timlittle) +* +********************************************************************************************/ + +#include "raylib.h" +#include "raymath.h" + +#define WORLD_SIZE 8 // Size of our voxel world (8x8x8 cubes) + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [models] example - basic voxel"); + + DisableCursor(); // Lock mouse to window center + + // Define the camera to look into our 3d world (first person) + Camera3D camera = { 0 }; + camera.position = (Vector3){ -2.0f, 0.0f, -2.0f }; // Camera position at ground level + camera.target = (Vector3){ 0.0f, 0.0f, 0.0f }; // Camera looking at point + camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Camera up vector + camera.fovy = 45.0f; // Camera field-of-view Y + camera.projection = CAMERA_PERSPECTIVE; // Camera projection type + + // Create a cube model + Mesh cubeMesh = GenMeshCube(1.0f, 1.0f, 1.0f); // Create a unit cube mesh + Model cubeModel = LoadModelFromMesh(cubeMesh); // Convert mesh to a model + cubeModel.materials[0].maps[MATERIAL_MAP_DIFFUSE].color = BEIGE; + + // Initialize voxel world - fill with voxels + bool voxels[WORLD_SIZE][WORLD_SIZE][WORLD_SIZE] = { false }; + for (int x = 0; x < WORLD_SIZE; x++) + { + for (int y = 0; y < WORLD_SIZE; y++) + { + for (int z = 0; z < WORLD_SIZE; z++) + { + voxels[x][y][z] = true; + } + } + } + + SetTargetFPS(60); + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + UpdateCamera(&camera, CAMERA_FIRST_PERSON); + + // Handle voxel removal with mouse click + if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) + { + // Cast a ray from the screen center (where crosshair would be) + Vector2 screenCenter = { screenWidth/2.0f, screenHeight/2.0f }; + Ray ray = GetMouseRay(screenCenter, camera); + + // Check ray collision with all voxels + bool voxelRemoved = false; + for (int x = 0; (x < WORLD_SIZE) && !voxelRemoved; x++) + { + for (int y = 0; (y < WORLD_SIZE) && !voxelRemoved; y++) + { + for (int z = 0; (z < WORLD_SIZE) && !voxelRemoved; z++) + { + if (!voxels[x][y][z]) continue; // Skip empty voxels + + // Build a bounding box for this voxel + Vector3 position = { x, y, z }; + BoundingBox box = { + (Vector3){ position.x - 0.5f, position.y - 0.5f, position.z - 0.5f }, + (Vector3){ position.x + 0.5f, position.y + 0.5f, position.z + 0.5f } + }; + + // Check ray-box collision + RayCollision collision = GetRayCollisionBox(ray, box); + if (collision.hit) + { + voxels[x][y][z] = false; // Remove this voxel + voxelRemoved = true; // Exit all loops + } + } + } + } + } + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + BeginMode3D(camera); + + DrawGrid(10, 1.0f); + + // Draw all voxels + for (int x = 0; x < WORLD_SIZE; x++) + { + for (int y = 0; y < WORLD_SIZE; y++) + { + for (int z = 0; z < WORLD_SIZE; z++) + { + if (!voxels[x][y][z]) continue; + + Vector3 position = { x, y, z }; + DrawModel(cubeModel, position, 1.0f, BEIGE); + DrawCubeWires(position, 1.0f, 1.0f, 1.0f, BLACK); + } + } + } + + EndMode3D(); + + DrawText("Left-click a voxel to remove it!", 10, 10, 20, DARKGRAY); + DrawText("WASD to move, mouse to look around", 10, 35, 10, GRAY); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + UnloadModel(cubeModel); + CloseWindow(); + //-------------------------------------------------------------------------------------- + + return 0; +} diff --git a/examples/models/models_basic_voxel.png b/examples/models/models_basic_voxel.png new file mode 100644 index 0000000000000000000000000000000000000000..8bbcaf8dae98aa01624392f07822e36f2f44a53d GIT binary patch literal 349583 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

D)bQt8=^%55 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¯=oYv~c#@#(mswRYT? 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

Tcf=}BV3J))r^4wjd0XKJ%z3Gk!MeR zs8;_t!4En+*pkb(=Js_%lKW>Tnu3@>XjF39_sXX=RK=h zUwD*^XkU0?>0QqveT5aRuVdKg{Ij%5IAz`GqK`#4fzH_ZaL(9`9KVf%P_o3xn&BoL z^C2L(rYtjjKOsfY6-?zD(5dn{O5 z$Ky+XXSR|X`N|8*`Dn(D)r381+WPHB!(3i2scf5nAwt`vXU(=*ZY3l5!HJxJ3EYMn z`?F^X*G&_>o?4YZom(kji5lXV8q1FG_7Q$<0ejWlyCa4x$d8)BMw`s@(;2SL_n)lUcHQ7^ zY!Yo;*j;|2Df$j))0-ug*K+rC1y<)fFq69iU6YeSgIlLPnKe}Ag!A^5?t|POM&@1s zT@Xmw01Ud?T=Ex3{8;)fW_87{?sGl1tJkURLiU(mN@% zjCdz$XV)Fg>nJfS$Tq49$YZZ0+XOAkI7xRvy-VU7Fo7H2i&ORPuv9C__A|7sh}1Ws zwYC(Eb$a-}%1bR%t|Tj0sL+{3bGFhe8pWFBFWiPNeRn@%5nCZGjoeVU$Azx9)bym2 zSSfE@$9N*Aa{^2Dr?nBbt<+DS`=$G@)z9rujZ-=tdJEP4PPVn1Dbczbfi(Lo5~>9V z)nv|ssQBBWqB`&5(;*a{OK=EEeMpMD9a3$7l6ekJ z0!?^Z0L2xoRA}7XWt(B_F!=a)p5dN(pwWIG?7{(>Lml5EkCIlp(S3zY_~UlTuGOF$~p{ppsbk zScRD^piHo;IlnWuEQ4CTB&}>fD`FFL&l1=`Bkcq2lC`;z_Kjg>)^f@}sRk16xc0xM zTwi|1(IW9)>_TEJQQY5Gt9--Avr#u`YRv`PS*MSP%(vd*z1F;0w0`_(=mQy>Fl7Rf zufQVd!gXmmWuxns`6P(8Qmybradjva)5299P@xi>&)M!eoy?*g^xfla8zU6px~ISC z3I0(y1zAEzg7se|T>ZC^5u#pfIM5)Pg*#heFLFZ@Vta4*a&P-{)77BL3;NIFsM)p&ixHjItIWuXAULcT3Apw1^TOgRn^J@s;iyQmx1y&Y7Y9_ zVRXWk6YZ~!F+&pui#$txik!M#?a%LL4&w+bVz#`n;)exS_(JyX0jx_ZP8GQA7Fcnr z38KqH7C86UGLW1Bi=0?EQvbBe@J|}BqUI#by9zWmr^v3P-qo7jFw+qDU#~S$6bs&s VXD-Jt1O447=QSRV7pQ@We*is``VRmA literal 0 HcmV?d00001 From 7383de3dea3037956710f2a8184665d7b925a883 Mon Sep 17 00:00:00 2001 From: Balamurugan R Date: Wed, 15 Oct 2025 23:00:37 +0530 Subject: [PATCH 114/167] feat(shapes): Add shapes_mouse_trail.c example and screenshot (#5246) Co-authored-by: Balamurugan R --- examples/shapes/shapes_mouse_trail.c | 106 +++++++++++++++++++++++++ examples/shapes/shapes_mouse_trail.png | Bin 0 -> 5525 bytes 2 files changed, 106 insertions(+) create mode 100644 examples/shapes/shapes_mouse_trail.c create mode 100644 examples/shapes/shapes_mouse_trail.png diff --git a/examples/shapes/shapes_mouse_trail.c b/examples/shapes/shapes_mouse_trail.c new file mode 100644 index 000000000..b1cb706f2 --- /dev/null +++ b/examples/shapes/shapes_mouse_trail.c @@ -0,0 +1,106 @@ +#include "raylib.h" +#include "raymath.h" + +/******************************************************************************************* +* +* raylib [shapes] example - Draw a mouse trail (position history) +* +* Example complexity rating: [★☆☆☆] 1/4 +* +* Example originally created with raylib 5.6 +* +* Example contributed by [Balamurugan R] (@[Bala050814]]) and reviewed by [Ray] (@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]) +* +********************************************************************************************/ + +// Define the maximum number of positions to store in the trail +#define MAX_TRAIL_LENGTH 30 + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [shapes] example - Draw a mouse trail"); + + // Array to store the history of mouse positions (our fixed-size queue) + Vector2 trailPositions[MAX_TRAIL_LENGTH] = { 0 }; + + SetTargetFPS(60); + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + Vector2 mousePosition = GetMousePosition(); + + // 1. 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) + trailPositions[0] = mousePosition; + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + 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 + 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) + { + // 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); + + // Size effect: oldest positions are smaller + float trailRadius = 15.0f * ratio; + + DrawCircleV(trailPositions[i], trailRadius, trailColor); + } + } + + // 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); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + + // No resources loaded, nothing to unload. + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} \ No newline at end of file diff --git a/examples/shapes/shapes_mouse_trail.png b/examples/shapes/shapes_mouse_trail.png new file mode 100644 index 0000000000000000000000000000000000000000..aa64efcdf420f0fa303aec119ce48dd5e9f20759 GIT binary patch literal 5525 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 Date: Wed, 15 Oct 2025 19:33:53 +0200 Subject: [PATCH 115/167] Added text alignment example (#5254) Co-authored-by: Ray --- examples/Makefile | 3 +- examples/Makefile.Web | 3 +- examples/README.md | 3 +- examples/examples_list.txt | 1 + examples/text/text_words_alignment.c | 130 +++++++++++++++++++++++++ examples/text/text_words_alignment.png | Bin 0 -> 15745 bytes 6 files changed, 137 insertions(+), 3 deletions(-) create mode 100644 examples/text/text_words_alignment.c create mode 100644 examples/text/text_words_alignment.png diff --git a/examples/Makefile b/examples/Makefile index 8b5faf634..69d100fdb 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -612,7 +612,8 @@ TEXT = \ text/text_sprite_fonts \ text/text_unicode_emojis \ text/text_unicode_ranges \ - text/text_writing_anim + text/text_writing_anim \ + text/text_words_alignment MODELS = \ models/models_animation_gpu_skinning \ diff --git a/examples/Makefile.Web b/examples/Makefile.Web index 510725b6e..933ea3499 100644 --- a/examples/Makefile.Web +++ b/examples/Makefile.Web @@ -612,7 +612,8 @@ TEXT = \ text/text_sprite_fonts \ text/text_unicode_emojis \ text/text_unicode_ranges \ - text/text_writing_anim + text/text_writing_anim \ + text/text_words_alignment MODELS = \ models/models_animation_gpu_skinning \ diff --git a/examples/README.md b/examples/README.md index 3468ff34a..9757cea60 100644 --- a/examples/README.md +++ b/examples/README.md @@ -133,7 +133,7 @@ Examples using raylib textures functionality, including image/textures loading/g | [textures_image_rotate](textures/textures_image_rotate.c) | textures_image_rotate | ⭐⭐☆☆ | 1.0 | 1.0 | [Ramon Santamaria](https://github.com/raysan5) | | [textures_textured_curve](textures/textures_textured_curve.c) | textures_textured_curve | ⭐⭐⭐☆ | 4.5 | 4.5 | [Jeffery Myers](https://github.com/JeffM2501) | -### category: text [14] +### category: text [15] Examples using raylib text functionality, including sprite fonts loading/generation and text drawing, provided by raylib [text](../src/rtext.c) module. @@ -153,6 +153,7 @@ Examples using raylib text functionality, including sprite fonts loading/generat | [text_3d_drawing](text/text_3d_drawing.c) | text_3d_drawing | ⭐⭐⭐⭐️ | 3.5 | 4.0 | [Vlad Adrian](https://github.com/demizdor) | | [text_codepoints_loading](text/text_codepoints_loading.c) | text_codepoints_loading | ⭐⭐⭐☆ | 4.2 | 4.2 | [Ramon Santamaria](https://github.com/raysan5) | | [text_inline_styling](text/text_inline_styling.c) | text_inline_styling | ⭐⭐⭐☆ | 5.6-dev | 5.6-dev | [Wagner Barongello](https://github.com/SultansOfCode) | +| [text_words_alignment](text/text_words_alignment.c) | text_words_alignment | ⭐⭐⭐☆ | 5.6-dev | 5.6-dev | [JP Mortiboys](https://github.com/themushroompirates) | ### category: models [25] diff --git a/examples/examples_list.txt b/examples/examples_list.txt index ed904d6f1..9770975fb 100644 --- a/examples/examples_list.txt +++ b/examples/examples_list.txt @@ -114,6 +114,7 @@ text;text_unicode_ranges;★★★★;5.5;5.6;2025;2025;"Vadim Gunko";@GuvaCode text;text_3d_drawing;★★★★;3.5;4.0;2021;2025;"Vlad Adrian";@demizdor text;text_codepoints_loading;★★★☆;4.2;4.2;2022;2025;"Ramon Santamaria";@raysan5 text;text_inline_styling;★★★☆;5.6-dev;5.6-dev;2025;2025;"Wagner Barongello";@SultansOfCode +text;text_words_alignment;★☆☆☆;5.6-dev;5.6-dev;2025;2025;"JP Mortiboys";@themushroompirates models;models_animation_playing;★★☆☆;2.5;3.5;2019;2025;"Culacant";@culacant models;models_billboard_rendering;★★★☆;1.3;3.5;2015;2025;"Ramon Santamaria";@raysan5 models;models_box_collisions;★☆☆☆;1.3;3.5;2015;2025;"Ramon Santamaria";@raysan5 diff --git a/examples/text/text_words_alignment.c b/examples/text/text_words_alignment.c new file mode 100644 index 000000000..0f012ab75 --- /dev/null +++ b/examples/text/text_words_alignment.c @@ -0,0 +1,130 @@ +/******************************************************************************************* +* +* raylib [text] example - text alignment +* +* Example complexity rating: [★☆☆☆] 1/4 +* +* Example originally created with raylib 5.0, last time updated with raylib 5.5 +* +* Example contributed by JP Mortiboys (@themushroompirates) 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 JP Mortiboys (@themushroompirates) +* +********************************************************************************************/ + +#include "raylib.h" + +#include "raymath.h" // Required for: Lerp() + +typedef enum TextAlignment { + TEXT_ALIGN_LEFT = 0, + TEXT_ALIGN_TOP = 0, + TEXT_ALIGN_CENTRE = 1, + TEXT_ALIGN_MIDDLE = 1, + TEXT_ALIGN_RIGHT = 2, + TEXT_ALIGN_BOTTOM = 2 +} TextAlignment; + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [text] example - text alignment"); + + // Define the rectangle we will draw the text in + Rectangle textContainerRect = (Rectangle){ screenWidth/2-screenWidth/4, screenHeight/2-screenHeight/3, screenWidth/2, screenHeight*2/3 }; + + // Some text to display the current alignment + const char *textAlignNameH[] = { "Left", "Centre", "Right" }; + const char *textAlignNameV[] = { "Top", "Middle", "Bottom" }; + + // Define the text we're going to draw in the rectangle + int wordIndex = 0; + int wordCount = 0; + char **words = TextSplit("raylib is a simple and easy-to-use library to enjoy videogames programming", ' ', &wordCount); + + // Initialize the font size we're going to use + int fontSize = 40; + + // And of course the font... + Font font = GetFontDefault(); + + // Intialize the alignment variables + TextAlignment hAlign = TEXT_ALIGN_CENTRE; + TextAlignment vAlign = TEXT_ALIGN_MIDDLE; + + 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 + //---------------------------------------------------------------------------------- + + if (IsKeyPressed(KEY_LEFT)) { + hAlign = hAlign - 1; + if (hAlign < 0) hAlign = 0; + } + if (IsKeyPressed(KEY_RIGHT)) { + hAlign = hAlign + 1; + if (hAlign > 2) hAlign = 2; + } + if (IsKeyPressed(KEY_UP)) { + vAlign = vAlign - 1; + if (vAlign < 0) vAlign = 0; + } + if (IsKeyPressed(KEY_DOWN)) { + vAlign = vAlign + 1; + if (vAlign > 2) vAlign = 2; + } + + // One word per second + wordIndex = (int)GetTime() % wordCount; + + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(DARKBLUE); + + DrawText("Use Arrow Keys to change the text alignment", 20, 20, 20, LIGHTGRAY); + DrawText(TextFormat("Alignment: Horizontal = %s, Vertical = %s", textAlignNameH[hAlign], textAlignNameV[vAlign]), 20, 40, 20, LIGHTGRAY); + + DrawRectangleRec(textContainerRect, BLUE); + + // Get the size of the text to draw + Vector2 textSize = MeasureTextEx(font, words[wordIndex], fontSize, fontSize*.1f); + + // Calculate the top-left text position based on the rectangle and alignment + Vector2 textPos = (Vector2) { + textContainerRect.x + Lerp(0.0f, textContainerRect.width - textSize.x, ((float)hAlign) * 0.5f), + textContainerRect.y + Lerp(0.0f, textContainerRect.height - textSize.y, ((float)vAlign) * 0.5f) + }; + + // Draw the text + DrawTextEx(font, words[wordIndex], textPos, fontSize, fontSize*.1f, RAYWHITE); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} \ No newline at end of file diff --git a/examples/text/text_words_alignment.png b/examples/text/text_words_alignment.png new file mode 100644 index 0000000000000000000000000000000000000000..ae0892381437200ccf3fd6e74005250d658e2282 GIT binary patch literal 15745 zcmeHOdsI?+9tUNROq3p$$_SEfR!+t!RvS`^idci1S$PZDuFpBx= z_?Ee8{Avzr>I2M@$_phO^mJpB5VR=|JQji20XJuGMFgUS-c$!8k!6;~0EzgYN1>X!qrm&% zEnd1r5trD;32K$v*|7Tw4^~r0vG$?6OK;egJzdk@Y;FI>#5A^<+-W@YGUQzSLzfEu zyeex7C9~%j>4V3rilCztq~=*t$(pH|Eh4yF#<0!NTp7kH#wMEdNLwO{W+n(6a-8$M zwU>O|R6O^Xy3&9W1bB{YG(w$^C$ga5yA;#j`bY{QJieazD7xn!4_WRb`;e~nl zq@^R$4oZ3RGsWE|j@>R*C6ynjRv0yKEbzcxV$7yE2){-dRZ^^qGlnr1@2s6{QY{Cl zEAp8AH=eN~M)o8&Y`BHmKj+LYLU(xBO_Lv=pOi}Op2+rHAXkEAogi+jisch(=K6!XayeW`^BMS1bGhpRQ^>!&V9F<3bw z;+V+W)N}Y}uJ3 z80P*iHe<7Bbeq{{n%QjBvlV54=ns&Wl+O;eoysgByibM|2{x~7%kO&mcg0txp#x-J zNB`~{o$OoJC2OxI4||@fD(;6DZF*~bDGETs(YKc^!C}YIeF_lC(Ml8=4tHSZQh zUlkSX3mQCFEe+{X4UU**e*DPrFF%#yW&gbz7*!>CR+q8 z?3xYf0*~9XOY%9k@yIx!yfp~r9c*X-xdV1nr+y+=Y*&P#c7E;P-&*%5eRVT`buI0z zQ*}9QxT!9$`JedH1D;{uVhZ{j8V8bpPU^5eU*2pfemP%UTOf;a_Klt`eub@gHnZxH zM_Bm=@|q_dB6=xn!R5!brT_+bc2CB=c4AthQX1f^)KZbH;qeE00dS^iJ2JU_mP5qe z@45BJysGX~wlOw;WA)dVvbrB%w(baF9X2Bt?Q9Ue#^uF`kNU#`{GNoR_A zdP$>mPZwp+INLVIXp}6p3%E?yqK^x>zGX$XM-Q@jx~sApvJj{_<{kt>vjv(QBN3+(~la0MXx* z-}`K5U_2^?(dOp#t#n=6(_B1%?Z}@4o9}btx2Z;bo2)9vFtB1Ysx-$0c_IuR=5M0* z7eyfq^WG674Z>`WK3Hrj?@X?R_u!Z(O_&v3^|1TF0_;xx!qHod1I3lUAr5)FE@(Yk zV{xsUk3T;U9dx+yd3OHwhK-pleAB9tv`asY3AL536d)8JT~IFGArv4KG{z&u1&9j} z7j&1hP(?r$0aXN45tAEpkS;*F@ZabHJXd;dg1MN0N;vCOx)Bq52Y>aRRq-+ZSG27< zb~{^b=05}V*Fn87-bcH!fc+<>Ol;`VfvyT=fk?Vi>pYUwk^BJGm-*Db@Z?B1bM+K& z{CvaE?{TQO0-rvdQCR04*WM~ZF@H>PEJu1`%eWWJnWJu0a6!CbRbPDip0slAkJ?ZD zfMuW=!sR4JICM;JZKG%imtB*awMc%!A^%IQ)%ZumM09s!m%n&w#yG6?xaxqWjM`_BT6*RcqVaxlWzRaS$`kIN`a71EV)KDRj!H1$_wt|m>SHpYo(A1@sx zDxez~cme{aaZH+`y6Ng!dVOa^u8vCVTtZO77d65tpPL+aAQ@SP2?bX?t+y)!fO(?Q z>}xC-zo%8IgmMr!A*DPg1nq^?jA5pwjs&IZs6{zV%(k|9pv?QPytIXvKFvvgGhqn$ zX#z1W{3fSX+gT8Ls2%$sKW!dRp@flM~3%c7)p^AVi z0;&k8A|`J`hjanb1xOblUHHG$1=t-@ zsFkL&DfP7;%%rorWokF?_3!BBK_RI8F6DbvP$D1{l&{f2C_pG^lo;Xy#07{8y6+eN f@f86yqF}HCWt?{TR#*%0YBkKu!`uA~m7Vx6f{qQv literal 0 HcmV?d00001 From 1c39d47b5b517d06b997bd68f05cc20cb480f6f2 Mon Sep 17 00:00:00 2001 From: themushroompirates <59015901+themushroompirates@users.noreply.github.com> Date: Wed, 15 Oct 2025 19:34:39 +0200 Subject: [PATCH 116/167] Added simple starfield example (#5255) --- examples/Makefile | 1 + examples/Makefile.Web | 1 + examples/README.md | 3 +- examples/shapes/shapes_starfield.c | 143 +++++++++++++++++++++++++++ examples/shapes/shapes_starfield.png | Bin 0 -> 20913 bytes 5 files changed, 147 insertions(+), 1 deletion(-) create mode 100644 examples/shapes/shapes_starfield.c create mode 100644 examples/shapes/shapes_starfield.png diff --git a/examples/Makefile b/examples/Makefile index 69d100fdb..523339d06 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -566,6 +566,7 @@ SHAPES = \ shapes/shapes_ring_drawing \ shapes/shapes_rounded_rectangle_drawing \ shapes/shapes_splines_drawing \ + shapes/shapes_starfield \ shapes/shapes_top_down_lights \ shapes/shapes_triangle_strip \ shapes/shapes_vector_angle diff --git a/examples/Makefile.Web b/examples/Makefile.Web index 933ea3499..c5e9138f5 100644 --- a/examples/Makefile.Web +++ b/examples/Makefile.Web @@ -566,6 +566,7 @@ SHAPES = \ shapes/shapes_ring_drawing \ shapes/shapes_rounded_rectangle_drawing \ shapes/shapes_splines_drawing \ + shapes/shapes_starfield \ shapes/shapes_top_down_lights \ shapes/shapes_triangle_strip \ shapes/shapes_vector_angle diff --git a/examples/README.md b/examples/README.md index 9757cea60..16e44aa2b 100644 --- a/examples/README.md +++ b/examples/README.md @@ -67,7 +67,7 @@ Examples using raylib[core](../src/rcore.c) platform functionality like window c | [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) | -### category: shapes [26] +### category: shapes [27] Examples using raylib shapes drawing functionality, provided by raylib [shapes](../src/rshapes.c) module. @@ -93,6 +93,7 @@ Examples using raylib shapes drawing functionality, provided by raylib [shapes]( | [shapes_top_down_lights](shapes/shapes_top_down_lights.c) | shapes_top_down_lights | ⭐⭐⭐⭐️ | 4.2 | 4.2 | [Jeffery Myers](https://github.com/JeffM2501) | | [shapes_rectangle_advanced](shapes/shapes_rectangle_advanced.c) | shapes_rectangle_advanced | ⭐⭐⭐⭐️ | 5.5 | 5.5 | [Everton Jr.](https://github.com/evertonse) | | [shapes_splines_drawing](shapes/shapes_splines_drawing.c) | shapes_splines_drawing | ⭐⭐⭐☆ | 5.0 | 5.0 | [Ramon Santamaria](https://github.com/raysan5) | +| [shapes_starfield](shapes/shapes_starfield.c) | shapes_starfield | ⭐⭐⭐☆ | 5.5 | 5.5 | [JP Mortiboys](https://github.com/themushroompirates) | | [shapes_digital_clock](shapes/shapes_digital_clock.c) | shapes_digital_clock | ⭐⭐⭐⭐️ | 5.5 | 5.6 | [Hamza RAHAL](https://github.com/hmz-rhl) | | [shapes_double_pendulum](shapes/shapes_double_pendulum.c) | shapes_double_pendulum | ⭐⭐☆☆ | 5.5 | 5.5 | [JoeCheong](https://github.com/Joecheong2006) | | [shapes_dashed_line](shapes/shapes_dashed_line.c) | shapes_dashed_line | ⭐☆☆☆ | 5.5 | 5.5 | [Luís Almeida](https://github.com/luis605) | diff --git a/examples/shapes/shapes_starfield.c b/examples/shapes/shapes_starfield.c new file mode 100644 index 000000000..457912dec --- /dev/null +++ b/examples/shapes/shapes_starfield.c @@ -0,0 +1,143 @@ +/******************************************************************************************* +* +* raylib [shapes] example - simple starfield +* +* Example complexity rating: [★☆☆☆] 1/4 +* +* Example originally created with raylib 5.5 +* +* Example contributed by JP Mortiboys (@themushroompirates) 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 JP Mortiboys (@themushroompirates) +* +********************************************************************************************/ + +#include "raylib.h" + +#include "raymath.h" // Required for: Lerp() + +#define STAR_COUNT 420 + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [shapes] example - starfield"); + + Color bgColor = ColorLerp(DARKBLUE, BLACK, 0.69f); + + // Speed at which we fly forward + float speed = 10.0f/9.0f; + + // We're either drawing lines or circles + bool drawLines = true; + + Vector3 stars[STAR_COUNT] = { 0 }; + 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); + stars[i].z = 1.0f; + } + + 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 + //---------------------------------------------------------------------------------- + + // 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; + } + } + + // Toggle lines / points with space bar + if (IsKeyPressed(KEY_SPACE)) { + drawLines = !drawLines; + } + + float dt = GetFrameTime(); + for (int i = 0; i < STAR_COUNT; i++) { + // Update star's timer + 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, + }; + // 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); + stars[i].z = 1.0f; + } + } + + + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(bgColor); + + 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) { + // Calculate the screen position of the old point + Vector2 startPos = (Vector2) { + screenWidth*.5f + stars[i].x / t, + screenHeight*.5f + stars[i].y / t, + }; + // Draw a line connecting the old point to the current point + DrawLineV(startPos, starsScreenPos[i], RAYWHITE); + } + } + 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); + } + } + + 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 + //-------------------------------------------------------------------------------------- + + return 0; +} \ No newline at end of file diff --git a/examples/shapes/shapes_starfield.png b/examples/shapes/shapes_starfield.png new file mode 100644 index 0000000000000000000000000000000000000000..6903f222b5e0e25b22be5717b79da5b66f6503d5 GIT binary patch literal 20913 zcmaKUdpuP6|NqRGWoR(n$1u#Ki!RD#Tym)~Q)eWkv~6p0?VjlIs zKO_d+Vjk-@#wTQ45ohUe|(UoxIqOv=D)ur9*E*vIceD_@1 zHKF*vvkvlX^S|b!4S#XwV7lS|`lfH2!%0DbH$_WHzwgp2MZcPQJsOyJ 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 Date: Wed, 15 Oct 2025 19:35:59 +0200 Subject: [PATCH 117/167] Update parse_api.yml --- .github/workflows/parse_api.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/parse_api.yml b/.github/workflows/parse_api.yml index ce7cb9f9a..e095e4a55 100644 --- a/.github/workflows/parse_api.yml +++ b/.github/workflows/parse_api.yml @@ -14,7 +14,7 @@ jobs: - uses: actions/checkout@v4 - name: Update parse files - working-directory: tools/parser + working-directory: tools/rlparser run: | make raylib_api mv raylib_api.* output @@ -22,7 +22,7 @@ jobs: - name: Diff parse files id: diff run: | - git add -N tools/parser + git add -N tools/rlparser git diff --name-only --exit-code continue-on-error: true From b020bed2b3388d7a6d2d014bee28ef3a1ff99de7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 15 Oct 2025 17:36:24 +0000 Subject: [PATCH 118/167] rlparser: update raylib_api.* by CI --- tools/rlparser/output/raylib_api.json | 15 + tools/rlparser/output/raylib_api.lua | 9 + tools/rlparser/output/raylib_api.txt | 884 +++++++++++++------------- tools/rlparser/output/raylib_api.xml | 6 +- tools/rlparser/rlparser | Bin 0 -> 43144 bytes 5 files changed, 474 insertions(+), 440 deletions(-) create mode 100755 tools/rlparser/rlparser diff --git a/tools/rlparser/output/raylib_api.json b/tools/rlparser/output/raylib_api.json index 9714d5d05..c0bc88681 100644 --- a/tools/rlparser/output/raylib_api.json +++ b/tools/rlparser/output/raylib_api.json @@ -4851,6 +4851,21 @@ } ] }, + { + "name": "ComputeSHA256", + "description": "Compute SHA256 hash code, returns static int[8] (32 bytes)", + "returnType": "unsigned int *", + "params": [ + { + "type": "unsigned char *", + "name": "data" + }, + { + "type": "int", + "name": "dataSize" + } + ] + }, { "name": "LoadAutomationEventList", "description": "Load automation events list from file, NULL for empty list, capacity = MAX_AUTOMATION_EVENTS", diff --git a/tools/rlparser/output/raylib_api.lua b/tools/rlparser/output/raylib_api.lua index 75fd06373..5cb3c1d55 100644 --- a/tools/rlparser/output/raylib_api.lua +++ b/tools/rlparser/output/raylib_api.lua @@ -4296,6 +4296,15 @@ return { {type = "int", name = "dataSize"} } }, + { + name = "ComputeSHA256", + description = "Compute SHA256 hash code, returns static int[8] (32 bytes)", + returnType = "unsigned int *", + params = { + {type = "unsigned char *", name = "data"}, + {type = "int", name = "dataSize"} + } + }, { name = "LoadAutomationEventList", description = "Load automation events list from file, NULL for empty list, capacity = MAX_AUTOMATION_EVENTS", diff --git a/tools/rlparser/output/raylib_api.txt b/tools/rlparser/output/raylib_api.txt index 849a97a56..9be8e517c 100644 --- a/tools/rlparser/output/raylib_api.txt +++ b/tools/rlparser/output/raylib_api.txt @@ -993,7 +993,7 @@ Callback 006: AudioCallback() (2 input parameters) Param[1]: bufferData (type: void *) Param[2]: frames (type: unsigned int) -Functions found: 596 +Functions found: 597 Function 001: InitWindow() (3 input parameters) Name: InitWindow @@ -1851,148 +1851,154 @@ Function 158: ComputeSHA1() (2 input parameters) Description: Compute SHA1 hash code, returns static int[5] (20 bytes) Param[1]: data (type: unsigned char *) Param[2]: dataSize (type: int) -Function 159: LoadAutomationEventList() (1 input parameters) +Function 159: ComputeSHA256() (2 input parameters) + Name: ComputeSHA256 + Return type: unsigned int * + Description: Compute SHA256 hash code, returns static int[8] (32 bytes) + Param[1]: data (type: unsigned char *) + Param[2]: dataSize (type: int) +Function 160: LoadAutomationEventList() (1 input parameters) Name: LoadAutomationEventList Return type: AutomationEventList Description: Load automation events list from file, NULL for empty list, capacity = MAX_AUTOMATION_EVENTS Param[1]: fileName (type: const char *) -Function 160: UnloadAutomationEventList() (1 input parameters) +Function 161: UnloadAutomationEventList() (1 input parameters) Name: UnloadAutomationEventList Return type: void Description: Unload automation events list from file Param[1]: list (type: AutomationEventList) -Function 161: ExportAutomationEventList() (2 input parameters) +Function 162: ExportAutomationEventList() (2 input parameters) Name: ExportAutomationEventList Return type: bool Description: Export automation events list as text file Param[1]: list (type: AutomationEventList) Param[2]: fileName (type: const char *) -Function 162: SetAutomationEventList() (1 input parameters) +Function 163: SetAutomationEventList() (1 input parameters) Name: SetAutomationEventList Return type: void Description: Set automation event list to record to Param[1]: list (type: AutomationEventList *) -Function 163: SetAutomationEventBaseFrame() (1 input parameters) +Function 164: SetAutomationEventBaseFrame() (1 input parameters) Name: SetAutomationEventBaseFrame Return type: void Description: Set automation event internal base frame to start recording Param[1]: frame (type: int) -Function 164: StartAutomationEventRecording() (0 input parameters) +Function 165: StartAutomationEventRecording() (0 input parameters) Name: StartAutomationEventRecording Return type: void Description: Start recording automation events (AutomationEventList must be set) No input parameters -Function 165: StopAutomationEventRecording() (0 input parameters) +Function 166: StopAutomationEventRecording() (0 input parameters) Name: StopAutomationEventRecording Return type: void Description: Stop recording automation events No input parameters -Function 166: PlayAutomationEvent() (1 input parameters) +Function 167: PlayAutomationEvent() (1 input parameters) Name: PlayAutomationEvent Return type: void Description: Play a recorded automation event Param[1]: event (type: AutomationEvent) -Function 167: IsKeyPressed() (1 input parameters) +Function 168: IsKeyPressed() (1 input parameters) Name: IsKeyPressed Return type: bool Description: Check if a key has been pressed once Param[1]: key (type: int) -Function 168: IsKeyPressedRepeat() (1 input parameters) +Function 169: IsKeyPressedRepeat() (1 input parameters) Name: IsKeyPressedRepeat Return type: bool Description: Check if a key has been pressed again Param[1]: key (type: int) -Function 169: IsKeyDown() (1 input parameters) +Function 170: IsKeyDown() (1 input parameters) Name: IsKeyDown Return type: bool Description: Check if a key is being pressed Param[1]: key (type: int) -Function 170: IsKeyReleased() (1 input parameters) +Function 171: IsKeyReleased() (1 input parameters) Name: IsKeyReleased Return type: bool Description: Check if a key has been released once Param[1]: key (type: int) -Function 171: IsKeyUp() (1 input parameters) +Function 172: IsKeyUp() (1 input parameters) Name: IsKeyUp Return type: bool Description: Check if a key is NOT being pressed Param[1]: key (type: int) -Function 172: GetKeyPressed() (0 input parameters) +Function 173: GetKeyPressed() (0 input parameters) Name: GetKeyPressed Return type: int Description: Get key pressed (keycode), call it multiple times for keys queued, returns 0 when the queue is empty No input parameters -Function 173: GetCharPressed() (0 input parameters) +Function 174: GetCharPressed() (0 input parameters) Name: GetCharPressed Return type: int Description: Get char pressed (unicode), call it multiple times for chars queued, returns 0 when the queue is empty No input parameters -Function 174: GetKeyName() (1 input parameters) +Function 175: GetKeyName() (1 input parameters) Name: GetKeyName Return type: const char * Description: Get name of a QWERTY key on the current keyboard layout (eg returns string 'q' for KEY_A on an AZERTY keyboard) Param[1]: key (type: int) -Function 175: SetExitKey() (1 input parameters) +Function 176: SetExitKey() (1 input parameters) Name: SetExitKey Return type: void Description: Set a custom key to exit program (default is ESC) Param[1]: key (type: int) -Function 176: IsGamepadAvailable() (1 input parameters) +Function 177: IsGamepadAvailable() (1 input parameters) Name: IsGamepadAvailable Return type: bool Description: Check if a gamepad is available Param[1]: gamepad (type: int) -Function 177: GetGamepadName() (1 input parameters) +Function 178: GetGamepadName() (1 input parameters) Name: GetGamepadName Return type: const char * Description: Get gamepad internal name id Param[1]: gamepad (type: int) -Function 178: IsGamepadButtonPressed() (2 input parameters) +Function 179: IsGamepadButtonPressed() (2 input parameters) Name: IsGamepadButtonPressed Return type: bool Description: Check if a gamepad button has been pressed once Param[1]: gamepad (type: int) Param[2]: button (type: int) -Function 179: IsGamepadButtonDown() (2 input parameters) +Function 180: IsGamepadButtonDown() (2 input parameters) Name: IsGamepadButtonDown Return type: bool Description: Check if a gamepad button is being pressed Param[1]: gamepad (type: int) Param[2]: button (type: int) -Function 180: IsGamepadButtonReleased() (2 input parameters) +Function 181: IsGamepadButtonReleased() (2 input parameters) Name: IsGamepadButtonReleased Return type: bool Description: Check if a gamepad button has been released once Param[1]: gamepad (type: int) Param[2]: button (type: int) -Function 181: IsGamepadButtonUp() (2 input parameters) +Function 182: IsGamepadButtonUp() (2 input parameters) Name: IsGamepadButtonUp Return type: bool Description: Check if a gamepad button is NOT being pressed Param[1]: gamepad (type: int) Param[2]: button (type: int) -Function 182: GetGamepadButtonPressed() (0 input parameters) +Function 183: GetGamepadButtonPressed() (0 input parameters) Name: GetGamepadButtonPressed Return type: int Description: Get the last gamepad button pressed No input parameters -Function 183: GetGamepadAxisCount() (1 input parameters) +Function 184: GetGamepadAxisCount() (1 input parameters) Name: GetGamepadAxisCount Return type: int Description: Get axis count for a gamepad Param[1]: gamepad (type: int) -Function 184: GetGamepadAxisMovement() (2 input parameters) +Function 185: GetGamepadAxisMovement() (2 input parameters) Name: GetGamepadAxisMovement Return type: float Description: Get movement value for a gamepad axis Param[1]: gamepad (type: int) Param[2]: axis (type: int) -Function 185: SetGamepadMappings() (1 input parameters) +Function 186: SetGamepadMappings() (1 input parameters) Name: SetGamepadMappings Return type: int Description: Set internal gamepad mappings (SDL_GameControllerDB) Param[1]: mappings (type: const char *) -Function 186: SetGamepadVibration() (4 input parameters) +Function 187: SetGamepadVibration() (4 input parameters) Name: SetGamepadVibration Return type: void Description: Set gamepad vibration for both motors (duration in seconds) @@ -2000,151 +2006,151 @@ Function 186: SetGamepadVibration() (4 input parameters) Param[2]: leftMotor (type: float) Param[3]: rightMotor (type: float) Param[4]: duration (type: float) -Function 187: IsMouseButtonPressed() (1 input parameters) +Function 188: IsMouseButtonPressed() (1 input parameters) Name: IsMouseButtonPressed Return type: bool Description: Check if a mouse button has been pressed once Param[1]: button (type: int) -Function 188: IsMouseButtonDown() (1 input parameters) +Function 189: IsMouseButtonDown() (1 input parameters) Name: IsMouseButtonDown Return type: bool Description: Check if a mouse button is being pressed Param[1]: button (type: int) -Function 189: IsMouseButtonReleased() (1 input parameters) +Function 190: IsMouseButtonReleased() (1 input parameters) Name: IsMouseButtonReleased Return type: bool Description: Check if a mouse button has been released once Param[1]: button (type: int) -Function 190: IsMouseButtonUp() (1 input parameters) +Function 191: IsMouseButtonUp() (1 input parameters) Name: IsMouseButtonUp Return type: bool Description: Check if a mouse button is NOT being pressed Param[1]: button (type: int) -Function 191: GetMouseX() (0 input parameters) +Function 192: GetMouseX() (0 input parameters) Name: GetMouseX Return type: int Description: Get mouse position X No input parameters -Function 192: GetMouseY() (0 input parameters) +Function 193: GetMouseY() (0 input parameters) Name: GetMouseY Return type: int Description: Get mouse position Y No input parameters -Function 193: GetMousePosition() (0 input parameters) +Function 194: GetMousePosition() (0 input parameters) Name: GetMousePosition Return type: Vector2 Description: Get mouse position XY No input parameters -Function 194: GetMouseDelta() (0 input parameters) +Function 195: GetMouseDelta() (0 input parameters) Name: GetMouseDelta Return type: Vector2 Description: Get mouse delta between frames No input parameters -Function 195: SetMousePosition() (2 input parameters) +Function 196: SetMousePosition() (2 input parameters) Name: SetMousePosition Return type: void Description: Set mouse position XY Param[1]: x (type: int) Param[2]: y (type: int) -Function 196: SetMouseOffset() (2 input parameters) +Function 197: SetMouseOffset() (2 input parameters) Name: SetMouseOffset Return type: void Description: Set mouse offset Param[1]: offsetX (type: int) Param[2]: offsetY (type: int) -Function 197: SetMouseScale() (2 input parameters) +Function 198: SetMouseScale() (2 input parameters) Name: SetMouseScale Return type: void Description: Set mouse scaling Param[1]: scaleX (type: float) Param[2]: scaleY (type: float) -Function 198: GetMouseWheelMove() (0 input parameters) +Function 199: GetMouseWheelMove() (0 input parameters) Name: GetMouseWheelMove Return type: float Description: Get mouse wheel movement for X or Y, whichever is larger No input parameters -Function 199: GetMouseWheelMoveV() (0 input parameters) +Function 200: GetMouseWheelMoveV() (0 input parameters) Name: GetMouseWheelMoveV Return type: Vector2 Description: Get mouse wheel movement for both X and Y No input parameters -Function 200: SetMouseCursor() (1 input parameters) +Function 201: SetMouseCursor() (1 input parameters) Name: SetMouseCursor Return type: void Description: Set mouse cursor Param[1]: cursor (type: int) -Function 201: GetTouchX() (0 input parameters) +Function 202: GetTouchX() (0 input parameters) Name: GetTouchX Return type: int Description: Get touch position X for touch point 0 (relative to screen size) No input parameters -Function 202: GetTouchY() (0 input parameters) +Function 203: GetTouchY() (0 input parameters) Name: GetTouchY Return type: int Description: Get touch position Y for touch point 0 (relative to screen size) No input parameters -Function 203: GetTouchPosition() (1 input parameters) +Function 204: GetTouchPosition() (1 input parameters) Name: GetTouchPosition Return type: Vector2 Description: Get touch position XY for a touch point index (relative to screen size) Param[1]: index (type: int) -Function 204: GetTouchPointId() (1 input parameters) +Function 205: GetTouchPointId() (1 input parameters) Name: GetTouchPointId Return type: int Description: Get touch point identifier for given index Param[1]: index (type: int) -Function 205: GetTouchPointCount() (0 input parameters) +Function 206: GetTouchPointCount() (0 input parameters) Name: GetTouchPointCount Return type: int Description: Get number of touch points No input parameters -Function 206: SetGesturesEnabled() (1 input parameters) +Function 207: SetGesturesEnabled() (1 input parameters) Name: SetGesturesEnabled Return type: void Description: Enable a set of gestures using flags Param[1]: flags (type: unsigned int) -Function 207: IsGestureDetected() (1 input parameters) +Function 208: IsGestureDetected() (1 input parameters) Name: IsGestureDetected Return type: bool Description: Check if a gesture have been detected Param[1]: gesture (type: unsigned int) -Function 208: GetGestureDetected() (0 input parameters) +Function 209: GetGestureDetected() (0 input parameters) Name: GetGestureDetected Return type: int Description: Get latest detected gesture No input parameters -Function 209: GetGestureHoldDuration() (0 input parameters) +Function 210: GetGestureHoldDuration() (0 input parameters) Name: GetGestureHoldDuration Return type: float Description: Get gesture hold time in seconds No input parameters -Function 210: GetGestureDragVector() (0 input parameters) +Function 211: GetGestureDragVector() (0 input parameters) Name: GetGestureDragVector Return type: Vector2 Description: Get gesture drag vector No input parameters -Function 211: GetGestureDragAngle() (0 input parameters) +Function 212: GetGestureDragAngle() (0 input parameters) Name: GetGestureDragAngle Return type: float Description: Get gesture drag angle No input parameters -Function 212: GetGesturePinchVector() (0 input parameters) +Function 213: GetGesturePinchVector() (0 input parameters) Name: GetGesturePinchVector Return type: Vector2 Description: Get gesture pinch delta No input parameters -Function 213: GetGesturePinchAngle() (0 input parameters) +Function 214: GetGesturePinchAngle() (0 input parameters) Name: GetGesturePinchAngle Return type: float Description: Get gesture pinch angle No input parameters -Function 214: UpdateCamera() (2 input parameters) +Function 215: UpdateCamera() (2 input parameters) Name: UpdateCamera Return type: void Description: Update camera position for selected mode Param[1]: camera (type: Camera *) Param[2]: mode (type: int) -Function 215: UpdateCameraPro() (4 input parameters) +Function 216: UpdateCameraPro() (4 input parameters) Name: UpdateCameraPro Return type: void Description: Update camera movement/rotation @@ -2152,36 +2158,36 @@ Function 215: UpdateCameraPro() (4 input parameters) Param[2]: movement (type: Vector3) Param[3]: rotation (type: Vector3) Param[4]: zoom (type: float) -Function 216: SetShapesTexture() (2 input parameters) +Function 217: SetShapesTexture() (2 input parameters) Name: SetShapesTexture Return type: void Description: Set texture and rectangle to be used on shapes drawing Param[1]: texture (type: Texture2D) Param[2]: source (type: Rectangle) -Function 217: GetShapesTexture() (0 input parameters) +Function 218: GetShapesTexture() (0 input parameters) Name: GetShapesTexture Return type: Texture2D Description: Get texture that is used for shapes drawing No input parameters -Function 218: GetShapesTextureRectangle() (0 input parameters) +Function 219: GetShapesTextureRectangle() (0 input parameters) Name: GetShapesTextureRectangle Return type: Rectangle Description: Get texture source rectangle that is used for shapes drawing No input parameters -Function 219: DrawPixel() (3 input parameters) +Function 220: DrawPixel() (3 input parameters) Name: DrawPixel Return type: void Description: Draw a pixel using geometry [Can be slow, use with care] Param[1]: posX (type: int) Param[2]: posY (type: int) Param[3]: color (type: Color) -Function 220: DrawPixelV() (2 input parameters) +Function 221: DrawPixelV() (2 input parameters) Name: DrawPixelV Return type: void Description: Draw a pixel using geometry (Vector version) [Can be slow, use with care] Param[1]: position (type: Vector2) Param[2]: color (type: Color) -Function 221: DrawLine() (5 input parameters) +Function 222: DrawLine() (5 input parameters) Name: DrawLine Return type: void Description: Draw a line @@ -2190,14 +2196,14 @@ Function 221: DrawLine() (5 input parameters) Param[3]: endPosX (type: int) Param[4]: endPosY (type: int) Param[5]: color (type: Color) -Function 222: DrawLineV() (3 input parameters) +Function 223: DrawLineV() (3 input parameters) Name: DrawLineV Return type: void Description: Draw a line (using gl lines) Param[1]: startPos (type: Vector2) Param[2]: endPos (type: Vector2) Param[3]: color (type: Color) -Function 223: DrawLineEx() (4 input parameters) +Function 224: DrawLineEx() (4 input parameters) Name: DrawLineEx Return type: void Description: Draw a line (using triangles/quads) @@ -2205,14 +2211,14 @@ Function 223: DrawLineEx() (4 input parameters) Param[2]: endPos (type: Vector2) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 224: DrawLineStrip() (3 input parameters) +Function 225: DrawLineStrip() (3 input parameters) Name: DrawLineStrip Return type: void Description: Draw lines sequence (using gl lines) Param[1]: points (type: const Vector2 *) Param[2]: pointCount (type: int) Param[3]: color (type: Color) -Function 225: DrawLineBezier() (4 input parameters) +Function 226: DrawLineBezier() (4 input parameters) Name: DrawLineBezier Return type: void Description: Draw line segment cubic-bezier in-out interpolation @@ -2220,7 +2226,7 @@ Function 225: DrawLineBezier() (4 input parameters) Param[2]: endPos (type: Vector2) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 226: DrawLineDashed() (5 input parameters) +Function 227: DrawLineDashed() (5 input parameters) Name: DrawLineDashed Return type: void Description: Draw a dashed line @@ -2229,7 +2235,7 @@ Function 226: DrawLineDashed() (5 input parameters) Param[3]: dashSize (type: int) Param[4]: spaceSize (type: int) Param[5]: color (type: Color) -Function 227: DrawCircle() (4 input parameters) +Function 228: DrawCircle() (4 input parameters) Name: DrawCircle Return type: void Description: Draw a color-filled circle @@ -2237,7 +2243,7 @@ Function 227: DrawCircle() (4 input parameters) Param[2]: centerY (type: int) Param[3]: radius (type: float) Param[4]: color (type: Color) -Function 228: DrawCircleSector() (6 input parameters) +Function 229: DrawCircleSector() (6 input parameters) Name: DrawCircleSector Return type: void Description: Draw a piece of a circle @@ -2247,7 +2253,7 @@ Function 228: DrawCircleSector() (6 input parameters) Param[4]: endAngle (type: float) Param[5]: segments (type: int) Param[6]: color (type: Color) -Function 229: DrawCircleSectorLines() (6 input parameters) +Function 230: DrawCircleSectorLines() (6 input parameters) Name: DrawCircleSectorLines Return type: void Description: Draw circle sector outline @@ -2257,7 +2263,7 @@ Function 229: DrawCircleSectorLines() (6 input parameters) Param[4]: endAngle (type: float) Param[5]: segments (type: int) Param[6]: color (type: Color) -Function 230: DrawCircleGradient() (5 input parameters) +Function 231: DrawCircleGradient() (5 input parameters) Name: DrawCircleGradient Return type: void Description: Draw a gradient-filled circle @@ -2266,14 +2272,14 @@ Function 230: DrawCircleGradient() (5 input parameters) Param[3]: radius (type: float) Param[4]: inner (type: Color) Param[5]: outer (type: Color) -Function 231: DrawCircleV() (3 input parameters) +Function 232: DrawCircleV() (3 input parameters) Name: DrawCircleV Return type: void Description: Draw a color-filled circle (Vector version) Param[1]: center (type: Vector2) Param[2]: radius (type: float) Param[3]: color (type: Color) -Function 232: DrawCircleLines() (4 input parameters) +Function 233: DrawCircleLines() (4 input parameters) Name: DrawCircleLines Return type: void Description: Draw circle outline @@ -2281,14 +2287,14 @@ Function 232: DrawCircleLines() (4 input parameters) Param[2]: centerY (type: int) Param[3]: radius (type: float) Param[4]: color (type: Color) -Function 233: DrawCircleLinesV() (3 input parameters) +Function 234: DrawCircleLinesV() (3 input parameters) Name: DrawCircleLinesV Return type: void Description: Draw circle outline (Vector version) Param[1]: center (type: Vector2) Param[2]: radius (type: float) Param[3]: color (type: Color) -Function 234: DrawEllipse() (5 input parameters) +Function 235: DrawEllipse() (5 input parameters) Name: DrawEllipse Return type: void Description: Draw ellipse @@ -2297,7 +2303,7 @@ Function 234: DrawEllipse() (5 input parameters) Param[3]: radiusH (type: float) Param[4]: radiusV (type: float) Param[5]: color (type: Color) -Function 235: DrawEllipseV() (4 input parameters) +Function 236: DrawEllipseV() (4 input parameters) Name: DrawEllipseV Return type: void Description: Draw ellipse (Vector version) @@ -2305,7 +2311,7 @@ Function 235: DrawEllipseV() (4 input parameters) Param[2]: radiusH (type: float) Param[3]: radiusV (type: float) Param[4]: color (type: Color) -Function 236: DrawEllipseLines() (5 input parameters) +Function 237: DrawEllipseLines() (5 input parameters) Name: DrawEllipseLines Return type: void Description: Draw ellipse outline @@ -2314,7 +2320,7 @@ Function 236: DrawEllipseLines() (5 input parameters) Param[3]: radiusH (type: float) Param[4]: radiusV (type: float) Param[5]: color (type: Color) -Function 237: DrawEllipseLinesV() (4 input parameters) +Function 238: DrawEllipseLinesV() (4 input parameters) Name: DrawEllipseLinesV Return type: void Description: Draw ellipse outline (Vector version) @@ -2322,7 +2328,7 @@ Function 237: DrawEllipseLinesV() (4 input parameters) Param[2]: radiusH (type: float) Param[3]: radiusV (type: float) Param[4]: color (type: Color) -Function 238: DrawRing() (7 input parameters) +Function 239: DrawRing() (7 input parameters) Name: DrawRing Return type: void Description: Draw ring @@ -2333,7 +2339,7 @@ Function 238: DrawRing() (7 input parameters) Param[5]: endAngle (type: float) Param[6]: segments (type: int) Param[7]: color (type: Color) -Function 239: DrawRingLines() (7 input parameters) +Function 240: DrawRingLines() (7 input parameters) Name: DrawRingLines Return type: void Description: Draw ring outline @@ -2344,7 +2350,7 @@ Function 239: DrawRingLines() (7 input parameters) Param[5]: endAngle (type: float) Param[6]: segments (type: int) Param[7]: color (type: Color) -Function 240: DrawRectangle() (5 input parameters) +Function 241: DrawRectangle() (5 input parameters) Name: DrawRectangle Return type: void Description: Draw a color-filled rectangle @@ -2353,20 +2359,20 @@ Function 240: DrawRectangle() (5 input parameters) Param[3]: width (type: int) Param[4]: height (type: int) Param[5]: color (type: Color) -Function 241: DrawRectangleV() (3 input parameters) +Function 242: DrawRectangleV() (3 input parameters) Name: DrawRectangleV Return type: void Description: Draw a color-filled rectangle (Vector version) Param[1]: position (type: Vector2) Param[2]: size (type: Vector2) Param[3]: color (type: Color) -Function 242: DrawRectangleRec() (2 input parameters) +Function 243: DrawRectangleRec() (2 input parameters) Name: DrawRectangleRec Return type: void Description: Draw a color-filled rectangle Param[1]: rec (type: Rectangle) Param[2]: color (type: Color) -Function 243: DrawRectanglePro() (4 input parameters) +Function 244: DrawRectanglePro() (4 input parameters) Name: DrawRectanglePro Return type: void Description: Draw a color-filled rectangle with pro parameters @@ -2374,7 +2380,7 @@ Function 243: DrawRectanglePro() (4 input parameters) Param[2]: origin (type: Vector2) Param[3]: rotation (type: float) Param[4]: color (type: Color) -Function 244: DrawRectangleGradientV() (6 input parameters) +Function 245: DrawRectangleGradientV() (6 input parameters) Name: DrawRectangleGradientV Return type: void Description: Draw a vertical-gradient-filled rectangle @@ -2384,7 +2390,7 @@ Function 244: DrawRectangleGradientV() (6 input parameters) Param[4]: height (type: int) Param[5]: top (type: Color) Param[6]: bottom (type: Color) -Function 245: DrawRectangleGradientH() (6 input parameters) +Function 246: DrawRectangleGradientH() (6 input parameters) Name: DrawRectangleGradientH Return type: void Description: Draw a horizontal-gradient-filled rectangle @@ -2394,7 +2400,7 @@ Function 245: DrawRectangleGradientH() (6 input parameters) Param[4]: height (type: int) Param[5]: left (type: Color) Param[6]: right (type: Color) -Function 246: DrawRectangleGradientEx() (5 input parameters) +Function 247: DrawRectangleGradientEx() (5 input parameters) Name: DrawRectangleGradientEx Return type: void Description: Draw a gradient-filled rectangle with custom vertex colors @@ -2403,7 +2409,7 @@ Function 246: DrawRectangleGradientEx() (5 input parameters) Param[3]: bottomLeft (type: Color) Param[4]: bottomRight (type: Color) Param[5]: topRight (type: Color) -Function 247: DrawRectangleLines() (5 input parameters) +Function 248: DrawRectangleLines() (5 input parameters) Name: DrawRectangleLines Return type: void Description: Draw rectangle outline @@ -2412,14 +2418,14 @@ Function 247: DrawRectangleLines() (5 input parameters) Param[3]: width (type: int) Param[4]: height (type: int) Param[5]: color (type: Color) -Function 248: DrawRectangleLinesEx() (3 input parameters) +Function 249: DrawRectangleLinesEx() (3 input parameters) Name: DrawRectangleLinesEx Return type: void Description: Draw rectangle outline with extended parameters Param[1]: rec (type: Rectangle) Param[2]: lineThick (type: float) Param[3]: color (type: Color) -Function 249: DrawRectangleRounded() (4 input parameters) +Function 250: DrawRectangleRounded() (4 input parameters) Name: DrawRectangleRounded Return type: void Description: Draw rectangle with rounded edges @@ -2427,7 +2433,7 @@ Function 249: DrawRectangleRounded() (4 input parameters) Param[2]: roundness (type: float) Param[3]: segments (type: int) Param[4]: color (type: Color) -Function 250: DrawRectangleRoundedLines() (4 input parameters) +Function 251: DrawRectangleRoundedLines() (4 input parameters) Name: DrawRectangleRoundedLines Return type: void Description: Draw rectangle lines with rounded edges @@ -2435,7 +2441,7 @@ Function 250: DrawRectangleRoundedLines() (4 input parameters) Param[2]: roundness (type: float) Param[3]: segments (type: int) Param[4]: color (type: Color) -Function 251: DrawRectangleRoundedLinesEx() (5 input parameters) +Function 252: DrawRectangleRoundedLinesEx() (5 input parameters) Name: DrawRectangleRoundedLinesEx Return type: void Description: Draw rectangle with rounded edges outline @@ -2444,7 +2450,7 @@ Function 251: DrawRectangleRoundedLinesEx() (5 input parameters) Param[3]: segments (type: int) Param[4]: lineThick (type: float) Param[5]: color (type: Color) -Function 252: DrawTriangle() (4 input parameters) +Function 253: DrawTriangle() (4 input parameters) Name: DrawTriangle Return type: void Description: Draw a color-filled triangle (vertex in counter-clockwise order!) @@ -2452,7 +2458,7 @@ Function 252: DrawTriangle() (4 input parameters) Param[2]: v2 (type: Vector2) Param[3]: v3 (type: Vector2) Param[4]: color (type: Color) -Function 253: DrawTriangleLines() (4 input parameters) +Function 254: DrawTriangleLines() (4 input parameters) Name: DrawTriangleLines Return type: void Description: Draw triangle outline (vertex in counter-clockwise order!) @@ -2460,21 +2466,21 @@ Function 253: DrawTriangleLines() (4 input parameters) Param[2]: v2 (type: Vector2) Param[3]: v3 (type: Vector2) Param[4]: color (type: Color) -Function 254: DrawTriangleFan() (3 input parameters) +Function 255: DrawTriangleFan() (3 input parameters) Name: DrawTriangleFan Return type: void Description: Draw a triangle fan defined by points (first vertex is the center) Param[1]: points (type: const Vector2 *) Param[2]: pointCount (type: int) Param[3]: color (type: Color) -Function 255: DrawTriangleStrip() (3 input parameters) +Function 256: DrawTriangleStrip() (3 input parameters) Name: DrawTriangleStrip Return type: void Description: Draw a triangle strip defined by points Param[1]: points (type: const Vector2 *) Param[2]: pointCount (type: int) Param[3]: color (type: Color) -Function 256: DrawPoly() (5 input parameters) +Function 257: DrawPoly() (5 input parameters) Name: DrawPoly Return type: void Description: Draw a regular polygon (Vector version) @@ -2483,7 +2489,7 @@ Function 256: DrawPoly() (5 input parameters) Param[3]: radius (type: float) Param[4]: rotation (type: float) Param[5]: color (type: Color) -Function 257: DrawPolyLines() (5 input parameters) +Function 258: DrawPolyLines() (5 input parameters) Name: DrawPolyLines Return type: void Description: Draw a polygon outline of n sides @@ -2492,7 +2498,7 @@ Function 257: DrawPolyLines() (5 input parameters) Param[3]: radius (type: float) Param[4]: rotation (type: float) Param[5]: color (type: Color) -Function 258: DrawPolyLinesEx() (6 input parameters) +Function 259: DrawPolyLinesEx() (6 input parameters) Name: DrawPolyLinesEx Return type: void Description: Draw a polygon outline of n sides with extended parameters @@ -2502,7 +2508,7 @@ Function 258: DrawPolyLinesEx() (6 input parameters) Param[4]: rotation (type: float) Param[5]: lineThick (type: float) Param[6]: color (type: Color) -Function 259: DrawSplineLinear() (4 input parameters) +Function 260: DrawSplineLinear() (4 input parameters) Name: DrawSplineLinear Return type: void Description: Draw spline: Linear, minimum 2 points @@ -2510,7 +2516,7 @@ Function 259: DrawSplineLinear() (4 input parameters) Param[2]: pointCount (type: int) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 260: DrawSplineBasis() (4 input parameters) +Function 261: DrawSplineBasis() (4 input parameters) Name: DrawSplineBasis Return type: void Description: Draw spline: B-Spline, minimum 4 points @@ -2518,7 +2524,7 @@ Function 260: DrawSplineBasis() (4 input parameters) Param[2]: pointCount (type: int) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 261: DrawSplineCatmullRom() (4 input parameters) +Function 262: DrawSplineCatmullRom() (4 input parameters) Name: DrawSplineCatmullRom Return type: void Description: Draw spline: Catmull-Rom, minimum 4 points @@ -2526,7 +2532,7 @@ Function 261: DrawSplineCatmullRom() (4 input parameters) Param[2]: pointCount (type: int) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 262: DrawSplineBezierQuadratic() (4 input parameters) +Function 263: DrawSplineBezierQuadratic() (4 input parameters) Name: DrawSplineBezierQuadratic Return type: void Description: Draw spline: Quadratic Bezier, minimum 3 points (1 control point): [p1, c2, p3, c4...] @@ -2534,7 +2540,7 @@ Function 262: DrawSplineBezierQuadratic() (4 input parameters) Param[2]: pointCount (type: int) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 263: DrawSplineBezierCubic() (4 input parameters) +Function 264: DrawSplineBezierCubic() (4 input parameters) Name: DrawSplineBezierCubic Return type: void Description: Draw spline: Cubic Bezier, minimum 4 points (2 control points): [p1, c2, c3, p4, c5, c6...] @@ -2542,7 +2548,7 @@ Function 263: DrawSplineBezierCubic() (4 input parameters) Param[2]: pointCount (type: int) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 264: DrawSplineSegmentLinear() (4 input parameters) +Function 265: DrawSplineSegmentLinear() (4 input parameters) Name: DrawSplineSegmentLinear Return type: void Description: Draw spline segment: Linear, 2 points @@ -2550,7 +2556,7 @@ Function 264: DrawSplineSegmentLinear() (4 input parameters) Param[2]: p2 (type: Vector2) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 265: DrawSplineSegmentBasis() (6 input parameters) +Function 266: DrawSplineSegmentBasis() (6 input parameters) Name: DrawSplineSegmentBasis Return type: void Description: Draw spline segment: B-Spline, 4 points @@ -2560,7 +2566,7 @@ Function 265: DrawSplineSegmentBasis() (6 input parameters) Param[4]: p4 (type: Vector2) Param[5]: thick (type: float) Param[6]: color (type: Color) -Function 266: DrawSplineSegmentCatmullRom() (6 input parameters) +Function 267: DrawSplineSegmentCatmullRom() (6 input parameters) Name: DrawSplineSegmentCatmullRom Return type: void Description: Draw spline segment: Catmull-Rom, 4 points @@ -2570,7 +2576,7 @@ Function 266: DrawSplineSegmentCatmullRom() (6 input parameters) Param[4]: p4 (type: Vector2) Param[5]: thick (type: float) Param[6]: color (type: Color) -Function 267: DrawSplineSegmentBezierQuadratic() (5 input parameters) +Function 268: DrawSplineSegmentBezierQuadratic() (5 input parameters) Name: DrawSplineSegmentBezierQuadratic Return type: void Description: Draw spline segment: Quadratic Bezier, 2 points, 1 control point @@ -2579,7 +2585,7 @@ Function 267: DrawSplineSegmentBezierQuadratic() (5 input parameters) Param[3]: p3 (type: Vector2) Param[4]: thick (type: float) Param[5]: color (type: Color) -Function 268: DrawSplineSegmentBezierCubic() (6 input parameters) +Function 269: DrawSplineSegmentBezierCubic() (6 input parameters) Name: DrawSplineSegmentBezierCubic Return type: void Description: Draw spline segment: Cubic Bezier, 2 points, 2 control points @@ -2589,14 +2595,14 @@ Function 268: DrawSplineSegmentBezierCubic() (6 input parameters) Param[4]: p4 (type: Vector2) Param[5]: thick (type: float) Param[6]: color (type: Color) -Function 269: GetSplinePointLinear() (3 input parameters) +Function 270: GetSplinePointLinear() (3 input parameters) Name: GetSplinePointLinear Return type: Vector2 Description: Get (evaluate) spline point: Linear Param[1]: startPos (type: Vector2) Param[2]: endPos (type: Vector2) Param[3]: t (type: float) -Function 270: GetSplinePointBasis() (5 input parameters) +Function 271: GetSplinePointBasis() (5 input parameters) Name: GetSplinePointBasis Return type: Vector2 Description: Get (evaluate) spline point: B-Spline @@ -2605,7 +2611,7 @@ Function 270: GetSplinePointBasis() (5 input parameters) Param[3]: p3 (type: Vector2) Param[4]: p4 (type: Vector2) Param[5]: t (type: float) -Function 271: GetSplinePointCatmullRom() (5 input parameters) +Function 272: GetSplinePointCatmullRom() (5 input parameters) Name: GetSplinePointCatmullRom Return type: Vector2 Description: Get (evaluate) spline point: Catmull-Rom @@ -2614,7 +2620,7 @@ Function 271: GetSplinePointCatmullRom() (5 input parameters) Param[3]: p3 (type: Vector2) Param[4]: p4 (type: Vector2) Param[5]: t (type: float) -Function 272: GetSplinePointBezierQuad() (4 input parameters) +Function 273: GetSplinePointBezierQuad() (4 input parameters) Name: GetSplinePointBezierQuad Return type: Vector2 Description: Get (evaluate) spline point: Quadratic Bezier @@ -2622,7 +2628,7 @@ Function 272: GetSplinePointBezierQuad() (4 input parameters) Param[2]: c2 (type: Vector2) Param[3]: p3 (type: Vector2) Param[4]: t (type: float) -Function 273: GetSplinePointBezierCubic() (5 input parameters) +Function 274: GetSplinePointBezierCubic() (5 input parameters) Name: GetSplinePointBezierCubic Return type: Vector2 Description: Get (evaluate) spline point: Cubic Bezier @@ -2631,13 +2637,13 @@ Function 273: GetSplinePointBezierCubic() (5 input parameters) Param[3]: c3 (type: Vector2) Param[4]: p4 (type: Vector2) Param[5]: t (type: float) -Function 274: CheckCollisionRecs() (2 input parameters) +Function 275: CheckCollisionRecs() (2 input parameters) Name: CheckCollisionRecs Return type: bool Description: Check collision between two rectangles Param[1]: rec1 (type: Rectangle) Param[2]: rec2 (type: Rectangle) -Function 275: CheckCollisionCircles() (4 input parameters) +Function 276: CheckCollisionCircles() (4 input parameters) Name: CheckCollisionCircles Return type: bool Description: Check collision between two circles @@ -2645,14 +2651,14 @@ Function 275: CheckCollisionCircles() (4 input parameters) Param[2]: radius1 (type: float) Param[3]: center2 (type: Vector2) Param[4]: radius2 (type: float) -Function 276: CheckCollisionCircleRec() (3 input parameters) +Function 277: CheckCollisionCircleRec() (3 input parameters) Name: CheckCollisionCircleRec Return type: bool Description: Check collision between circle and rectangle Param[1]: center (type: Vector2) Param[2]: radius (type: float) Param[3]: rec (type: Rectangle) -Function 277: CheckCollisionCircleLine() (4 input parameters) +Function 278: CheckCollisionCircleLine() (4 input parameters) Name: CheckCollisionCircleLine Return type: bool Description: Check if circle collides with a line created betweeen two points [p1] and [p2] @@ -2660,20 +2666,20 @@ Function 277: CheckCollisionCircleLine() (4 input parameters) Param[2]: radius (type: float) Param[3]: p1 (type: Vector2) Param[4]: p2 (type: Vector2) -Function 278: CheckCollisionPointRec() (2 input parameters) +Function 279: CheckCollisionPointRec() (2 input parameters) Name: CheckCollisionPointRec Return type: bool Description: Check if point is inside rectangle Param[1]: point (type: Vector2) Param[2]: rec (type: Rectangle) -Function 279: CheckCollisionPointCircle() (3 input parameters) +Function 280: CheckCollisionPointCircle() (3 input parameters) Name: CheckCollisionPointCircle Return type: bool Description: Check if point is inside circle Param[1]: point (type: Vector2) Param[2]: center (type: Vector2) Param[3]: radius (type: float) -Function 280: CheckCollisionPointTriangle() (4 input parameters) +Function 281: CheckCollisionPointTriangle() (4 input parameters) Name: CheckCollisionPointTriangle Return type: bool Description: Check if point is inside a triangle @@ -2681,7 +2687,7 @@ Function 280: CheckCollisionPointTriangle() (4 input parameters) Param[2]: p1 (type: Vector2) Param[3]: p2 (type: Vector2) Param[4]: p3 (type: Vector2) -Function 281: CheckCollisionPointLine() (4 input parameters) +Function 282: CheckCollisionPointLine() (4 input parameters) Name: CheckCollisionPointLine Return type: bool Description: Check if point belongs to line created between two points [p1] and [p2] with defined margin in pixels [threshold] @@ -2689,14 +2695,14 @@ Function 281: CheckCollisionPointLine() (4 input parameters) Param[2]: p1 (type: Vector2) Param[3]: p2 (type: Vector2) Param[4]: threshold (type: int) -Function 282: CheckCollisionPointPoly() (3 input parameters) +Function 283: CheckCollisionPointPoly() (3 input parameters) Name: CheckCollisionPointPoly Return type: bool Description: Check if point is within a polygon described by array of vertices Param[1]: point (type: Vector2) Param[2]: points (type: const Vector2 *) Param[3]: pointCount (type: int) -Function 283: CheckCollisionLines() (5 input parameters) +Function 284: CheckCollisionLines() (5 input parameters) Name: CheckCollisionLines Return type: bool Description: Check the collision between two lines defined by two points each, returns collision point by reference @@ -2705,18 +2711,18 @@ Function 283: CheckCollisionLines() (5 input parameters) Param[3]: startPos2 (type: Vector2) Param[4]: endPos2 (type: Vector2) Param[5]: collisionPoint (type: Vector2 *) -Function 284: GetCollisionRec() (2 input parameters) +Function 285: GetCollisionRec() (2 input parameters) Name: GetCollisionRec Return type: Rectangle Description: Get collision rectangle for two rectangles collision Param[1]: rec1 (type: Rectangle) Param[2]: rec2 (type: Rectangle) -Function 285: LoadImage() (1 input parameters) +Function 286: LoadImage() (1 input parameters) Name: LoadImage Return type: Image Description: Load image from file into CPU memory (RAM) Param[1]: fileName (type: const char *) -Function 286: LoadImageRaw() (5 input parameters) +Function 287: LoadImageRaw() (5 input parameters) Name: LoadImageRaw Return type: Image Description: Load image from RAW file data @@ -2725,13 +2731,13 @@ Function 286: LoadImageRaw() (5 input parameters) Param[3]: height (type: int) Param[4]: format (type: int) Param[5]: headerSize (type: int) -Function 287: LoadImageAnim() (2 input parameters) +Function 288: LoadImageAnim() (2 input parameters) Name: LoadImageAnim Return type: Image Description: Load image sequence from file (frames appended to image.data) Param[1]: fileName (type: const char *) Param[2]: frames (type: int *) -Function 288: LoadImageAnimFromMemory() (4 input parameters) +Function 289: LoadImageAnimFromMemory() (4 input parameters) Name: LoadImageAnimFromMemory Return type: Image Description: Load image sequence from memory buffer @@ -2739,60 +2745,60 @@ Function 288: LoadImageAnimFromMemory() (4 input parameters) Param[2]: fileData (type: const unsigned char *) Param[3]: dataSize (type: int) Param[4]: frames (type: int *) -Function 289: LoadImageFromMemory() (3 input parameters) +Function 290: LoadImageFromMemory() (3 input parameters) Name: LoadImageFromMemory Return type: Image Description: Load image from memory buffer, fileType refers to extension: i.e. '.png' Param[1]: fileType (type: const char *) Param[2]: fileData (type: const unsigned char *) Param[3]: dataSize (type: int) -Function 290: LoadImageFromTexture() (1 input parameters) +Function 291: LoadImageFromTexture() (1 input parameters) Name: LoadImageFromTexture Return type: Image Description: Load image from GPU texture data Param[1]: texture (type: Texture2D) -Function 291: LoadImageFromScreen() (0 input parameters) +Function 292: LoadImageFromScreen() (0 input parameters) Name: LoadImageFromScreen Return type: Image Description: Load image from screen buffer and (screenshot) No input parameters -Function 292: IsImageValid() (1 input parameters) +Function 293: IsImageValid() (1 input parameters) Name: IsImageValid Return type: bool Description: Check if an image is valid (data and parameters) Param[1]: image (type: Image) -Function 293: UnloadImage() (1 input parameters) +Function 294: UnloadImage() (1 input parameters) Name: UnloadImage Return type: void Description: Unload image from CPU memory (RAM) Param[1]: image (type: Image) -Function 294: ExportImage() (2 input parameters) +Function 295: ExportImage() (2 input parameters) Name: ExportImage Return type: bool Description: Export image data to file, returns true on success Param[1]: image (type: Image) Param[2]: fileName (type: const char *) -Function 295: ExportImageToMemory() (3 input parameters) +Function 296: ExportImageToMemory() (3 input parameters) Name: ExportImageToMemory Return type: unsigned char * Description: Export image to memory buffer Param[1]: image (type: Image) Param[2]: fileType (type: const char *) Param[3]: fileSize (type: int *) -Function 296: ExportImageAsCode() (2 input parameters) +Function 297: ExportImageAsCode() (2 input parameters) Name: ExportImageAsCode Return type: bool Description: Export image as code file defining an array of bytes, returns true on success Param[1]: image (type: Image) Param[2]: fileName (type: const char *) -Function 297: GenImageColor() (3 input parameters) +Function 298: GenImageColor() (3 input parameters) Name: GenImageColor Return type: Image Description: Generate image: plain color Param[1]: width (type: int) Param[2]: height (type: int) Param[3]: color (type: Color) -Function 298: GenImageGradientLinear() (5 input parameters) +Function 299: GenImageGradientLinear() (5 input parameters) Name: GenImageGradientLinear Return type: Image Description: Generate image: linear gradient, direction in degrees [0..360], 0=Vertical gradient @@ -2801,7 +2807,7 @@ Function 298: GenImageGradientLinear() (5 input parameters) Param[3]: direction (type: int) Param[4]: start (type: Color) Param[5]: end (type: Color) -Function 299: GenImageGradientRadial() (5 input parameters) +Function 300: GenImageGradientRadial() (5 input parameters) Name: GenImageGradientRadial Return type: Image Description: Generate image: radial gradient @@ -2810,7 +2816,7 @@ Function 299: GenImageGradientRadial() (5 input parameters) Param[3]: density (type: float) Param[4]: inner (type: Color) Param[5]: outer (type: Color) -Function 300: GenImageGradientSquare() (5 input parameters) +Function 301: GenImageGradientSquare() (5 input parameters) Name: GenImageGradientSquare Return type: Image Description: Generate image: square gradient @@ -2819,7 +2825,7 @@ Function 300: GenImageGradientSquare() (5 input parameters) Param[3]: density (type: float) Param[4]: inner (type: Color) Param[5]: outer (type: Color) -Function 301: GenImageChecked() (6 input parameters) +Function 302: GenImageChecked() (6 input parameters) Name: GenImageChecked Return type: Image Description: Generate image: checked @@ -2829,14 +2835,14 @@ Function 301: GenImageChecked() (6 input parameters) Param[4]: checksY (type: int) Param[5]: col1 (type: Color) Param[6]: col2 (type: Color) -Function 302: GenImageWhiteNoise() (3 input parameters) +Function 303: GenImageWhiteNoise() (3 input parameters) Name: GenImageWhiteNoise Return type: Image Description: Generate image: white noise Param[1]: width (type: int) Param[2]: height (type: int) Param[3]: factor (type: float) -Function 303: GenImagePerlinNoise() (5 input parameters) +Function 304: GenImagePerlinNoise() (5 input parameters) Name: GenImagePerlinNoise Return type: Image Description: Generate image: perlin noise @@ -2845,45 +2851,45 @@ Function 303: GenImagePerlinNoise() (5 input parameters) Param[3]: offsetX (type: int) Param[4]: offsetY (type: int) Param[5]: scale (type: float) -Function 304: GenImageCellular() (3 input parameters) +Function 305: GenImageCellular() (3 input parameters) Name: GenImageCellular Return type: Image Description: Generate image: cellular algorithm, bigger tileSize means bigger cells Param[1]: width (type: int) Param[2]: height (type: int) Param[3]: tileSize (type: int) -Function 305: GenImageText() (3 input parameters) +Function 306: GenImageText() (3 input parameters) Name: GenImageText Return type: Image Description: Generate image: grayscale image from text data Param[1]: width (type: int) Param[2]: height (type: int) Param[3]: text (type: const char *) -Function 306: ImageCopy() (1 input parameters) +Function 307: ImageCopy() (1 input parameters) Name: ImageCopy Return type: Image Description: Create an image duplicate (useful for transformations) Param[1]: image (type: Image) -Function 307: ImageFromImage() (2 input parameters) +Function 308: ImageFromImage() (2 input parameters) Name: ImageFromImage Return type: Image Description: Create an image from another image piece Param[1]: image (type: Image) Param[2]: rec (type: Rectangle) -Function 308: ImageFromChannel() (2 input parameters) +Function 309: ImageFromChannel() (2 input parameters) Name: ImageFromChannel Return type: Image Description: Create an image from a selected channel of another image (GRAYSCALE) Param[1]: image (type: Image) Param[2]: selectedChannel (type: int) -Function 309: ImageText() (3 input parameters) +Function 310: ImageText() (3 input parameters) Name: ImageText Return type: Image Description: Create an image from text (default font) Param[1]: text (type: const char *) Param[2]: fontSize (type: int) Param[3]: color (type: Color) -Function 310: ImageTextEx() (5 input parameters) +Function 311: ImageTextEx() (5 input parameters) Name: ImageTextEx Return type: Image Description: Create an image from text (custom sprite font) @@ -2892,76 +2898,76 @@ Function 310: ImageTextEx() (5 input parameters) Param[3]: fontSize (type: float) Param[4]: spacing (type: float) Param[5]: tint (type: Color) -Function 311: ImageFormat() (2 input parameters) +Function 312: ImageFormat() (2 input parameters) Name: ImageFormat Return type: void Description: Convert image data to desired format Param[1]: image (type: Image *) Param[2]: newFormat (type: int) -Function 312: ImageToPOT() (2 input parameters) +Function 313: ImageToPOT() (2 input parameters) Name: ImageToPOT Return type: void Description: Convert image to POT (power-of-two) Param[1]: image (type: Image *) Param[2]: fill (type: Color) -Function 313: ImageCrop() (2 input parameters) +Function 314: ImageCrop() (2 input parameters) Name: ImageCrop Return type: void Description: Crop an image to a defined rectangle Param[1]: image (type: Image *) Param[2]: crop (type: Rectangle) -Function 314: ImageAlphaCrop() (2 input parameters) +Function 315: ImageAlphaCrop() (2 input parameters) Name: ImageAlphaCrop Return type: void Description: Crop image depending on alpha value Param[1]: image (type: Image *) Param[2]: threshold (type: float) -Function 315: ImageAlphaClear() (3 input parameters) +Function 316: ImageAlphaClear() (3 input parameters) Name: ImageAlphaClear Return type: void Description: Clear alpha channel to desired color Param[1]: image (type: Image *) Param[2]: color (type: Color) Param[3]: threshold (type: float) -Function 316: ImageAlphaMask() (2 input parameters) +Function 317: ImageAlphaMask() (2 input parameters) Name: ImageAlphaMask Return type: void Description: Apply alpha mask to image Param[1]: image (type: Image *) Param[2]: alphaMask (type: Image) -Function 317: ImageAlphaPremultiply() (1 input parameters) +Function 318: ImageAlphaPremultiply() (1 input parameters) Name: ImageAlphaPremultiply Return type: void Description: Premultiply alpha channel Param[1]: image (type: Image *) -Function 318: ImageBlurGaussian() (2 input parameters) +Function 319: ImageBlurGaussian() (2 input parameters) Name: ImageBlurGaussian Return type: void Description: Apply Gaussian blur using a box blur approximation Param[1]: image (type: Image *) Param[2]: blurSize (type: int) -Function 319: ImageKernelConvolution() (3 input parameters) +Function 320: ImageKernelConvolution() (3 input parameters) Name: ImageKernelConvolution Return type: void Description: Apply custom square convolution kernel to image Param[1]: image (type: Image *) Param[2]: kernel (type: const float *) Param[3]: kernelSize (type: int) -Function 320: ImageResize() (3 input parameters) +Function 321: ImageResize() (3 input parameters) Name: ImageResize Return type: void Description: Resize image (Bicubic scaling algorithm) Param[1]: image (type: Image *) Param[2]: newWidth (type: int) Param[3]: newHeight (type: int) -Function 321: ImageResizeNN() (3 input parameters) +Function 322: ImageResizeNN() (3 input parameters) Name: ImageResizeNN Return type: void Description: Resize image (Nearest-Neighbor scaling algorithm) Param[1]: image (type: Image *) Param[2]: newWidth (type: int) Param[3]: newHeight (type: int) -Function 322: ImageResizeCanvas() (6 input parameters) +Function 323: ImageResizeCanvas() (6 input parameters) Name: ImageResizeCanvas Return type: void Description: Resize canvas and fill with color @@ -2971,12 +2977,12 @@ Function 322: ImageResizeCanvas() (6 input parameters) Param[4]: offsetX (type: int) Param[5]: offsetY (type: int) Param[6]: fill (type: Color) -Function 323: ImageMipmaps() (1 input parameters) +Function 324: ImageMipmaps() (1 input parameters) Name: ImageMipmaps Return type: void Description: Compute all mipmap levels for a provided image Param[1]: image (type: Image *) -Function 324: ImageDither() (5 input parameters) +Function 325: ImageDither() (5 input parameters) Name: ImageDither Return type: void Description: Dither image data to 16bpp or lower (Floyd-Steinberg dithering) @@ -2985,109 +2991,109 @@ Function 324: ImageDither() (5 input parameters) Param[3]: gBpp (type: int) Param[4]: bBpp (type: int) Param[5]: aBpp (type: int) -Function 325: ImageFlipVertical() (1 input parameters) +Function 326: ImageFlipVertical() (1 input parameters) Name: ImageFlipVertical Return type: void Description: Flip image vertically Param[1]: image (type: Image *) -Function 326: ImageFlipHorizontal() (1 input parameters) +Function 327: ImageFlipHorizontal() (1 input parameters) Name: ImageFlipHorizontal Return type: void Description: Flip image horizontally Param[1]: image (type: Image *) -Function 327: ImageRotate() (2 input parameters) +Function 328: ImageRotate() (2 input parameters) Name: ImageRotate Return type: void Description: Rotate image by input angle in degrees (-359 to 359) Param[1]: image (type: Image *) Param[2]: degrees (type: int) -Function 328: ImageRotateCW() (1 input parameters) +Function 329: ImageRotateCW() (1 input parameters) Name: ImageRotateCW Return type: void Description: Rotate image clockwise 90deg Param[1]: image (type: Image *) -Function 329: ImageRotateCCW() (1 input parameters) +Function 330: ImageRotateCCW() (1 input parameters) Name: ImageRotateCCW Return type: void Description: Rotate image counter-clockwise 90deg Param[1]: image (type: Image *) -Function 330: ImageColorTint() (2 input parameters) +Function 331: ImageColorTint() (2 input parameters) Name: ImageColorTint Return type: void Description: Modify image color: tint Param[1]: image (type: Image *) Param[2]: color (type: Color) -Function 331: ImageColorInvert() (1 input parameters) +Function 332: ImageColorInvert() (1 input parameters) Name: ImageColorInvert Return type: void Description: Modify image color: invert Param[1]: image (type: Image *) -Function 332: ImageColorGrayscale() (1 input parameters) +Function 333: ImageColorGrayscale() (1 input parameters) Name: ImageColorGrayscale Return type: void Description: Modify image color: grayscale Param[1]: image (type: Image *) -Function 333: ImageColorContrast() (2 input parameters) +Function 334: ImageColorContrast() (2 input parameters) Name: ImageColorContrast Return type: void Description: Modify image color: contrast (-100 to 100) Param[1]: image (type: Image *) Param[2]: contrast (type: float) -Function 334: ImageColorBrightness() (2 input parameters) +Function 335: ImageColorBrightness() (2 input parameters) Name: ImageColorBrightness Return type: void Description: Modify image color: brightness (-255 to 255) Param[1]: image (type: Image *) Param[2]: brightness (type: int) -Function 335: ImageColorReplace() (3 input parameters) +Function 336: ImageColorReplace() (3 input parameters) Name: ImageColorReplace Return type: void Description: Modify image color: replace color Param[1]: image (type: Image *) Param[2]: color (type: Color) Param[3]: replace (type: Color) -Function 336: LoadImageColors() (1 input parameters) +Function 337: LoadImageColors() (1 input parameters) Name: LoadImageColors Return type: Color * Description: Load color data from image as a Color array (RGBA - 32bit) Param[1]: image (type: Image) -Function 337: LoadImagePalette() (3 input parameters) +Function 338: LoadImagePalette() (3 input parameters) Name: LoadImagePalette Return type: Color * Description: Load colors palette from image as a Color array (RGBA - 32bit) Param[1]: image (type: Image) Param[2]: maxPaletteSize (type: int) Param[3]: colorCount (type: int *) -Function 338: UnloadImageColors() (1 input parameters) +Function 339: UnloadImageColors() (1 input parameters) Name: UnloadImageColors Return type: void Description: Unload color data loaded with LoadImageColors() Param[1]: colors (type: Color *) -Function 339: UnloadImagePalette() (1 input parameters) +Function 340: UnloadImagePalette() (1 input parameters) Name: UnloadImagePalette Return type: void Description: Unload colors palette loaded with LoadImagePalette() Param[1]: colors (type: Color *) -Function 340: GetImageAlphaBorder() (2 input parameters) +Function 341: GetImageAlphaBorder() (2 input parameters) Name: GetImageAlphaBorder Return type: Rectangle Description: Get image alpha border rectangle Param[1]: image (type: Image) Param[2]: threshold (type: float) -Function 341: GetImageColor() (3 input parameters) +Function 342: GetImageColor() (3 input parameters) Name: GetImageColor Return type: Color Description: Get image pixel color at (x, y) position Param[1]: image (type: Image) Param[2]: x (type: int) Param[3]: y (type: int) -Function 342: ImageClearBackground() (2 input parameters) +Function 343: ImageClearBackground() (2 input parameters) Name: ImageClearBackground Return type: void Description: Clear image background with given color Param[1]: dst (type: Image *) Param[2]: color (type: Color) -Function 343: ImageDrawPixel() (4 input parameters) +Function 344: ImageDrawPixel() (4 input parameters) Name: ImageDrawPixel Return type: void Description: Draw pixel within an image @@ -3095,14 +3101,14 @@ Function 343: ImageDrawPixel() (4 input parameters) Param[2]: posX (type: int) Param[3]: posY (type: int) Param[4]: color (type: Color) -Function 344: ImageDrawPixelV() (3 input parameters) +Function 345: ImageDrawPixelV() (3 input parameters) Name: ImageDrawPixelV Return type: void Description: Draw pixel within an image (Vector version) Param[1]: dst (type: Image *) Param[2]: position (type: Vector2) Param[3]: color (type: Color) -Function 345: ImageDrawLine() (6 input parameters) +Function 346: ImageDrawLine() (6 input parameters) Name: ImageDrawLine Return type: void Description: Draw line within an image @@ -3112,7 +3118,7 @@ Function 345: ImageDrawLine() (6 input parameters) Param[4]: endPosX (type: int) Param[5]: endPosY (type: int) Param[6]: color (type: Color) -Function 346: ImageDrawLineV() (4 input parameters) +Function 347: ImageDrawLineV() (4 input parameters) Name: ImageDrawLineV Return type: void Description: Draw line within an image (Vector version) @@ -3120,7 +3126,7 @@ Function 346: ImageDrawLineV() (4 input parameters) Param[2]: start (type: Vector2) Param[3]: end (type: Vector2) Param[4]: color (type: Color) -Function 347: ImageDrawLineEx() (5 input parameters) +Function 348: ImageDrawLineEx() (5 input parameters) Name: ImageDrawLineEx Return type: void Description: Draw a line defining thickness within an image @@ -3129,7 +3135,7 @@ Function 347: ImageDrawLineEx() (5 input parameters) Param[3]: end (type: Vector2) Param[4]: thick (type: int) Param[5]: color (type: Color) -Function 348: ImageDrawCircle() (5 input parameters) +Function 349: ImageDrawCircle() (5 input parameters) Name: ImageDrawCircle Return type: void Description: Draw a filled circle within an image @@ -3138,7 +3144,7 @@ Function 348: ImageDrawCircle() (5 input parameters) Param[3]: centerY (type: int) Param[4]: radius (type: int) Param[5]: color (type: Color) -Function 349: ImageDrawCircleV() (4 input parameters) +Function 350: ImageDrawCircleV() (4 input parameters) Name: ImageDrawCircleV Return type: void Description: Draw a filled circle within an image (Vector version) @@ -3146,7 +3152,7 @@ Function 349: ImageDrawCircleV() (4 input parameters) Param[2]: center (type: Vector2) Param[3]: radius (type: int) Param[4]: color (type: Color) -Function 350: ImageDrawCircleLines() (5 input parameters) +Function 351: ImageDrawCircleLines() (5 input parameters) Name: ImageDrawCircleLines Return type: void Description: Draw circle outline within an image @@ -3155,7 +3161,7 @@ Function 350: ImageDrawCircleLines() (5 input parameters) Param[3]: centerY (type: int) Param[4]: radius (type: int) Param[5]: color (type: Color) -Function 351: ImageDrawCircleLinesV() (4 input parameters) +Function 352: ImageDrawCircleLinesV() (4 input parameters) Name: ImageDrawCircleLinesV Return type: void Description: Draw circle outline within an image (Vector version) @@ -3163,7 +3169,7 @@ Function 351: ImageDrawCircleLinesV() (4 input parameters) Param[2]: center (type: Vector2) Param[3]: radius (type: int) Param[4]: color (type: Color) -Function 352: ImageDrawRectangle() (6 input parameters) +Function 353: ImageDrawRectangle() (6 input parameters) Name: ImageDrawRectangle Return type: void Description: Draw rectangle within an image @@ -3173,7 +3179,7 @@ Function 352: ImageDrawRectangle() (6 input parameters) Param[4]: width (type: int) Param[5]: height (type: int) Param[6]: color (type: Color) -Function 353: ImageDrawRectangleV() (4 input parameters) +Function 354: ImageDrawRectangleV() (4 input parameters) Name: ImageDrawRectangleV Return type: void Description: Draw rectangle within an image (Vector version) @@ -3181,14 +3187,14 @@ Function 353: ImageDrawRectangleV() (4 input parameters) Param[2]: position (type: Vector2) Param[3]: size (type: Vector2) Param[4]: color (type: Color) -Function 354: ImageDrawRectangleRec() (3 input parameters) +Function 355: ImageDrawRectangleRec() (3 input parameters) Name: ImageDrawRectangleRec Return type: void Description: Draw rectangle within an image Param[1]: dst (type: Image *) Param[2]: rec (type: Rectangle) Param[3]: color (type: Color) -Function 355: ImageDrawRectangleLines() (4 input parameters) +Function 356: ImageDrawRectangleLines() (4 input parameters) Name: ImageDrawRectangleLines Return type: void Description: Draw rectangle lines within an image @@ -3196,7 +3202,7 @@ Function 355: ImageDrawRectangleLines() (4 input parameters) Param[2]: rec (type: Rectangle) Param[3]: thick (type: int) Param[4]: color (type: Color) -Function 356: ImageDrawTriangle() (5 input parameters) +Function 357: ImageDrawTriangle() (5 input parameters) Name: ImageDrawTriangle Return type: void Description: Draw triangle within an image @@ -3205,7 +3211,7 @@ Function 356: ImageDrawTriangle() (5 input parameters) Param[3]: v2 (type: Vector2) Param[4]: v3 (type: Vector2) Param[5]: color (type: Color) -Function 357: ImageDrawTriangleEx() (7 input parameters) +Function 358: ImageDrawTriangleEx() (7 input parameters) Name: ImageDrawTriangleEx Return type: void Description: Draw triangle with interpolated colors within an image @@ -3216,7 +3222,7 @@ Function 357: ImageDrawTriangleEx() (7 input parameters) Param[5]: c1 (type: Color) Param[6]: c2 (type: Color) Param[7]: c3 (type: Color) -Function 358: ImageDrawTriangleLines() (5 input parameters) +Function 359: ImageDrawTriangleLines() (5 input parameters) Name: ImageDrawTriangleLines Return type: void Description: Draw triangle outline within an image @@ -3225,7 +3231,7 @@ Function 358: ImageDrawTriangleLines() (5 input parameters) Param[3]: v2 (type: Vector2) Param[4]: v3 (type: Vector2) Param[5]: color (type: Color) -Function 359: ImageDrawTriangleFan() (4 input parameters) +Function 360: ImageDrawTriangleFan() (4 input parameters) Name: ImageDrawTriangleFan Return type: void Description: Draw a triangle fan defined by points within an image (first vertex is the center) @@ -3233,7 +3239,7 @@ Function 359: ImageDrawTriangleFan() (4 input parameters) Param[2]: points (type: const Vector2 *) Param[3]: pointCount (type: int) Param[4]: color (type: Color) -Function 360: ImageDrawTriangleStrip() (4 input parameters) +Function 361: ImageDrawTriangleStrip() (4 input parameters) Name: ImageDrawTriangleStrip Return type: void Description: Draw a triangle strip defined by points within an image @@ -3241,7 +3247,7 @@ Function 360: ImageDrawTriangleStrip() (4 input parameters) Param[2]: points (type: const Vector2 *) Param[3]: pointCount (type: int) Param[4]: color (type: Color) -Function 361: ImageDraw() (5 input parameters) +Function 362: ImageDraw() (5 input parameters) Name: ImageDraw Return type: void Description: Draw a source image within a destination image (tint applied to source) @@ -3250,7 +3256,7 @@ Function 361: ImageDraw() (5 input parameters) Param[3]: srcRec (type: Rectangle) Param[4]: dstRec (type: Rectangle) Param[5]: tint (type: Color) -Function 362: ImageDrawText() (6 input parameters) +Function 363: ImageDrawText() (6 input parameters) Name: ImageDrawText Return type: void Description: Draw text (using default font) within an image (destination) @@ -3260,7 +3266,7 @@ Function 362: ImageDrawText() (6 input parameters) Param[4]: posY (type: int) Param[5]: fontSize (type: int) Param[6]: color (type: Color) -Function 363: ImageDrawTextEx() (7 input parameters) +Function 364: ImageDrawTextEx() (7 input parameters) Name: ImageDrawTextEx Return type: void Description: Draw text (custom sprite font) within an image (destination) @@ -3271,79 +3277,79 @@ Function 363: ImageDrawTextEx() (7 input parameters) Param[5]: fontSize (type: float) Param[6]: spacing (type: float) Param[7]: tint (type: Color) -Function 364: LoadTexture() (1 input parameters) +Function 365: LoadTexture() (1 input parameters) Name: LoadTexture Return type: Texture2D Description: Load texture from file into GPU memory (VRAM) Param[1]: fileName (type: const char *) -Function 365: LoadTextureFromImage() (1 input parameters) +Function 366: LoadTextureFromImage() (1 input parameters) Name: LoadTextureFromImage Return type: Texture2D Description: Load texture from image data Param[1]: image (type: Image) -Function 366: LoadTextureCubemap() (2 input parameters) +Function 367: LoadTextureCubemap() (2 input parameters) Name: LoadTextureCubemap Return type: TextureCubemap Description: Load cubemap from image, multiple image cubemap layouts supported Param[1]: image (type: Image) Param[2]: layout (type: int) -Function 367: LoadRenderTexture() (2 input parameters) +Function 368: LoadRenderTexture() (2 input parameters) Name: LoadRenderTexture Return type: RenderTexture2D Description: Load texture for rendering (framebuffer) Param[1]: width (type: int) Param[2]: height (type: int) -Function 368: IsTextureValid() (1 input parameters) +Function 369: IsTextureValid() (1 input parameters) Name: IsTextureValid Return type: bool Description: Check if a texture is valid (loaded in GPU) Param[1]: texture (type: Texture2D) -Function 369: UnloadTexture() (1 input parameters) +Function 370: UnloadTexture() (1 input parameters) Name: UnloadTexture Return type: void Description: Unload texture from GPU memory (VRAM) Param[1]: texture (type: Texture2D) -Function 370: IsRenderTextureValid() (1 input parameters) +Function 371: IsRenderTextureValid() (1 input parameters) Name: IsRenderTextureValid Return type: bool Description: Check if a render texture is valid (loaded in GPU) Param[1]: target (type: RenderTexture2D) -Function 371: UnloadRenderTexture() (1 input parameters) +Function 372: UnloadRenderTexture() (1 input parameters) Name: UnloadRenderTexture Return type: void Description: Unload render texture from GPU memory (VRAM) Param[1]: target (type: RenderTexture2D) -Function 372: UpdateTexture() (2 input parameters) +Function 373: UpdateTexture() (2 input parameters) Name: UpdateTexture Return type: void Description: Update GPU texture with new data (pixels should be able to fill texture) Param[1]: texture (type: Texture2D) Param[2]: pixels (type: const void *) -Function 373: UpdateTextureRec() (3 input parameters) +Function 374: UpdateTextureRec() (3 input parameters) Name: UpdateTextureRec Return type: void Description: Update GPU texture rectangle with new data (pixels and rec should fit in texture) Param[1]: texture (type: Texture2D) Param[2]: rec (type: Rectangle) Param[3]: pixels (type: const void *) -Function 374: GenTextureMipmaps() (1 input parameters) +Function 375: GenTextureMipmaps() (1 input parameters) Name: GenTextureMipmaps Return type: void Description: Generate GPU mipmaps for a texture Param[1]: texture (type: Texture2D *) -Function 375: SetTextureFilter() (2 input parameters) +Function 376: SetTextureFilter() (2 input parameters) Name: SetTextureFilter Return type: void Description: Set texture scaling filter mode Param[1]: texture (type: Texture2D) Param[2]: filter (type: int) -Function 376: SetTextureWrap() (2 input parameters) +Function 377: SetTextureWrap() (2 input parameters) Name: SetTextureWrap Return type: void Description: Set texture wrapping mode Param[1]: texture (type: Texture2D) Param[2]: wrap (type: int) -Function 377: DrawTexture() (4 input parameters) +Function 378: DrawTexture() (4 input parameters) Name: DrawTexture Return type: void Description: Draw a Texture2D @@ -3351,14 +3357,14 @@ Function 377: DrawTexture() (4 input parameters) Param[2]: posX (type: int) Param[3]: posY (type: int) Param[4]: tint (type: Color) -Function 378: DrawTextureV() (3 input parameters) +Function 379: DrawTextureV() (3 input parameters) Name: DrawTextureV Return type: void Description: Draw a Texture2D with position defined as Vector2 Param[1]: texture (type: Texture2D) Param[2]: position (type: Vector2) Param[3]: tint (type: Color) -Function 379: DrawTextureEx() (5 input parameters) +Function 380: DrawTextureEx() (5 input parameters) Name: DrawTextureEx Return type: void Description: Draw a Texture2D with extended parameters @@ -3367,7 +3373,7 @@ Function 379: DrawTextureEx() (5 input parameters) Param[3]: rotation (type: float) Param[4]: scale (type: float) Param[5]: tint (type: Color) -Function 380: DrawTextureRec() (4 input parameters) +Function 381: DrawTextureRec() (4 input parameters) Name: DrawTextureRec Return type: void Description: Draw a part of a texture defined by a rectangle @@ -3375,7 +3381,7 @@ Function 380: DrawTextureRec() (4 input parameters) Param[2]: source (type: Rectangle) Param[3]: position (type: Vector2) Param[4]: tint (type: Color) -Function 381: DrawTexturePro() (6 input parameters) +Function 382: DrawTexturePro() (6 input parameters) Name: DrawTexturePro Return type: void Description: Draw a part of a texture defined by a rectangle with 'pro' parameters @@ -3385,7 +3391,7 @@ Function 381: DrawTexturePro() (6 input parameters) Param[4]: origin (type: Vector2) Param[5]: rotation (type: float) Param[6]: tint (type: Color) -Function 382: DrawTextureNPatch() (6 input parameters) +Function 383: DrawTextureNPatch() (6 input parameters) Name: DrawTextureNPatch Return type: void Description: Draws a texture (or part of it) that stretches or shrinks nicely @@ -3395,119 +3401,119 @@ Function 382: DrawTextureNPatch() (6 input parameters) Param[4]: origin (type: Vector2) Param[5]: rotation (type: float) Param[6]: tint (type: Color) -Function 383: ColorIsEqual() (2 input parameters) +Function 384: ColorIsEqual() (2 input parameters) Name: ColorIsEqual Return type: bool Description: Check if two colors are equal Param[1]: col1 (type: Color) Param[2]: col2 (type: Color) -Function 384: Fade() (2 input parameters) +Function 385: Fade() (2 input parameters) Name: Fade Return type: Color Description: Get color with alpha applied, alpha goes from 0.0f to 1.0f Param[1]: color (type: Color) Param[2]: alpha (type: float) -Function 385: ColorToInt() (1 input parameters) +Function 386: ColorToInt() (1 input parameters) Name: ColorToInt Return type: int Description: Get hexadecimal value for a Color (0xRRGGBBAA) Param[1]: color (type: Color) -Function 386: ColorNormalize() (1 input parameters) +Function 387: ColorNormalize() (1 input parameters) Name: ColorNormalize Return type: Vector4 Description: Get Color normalized as float [0..1] Param[1]: color (type: Color) -Function 387: ColorFromNormalized() (1 input parameters) +Function 388: ColorFromNormalized() (1 input parameters) Name: ColorFromNormalized Return type: Color Description: Get Color from normalized values [0..1] Param[1]: normalized (type: Vector4) -Function 388: ColorToHSV() (1 input parameters) +Function 389: ColorToHSV() (1 input parameters) Name: ColorToHSV Return type: Vector3 Description: Get HSV values for a Color, hue [0..360], saturation/value [0..1] Param[1]: color (type: Color) -Function 389: ColorFromHSV() (3 input parameters) +Function 390: ColorFromHSV() (3 input parameters) Name: ColorFromHSV Return type: Color Description: Get a Color from HSV values, hue [0..360], saturation/value [0..1] Param[1]: hue (type: float) Param[2]: saturation (type: float) Param[3]: value (type: float) -Function 390: ColorTint() (2 input parameters) +Function 391: ColorTint() (2 input parameters) Name: ColorTint Return type: Color Description: Get color multiplied with another color Param[1]: color (type: Color) Param[2]: tint (type: Color) -Function 391: ColorBrightness() (2 input parameters) +Function 392: ColorBrightness() (2 input parameters) Name: ColorBrightness Return type: Color Description: Get color with brightness correction, brightness factor goes from -1.0f to 1.0f Param[1]: color (type: Color) Param[2]: factor (type: float) -Function 392: ColorContrast() (2 input parameters) +Function 393: ColorContrast() (2 input parameters) Name: ColorContrast Return type: Color Description: Get color with contrast correction, contrast values between -1.0f and 1.0f Param[1]: color (type: Color) Param[2]: contrast (type: float) -Function 393: ColorAlpha() (2 input parameters) +Function 394: ColorAlpha() (2 input parameters) Name: ColorAlpha Return type: Color Description: Get color with alpha applied, alpha goes from 0.0f to 1.0f Param[1]: color (type: Color) Param[2]: alpha (type: float) -Function 394: ColorAlphaBlend() (3 input parameters) +Function 395: ColorAlphaBlend() (3 input parameters) Name: ColorAlphaBlend Return type: Color Description: Get src alpha-blended into dst color with tint Param[1]: dst (type: Color) Param[2]: src (type: Color) Param[3]: tint (type: Color) -Function 395: ColorLerp() (3 input parameters) +Function 396: ColorLerp() (3 input parameters) Name: ColorLerp Return type: Color Description: Get color lerp interpolation between two colors, factor [0.0f..1.0f] Param[1]: color1 (type: Color) Param[2]: color2 (type: Color) Param[3]: factor (type: float) -Function 396: GetColor() (1 input parameters) +Function 397: GetColor() (1 input parameters) Name: GetColor Return type: Color Description: Get Color structure from hexadecimal value Param[1]: hexValue (type: unsigned int) -Function 397: GetPixelColor() (2 input parameters) +Function 398: GetPixelColor() (2 input parameters) Name: GetPixelColor Return type: Color Description: Get Color from a source pixel pointer of certain format Param[1]: srcPtr (type: void *) Param[2]: format (type: int) -Function 398: SetPixelColor() (3 input parameters) +Function 399: SetPixelColor() (3 input parameters) Name: SetPixelColor Return type: void Description: Set color formatted into destination pixel pointer Param[1]: dstPtr (type: void *) Param[2]: color (type: Color) Param[3]: format (type: int) -Function 399: GetPixelDataSize() (3 input parameters) +Function 400: GetPixelDataSize() (3 input parameters) Name: GetPixelDataSize Return type: int Description: Get pixel data size in bytes for certain format Param[1]: width (type: int) Param[2]: height (type: int) Param[3]: format (type: int) -Function 400: GetFontDefault() (0 input parameters) +Function 401: GetFontDefault() (0 input parameters) Name: GetFontDefault Return type: Font Description: Get the default Font No input parameters -Function 401: LoadFont() (1 input parameters) +Function 402: LoadFont() (1 input parameters) Name: LoadFont Return type: Font Description: Load font from file into GPU memory (VRAM) Param[1]: fileName (type: const char *) -Function 402: LoadFontEx() (4 input parameters) +Function 403: LoadFontEx() (4 input parameters) Name: LoadFontEx Return type: Font Description: Load font from file with extended parameters, use NULL for codepoints and 0 for codepointCount to load the default character set, font size is provided in pixels height @@ -3515,14 +3521,14 @@ Function 402: LoadFontEx() (4 input parameters) Param[2]: fontSize (type: int) Param[3]: codepoints (type: const int *) Param[4]: codepointCount (type: int) -Function 403: LoadFontFromImage() (3 input parameters) +Function 404: LoadFontFromImage() (3 input parameters) Name: LoadFontFromImage Return type: Font Description: Load font from Image (XNA style) Param[1]: image (type: Image) Param[2]: key (type: Color) Param[3]: firstChar (type: int) -Function 404: LoadFontFromMemory() (6 input parameters) +Function 405: LoadFontFromMemory() (6 input parameters) Name: LoadFontFromMemory Return type: Font Description: Load font from memory buffer, fileType refers to extension: i.e. '.ttf' @@ -3532,12 +3538,12 @@ Function 404: LoadFontFromMemory() (6 input parameters) Param[4]: fontSize (type: int) Param[5]: codepoints (type: const int *) Param[6]: codepointCount (type: int) -Function 405: IsFontValid() (1 input parameters) +Function 406: IsFontValid() (1 input parameters) Name: IsFontValid Return type: bool Description: Check if a font is valid (font data loaded, WARNING: GPU texture not checked) Param[1]: font (type: Font) -Function 406: LoadFontData() (7 input parameters) +Function 407: LoadFontData() (7 input parameters) Name: LoadFontData Return type: GlyphInfo * Description: Load font data for further use @@ -3548,7 +3554,7 @@ Function 406: LoadFontData() (7 input parameters) Param[5]: codepointCount (type: int) Param[6]: type (type: int) Param[7]: glyphCount (type: int *) -Function 407: GenImageFontAtlas() (6 input parameters) +Function 408: GenImageFontAtlas() (6 input parameters) Name: GenImageFontAtlas Return type: Image Description: Generate image font atlas using chars info @@ -3558,30 +3564,30 @@ Function 407: GenImageFontAtlas() (6 input parameters) Param[4]: fontSize (type: int) Param[5]: padding (type: int) Param[6]: packMethod (type: int) -Function 408: UnloadFontData() (2 input parameters) +Function 409: UnloadFontData() (2 input parameters) Name: UnloadFontData Return type: void Description: Unload font chars info data (RAM) Param[1]: glyphs (type: GlyphInfo *) Param[2]: glyphCount (type: int) -Function 409: UnloadFont() (1 input parameters) +Function 410: UnloadFont() (1 input parameters) Name: UnloadFont Return type: void Description: Unload font from GPU memory (VRAM) Param[1]: font (type: Font) -Function 410: ExportFontAsCode() (2 input parameters) +Function 411: ExportFontAsCode() (2 input parameters) Name: ExportFontAsCode Return type: bool Description: Export font as code file, returns true on success Param[1]: font (type: Font) Param[2]: fileName (type: const char *) -Function 411: DrawFPS() (2 input parameters) +Function 412: DrawFPS() (2 input parameters) Name: DrawFPS Return type: void Description: Draw current FPS Param[1]: posX (type: int) Param[2]: posY (type: int) -Function 412: DrawText() (5 input parameters) +Function 413: DrawText() (5 input parameters) Name: DrawText Return type: void Description: Draw text (using default font) @@ -3590,7 +3596,7 @@ Function 412: DrawText() (5 input parameters) Param[3]: posY (type: int) Param[4]: fontSize (type: int) Param[5]: color (type: Color) -Function 413: DrawTextEx() (6 input parameters) +Function 414: DrawTextEx() (6 input parameters) Name: DrawTextEx Return type: void Description: Draw text using font and additional parameters @@ -3600,7 +3606,7 @@ Function 413: DrawTextEx() (6 input parameters) Param[4]: fontSize (type: float) Param[5]: spacing (type: float) Param[6]: tint (type: Color) -Function 414: DrawTextPro() (8 input parameters) +Function 415: DrawTextPro() (8 input parameters) Name: DrawTextPro Return type: void Description: Draw text using Font and pro parameters (rotation) @@ -3612,7 +3618,7 @@ Function 414: DrawTextPro() (8 input parameters) Param[6]: fontSize (type: float) Param[7]: spacing (type: float) Param[8]: tint (type: Color) -Function 415: DrawTextCodepoint() (5 input parameters) +Function 416: DrawTextCodepoint() (5 input parameters) Name: DrawTextCodepoint Return type: void Description: Draw one character (codepoint) @@ -3621,7 +3627,7 @@ Function 415: DrawTextCodepoint() (5 input parameters) Param[3]: position (type: Vector2) Param[4]: fontSize (type: float) Param[5]: tint (type: Color) -Function 416: DrawTextCodepoints() (7 input parameters) +Function 417: DrawTextCodepoints() (7 input parameters) Name: DrawTextCodepoints Return type: void Description: Draw multiple character (codepoint) @@ -3632,18 +3638,18 @@ Function 416: DrawTextCodepoints() (7 input parameters) Param[5]: fontSize (type: float) Param[6]: spacing (type: float) Param[7]: tint (type: Color) -Function 417: SetTextLineSpacing() (1 input parameters) +Function 418: SetTextLineSpacing() (1 input parameters) Name: SetTextLineSpacing Return type: void Description: Set vertical line spacing when drawing with line-breaks Param[1]: spacing (type: int) -Function 418: MeasureText() (2 input parameters) +Function 419: MeasureText() (2 input parameters) Name: MeasureText Return type: int Description: Measure string width for default font Param[1]: text (type: const char *) Param[2]: fontSize (type: int) -Function 419: MeasureTextEx() (4 input parameters) +Function 420: MeasureTextEx() (4 input parameters) Name: MeasureTextEx Return type: Vector2 Description: Measure string size for Font @@ -3651,137 +3657,137 @@ Function 419: MeasureTextEx() (4 input parameters) Param[2]: text (type: const char *) Param[3]: fontSize (type: float) Param[4]: spacing (type: float) -Function 420: GetGlyphIndex() (2 input parameters) +Function 421: GetGlyphIndex() (2 input parameters) Name: GetGlyphIndex Return type: int Description: Get glyph index position in font for a codepoint (unicode character), fallback to '?' if not found Param[1]: font (type: Font) Param[2]: codepoint (type: int) -Function 421: GetGlyphInfo() (2 input parameters) +Function 422: GetGlyphInfo() (2 input parameters) Name: GetGlyphInfo Return type: GlyphInfo Description: Get glyph font info data for a codepoint (unicode character), fallback to '?' if not found Param[1]: font (type: Font) Param[2]: codepoint (type: int) -Function 422: GetGlyphAtlasRec() (2 input parameters) +Function 423: GetGlyphAtlasRec() (2 input parameters) Name: GetGlyphAtlasRec Return type: Rectangle Description: Get glyph rectangle in font atlas for a codepoint (unicode character), fallback to '?' if not found Param[1]: font (type: Font) Param[2]: codepoint (type: int) -Function 423: LoadUTF8() (2 input parameters) +Function 424: LoadUTF8() (2 input parameters) Name: LoadUTF8 Return type: char * Description: Load UTF-8 text encoded from codepoints array Param[1]: codepoints (type: const int *) Param[2]: length (type: int) -Function 424: UnloadUTF8() (1 input parameters) +Function 425: UnloadUTF8() (1 input parameters) Name: UnloadUTF8 Return type: void Description: Unload UTF-8 text encoded from codepoints array Param[1]: text (type: char *) -Function 425: LoadCodepoints() (2 input parameters) +Function 426: LoadCodepoints() (2 input parameters) Name: LoadCodepoints Return type: int * Description: Load all codepoints from a UTF-8 text string, codepoints count returned by parameter Param[1]: text (type: const char *) Param[2]: count (type: int *) -Function 426: UnloadCodepoints() (1 input parameters) +Function 427: UnloadCodepoints() (1 input parameters) Name: UnloadCodepoints Return type: void Description: Unload codepoints data from memory Param[1]: codepoints (type: int *) -Function 427: GetCodepointCount() (1 input parameters) +Function 428: GetCodepointCount() (1 input parameters) Name: GetCodepointCount Return type: int Description: Get total number of codepoints in a UTF-8 encoded string Param[1]: text (type: const char *) -Function 428: GetCodepoint() (2 input parameters) +Function 429: GetCodepoint() (2 input parameters) Name: GetCodepoint Return type: int Description: Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure Param[1]: text (type: const char *) Param[2]: codepointSize (type: int *) -Function 429: GetCodepointNext() (2 input parameters) +Function 430: GetCodepointNext() (2 input parameters) Name: GetCodepointNext Return type: int Description: Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure Param[1]: text (type: const char *) Param[2]: codepointSize (type: int *) -Function 430: GetCodepointPrevious() (2 input parameters) +Function 431: GetCodepointPrevious() (2 input parameters) Name: GetCodepointPrevious Return type: int Description: Get previous codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure Param[1]: text (type: const char *) Param[2]: codepointSize (type: int *) -Function 431: CodepointToUTF8() (2 input parameters) +Function 432: CodepointToUTF8() (2 input parameters) Name: CodepointToUTF8 Return type: const char * Description: Encode one codepoint into UTF-8 byte array (array length returned as parameter) Param[1]: codepoint (type: int) Param[2]: utf8Size (type: int *) -Function 432: LoadTextLines() (2 input parameters) +Function 433: LoadTextLines() (2 input parameters) Name: LoadTextLines Return type: char ** Description: Load text as separate lines ('\n') Param[1]: text (type: const char *) Param[2]: count (type: int *) -Function 433: UnloadTextLines() (2 input parameters) +Function 434: UnloadTextLines() (2 input parameters) Name: UnloadTextLines Return type: void Description: Unload text lines Param[1]: text (type: char **) Param[2]: lineCount (type: int) -Function 434: TextCopy() (2 input parameters) +Function 435: TextCopy() (2 input parameters) Name: TextCopy Return type: int Description: Copy one string to another, returns bytes copied Param[1]: dst (type: char *) Param[2]: src (type: const char *) -Function 435: TextIsEqual() (2 input parameters) +Function 436: TextIsEqual() (2 input parameters) Name: TextIsEqual Return type: bool Description: Check if two text string are equal Param[1]: text1 (type: const char *) Param[2]: text2 (type: const char *) -Function 436: TextLength() (1 input parameters) +Function 437: TextLength() (1 input parameters) Name: TextLength Return type: unsigned int Description: Get text length, checks for '\0' ending Param[1]: text (type: const char *) -Function 437: TextFormat() (2 input parameters) +Function 438: TextFormat() (2 input parameters) Name: TextFormat Return type: const char * Description: Text formatting with variables (sprintf() style) Param[1]: text (type: const char *) Param[2]: args (type: ...) -Function 438: TextSubtext() (3 input parameters) +Function 439: TextSubtext() (3 input parameters) Name: TextSubtext Return type: const char * Description: Get a piece of a text string Param[1]: text (type: const char *) Param[2]: position (type: int) Param[3]: length (type: int) -Function 439: TextRemoveSpaces() (1 input parameters) +Function 440: TextRemoveSpaces() (1 input parameters) Name: TextRemoveSpaces Return type: const char * Description: Remove text spaces, concat words Param[1]: text (type: const char *) -Function 440: GetTextBetween() (3 input parameters) +Function 441: GetTextBetween() (3 input parameters) Name: GetTextBetween Return type: char * Description: Get text between two strings Param[1]: text (type: const char *) Param[2]: begin (type: const char *) Param[3]: end (type: const char *) -Function 441: TextReplace() (3 input parameters) +Function 442: TextReplace() (3 input parameters) Name: TextReplace Return type: char * Description: Replace text string (WARNING: memory must be freed!) Param[1]: text (type: const char *) Param[2]: search (type: const char *) Param[3]: replacement (type: const char *) -Function 442: TextReplaceBetween() (4 input parameters) +Function 443: TextReplaceBetween() (4 input parameters) Name: TextReplaceBetween Return type: char * Description: Replace text between two specific strings (WARNING: memory must be freed!) @@ -3789,89 +3795,89 @@ Function 442: TextReplaceBetween() (4 input parameters) Param[2]: begin (type: const char *) Param[3]: end (type: const char *) Param[4]: replacement (type: const char *) -Function 443: TextInsert() (3 input parameters) +Function 444: TextInsert() (3 input parameters) Name: TextInsert Return type: char * Description: Insert text in a position (WARNING: memory must be freed!) Param[1]: text (type: const char *) Param[2]: insert (type: const char *) Param[3]: position (type: int) -Function 444: TextJoin() (3 input parameters) +Function 445: TextJoin() (3 input parameters) Name: TextJoin Return type: char * Description: Join text strings with delimiter Param[1]: textList (type: char **) Param[2]: count (type: int) Param[3]: delimiter (type: const char *) -Function 445: TextSplit() (3 input parameters) +Function 446: TextSplit() (3 input parameters) Name: TextSplit Return type: char ** Description: Split text into multiple strings, using MAX_TEXTSPLIT_COUNT static strings Param[1]: text (type: const char *) Param[2]: delimiter (type: char) Param[3]: count (type: int *) -Function 446: TextAppend() (3 input parameters) +Function 447: TextAppend() (3 input parameters) Name: TextAppend Return type: void Description: Append text at specific position and move cursor Param[1]: text (type: char *) Param[2]: append (type: const char *) Param[3]: position (type: int *) -Function 447: TextFindIndex() (2 input parameters) +Function 448: TextFindIndex() (2 input parameters) Name: TextFindIndex Return type: int Description: Find first text occurrence within a string, -1 if not found Param[1]: text (type: const char *) Param[2]: search (type: const char *) -Function 448: TextToUpper() (1 input parameters) +Function 449: TextToUpper() (1 input parameters) Name: TextToUpper Return type: char * Description: Get upper case version of provided string Param[1]: text (type: const char *) -Function 449: TextToLower() (1 input parameters) +Function 450: TextToLower() (1 input parameters) Name: TextToLower Return type: char * Description: Get lower case version of provided string Param[1]: text (type: const char *) -Function 450: TextToPascal() (1 input parameters) +Function 451: TextToPascal() (1 input parameters) Name: TextToPascal Return type: char * Description: Get Pascal case notation version of provided string Param[1]: text (type: const char *) -Function 451: TextToSnake() (1 input parameters) +Function 452: TextToSnake() (1 input parameters) Name: TextToSnake Return type: char * Description: Get Snake case notation version of provided string Param[1]: text (type: const char *) -Function 452: TextToCamel() (1 input parameters) +Function 453: TextToCamel() (1 input parameters) Name: TextToCamel Return type: char * Description: Get Camel case notation version of provided string Param[1]: text (type: const char *) -Function 453: TextToInteger() (1 input parameters) +Function 454: TextToInteger() (1 input parameters) Name: TextToInteger Return type: int Description: Get integer value from text Param[1]: text (type: const char *) -Function 454: TextToFloat() (1 input parameters) +Function 455: TextToFloat() (1 input parameters) Name: TextToFloat Return type: float Description: Get float value from text Param[1]: text (type: const char *) -Function 455: DrawLine3D() (3 input parameters) +Function 456: DrawLine3D() (3 input parameters) Name: DrawLine3D Return type: void Description: Draw a line in 3D world space Param[1]: startPos (type: Vector3) Param[2]: endPos (type: Vector3) Param[3]: color (type: Color) -Function 456: DrawPoint3D() (2 input parameters) +Function 457: DrawPoint3D() (2 input parameters) Name: DrawPoint3D Return type: void Description: Draw a point in 3D space, actually a small line Param[1]: position (type: Vector3) Param[2]: color (type: Color) -Function 457: DrawCircle3D() (5 input parameters) +Function 458: DrawCircle3D() (5 input parameters) Name: DrawCircle3D Return type: void Description: Draw a circle in 3D world space @@ -3880,7 +3886,7 @@ Function 457: DrawCircle3D() (5 input parameters) Param[3]: rotationAxis (type: Vector3) Param[4]: rotationAngle (type: float) Param[5]: color (type: Color) -Function 458: DrawTriangle3D() (4 input parameters) +Function 459: DrawTriangle3D() (4 input parameters) Name: DrawTriangle3D Return type: void Description: Draw a color-filled triangle (vertex in counter-clockwise order!) @@ -3888,14 +3894,14 @@ Function 458: DrawTriangle3D() (4 input parameters) Param[2]: v2 (type: Vector3) Param[3]: v3 (type: Vector3) Param[4]: color (type: Color) -Function 459: DrawTriangleStrip3D() (3 input parameters) +Function 460: DrawTriangleStrip3D() (3 input parameters) Name: DrawTriangleStrip3D Return type: void Description: Draw a triangle strip defined by points Param[1]: points (type: const Vector3 *) Param[2]: pointCount (type: int) Param[3]: color (type: Color) -Function 460: DrawCube() (5 input parameters) +Function 461: DrawCube() (5 input parameters) Name: DrawCube Return type: void Description: Draw cube @@ -3904,14 +3910,14 @@ Function 460: DrawCube() (5 input parameters) Param[3]: height (type: float) Param[4]: length (type: float) Param[5]: color (type: Color) -Function 461: DrawCubeV() (3 input parameters) +Function 462: DrawCubeV() (3 input parameters) Name: DrawCubeV Return type: void Description: Draw cube (Vector version) Param[1]: position (type: Vector3) Param[2]: size (type: Vector3) Param[3]: color (type: Color) -Function 462: DrawCubeWires() (5 input parameters) +Function 463: DrawCubeWires() (5 input parameters) Name: DrawCubeWires Return type: void Description: Draw cube wires @@ -3920,21 +3926,21 @@ Function 462: DrawCubeWires() (5 input parameters) Param[3]: height (type: float) Param[4]: length (type: float) Param[5]: color (type: Color) -Function 463: DrawCubeWiresV() (3 input parameters) +Function 464: DrawCubeWiresV() (3 input parameters) Name: DrawCubeWiresV Return type: void Description: Draw cube wires (Vector version) Param[1]: position (type: Vector3) Param[2]: size (type: Vector3) Param[3]: color (type: Color) -Function 464: DrawSphere() (3 input parameters) +Function 465: DrawSphere() (3 input parameters) Name: DrawSphere Return type: void Description: Draw sphere Param[1]: centerPos (type: Vector3) Param[2]: radius (type: float) Param[3]: color (type: Color) -Function 465: DrawSphereEx() (5 input parameters) +Function 466: DrawSphereEx() (5 input parameters) Name: DrawSphereEx Return type: void Description: Draw sphere with extended parameters @@ -3943,7 +3949,7 @@ Function 465: DrawSphereEx() (5 input parameters) Param[3]: rings (type: int) Param[4]: slices (type: int) Param[5]: color (type: Color) -Function 466: DrawSphereWires() (5 input parameters) +Function 467: DrawSphereWires() (5 input parameters) Name: DrawSphereWires Return type: void Description: Draw sphere wires @@ -3952,7 +3958,7 @@ Function 466: DrawSphereWires() (5 input parameters) Param[3]: rings (type: int) Param[4]: slices (type: int) Param[5]: color (type: Color) -Function 467: DrawCylinder() (6 input parameters) +Function 468: DrawCylinder() (6 input parameters) Name: DrawCylinder Return type: void Description: Draw a cylinder/cone @@ -3962,7 +3968,7 @@ Function 467: DrawCylinder() (6 input parameters) Param[4]: height (type: float) Param[5]: slices (type: int) Param[6]: color (type: Color) -Function 468: DrawCylinderEx() (6 input parameters) +Function 469: DrawCylinderEx() (6 input parameters) Name: DrawCylinderEx Return type: void Description: Draw a cylinder with base at startPos and top at endPos @@ -3972,7 +3978,7 @@ Function 468: DrawCylinderEx() (6 input parameters) Param[4]: endRadius (type: float) Param[5]: sides (type: int) Param[6]: color (type: Color) -Function 469: DrawCylinderWires() (6 input parameters) +Function 470: DrawCylinderWires() (6 input parameters) Name: DrawCylinderWires Return type: void Description: Draw a cylinder/cone wires @@ -3982,7 +3988,7 @@ Function 469: DrawCylinderWires() (6 input parameters) Param[4]: height (type: float) Param[5]: slices (type: int) Param[6]: color (type: Color) -Function 470: DrawCylinderWiresEx() (6 input parameters) +Function 471: DrawCylinderWiresEx() (6 input parameters) Name: DrawCylinderWiresEx Return type: void Description: Draw a cylinder wires with base at startPos and top at endPos @@ -3992,7 +3998,7 @@ Function 470: DrawCylinderWiresEx() (6 input parameters) Param[4]: endRadius (type: float) Param[5]: sides (type: int) Param[6]: color (type: Color) -Function 471: DrawCapsule() (6 input parameters) +Function 472: DrawCapsule() (6 input parameters) Name: DrawCapsule Return type: void Description: Draw a capsule with the center of its sphere caps at startPos and endPos @@ -4002,7 +4008,7 @@ Function 471: DrawCapsule() (6 input parameters) Param[4]: slices (type: int) Param[5]: rings (type: int) Param[6]: color (type: Color) -Function 472: DrawCapsuleWires() (6 input parameters) +Function 473: DrawCapsuleWires() (6 input parameters) Name: DrawCapsuleWires Return type: void Description: Draw capsule wireframe with the center of its sphere caps at startPos and endPos @@ -4012,51 +4018,51 @@ Function 472: DrawCapsuleWires() (6 input parameters) Param[4]: slices (type: int) Param[5]: rings (type: int) Param[6]: color (type: Color) -Function 473: DrawPlane() (3 input parameters) +Function 474: DrawPlane() (3 input parameters) Name: DrawPlane Return type: void Description: Draw a plane XZ Param[1]: centerPos (type: Vector3) Param[2]: size (type: Vector2) Param[3]: color (type: Color) -Function 474: DrawRay() (2 input parameters) +Function 475: DrawRay() (2 input parameters) Name: DrawRay Return type: void Description: Draw a ray line Param[1]: ray (type: Ray) Param[2]: color (type: Color) -Function 475: DrawGrid() (2 input parameters) +Function 476: DrawGrid() (2 input parameters) Name: DrawGrid Return type: void Description: Draw a grid (centered at (0, 0, 0)) Param[1]: slices (type: int) Param[2]: spacing (type: float) -Function 476: LoadModel() (1 input parameters) +Function 477: LoadModel() (1 input parameters) Name: LoadModel Return type: Model Description: Load model from files (meshes and materials) Param[1]: fileName (type: const char *) -Function 477: LoadModelFromMesh() (1 input parameters) +Function 478: LoadModelFromMesh() (1 input parameters) Name: LoadModelFromMesh Return type: Model Description: Load model from generated mesh (default material) Param[1]: mesh (type: Mesh) -Function 478: IsModelValid() (1 input parameters) +Function 479: IsModelValid() (1 input parameters) Name: IsModelValid Return type: bool Description: Check if a model is valid (loaded in GPU, VAO/VBOs) Param[1]: model (type: Model) -Function 479: UnloadModel() (1 input parameters) +Function 480: UnloadModel() (1 input parameters) Name: UnloadModel Return type: void Description: Unload model (including meshes) from memory (RAM and/or VRAM) Param[1]: model (type: Model) -Function 480: GetModelBoundingBox() (1 input parameters) +Function 481: GetModelBoundingBox() (1 input parameters) Name: GetModelBoundingBox Return type: BoundingBox Description: Compute model bounding box limits (considers all meshes) Param[1]: model (type: Model) -Function 481: DrawModel() (4 input parameters) +Function 482: DrawModel() (4 input parameters) Name: DrawModel Return type: void Description: Draw a model (with texture if set) @@ -4064,7 +4070,7 @@ Function 481: DrawModel() (4 input parameters) Param[2]: position (type: Vector3) Param[3]: scale (type: float) Param[4]: tint (type: Color) -Function 482: DrawModelEx() (6 input parameters) +Function 483: DrawModelEx() (6 input parameters) Name: DrawModelEx Return type: void Description: Draw a model with extended parameters @@ -4074,7 +4080,7 @@ Function 482: DrawModelEx() (6 input parameters) Param[4]: rotationAngle (type: float) Param[5]: scale (type: Vector3) Param[6]: tint (type: Color) -Function 483: DrawModelWires() (4 input parameters) +Function 484: DrawModelWires() (4 input parameters) Name: DrawModelWires Return type: void Description: Draw a model wires (with texture if set) @@ -4082,7 +4088,7 @@ Function 483: DrawModelWires() (4 input parameters) Param[2]: position (type: Vector3) Param[3]: scale (type: float) Param[4]: tint (type: Color) -Function 484: DrawModelWiresEx() (6 input parameters) +Function 485: DrawModelWiresEx() (6 input parameters) Name: DrawModelWiresEx Return type: void Description: Draw a model wires (with texture if set) with extended parameters @@ -4092,7 +4098,7 @@ Function 484: DrawModelWiresEx() (6 input parameters) Param[4]: rotationAngle (type: float) Param[5]: scale (type: Vector3) Param[6]: tint (type: Color) -Function 485: DrawModelPoints() (4 input parameters) +Function 486: DrawModelPoints() (4 input parameters) Name: DrawModelPoints Return type: void Description: Draw a model as points @@ -4100,7 +4106,7 @@ Function 485: DrawModelPoints() (4 input parameters) Param[2]: position (type: Vector3) Param[3]: scale (type: float) Param[4]: tint (type: Color) -Function 486: DrawModelPointsEx() (6 input parameters) +Function 487: DrawModelPointsEx() (6 input parameters) Name: DrawModelPointsEx Return type: void Description: Draw a model as points with extended parameters @@ -4110,13 +4116,13 @@ Function 486: DrawModelPointsEx() (6 input parameters) Param[4]: rotationAngle (type: float) Param[5]: scale (type: Vector3) Param[6]: tint (type: Color) -Function 487: DrawBoundingBox() (2 input parameters) +Function 488: DrawBoundingBox() (2 input parameters) Name: DrawBoundingBox Return type: void Description: Draw bounding box (wires) Param[1]: box (type: BoundingBox) Param[2]: color (type: Color) -Function 488: DrawBillboard() (5 input parameters) +Function 489: DrawBillboard() (5 input parameters) Name: DrawBillboard Return type: void Description: Draw a billboard texture @@ -4125,7 +4131,7 @@ Function 488: DrawBillboard() (5 input parameters) Param[3]: position (type: Vector3) Param[4]: scale (type: float) Param[5]: tint (type: Color) -Function 489: DrawBillboardRec() (6 input parameters) +Function 490: DrawBillboardRec() (6 input parameters) Name: DrawBillboardRec Return type: void Description: Draw a billboard texture defined by source @@ -4135,7 +4141,7 @@ Function 489: DrawBillboardRec() (6 input parameters) Param[4]: position (type: Vector3) Param[5]: size (type: Vector2) Param[6]: tint (type: Color) -Function 490: DrawBillboardPro() (9 input parameters) +Function 491: DrawBillboardPro() (9 input parameters) Name: DrawBillboardPro Return type: void Description: Draw a billboard texture defined by source and rotation @@ -4148,13 +4154,13 @@ Function 490: DrawBillboardPro() (9 input parameters) Param[7]: origin (type: Vector2) Param[8]: rotation (type: float) Param[9]: tint (type: Color) -Function 491: UploadMesh() (2 input parameters) +Function 492: UploadMesh() (2 input parameters) Name: UploadMesh Return type: void Description: Upload mesh vertex data in GPU and provide VAO/VBO ids Param[1]: mesh (type: Mesh *) Param[2]: dynamic (type: bool) -Function 492: UpdateMeshBuffer() (5 input parameters) +Function 493: UpdateMeshBuffer() (5 input parameters) Name: UpdateMeshBuffer Return type: void Description: Update mesh vertex data in GPU for a specific buffer index @@ -4163,19 +4169,19 @@ Function 492: UpdateMeshBuffer() (5 input parameters) Param[3]: data (type: const void *) Param[4]: dataSize (type: int) Param[5]: offset (type: int) -Function 493: UnloadMesh() (1 input parameters) +Function 494: UnloadMesh() (1 input parameters) Name: UnloadMesh Return type: void Description: Unload mesh data from CPU and GPU Param[1]: mesh (type: Mesh) -Function 494: DrawMesh() (3 input parameters) +Function 495: DrawMesh() (3 input parameters) Name: DrawMesh Return type: void Description: Draw a 3d mesh with material and transform Param[1]: mesh (type: Mesh) Param[2]: material (type: Material) Param[3]: transform (type: Matrix) -Function 495: DrawMeshInstanced() (4 input parameters) +Function 496: DrawMeshInstanced() (4 input parameters) Name: DrawMeshInstanced Return type: void Description: Draw multiple mesh instances with material and different transforms @@ -4183,35 +4189,35 @@ Function 495: DrawMeshInstanced() (4 input parameters) Param[2]: material (type: Material) Param[3]: transforms (type: const Matrix *) Param[4]: instances (type: int) -Function 496: GetMeshBoundingBox() (1 input parameters) +Function 497: GetMeshBoundingBox() (1 input parameters) Name: GetMeshBoundingBox Return type: BoundingBox Description: Compute mesh bounding box limits Param[1]: mesh (type: Mesh) -Function 497: GenMeshTangents() (1 input parameters) +Function 498: GenMeshTangents() (1 input parameters) Name: GenMeshTangents Return type: void Description: Compute mesh tangents Param[1]: mesh (type: Mesh *) -Function 498: ExportMesh() (2 input parameters) +Function 499: ExportMesh() (2 input parameters) Name: ExportMesh Return type: bool Description: Export mesh data to file, returns true on success Param[1]: mesh (type: Mesh) Param[2]: fileName (type: const char *) -Function 499: ExportMeshAsCode() (2 input parameters) +Function 500: ExportMeshAsCode() (2 input parameters) Name: ExportMeshAsCode Return type: bool Description: Export mesh as code file (.h) defining multiple arrays of vertex attributes Param[1]: mesh (type: Mesh) Param[2]: fileName (type: const char *) -Function 500: GenMeshPoly() (2 input parameters) +Function 501: GenMeshPoly() (2 input parameters) Name: GenMeshPoly Return type: Mesh Description: Generate polygonal mesh Param[1]: sides (type: int) Param[2]: radius (type: float) -Function 501: GenMeshPlane() (4 input parameters) +Function 502: GenMeshPlane() (4 input parameters) Name: GenMeshPlane Return type: Mesh Description: Generate plane mesh (with subdivisions) @@ -4219,42 +4225,42 @@ Function 501: GenMeshPlane() (4 input parameters) Param[2]: length (type: float) Param[3]: resX (type: int) Param[4]: resZ (type: int) -Function 502: GenMeshCube() (3 input parameters) +Function 503: GenMeshCube() (3 input parameters) Name: GenMeshCube Return type: Mesh Description: Generate cuboid mesh Param[1]: width (type: float) Param[2]: height (type: float) Param[3]: length (type: float) -Function 503: GenMeshSphere() (3 input parameters) +Function 504: GenMeshSphere() (3 input parameters) Name: GenMeshSphere Return type: Mesh Description: Generate sphere mesh (standard sphere) Param[1]: radius (type: float) Param[2]: rings (type: int) Param[3]: slices (type: int) -Function 504: GenMeshHemiSphere() (3 input parameters) +Function 505: GenMeshHemiSphere() (3 input parameters) Name: GenMeshHemiSphere Return type: Mesh Description: Generate half-sphere mesh (no bottom cap) Param[1]: radius (type: float) Param[2]: rings (type: int) Param[3]: slices (type: int) -Function 505: GenMeshCylinder() (3 input parameters) +Function 506: GenMeshCylinder() (3 input parameters) Name: GenMeshCylinder Return type: Mesh Description: Generate cylinder mesh Param[1]: radius (type: float) Param[2]: height (type: float) Param[3]: slices (type: int) -Function 506: GenMeshCone() (3 input parameters) +Function 507: GenMeshCone() (3 input parameters) Name: GenMeshCone Return type: Mesh Description: Generate cone/pyramid mesh Param[1]: radius (type: float) Param[2]: height (type: float) Param[3]: slices (type: int) -Function 507: GenMeshTorus() (4 input parameters) +Function 508: GenMeshTorus() (4 input parameters) Name: GenMeshTorus Return type: Mesh Description: Generate torus mesh @@ -4262,7 +4268,7 @@ Function 507: GenMeshTorus() (4 input parameters) Param[2]: size (type: float) Param[3]: radSeg (type: int) Param[4]: sides (type: int) -Function 508: GenMeshKnot() (4 input parameters) +Function 509: GenMeshKnot() (4 input parameters) Name: GenMeshKnot Return type: Mesh Description: Generate trefoil knot mesh @@ -4270,91 +4276,91 @@ Function 508: GenMeshKnot() (4 input parameters) Param[2]: size (type: float) Param[3]: radSeg (type: int) Param[4]: sides (type: int) -Function 509: GenMeshHeightmap() (2 input parameters) +Function 510: GenMeshHeightmap() (2 input parameters) Name: GenMeshHeightmap Return type: Mesh Description: Generate heightmap mesh from image data Param[1]: heightmap (type: Image) Param[2]: size (type: Vector3) -Function 510: GenMeshCubicmap() (2 input parameters) +Function 511: GenMeshCubicmap() (2 input parameters) Name: GenMeshCubicmap Return type: Mesh Description: Generate cubes-based map mesh from image data Param[1]: cubicmap (type: Image) Param[2]: cubeSize (type: Vector3) -Function 511: LoadMaterials() (2 input parameters) +Function 512: LoadMaterials() (2 input parameters) Name: LoadMaterials Return type: Material * Description: Load materials from model file Param[1]: fileName (type: const char *) Param[2]: materialCount (type: int *) -Function 512: LoadMaterialDefault() (0 input parameters) +Function 513: LoadMaterialDefault() (0 input parameters) Name: LoadMaterialDefault Return type: Material Description: Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps) No input parameters -Function 513: IsMaterialValid() (1 input parameters) +Function 514: IsMaterialValid() (1 input parameters) Name: IsMaterialValid Return type: bool Description: Check if a material is valid (shader assigned, map textures loaded in GPU) Param[1]: material (type: Material) -Function 514: UnloadMaterial() (1 input parameters) +Function 515: UnloadMaterial() (1 input parameters) Name: UnloadMaterial Return type: void Description: Unload material from GPU memory (VRAM) Param[1]: material (type: Material) -Function 515: SetMaterialTexture() (3 input parameters) +Function 516: SetMaterialTexture() (3 input parameters) Name: SetMaterialTexture Return type: void Description: Set texture for a material map type (MATERIAL_MAP_DIFFUSE, MATERIAL_MAP_SPECULAR...) Param[1]: material (type: Material *) Param[2]: mapType (type: int) Param[3]: texture (type: Texture2D) -Function 516: SetModelMeshMaterial() (3 input parameters) +Function 517: SetModelMeshMaterial() (3 input parameters) Name: SetModelMeshMaterial Return type: void Description: Set material for a mesh Param[1]: model (type: Model *) Param[2]: meshId (type: int) Param[3]: materialId (type: int) -Function 517: LoadModelAnimations() (2 input parameters) +Function 518: LoadModelAnimations() (2 input parameters) Name: LoadModelAnimations Return type: ModelAnimation * Description: Load model animations from file Param[1]: fileName (type: const char *) Param[2]: animCount (type: int *) -Function 518: UpdateModelAnimation() (3 input parameters) +Function 519: UpdateModelAnimation() (3 input parameters) Name: UpdateModelAnimation Return type: void Description: Update model animation pose (CPU) Param[1]: model (type: Model) Param[2]: anim (type: ModelAnimation) Param[3]: frame (type: int) -Function 519: UpdateModelAnimationBones() (3 input parameters) +Function 520: UpdateModelAnimationBones() (3 input parameters) Name: UpdateModelAnimationBones Return type: void Description: Update model animation mesh bone matrices (GPU skinning) Param[1]: model (type: Model) Param[2]: anim (type: ModelAnimation) Param[3]: frame (type: int) -Function 520: UnloadModelAnimation() (1 input parameters) +Function 521: UnloadModelAnimation() (1 input parameters) Name: UnloadModelAnimation Return type: void Description: Unload animation data Param[1]: anim (type: ModelAnimation) -Function 521: UnloadModelAnimations() (2 input parameters) +Function 522: UnloadModelAnimations() (2 input parameters) Name: UnloadModelAnimations Return type: void Description: Unload animation array data Param[1]: animations (type: ModelAnimation *) Param[2]: animCount (type: int) -Function 522: IsModelAnimationValid() (2 input parameters) +Function 523: IsModelAnimationValid() (2 input parameters) Name: IsModelAnimationValid Return type: bool Description: Check model animation skeleton match Param[1]: model (type: Model) Param[2]: anim (type: ModelAnimation) -Function 523: CheckCollisionSpheres() (4 input parameters) +Function 524: CheckCollisionSpheres() (4 input parameters) Name: CheckCollisionSpheres Return type: bool Description: Check collision between two spheres @@ -4362,40 +4368,40 @@ Function 523: CheckCollisionSpheres() (4 input parameters) Param[2]: radius1 (type: float) Param[3]: center2 (type: Vector3) Param[4]: radius2 (type: float) -Function 524: CheckCollisionBoxes() (2 input parameters) +Function 525: CheckCollisionBoxes() (2 input parameters) Name: CheckCollisionBoxes Return type: bool Description: Check collision between two bounding boxes Param[1]: box1 (type: BoundingBox) Param[2]: box2 (type: BoundingBox) -Function 525: CheckCollisionBoxSphere() (3 input parameters) +Function 526: CheckCollisionBoxSphere() (3 input parameters) Name: CheckCollisionBoxSphere Return type: bool Description: Check collision between box and sphere Param[1]: box (type: BoundingBox) Param[2]: center (type: Vector3) Param[3]: radius (type: float) -Function 526: GetRayCollisionSphere() (3 input parameters) +Function 527: GetRayCollisionSphere() (3 input parameters) Name: GetRayCollisionSphere Return type: RayCollision Description: Get collision info between ray and sphere Param[1]: ray (type: Ray) Param[2]: center (type: Vector3) Param[3]: radius (type: float) -Function 527: GetRayCollisionBox() (2 input parameters) +Function 528: GetRayCollisionBox() (2 input parameters) Name: GetRayCollisionBox Return type: RayCollision Description: Get collision info between ray and box Param[1]: ray (type: Ray) Param[2]: box (type: BoundingBox) -Function 528: GetRayCollisionMesh() (3 input parameters) +Function 529: GetRayCollisionMesh() (3 input parameters) Name: GetRayCollisionMesh Return type: RayCollision Description: Get collision info between ray and mesh Param[1]: ray (type: Ray) Param[2]: mesh (type: Mesh) Param[3]: transform (type: Matrix) -Function 529: GetRayCollisionTriangle() (4 input parameters) +Function 530: GetRayCollisionTriangle() (4 input parameters) Name: GetRayCollisionTriangle Return type: RayCollision Description: Get collision info between ray and triangle @@ -4403,7 +4409,7 @@ Function 529: GetRayCollisionTriangle() (4 input parameters) Param[2]: p1 (type: Vector3) Param[3]: p2 (type: Vector3) Param[4]: p3 (type: Vector3) -Function 530: GetRayCollisionQuad() (5 input parameters) +Function 531: GetRayCollisionQuad() (5 input parameters) Name: GetRayCollisionQuad Return type: RayCollision Description: Get collision info between ray and quad @@ -4412,158 +4418,158 @@ Function 530: GetRayCollisionQuad() (5 input parameters) Param[3]: p2 (type: Vector3) Param[4]: p3 (type: Vector3) Param[5]: p4 (type: Vector3) -Function 531: InitAudioDevice() (0 input parameters) +Function 532: InitAudioDevice() (0 input parameters) Name: InitAudioDevice Return type: void Description: Initialize audio device and context No input parameters -Function 532: CloseAudioDevice() (0 input parameters) +Function 533: CloseAudioDevice() (0 input parameters) Name: CloseAudioDevice Return type: void Description: Close the audio device and context No input parameters -Function 533: IsAudioDeviceReady() (0 input parameters) +Function 534: IsAudioDeviceReady() (0 input parameters) Name: IsAudioDeviceReady Return type: bool Description: Check if audio device has been initialized successfully No input parameters -Function 534: SetMasterVolume() (1 input parameters) +Function 535: SetMasterVolume() (1 input parameters) Name: SetMasterVolume Return type: void Description: Set master volume (listener) Param[1]: volume (type: float) -Function 535: GetMasterVolume() (0 input parameters) +Function 536: GetMasterVolume() (0 input parameters) Name: GetMasterVolume Return type: float Description: Get master volume (listener) No input parameters -Function 536: LoadWave() (1 input parameters) +Function 537: LoadWave() (1 input parameters) Name: LoadWave Return type: Wave Description: Load wave data from file Param[1]: fileName (type: const char *) -Function 537: LoadWaveFromMemory() (3 input parameters) +Function 538: LoadWaveFromMemory() (3 input parameters) Name: LoadWaveFromMemory Return type: Wave Description: Load wave from memory buffer, fileType refers to extension: i.e. '.wav' Param[1]: fileType (type: const char *) Param[2]: fileData (type: const unsigned char *) Param[3]: dataSize (type: int) -Function 538: IsWaveValid() (1 input parameters) +Function 539: IsWaveValid() (1 input parameters) Name: IsWaveValid Return type: bool Description: Checks if wave data is valid (data loaded and parameters) Param[1]: wave (type: Wave) -Function 539: LoadSound() (1 input parameters) +Function 540: LoadSound() (1 input parameters) Name: LoadSound Return type: Sound Description: Load sound from file Param[1]: fileName (type: const char *) -Function 540: LoadSoundFromWave() (1 input parameters) +Function 541: LoadSoundFromWave() (1 input parameters) Name: LoadSoundFromWave Return type: Sound Description: Load sound from wave data Param[1]: wave (type: Wave) -Function 541: LoadSoundAlias() (1 input parameters) +Function 542: LoadSoundAlias() (1 input parameters) Name: LoadSoundAlias Return type: Sound Description: Create a new sound that shares the same sample data as the source sound, does not own the sound data Param[1]: source (type: Sound) -Function 542: IsSoundValid() (1 input parameters) +Function 543: IsSoundValid() (1 input parameters) Name: IsSoundValid Return type: bool Description: Checks if a sound is valid (data loaded and buffers initialized) Param[1]: sound (type: Sound) -Function 543: UpdateSound() (3 input parameters) +Function 544: UpdateSound() (3 input parameters) Name: UpdateSound Return type: void Description: Update sound buffer with new data (data and frame count should fit in sound) Param[1]: sound (type: Sound) Param[2]: data (type: const void *) Param[3]: sampleCount (type: int) -Function 544: UnloadWave() (1 input parameters) +Function 545: UnloadWave() (1 input parameters) Name: UnloadWave Return type: void Description: Unload wave data Param[1]: wave (type: Wave) -Function 545: UnloadSound() (1 input parameters) +Function 546: UnloadSound() (1 input parameters) Name: UnloadSound Return type: void Description: Unload sound Param[1]: sound (type: Sound) -Function 546: UnloadSoundAlias() (1 input parameters) +Function 547: UnloadSoundAlias() (1 input parameters) Name: UnloadSoundAlias Return type: void Description: Unload a sound alias (does not deallocate sample data) Param[1]: alias (type: Sound) -Function 547: ExportWave() (2 input parameters) +Function 548: ExportWave() (2 input parameters) Name: ExportWave Return type: bool Description: Export wave data to file, returns true on success Param[1]: wave (type: Wave) Param[2]: fileName (type: const char *) -Function 548: ExportWaveAsCode() (2 input parameters) +Function 549: ExportWaveAsCode() (2 input parameters) Name: ExportWaveAsCode Return type: bool Description: Export wave sample data to code (.h), returns true on success Param[1]: wave (type: Wave) Param[2]: fileName (type: const char *) -Function 549: PlaySound() (1 input parameters) +Function 550: PlaySound() (1 input parameters) Name: PlaySound Return type: void Description: Play a sound Param[1]: sound (type: Sound) -Function 550: StopSound() (1 input parameters) +Function 551: StopSound() (1 input parameters) Name: StopSound Return type: void Description: Stop playing a sound Param[1]: sound (type: Sound) -Function 551: PauseSound() (1 input parameters) +Function 552: PauseSound() (1 input parameters) Name: PauseSound Return type: void Description: Pause a sound Param[1]: sound (type: Sound) -Function 552: ResumeSound() (1 input parameters) +Function 553: ResumeSound() (1 input parameters) Name: ResumeSound Return type: void Description: Resume a paused sound Param[1]: sound (type: Sound) -Function 553: IsSoundPlaying() (1 input parameters) +Function 554: IsSoundPlaying() (1 input parameters) Name: IsSoundPlaying Return type: bool Description: Check if a sound is currently playing Param[1]: sound (type: Sound) -Function 554: SetSoundVolume() (2 input parameters) +Function 555: SetSoundVolume() (2 input parameters) Name: SetSoundVolume Return type: void Description: Set volume for a sound (1.0 is max level) Param[1]: sound (type: Sound) Param[2]: volume (type: float) -Function 555: SetSoundPitch() (2 input parameters) +Function 556: SetSoundPitch() (2 input parameters) Name: SetSoundPitch Return type: void Description: Set pitch for a sound (1.0 is base level) Param[1]: sound (type: Sound) Param[2]: pitch (type: float) -Function 556: SetSoundPan() (2 input parameters) +Function 557: SetSoundPan() (2 input parameters) Name: SetSoundPan Return type: void Description: Set pan for a sound (0.5 is center) Param[1]: sound (type: Sound) Param[2]: pan (type: float) -Function 557: WaveCopy() (1 input parameters) +Function 558: WaveCopy() (1 input parameters) Name: WaveCopy Return type: Wave Description: Copy a wave to a new wave Param[1]: wave (type: Wave) -Function 558: WaveCrop() (3 input parameters) +Function 559: WaveCrop() (3 input parameters) Name: WaveCrop Return type: void Description: Crop a wave to defined frames range Param[1]: wave (type: Wave *) Param[2]: initFrame (type: int) Param[3]: finalFrame (type: int) -Function 559: WaveFormat() (4 input parameters) +Function 560: WaveFormat() (4 input parameters) Name: WaveFormat Return type: void Description: Convert wave data to desired format @@ -4571,203 +4577,203 @@ Function 559: WaveFormat() (4 input parameters) Param[2]: sampleRate (type: int) Param[3]: sampleSize (type: int) Param[4]: channels (type: int) -Function 560: LoadWaveSamples() (1 input parameters) +Function 561: LoadWaveSamples() (1 input parameters) Name: LoadWaveSamples Return type: float * Description: Load samples data from wave as a 32bit float data array Param[1]: wave (type: Wave) -Function 561: UnloadWaveSamples() (1 input parameters) +Function 562: UnloadWaveSamples() (1 input parameters) Name: UnloadWaveSamples Return type: void Description: Unload samples data loaded with LoadWaveSamples() Param[1]: samples (type: float *) -Function 562: LoadMusicStream() (1 input parameters) +Function 563: LoadMusicStream() (1 input parameters) Name: LoadMusicStream Return type: Music Description: Load music stream from file Param[1]: fileName (type: const char *) -Function 563: LoadMusicStreamFromMemory() (3 input parameters) +Function 564: LoadMusicStreamFromMemory() (3 input parameters) Name: LoadMusicStreamFromMemory Return type: Music Description: Load music stream from data Param[1]: fileType (type: const char *) Param[2]: data (type: const unsigned char *) Param[3]: dataSize (type: int) -Function 564: IsMusicValid() (1 input parameters) +Function 565: IsMusicValid() (1 input parameters) Name: IsMusicValid Return type: bool Description: Checks if a music stream is valid (context and buffers initialized) Param[1]: music (type: Music) -Function 565: UnloadMusicStream() (1 input parameters) +Function 566: UnloadMusicStream() (1 input parameters) Name: UnloadMusicStream Return type: void Description: Unload music stream Param[1]: music (type: Music) -Function 566: PlayMusicStream() (1 input parameters) +Function 567: PlayMusicStream() (1 input parameters) Name: PlayMusicStream Return type: void Description: Start music playing Param[1]: music (type: Music) -Function 567: IsMusicStreamPlaying() (1 input parameters) +Function 568: IsMusicStreamPlaying() (1 input parameters) Name: IsMusicStreamPlaying Return type: bool Description: Check if music is playing Param[1]: music (type: Music) -Function 568: UpdateMusicStream() (1 input parameters) +Function 569: UpdateMusicStream() (1 input parameters) Name: UpdateMusicStream Return type: void Description: Updates buffers for music streaming Param[1]: music (type: Music) -Function 569: StopMusicStream() (1 input parameters) +Function 570: StopMusicStream() (1 input parameters) Name: StopMusicStream Return type: void Description: Stop music playing Param[1]: music (type: Music) -Function 570: PauseMusicStream() (1 input parameters) +Function 571: PauseMusicStream() (1 input parameters) Name: PauseMusicStream Return type: void Description: Pause music playing Param[1]: music (type: Music) -Function 571: ResumeMusicStream() (1 input parameters) +Function 572: ResumeMusicStream() (1 input parameters) Name: ResumeMusicStream Return type: void Description: Resume playing paused music Param[1]: music (type: Music) -Function 572: SeekMusicStream() (2 input parameters) +Function 573: SeekMusicStream() (2 input parameters) Name: SeekMusicStream Return type: void Description: Seek music to a position (in seconds) Param[1]: music (type: Music) Param[2]: position (type: float) -Function 573: SetMusicVolume() (2 input parameters) +Function 574: SetMusicVolume() (2 input parameters) Name: SetMusicVolume Return type: void Description: Set volume for music (1.0 is max level) Param[1]: music (type: Music) Param[2]: volume (type: float) -Function 574: SetMusicPitch() (2 input parameters) +Function 575: SetMusicPitch() (2 input parameters) Name: SetMusicPitch Return type: void Description: Set pitch for a music (1.0 is base level) Param[1]: music (type: Music) Param[2]: pitch (type: float) -Function 575: SetMusicPan() (2 input parameters) +Function 576: SetMusicPan() (2 input parameters) Name: SetMusicPan Return type: void Description: Set pan for a music (0.5 is center) Param[1]: music (type: Music) Param[2]: pan (type: float) -Function 576: GetMusicTimeLength() (1 input parameters) +Function 577: GetMusicTimeLength() (1 input parameters) Name: GetMusicTimeLength Return type: float Description: Get music time length (in seconds) Param[1]: music (type: Music) -Function 577: GetMusicTimePlayed() (1 input parameters) +Function 578: GetMusicTimePlayed() (1 input parameters) Name: GetMusicTimePlayed Return type: float Description: Get current music time played (in seconds) Param[1]: music (type: Music) -Function 578: LoadAudioStream() (3 input parameters) +Function 579: LoadAudioStream() (3 input parameters) Name: LoadAudioStream Return type: AudioStream Description: Load audio stream (to stream raw audio pcm data) Param[1]: sampleRate (type: unsigned int) Param[2]: sampleSize (type: unsigned int) Param[3]: channels (type: unsigned int) -Function 579: IsAudioStreamValid() (1 input parameters) +Function 580: IsAudioStreamValid() (1 input parameters) Name: IsAudioStreamValid Return type: bool Description: Checks if an audio stream is valid (buffers initialized) Param[1]: stream (type: AudioStream) -Function 580: UnloadAudioStream() (1 input parameters) +Function 581: UnloadAudioStream() (1 input parameters) Name: UnloadAudioStream Return type: void Description: Unload audio stream and free memory Param[1]: stream (type: AudioStream) -Function 581: UpdateAudioStream() (3 input parameters) +Function 582: UpdateAudioStream() (3 input parameters) Name: UpdateAudioStream Return type: void Description: Update audio stream buffers with data Param[1]: stream (type: AudioStream) Param[2]: data (type: const void *) Param[3]: frameCount (type: int) -Function 582: IsAudioStreamProcessed() (1 input parameters) +Function 583: IsAudioStreamProcessed() (1 input parameters) Name: IsAudioStreamProcessed Return type: bool Description: Check if any audio stream buffers requires refill Param[1]: stream (type: AudioStream) -Function 583: PlayAudioStream() (1 input parameters) +Function 584: PlayAudioStream() (1 input parameters) Name: PlayAudioStream Return type: void Description: Play audio stream Param[1]: stream (type: AudioStream) -Function 584: PauseAudioStream() (1 input parameters) +Function 585: PauseAudioStream() (1 input parameters) Name: PauseAudioStream Return type: void Description: Pause audio stream Param[1]: stream (type: AudioStream) -Function 585: ResumeAudioStream() (1 input parameters) +Function 586: ResumeAudioStream() (1 input parameters) Name: ResumeAudioStream Return type: void Description: Resume audio stream Param[1]: stream (type: AudioStream) -Function 586: IsAudioStreamPlaying() (1 input parameters) +Function 587: IsAudioStreamPlaying() (1 input parameters) Name: IsAudioStreamPlaying Return type: bool Description: Check if audio stream is playing Param[1]: stream (type: AudioStream) -Function 587: StopAudioStream() (1 input parameters) +Function 588: StopAudioStream() (1 input parameters) Name: StopAudioStream Return type: void Description: Stop audio stream Param[1]: stream (type: AudioStream) -Function 588: SetAudioStreamVolume() (2 input parameters) +Function 589: SetAudioStreamVolume() (2 input parameters) Name: SetAudioStreamVolume Return type: void Description: Set volume for audio stream (1.0 is max level) Param[1]: stream (type: AudioStream) Param[2]: volume (type: float) -Function 589: SetAudioStreamPitch() (2 input parameters) +Function 590: SetAudioStreamPitch() (2 input parameters) Name: SetAudioStreamPitch Return type: void Description: Set pitch for audio stream (1.0 is base level) Param[1]: stream (type: AudioStream) Param[2]: pitch (type: float) -Function 590: SetAudioStreamPan() (2 input parameters) +Function 591: SetAudioStreamPan() (2 input parameters) Name: SetAudioStreamPan Return type: void Description: Set pan for audio stream (0.5 is centered) Param[1]: stream (type: AudioStream) Param[2]: pan (type: float) -Function 591: SetAudioStreamBufferSizeDefault() (1 input parameters) +Function 592: SetAudioStreamBufferSizeDefault() (1 input parameters) Name: SetAudioStreamBufferSizeDefault Return type: void Description: Default size for new audio streams Param[1]: size (type: int) -Function 592: SetAudioStreamCallback() (2 input parameters) +Function 593: SetAudioStreamCallback() (2 input parameters) Name: SetAudioStreamCallback Return type: void Description: Audio thread callback to request new data Param[1]: stream (type: AudioStream) Param[2]: callback (type: AudioCallback) -Function 593: AttachAudioStreamProcessor() (2 input parameters) +Function 594: AttachAudioStreamProcessor() (2 input parameters) Name: AttachAudioStreamProcessor Return type: void Description: Attach audio stream processor to stream, receives frames x 2 samples as 'float' (stereo) Param[1]: stream (type: AudioStream) Param[2]: processor (type: AudioCallback) -Function 594: DetachAudioStreamProcessor() (2 input parameters) +Function 595: DetachAudioStreamProcessor() (2 input parameters) Name: DetachAudioStreamProcessor Return type: void Description: Detach audio stream processor from stream Param[1]: stream (type: AudioStream) Param[2]: processor (type: AudioCallback) -Function 595: AttachAudioMixedProcessor() (1 input parameters) +Function 596: AttachAudioMixedProcessor() (1 input parameters) Name: AttachAudioMixedProcessor Return type: void Description: Attach audio stream processor to the entire audio pipeline, receives frames x 2 samples as 'float' (stereo) Param[1]: processor (type: AudioCallback) -Function 596: DetachAudioMixedProcessor() (1 input parameters) +Function 597: DetachAudioMixedProcessor() (1 input parameters) Name: DetachAudioMixedProcessor Return type: void Description: Detach audio stream processor from the entire audio pipeline diff --git a/tools/rlparser/output/raylib_api.xml b/tools/rlparser/output/raylib_api.xml index 59f2d4a50..96dbdbf64 100644 --- a/tools/rlparser/output/raylib_api.xml +++ b/tools/rlparser/output/raylib_api.xml @@ -679,7 +679,7 @@ - + @@ -1168,6 +1168,10 @@ + + + + diff --git a/tools/rlparser/rlparser b/tools/rlparser/rlparser new file mode 100755 index 0000000000000000000000000000000000000000..b68032c023debdd4b5e656b794864b81bd2e123c GIT binary patch literal 43144 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 literal 0 HcmV?d00001 From 1c45776bb700b55c81d5bbc5f16a4f601e602c38 Mon Sep 17 00:00:00 2001 From: themushroompirates <59015901+themushroompirates@users.noreply.github.com> Date: Wed, 15 Oct 2025 19:37:17 +0200 Subject: [PATCH 119/167] Added clock of clocks example (#5263) --- examples/shapes/shapes_clock_of_clocks.c | 227 +++++++++++++++++++++ examples/shapes/shapes_clock_of_clocks.png | Bin 0 -> 23916 bytes 2 files changed, 227 insertions(+) create mode 100644 examples/shapes/shapes_clock_of_clocks.c create mode 100644 examples/shapes/shapes_clock_of_clocks.png diff --git a/examples/shapes/shapes_clock_of_clocks.c b/examples/shapes/shapes_clock_of_clocks.c new file mode 100644 index 000000000..0418255e4 --- /dev/null +++ b/examples/shapes/shapes_clock_of_clocks.c @@ -0,0 +1,227 @@ +/******************************************************************************************* +* +* raylib [shapes] example - clock of clocks +* +* Example complexity rating: [★★☆☆] 2/4 +* +* Example originally created with raylib 5.5 +* +* Example contributed by JP Mortiboys (@themushroompirates) 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 JP Mortiboys (@themushroompirates) +* +********************************************************************************************/ + +#include "raylib.h" + +#include "raymath.h" // Required for: Lerp() +#include // Required for: time(), localtime() + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + SetConfigFlags(FLAG_MSAA_4X_HINT); + InitWindow(screenWidth, screenHeight, "raylib [shapes] example - clock of clocks"); + + const Color bgColor = ColorLerp(DARKBLUE, BLACK, 0.75f); + const Color handsColor = ColorLerp(YELLOW, RAYWHITE, .25f); + + const float clockFaceSize = 24; + const float clockFaceSpacing = 8.0f; + const float sectionSpacing = 16.0f; + + const Vector2 TL = (Vector2){ 0.0f, 90.0f }; // Top-left corner + const Vector2 TR = (Vector2){ 90.0f, 180.0f }; // Top-right corner + const Vector2 BR = (Vector2){ 180.0f, 270.0f }; // Bottom-right corner + const Vector2 BL = (Vector2){ 0.0f, 270.0f }; // Bottom-left corner + const Vector2 HH = (Vector2){ 0.0f, 180.0f }; // Horizontal line + const Vector2 VV = (Vector2){ 90.0f, 270.0f }; // Vertical line + const Vector2 ZZ = (Vector2){ 135.0f, 135.0f }; // Not relevant + + const Vector2 digitAngles[10][24] = { + /* 0 */ { TL,HH,HH,TR, /* */ VV,TL,TR,VV,/* */ VV,VV,VV,VV,/* */ VV,VV,VV,VV,/* */ VV,BL,BR,VV,/* */ BL,HH,HH,BR }, + /* 1 */ { TL,HH,TR,ZZ, /* */ BL,TR,VV,ZZ,/* */ ZZ,VV,VV,ZZ,/* */ ZZ,VV,VV,ZZ,/* */ TL,BR,BL,TR,/* */ BL,HH,HH,BR }, + /* 2 */ { TL,HH,HH,TR, /* */ BL,HH,TR,VV,/* */ TL,HH,BR,VV,/* */ VV,TL,HH,BR,/* */ VV,BL,HH,TR,/* */ BL,HH,HH,BR }, + /* 3 */ { TL,HH,HH,TR, /* */ BL,HH,TR,VV,/* */ TL,HH,BR,VV,/* */ BL,HH,TR,VV,/* */ TL,HH,BR,VV,/* */ BL,HH,HH,BR }, + /* 4 */ { TL,TR,TL,TR, /* */ VV,VV,VV,VV,/* */ VV,BL,BR,VV,/* */ BL,HH,TR,VV,/* */ ZZ,ZZ,VV,VV,/* */ ZZ,ZZ,BL,BR }, + /* 5 */ { TL,HH,HH,TR, /* */ VV,TL,HH,BR,/* */ VV,BL,HH,TR,/* */ BL,HH,TR,VV,/* */ TL,HH,BR,VV,/* */ BL,HH,HH,BR }, + /* 6 */ { TL,HH,HH,TR, /* */ VV,TL,HH,BR,/* */ VV,BL,HH,TR,/* */ VV,TL,TR,VV,/* */ VV,BL,BR,VV,/* */ BL,HH,HH,BR }, + /* 7 */ { TL,HH,HH,TR, /* */ BL,HH,TR,VV,/* */ ZZ,ZZ,VV,VV,/* */ ZZ,ZZ,VV,VV,/* */ ZZ,ZZ,VV,VV,/* */ ZZ,ZZ,BL,BR }, + /* 8 */ { TL,HH,HH,TR, /* */ VV,TL,TR,VV,/* */ VV,BL,BR,VV,/* */ VV,TL,TR,VV,/* */ VV,BL,BR,VV,/* */ BL,HH,HH,BR }, + /* 9 */ { TL,HH,HH,TR, /* */ VV,TL,TR,VV,/* */ VV,BL,BR,VV,/* */ BL,HH,TR,VV,/* */ TL,HH,BR,VV,/* */ BL,HH,HH,BR }, + }; + // Time for the hands to move to the new position (in seconds); this must be <1s + const float handsMoveDuration = .5f; + + // We store the previous seconds value so we can see if the time has changed + int prevSeconds = -1; + + // This represents the real position where the hands are right now + Vector2 currentAngles[6][24] = { 0 }; + + // This is the position where the hands were moving from + Vector2 srcAngles[6][24] = { 0 }; + // This is the position where the hands are moving to + Vector2 dstAngles[6][24] = { 0 }; + + // Current animation timer + float handsMoveTimer = 0.0f; + + // 12 or 24 hour mode + int hourMode = 24; + + 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 + //---------------------------------------------------------------------------------- + + // Get the current time + time_t rawtime; + struct tm *timeinfo; + + time(&rawtime); + timeinfo = localtime(&rawtime); + + if (timeinfo->tm_sec != prevSeconds) { + // The time has changed, so we need to move the hands to the new positions + prevSeconds = timeinfo->tm_sec; + + // Format the current time so we can access the individual digits + const char *clockDigits = TextFormat("%02d%02d%02d", timeinfo->tm_hour % hourMode, timeinfo->tm_min, timeinfo->tm_sec); + + // Fetch where we want all the hands to be + for (int digit = 0; digit < 6; digit++) { + for (int cell = 0; cell < 24; cell++) { + srcAngles[digit][cell] = currentAngles[digit][cell]; + dstAngles[digit][cell] = digitAngles[ clockDigits[digit] - '0' ][cell]; + + // Quick exception for 12h mode + if (digit == 0 && hourMode == 12 && clockDigits[0] == '0') { + dstAngles[digit][cell] = ZZ; + } + + if (srcAngles[digit][cell].x > dstAngles[digit][cell].x) { + srcAngles[digit][cell].x -= 360.0f; + } + if (srcAngles[digit][cell].y > dstAngles[digit][cell].y) { + srcAngles[digit][cell].y -= 360.0f; + } + } + } + + // Reset the timer + handsMoveTimer = -GetFrameTime(); + } + + // Now let's animate all the hands if we need to + if (handsMoveTimer < handsMoveDuration) { + // Increase the timer but don't go above the maximum + handsMoveTimer = Clamp(handsMoveTimer + GetFrameTime(), 0, handsMoveDuration); + + // Calculate the % completion of the animation + float t = handsMoveTimer / handsMoveDuration; + + // A little cheeky smoothstep + t = t * t * (3.0f - 2.0f * t); + + for (int digit = 0; digit < 6; digit++) { + for (int cell = 0; cell < 24; cell++) { + currentAngles[digit][cell].x = Lerp(srcAngles[digit][cell].x, dstAngles[digit][cell].x, t); + currentAngles[digit][cell].y = Lerp(srcAngles[digit][cell].y, dstAngles[digit][cell].y, t); + } + } + + if (handsMoveTimer == handsMoveDuration) { + // The animation has now finished + } + } + + // Handle input + + // Toggle between 12 and 24 hour mode with space + if (IsKeyPressed(KEY_SPACE)) { + hourMode = 36 - hourMode; + } + + + + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(bgColor); + + DrawText(TextFormat("%d-h mode, space to change", hourMode), 10, 30, 20, RAYWHITE); + + float xOffset = 4.0f; + + for (int digit = 0; digit < 6; digit++) { + + for (int row = 0; row < 6; row++) { + for (int col = 0; col < 4; col++) { + Vector2 centre = (Vector2){ + xOffset + col*(clockFaceSize+clockFaceSpacing) + clockFaceSize * .5f, + 100 + row*(clockFaceSize+clockFaceSpacing) + clockFaceSize * .5f + }; + DrawRing(centre, clockFaceSize * 0.5f - 2.0f, clockFaceSize * 0.5f, 0, 360, 24, DARKGRAY); + + // Big hand + DrawRectanglePro( + (Rectangle){centre.x, centre.y, clockFaceSize*.5f+4.0f, 4.0f}, + (Vector2){ 2.0f, 2.0f }, + currentAngles[digit][row*4+col].x, + handsColor + ); + + // Little hand + DrawRectanglePro( + (Rectangle){centre.x, centre.y, clockFaceSize*.5f+2.0f, 4.0f}, + (Vector2){ 2.0f, 2.0f }, + currentAngles[digit][row*4+col].y, + handsColor + ); + } + } + + xOffset += (clockFaceSize+clockFaceSpacing) * 4; + if (digit % 2 == 1) { + + DrawRing((Vector2){xOffset + 4.0f, 160.0f}, 6.0f, 8.0f, 0.0f, 360.0f, 24, handsColor); + DrawRing((Vector2){xOffset + 4.0f, 225.0f}, 6.0f, 8.0f, 0.0f, 360.0f, 24, handsColor); + + xOffset += sectionSpacing; + + } + } + + DrawFPS(10, 10); + + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} \ No newline at end of file diff --git a/examples/shapes/shapes_clock_of_clocks.png b/examples/shapes/shapes_clock_of_clocks.png new file mode 100644 index 0000000000000000000000000000000000000000..fb91d7263d90be64df868cbbc616fa7eb707c4ef GIT binary patch literal 23916 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 aY>0V$y}2MX6?}_2V)?SwORqRmWBwP&WT=t= literal 0 HcmV?d00001 From 2a04317cff9dfdd7e0880dc5105ced8ca48b1eb9 Mon Sep 17 00:00:00 2001 From: JordSant <77529699+JordSant@users.noreply.github.com> Date: Wed, 15 Oct 2025 19:39:47 +0200 Subject: [PATCH 120/167] [examples] Added: `shapes_particles` (#5260) * [Examples] Added shapes_particles * Changes to follow the code conventions. Improved some things. * Fixed name * Fixed PNG name --------- Co-authored-by: Ray --- examples/shapes/shapes_simple_particles.c | 277 +++++++++ examples/shapes/shapes_simple_particles.png | Bin 0 -> 32265 bytes .../examples/shapes_simple_particles.vcxproj | 569 ++++++++++++++++++ projects/VS2022/raylib.sln | 8 + 4 files changed, 854 insertions(+) create mode 100644 examples/shapes/shapes_simple_particles.c create mode 100644 examples/shapes/shapes_simple_particles.png create mode 100644 projects/VS2022/examples/shapes_simple_particles.vcxproj diff --git a/examples/shapes/shapes_simple_particles.c b/examples/shapes/shapes_simple_particles.c new file mode 100644 index 000000000..aae85f35d --- /dev/null +++ b/examples/shapes/shapes_simple_particles.c @@ -0,0 +1,277 @@ +/******************************************************************************************* +* +* raylib [shapes] example - simple particles +* +* Example complexity rating: [★☆☆☆] 1/4 +* +* Example originally created with raylib 5.6, last time updated with raylib 5.6 +* +* Example contributed by Jordi Santonja (@JordSant) +* +* 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 // Required for: calloc(), free() +#include // Required for: cosf(), sinf() + +#define MAX_PARTICLES 3000 // Max number particles + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- +typedef enum ParticleType { + WATER = 0, + SMOKE, + FIRE +} ParticleType; + +static const char particleTypesChar[3][10] = { "WATER", "SMOKE", "FIRE" }; + +typedef struct Particle { + Vector2 position; // Particle position on screen + Vector2 velocity; // Particle current speed and direction + bool alive; // Particle alive: inside screen and life time + float lifeTime; // Particle life time + ParticleType type; // Particle type (WATER, SMOKE, FIRE) + float radius; // Particle radius + Color color; // Particle color +} Particle; + +typedef struct CircularBuffer { + int head; // Index for the next write + int tail; // Index for the next read + Particle *buffer; // Particle buffer array +} CircularBuffer; + +//---------------------------------------------------------------------------------- +// Module Functions Declaration +//---------------------------------------------------------------------------------- +static void EmitParticle(CircularBuffer *circularBuffer, Vector2 emitterPosition, ParticleType type); +static Particle *AddToCircularBuffer(CircularBuffer *circularBuffer); +static void UpdateParticles(CircularBuffer *circularBuffer, int screenWidth, int screenHeight); +static void UpdateCircularBuffer(CircularBuffer *circularBuffer); +static void DrawParticles(CircularBuffer *circularBuffer); + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [shapes] example - particles"); + + // 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; + Vector2 emitterPosition = { screenWidth/2.0f, screenHeight/2.0f }; + + 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 + //---------------------------------------------------------------------------------- + // Emit new particles: when emissionRate is 1, emit every frame + if (emissionRate < 0) + { + if (rand()%(-emissionRate) == 0) + EmitParticle(&circularBuffer, emitterPosition, currentType); + } + else + { + for (int i = 0; i <= emissionRate; ++i) + EmitParticle(&circularBuffer, emitterPosition, currentType); + } + + // Update the parameters of each particle + UpdateParticles(&circularBuffer, screenWidth, screenHeight); + // Remove dead particles from the circular buffer + UpdateCircularBuffer(&circularBuffer); + + // Change Particle Emission Rate (UP/DOWN arrows) + if (IsKeyPressed(KEY_UP)) + ++emissionRate; + if (IsKeyPressed(KEY_DOWN)) + --emissionRate; + + // Change Particle Type (LEFT/RIGHT arrows) + if (IsKeyPressed(KEY_RIGHT)) + (currentType == FIRE) ? (currentType = WATER) : ++currentType; + if (IsKeyPressed(KEY_LEFT)) + (currentType == WATER) ? (currentType = FIRE) : --currentType; + + if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) + emitterPosition = GetMousePosition(); + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + // Call the function with a loop to draw all particles + DrawParticles(&circularBuffer); + + // Draw UI and Instructions + DrawRectangle(5, 5, 315, 75, Fade(SKYBLUE, 0.5f)); + DrawRectangleLines(5, 5, 315, 75, BLUE); + + DrawText("CONTROLS:", 15, 15, 10, BLACK); + DrawText("UP/DOWN: Change Particle Emission Rate", 15, 35, 10, BLACK); + DrawText("LEFT/RIGHT: Change Particle Type (Water, Smoke, Fire)", 15, 55, 10, BLACK); + + if (emissionRate < 0) + DrawText(TextFormat("Particles every %d frames | Type: %s", -emissionRate, particleTypesChar[currentType]), 15, 95, 10, DARKGRAY); + else + DrawText(TextFormat("%d Particles per frame | Type: %s", emissionRate + 1, particleTypesChar[currentType]), 15, 95, 10, DARKGRAY); + + DrawFPS(screenWidth - 80, 10); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + RL_FREE(particles); // Free particles array data + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} + +//---------------------------------------------------------------------------------- +// Module Functions Definition +//---------------------------------------------------------------------------------- +static void EmitParticle(CircularBuffer *circularBuffer, Vector2 emitterPosition, ParticleType type) +{ + Particle *newParticle = AddToCircularBuffer(circularBuffer); + // If buffer is full, newParticle is NULL + if (newParticle != NULL) + { + // Fill particle properties + newParticle->position = emitterPosition; + newParticle->alive = true; + newParticle->lifeTime = 0.0f; + newParticle->type = type; + float speed = (float)(rand()%10)/5.0f; + switch (type) + { + case WATER: + newParticle->radius = 5.0f; + newParticle->color = BLUE; + break; + case SMOKE: + newParticle->radius = 7.0f; + newParticle->color = GRAY; + break; + case FIRE: + newParticle->radius = 10.0f; + newParticle->color = YELLOW; + speed /= 10.0f; + break; + default: break; + } + float direction = (float)(rand()%360); + newParticle->velocity = (Vector2){ speed*cosf(direction*DEG2RAD), speed*sinf(direction*DEG2RAD) }; + } +} + +static Particle *AddToCircularBuffer(CircularBuffer *circularBuffer) +{ + Particle *particle = NULL; + + // Check if buffer full + if (((circularBuffer->head + 1)%MAX_PARTICLES) != circularBuffer->tail) + { + // Add new particle to the head position and advance head + particle = &circularBuffer->buffer[circularBuffer->head]; + circularBuffer->head = (circularBuffer->head + 1)%MAX_PARTICLES; + } + + return particle; +} + +static void UpdateParticles(CircularBuffer *circularBuffer, int screenWidth, int screenHeight) +{ + for (int i = circularBuffer->tail; i != circularBuffer->head; i = (i + 1)%MAX_PARTICLES) + { + // Update particle life and positions + circularBuffer->buffer[i].lifeTime += 1.0f/60.0f; // 60 FPS -> 1/60 seconds per frame + + 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; + 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; + 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; + 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)) + 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) + { + circularBuffer->tail = (circularBuffer->tail + 1)%MAX_PARTICLES; + } +} + +static void DrawParticles(CircularBuffer *circularBuffer) +{ + for (int i = circularBuffer->tail; i != circularBuffer->head; i = (i + 1)%MAX_PARTICLES) + { + if (circularBuffer->buffer[i].alive) + { + DrawCircleV(circularBuffer->buffer[i].position, + circularBuffer->buffer[i].radius, + circularBuffer->buffer[i].color); + } + } +} diff --git a/examples/shapes/shapes_simple_particles.png b/examples/shapes/shapes_simple_particles.png new file mode 100644 index 0000000000000000000000000000000000000000..78abece57c0dccecba54c3c679beb9e163d6460a GIT binary patch literal 32265 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 A2LJ#7 literal 0 HcmV?d00001 diff --git a/projects/VS2022/examples/shapes_simple_particles.vcxproj b/projects/VS2022/examples/shapes_simple_particles.vcxproj new file mode 100644 index 000000000..8a5270503 --- /dev/null +++ b/projects/VS2022/examples/shapes_simple_particles.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 + + + + {497FDF54-9762-4048-A833-61CC3980A0FB} + Win32Proj + shapes_simple_particles + 10.0 + shapes_simple_particles + + + + 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\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + 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 881c489ba..48f3762dd 100644 --- a/projects/VS2022/raylib.sln +++ b/projects/VS2022/raylib.sln @@ -383,6 +383,14 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_triangle_strip", "ex EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_directory_files", "examples\core_directory_files.vcxproj", "{6B1A933E-71B8-4C1F-9E79-02D98830E671}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_kaleidoscope", "examples\shapes_kaleidoscope.vcxproj", "{6B1A933E-71B8-4C1F-9E79-02D98830E671}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_recursive_tree", "examples\shapes_recursive_tree.vcxproj", "{6B1A933E-71B8-4C1F-9E79-02D98830E671}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_triangle_strip", "examples\shapes_triangle_strip.vcxproj", "{2CCCD9E4-9058-4291-BD89-39C979F0CA1E}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_simple_particles", "examples\shapes_simple_particles.vcxproj", "{6B1A933E-71B8-4C1F-9E79-02D98830E671}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug.DLL|ARM64 = Debug.DLL|ARM64 From 4ba92f8962ef199ebf85f89b68a40988775de947 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 15 Oct 2025 19:48:36 +0200 Subject: [PATCH 121/167] REVIEWED: Solution when adding new examples --- examples/core/core_directory_files.c | 33 +- examples/core/raygui.h | 5757 +++++++++++++++++ .../examples/core_directory_files.vcxproj | 2 +- .../VS2022/examples/shapes_pie_chart.vcxproj | 2 +- projects/VS2022/raylib.sln | 517 +- 5 files changed, 6059 insertions(+), 252 deletions(-) create mode 100644 examples/core/raygui.h diff --git a/examples/core/core_directory_files.c b/examples/core/core_directory_files.c index 27764315b..b7e11b686 100644 --- a/examples/core/core_directory_files.c +++ b/examples/core/core_directory_files.c @@ -16,12 +16,13 @@ ********************************************************************************************/ #include "raylib.h" -#include // Required for: strcpy() - -#define MAX_FILEPATH_SIZE 2048 #define RAYGUI_IMPLEMENTATION -#include "../shapes/raygui.h" // Required for GUI controls +#include "raygui.h" // Required for GUI controls + +#include // Required for: strcpy() + +#define MAX_FILEPATH_SIZE 2048 //------------------------------------------------------------------------------------ // Program main entry point @@ -37,8 +38,11 @@ int main(void) char directory[MAX_FILEPATH_SIZE] = { 0 }; strcpy(directory, GetWorkingDirectory()); + FilePathList files = LoadDirectoryFiles(directory); + int btnBackPressed = false; + SetTargetFPS(60); //-------------------------------------------------------------------------------------- @@ -46,6 +50,15 @@ int main(void) while (!WindowShouldClose()) // Detect window close button or ESC key { // Update + //---------------------------------------------------------------------------------- + if (btnBackPressed) + { + strcpy(directory, GetPrevDirectoryPath(directory)); + UnloadDirectoryFiles(files); + files = LoadDirectoryFiles(directory); + } + + //---------------------------------------------------------------------------------- // Draw @@ -55,13 +68,8 @@ int main(void) DrawText(directory, 100, 40, 20, DARKGRAY); - if (GuiButton((Rectangle){40.0f, 40.0f, 20, 20}, "<")) - { - strcpy(directory, GetPrevDirectoryPath(directory)); - UnloadDirectoryFiles(files); - files = LoadDirectoryFiles(directory); - } - + btnBackPressed = GuiButton((Rectangle){ 40.0f, 40.0f, 20, 20 }, "<"); + for (int i = 0; i < (int)files.count; i++) { Color color = Fade(LIGHTGRAY, 0.3f); @@ -75,10 +83,11 @@ int main(void) files = LoadDirectoryFiles(directory); } } - DrawRectangle(0, 85 + 40*i, screenWidth, 40, color); + DrawRectangle(0, 85 + 40*i, screenWidth, 40, color); DrawText(GetFileName(files.paths[i]), 120, 100 + 40*i, 10, GRAY); } + EndDrawing(); //---------------------------------------------------------------------------------- } diff --git a/examples/core/raygui.h b/examples/core/raygui.h new file mode 100644 index 000000000..a3fc51f0f --- /dev/null +++ b/examples/core/raygui.h @@ -0,0 +1,5757 @@ +/******************************************************************************************* +* +* raygui v4.5-dev - A simple and easy-to-use immediate-mode gui library +* +* DESCRIPTION: +* raygui is a tools-dev-focused immediate-mode-gui library based on raylib but also +* available as a standalone library, as long as input and drawing functions are provided. +* +* FEATURES: +* - Immediate-mode gui, minimal retained data +* - +25 controls provided (basic and advanced) +* - Styling system for colors, font and metrics +* - Icons supported, embedded as a 1-bit icons pack +* - Standalone mode option (custom input/graphics backend) +* - Multiple support tools provided for raygui development +* +* POSSIBLE IMPROVEMENTS: +* - Better standalone mode API for easy plug of custom backends +* - Externalize required inputs, allow user easier customization +* +* LIMITATIONS: +* - No editable multi-line word-wraped text box supported +* - No auto-layout mechanism, up to the user to define controls position and size +* - Standalone mode requires library modification and some user work to plug another backend +* +* NOTES: +* - WARNING: GuiLoadStyle() and GuiLoadStyle{Custom}() functions, allocate memory for +* font atlas recs and glyphs, freeing that memory is (usually) up to the user, +* no unload function is explicitly provided... but note that GuiLoadStyleDefault() unloads +* by default any previously loaded font (texture, recs, glyphs). +* - Global UI alpha (guiAlpha) is applied inside GuiDrawRectangle() and GuiDrawText() functions +* +* CONTROLS PROVIDED: +* # Container/separators Controls +* - WindowBox --> StatusBar, Panel +* - GroupBox --> Line +* - Line +* - Panel --> StatusBar +* - ScrollPanel --> StatusBar +* - TabBar --> Button +* +* # Basic Controls +* - Label +* - LabelButton --> Label +* - Button +* - Toggle +* - ToggleGroup --> Toggle +* - ToggleSlider +* - CheckBox +* - ComboBox +* - DropdownBox +* - TextBox +* - ValueBox --> TextBox +* - Spinner --> Button, ValueBox +* - Slider +* - SliderBar --> Slider +* - ProgressBar +* - StatusBar +* - DummyRec +* - Grid +* +* # Advance Controls +* - ListView +* - ColorPicker --> ColorPanel, ColorBarHue +* - MessageBox --> Window, Label, Button +* - TextInputBox --> Window, Label, TextBox, Button +* +* It also provides a set of functions for styling the controls based on its properties (size, color). +* +* +* RAYGUI STYLE (guiStyle): +* raygui uses a global data array for all gui style properties (allocated on data segment by default), +* when a new style is loaded, it is loaded over the global style... but a default gui style could always be +* recovered with GuiLoadStyleDefault() function, that overwrites the current style to the default one +* +* The global style array size is fixed and depends on the number of controls and properties: +* +* static unsigned int guiStyle[RAYGUI_MAX_CONTROLS*(RAYGUI_MAX_PROPS_BASE + RAYGUI_MAX_PROPS_EXTENDED)]; +* +* guiStyle size is by default: 16*(16 + 8) = 384*4 = 1536 bytes = 1.5 KB +* +* Note that the first set of BASE properties (by default guiStyle[0..15]) belong to the generic style +* used for all controls, when any of those base values is set, it is automatically populated to all +* controls, so, specific control values overwriting generic style should be set after base values. +* +* After the first BASE set we have the EXTENDED properties (by default guiStyle[16..23]), those +* properties are actually common to all controls and can not be overwritten individually (like BASE ones) +* Some of those properties are: TEXT_SIZE, TEXT_SPACING, LINE_COLOR, BACKGROUND_COLOR +* +* Custom control properties can be defined using the EXTENDED properties for each independent control. +* +* TOOL: rGuiStyler is a visual tool to customize raygui style: github.com/raysan5/rguistyler +* +* +* RAYGUI ICONS (guiIcons): +* raygui could use a global array containing icons data (allocated on data segment by default), +* a custom icons set could be loaded over this array using GuiLoadIcons(), but loaded icons set +* must be same RAYGUI_ICON_SIZE and no more than RAYGUI_ICON_MAX_ICONS will be loaded +* +* Every icon is codified in binary form, using 1 bit per pixel, so, every 16x16 icon +* requires 8 integers (16*16/32) to be stored in memory. +* +* When the icon is draw, actually one quad per pixel is drawn if the bit for that pixel is set. +* +* The global icons array size is fixed and depends on the number of icons and size: +* +* static unsigned int guiIcons[RAYGUI_ICON_MAX_ICONS*RAYGUI_ICON_DATA_ELEMENTS]; +* +* guiIcons size is by default: 256*(16*16/32) = 2048*4 = 8192 bytes = 8 KB +* +* TOOL: rGuiIcons is a visual tool to customize/create raygui icons: github.com/raysan5/rguiicons +* +* RAYGUI LAYOUT: +* raygui currently does not provide an auto-layout mechanism like other libraries, +* layouts must be defined manually on controls drawing, providing the right bounds Rectangle for it. +* +* TOOL: rGuiLayout is a visual tool to create raygui layouts: github.com/raysan5/rguilayout +* +* CONFIGURATION: +* #define RAYGUI_IMPLEMENTATION +* Generates the implementation of the library into the included file. +* If not defined, the library is in header only mode and can be included in other headers +* or source files without problems. But only ONE file should hold the implementation. +* +* #define RAYGUI_STANDALONE +* Avoid raylib.h header inclusion in this file. Data types defined on raylib are defined +* internally in the library and input management and drawing functions must be provided by +* the user (check library implementation for further details). +* +* #define RAYGUI_NO_ICONS +* Avoid including embedded ricons data (256 icons, 16x16 pixels, 1-bit per pixel, 2KB) +* +* #define RAYGUI_CUSTOM_ICONS +* Includes custom ricons.h header defining a set of custom icons, +* this file can be generated using rGuiIcons tool +* +* #define RAYGUI_DEBUG_RECS_BOUNDS +* Draw control bounds rectangles for debug +* +* #define RAYGUI_DEBUG_TEXT_BOUNDS +* Draw text bounds rectangles for debug +* +* VERSIONS HISTORY: +* 4.5-dev (Sep-2024) Current dev version... +* ADDED: guiControlExclusiveMode and guiControlExclusiveRec for exclusive modes +* ADDED: GuiValueBoxFloat() +* ADDED: GuiDropdonwBox() properties: DROPDOWN_ARROW_HIDDEN, DROPDOWN_ROLL_UP +* ADDED: GuiListView() property: LIST_ITEMS_BORDER_WIDTH +* ADDED: Multiple new icons +* REVIEWED: GuiTabBar(), close tab with mouse middle button +* REVIEWED: GuiScrollPanel(), scroll speed proportional to content +* REVIEWED: GuiDropdownBox(), support roll up and hidden arrow +* REVIEWED: GuiTextBox(), cursor position initialization +* REVIEWED: GuiSliderPro(), control value change check +* REVIEWED: GuiGrid(), simplified implementation +* REVIEWED: GuiIconText(), increase buffer size and reviewed padding +* REVIEWED: GuiDrawText(), improved wrap mode drawing +* REVIEWED: GuiScrollBar(), minor tweaks +* REVIEWED: Functions descriptions, removed wrong return value reference +* REDESIGNED: GuiColorPanel(), improved HSV <-> RGBA convertion +* +* 4.0 (12-Sep-2023) ADDED: GuiToggleSlider() +* ADDED: GuiColorPickerHSV() and GuiColorPanelHSV() +* ADDED: Multiple new icons, mostly compiler related +* ADDED: New DEFAULT properties: TEXT_LINE_SPACING, TEXT_ALIGNMENT_VERTICAL, TEXT_WRAP_MODE +* ADDED: New enum values: GuiTextAlignment, GuiTextAlignmentVertical, GuiTextWrapMode +* ADDED: Support loading styles with custom font charset from external file +* REDESIGNED: GuiTextBox(), support mouse cursor positioning +* REDESIGNED: GuiDrawText(), support multiline and word-wrap modes (read only) +* REDESIGNED: GuiProgressBar() to be more visual, progress affects border color +* REDESIGNED: Global alpha consideration moved to GuiDrawRectangle() and GuiDrawText() +* REDESIGNED: GuiScrollPanel(), get parameters by reference and return result value +* REDESIGNED: GuiToggleGroup(), get parameters by reference and return result value +* REDESIGNED: GuiComboBox(), get parameters by reference and return result value +* REDESIGNED: GuiCheckBox(), get parameters by reference and return result value +* REDESIGNED: GuiSlider(), get parameters by reference and return result value +* REDESIGNED: GuiSliderBar(), get parameters by reference and return result value +* REDESIGNED: GuiProgressBar(), get parameters by reference and return result value +* REDESIGNED: GuiListView(), get parameters by reference and return result value +* REDESIGNED: GuiColorPicker(), get parameters by reference and return result value +* REDESIGNED: GuiColorPanel(), get parameters by reference and return result value +* REDESIGNED: GuiColorBarAlpha(), get parameters by reference and return result value +* REDESIGNED: GuiColorBarHue(), get parameters by reference and return result value +* REDESIGNED: GuiGrid(), get parameters by reference and return result value +* REDESIGNED: GuiGrid(), added extra parameter +* REDESIGNED: GuiListViewEx(), change parameters order +* REDESIGNED: All controls return result as int value +* REVIEWED: GuiScrollPanel() to avoid smallish scroll-bars +* REVIEWED: All examples and specially controls_test_suite +* RENAMED: gui_file_dialog module to gui_window_file_dialog +* UPDATED: All styles to include ISO-8859-15 charset (as much as possible) +* +* 3.6 (10-May-2023) ADDED: New icon: SAND_TIMER +* ADDED: GuiLoadStyleFromMemory() (binary only) +* REVIEWED: GuiScrollBar() horizontal movement key +* REVIEWED: GuiTextBox() crash on cursor movement +* REVIEWED: GuiTextBox(), additional inputs support +* REVIEWED: GuiLabelButton(), avoid text cut +* REVIEWED: GuiTextInputBox(), password input +* REVIEWED: Local GetCodepointNext(), aligned with raylib +* REDESIGNED: GuiSlider*()/GuiScrollBar() to support out-of-bounds +* +* 3.5 (20-Apr-2023) ADDED: GuiTabBar(), based on GuiToggle() +* ADDED: Helper functions to split text in separate lines +* ADDED: Multiple new icons, useful for code editing tools +* REMOVED: Unneeded icon editing functions +* REMOVED: GuiTextBoxMulti(), very limited and broken +* REMOVED: MeasureTextEx() dependency, logic directly implemented +* REMOVED: DrawTextEx() dependency, logic directly implemented +* REVIEWED: GuiScrollBar(), improve mouse-click behaviour +* REVIEWED: Library header info, more info, better organized +* REDESIGNED: GuiTextBox() to support cursor movement +* REDESIGNED: GuiDrawText() to divide drawing by lines +* +* 3.2 (22-May-2022) RENAMED: Some enum values, for unification, avoiding prefixes +* REMOVED: GuiScrollBar(), only internal +* REDESIGNED: GuiPanel() to support text parameter +* REDESIGNED: GuiScrollPanel() to support text parameter +* REDESIGNED: GuiColorPicker() to support text parameter +* REDESIGNED: GuiColorPanel() to support text parameter +* REDESIGNED: GuiColorBarAlpha() to support text parameter +* REDESIGNED: GuiColorBarHue() to support text parameter +* REDESIGNED: GuiTextInputBox() to support password +* +* 3.1 (12-Jan-2022) REVIEWED: Default style for consistency (aligned with rGuiLayout v2.5 tool) +* REVIEWED: GuiLoadStyle() to support compressed font atlas image data and unload previous textures +* REVIEWED: External icons usage logic +* REVIEWED: GuiLine() for centered alignment when including text +* RENAMED: Multiple controls properties definitions to prepend RAYGUI_ +* RENAMED: RICON_ references to RAYGUI_ICON_ for library consistency +* Projects updated and multiple tweaks +* +* 3.0 (04-Nov-2021) Integrated ricons data to avoid external file +* REDESIGNED: GuiTextBoxMulti() +* REMOVED: GuiImageButton*() +* Multiple minor tweaks and bugs corrected +* +* 2.9 (17-Mar-2021) REMOVED: Tooltip API +* 2.8 (03-May-2020) Centralized rectangles drawing to GuiDrawRectangle() +* 2.7 (20-Feb-2020) ADDED: Possible tooltips API +* 2.6 (09-Sep-2019) ADDED: GuiTextInputBox() +* REDESIGNED: GuiListView*(), GuiDropdownBox(), GuiSlider*(), GuiProgressBar(), GuiMessageBox() +* REVIEWED: GuiTextBox(), GuiSpinner(), GuiValueBox(), GuiLoadStyle() +* Replaced property INNER_PADDING by TEXT_PADDING, renamed some properties +* ADDED: 8 new custom styles ready to use +* Multiple minor tweaks and bugs corrected +* +* 2.5 (28-May-2019) Implemented extended GuiTextBox(), GuiValueBox(), GuiSpinner() +* 2.3 (29-Apr-2019) ADDED: rIcons auxiliar library and support for it, multiple controls reviewed +* Refactor all controls drawing mechanism to use control state +* 2.2 (05-Feb-2019) ADDED: GuiScrollBar(), GuiScrollPanel(), reviewed GuiListView(), removed Gui*Ex() controls +* 2.1 (26-Dec-2018) REDESIGNED: GuiCheckBox(), GuiComboBox(), GuiDropdownBox(), GuiToggleGroup() > Use combined text string +* REDESIGNED: Style system (breaking change) +* 2.0 (08-Nov-2018) ADDED: Support controls guiLock and custom fonts +* REVIEWED: GuiComboBox(), GuiListView()... +* 1.9 (09-Oct-2018) REVIEWED: GuiGrid(), GuiTextBox(), GuiTextBoxMulti(), GuiValueBox()... +* 1.8 (01-May-2018) Lot of rework and redesign to align with rGuiStyler and rGuiLayout +* 1.5 (21-Jun-2017) Working in an improved styles system +* 1.4 (15-Jun-2017) Rewritten all GUI functions (removed useless ones) +* 1.3 (12-Jun-2017) Complete redesign of style system +* 1.1 (01-Jun-2017) Complete review of the library +* 1.0 (07-Jun-2016) Converted to header-only by Ramon Santamaria. +* 0.9 (07-Mar-2016) Reviewed and tested by Albert Martos, Ian Eito, Sergio Martinez and Ramon Santamaria. +* 0.8 (27-Aug-2015) Initial release. Implemented by Kevin Gato, Daniel Nicolás and Ramon Santamaria. +* +* DEPENDENCIES: +* raylib 5.0 - Inputs reading (keyboard/mouse), shapes drawing, font loading and text drawing +* +* STANDALONE MODE: +* By default raygui depends on raylib mostly for the inputs and the drawing functionality but that dependency can be disabled +* with the config flag RAYGUI_STANDALONE. In that case is up to the user to provide another backend to cover library needs. +* +* The following functions should be redefined for a custom backend: +* +* - Vector2 GetMousePosition(void); +* - float GetMouseWheelMove(void); +* - bool IsMouseButtonDown(int button); +* - bool IsMouseButtonPressed(int button); +* - bool IsMouseButtonReleased(int button); +* - bool IsKeyDown(int key); +* - bool IsKeyPressed(int key); +* - int GetCharPressed(void); // -- GuiTextBox(), GuiValueBox() +* +* - void DrawRectangle(int x, int y, int width, int height, Color color); // -- GuiDrawRectangle() +* - void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3, Color col4); // -- GuiColorPicker() +* +* - Font GetFontDefault(void); // -- GuiLoadStyleDefault() +* - Font LoadFontEx(const char *fileName, int fontSize, int *codepoints, int codepointCount); // -- GuiLoadStyle() +* - Texture2D LoadTextureFromImage(Image image); // -- GuiLoadStyle(), required to load texture from embedded font atlas image +* - void SetShapesTexture(Texture2D tex, Rectangle rec); // -- GuiLoadStyle(), required to set shapes rec to font white rec (optimization) +* - char *LoadFileText(const char *fileName); // -- GuiLoadStyle(), required to load charset data +* - void UnloadFileText(char *text); // -- GuiLoadStyle(), required to unload charset data +* - const char *GetDirectoryPath(const char *filePath); // -- GuiLoadStyle(), required to find charset/font file from text .rgs +* - int *LoadCodepoints(const char *text, int *count); // -- GuiLoadStyle(), required to load required font codepoints list +* - void UnloadCodepoints(int *codepoints); // -- GuiLoadStyle(), required to unload codepoints list +* - unsigned char *DecompressData(const unsigned char *compData, int compDataSize, int *dataSize); // -- GuiLoadStyle() +* +* CONTRIBUTORS: +* Ramon Santamaria: Supervision, review, redesign, update and maintenance +* Vlad Adrian: Complete rewrite of GuiTextBox() to support extended features (2019) +* Sergio Martinez: Review, testing (2015) and redesign of multiple controls (2018) +* Adria Arranz: Testing and implementation of additional controls (2018) +* Jordi Jorba: Testing and implementation of additional controls (2018) +* Albert Martos: Review and testing of the library (2015) +* Ian Eito: Review and testing of the library (2015) +* Kevin Gato: Initial implementation of basic components (2014) +* Daniel Nicolas: Initial implementation of basic components (2014) +* +* +* LICENSE: zlib/libpng +* +* Copyright (c) 2014-2024 Ramon Santamaria (@raysan5) +* +* This software is provided "as-is", without any express or implied warranty. In no event +* will the authors be held liable for any damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, including commercial +* applications, and to alter it and redistribute it freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not claim that you +* wrote the original software. If you use this software in a product, an acknowledgment +* in the product documentation would be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be misrepresented +* as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +* +**********************************************************************************************/ + +#ifndef RAYGUI_H +#define RAYGUI_H + +#define RAYGUI_VERSION_MAJOR 4 +#define RAYGUI_VERSION_MINOR 5 +#define RAYGUI_VERSION_PATCH 0 +#define RAYGUI_VERSION "4.5-dev" + +#if !defined(RAYGUI_STANDALONE) + #include "raylib.h" +#endif + +// Function specifiers in case library is build/used as a shared library (Windows) +// NOTE: Microsoft specifiers to tell compiler that symbols are imported/exported from a .dll +#if defined(_WIN32) + #if defined(BUILD_LIBTYPE_SHARED) + #define RAYGUIAPI __declspec(dllexport) // We are building the library as a Win32 shared library (.dll) + #elif defined(USE_LIBTYPE_SHARED) + #define RAYGUIAPI __declspec(dllimport) // We are using the library as a Win32 shared library (.dll) + #endif +#endif + +// Function specifiers definition +#ifndef RAYGUIAPI + #define RAYGUIAPI // Functions defined as 'extern' by default (implicit specifiers) +#endif + +//---------------------------------------------------------------------------------- +// Defines and Macros +//---------------------------------------------------------------------------------- +// Allow custom memory allocators +#ifndef RAYGUI_MALLOC + #define RAYGUI_MALLOC(sz) malloc(sz) +#endif +#ifndef RAYGUI_CALLOC + #define RAYGUI_CALLOC(n,sz) calloc(n,sz) +#endif +#ifndef RAYGUI_FREE + #define RAYGUI_FREE(p) free(p) +#endif + +// Simple log system to avoid printf() calls if required +// NOTE: Avoiding those calls, also avoids const strings memory usage +#define RAYGUI_SUPPORT_LOG_INFO +#if defined(RAYGUI_SUPPORT_LOG_INFO) + #define RAYGUI_LOG(...) printf(__VA_ARGS__) +#else + #define RAYGUI_LOG(...) +#endif + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +// NOTE: Some types are required for RAYGUI_STANDALONE usage +//---------------------------------------------------------------------------------- +#if defined(RAYGUI_STANDALONE) + #ifndef __cplusplus + // Boolean type + #ifndef true + typedef enum { false, true } bool; + #endif + #endif + + // Vector2 type + typedef struct Vector2 { + float x; + float y; + } Vector2; + + // Vector3 type // -- ConvertHSVtoRGB(), ConvertRGBtoHSV() + typedef struct Vector3 { + float x; + float y; + float z; + } Vector3; + + // Color type, RGBA (32bit) + typedef struct Color { + unsigned char r; + unsigned char g; + unsigned char b; + unsigned char a; + } Color; + + // Rectangle type + typedef struct Rectangle { + float x; + float y; + float width; + float height; + } Rectangle; + + // TODO: Texture2D type is very coupled to raylib, required by Font type + // It should be redesigned to be provided by user + typedef struct Texture2D { + unsigned int id; // OpenGL texture id + int width; // Texture base width + int height; // Texture base height + int mipmaps; // Mipmap levels, 1 by default + int format; // Data format (PixelFormat type) + } Texture2D; + + // Image, pixel data stored in CPU memory (RAM) + typedef struct Image { + void *data; // Image raw data + int width; // Image base width + int height; // Image base height + int mipmaps; // Mipmap levels, 1 by default + int format; // Data format (PixelFormat type) + } Image; + + // GlyphInfo, font characters glyphs info + typedef struct GlyphInfo { + int value; // Character value (Unicode) + int offsetX; // Character offset X when drawing + int offsetY; // Character offset Y when drawing + int advanceX; // Character advance position X + Image image; // Character image data + } GlyphInfo; + + // TODO: Font type is very coupled to raylib, mostly required by GuiLoadStyle() + // It should be redesigned to be provided by user + typedef struct Font { + int baseSize; // Base size (default chars height) + int glyphCount; // Number of glyph characters + int glyphPadding; // Padding around the glyph characters + Texture2D texture; // Texture atlas containing the glyphs + Rectangle *recs; // Rectangles in texture for the glyphs + GlyphInfo *glyphs; // Glyphs info data + } Font; +#endif + +// Style property +// NOTE: Used when exporting style as code for convenience +typedef struct GuiStyleProp { + unsigned short controlId; // Control identifier + unsigned short propertyId; // Property identifier + int propertyValue; // Property value +} GuiStyleProp; + +/* +// Controls text style -NOT USED- +// NOTE: Text style is defined by control +typedef struct GuiTextStyle { + unsigned int size; + int charSpacing; + int lineSpacing; + int alignmentH; + int alignmentV; + int padding; +} GuiTextStyle; +*/ + +// Gui control state +typedef enum { + STATE_NORMAL = 0, + STATE_FOCUSED, + STATE_PRESSED, + STATE_DISABLED +} GuiState; + +// Gui control text alignment +typedef enum { + TEXT_ALIGN_LEFT = 0, + TEXT_ALIGN_CENTER, + TEXT_ALIGN_RIGHT +} GuiTextAlignment; + +// Gui control text alignment vertical +// NOTE: Text vertical position inside the text bounds +typedef enum { + TEXT_ALIGN_TOP = 0, + TEXT_ALIGN_MIDDLE, + TEXT_ALIGN_BOTTOM +} GuiTextAlignmentVertical; + +// Gui control text wrap mode +// NOTE: Useful for multiline text +typedef enum { + TEXT_WRAP_NONE = 0, + TEXT_WRAP_CHAR, + TEXT_WRAP_WORD +} GuiTextWrapMode; + +// Gui controls +typedef enum { + // Default -> populates to all controls when set + DEFAULT = 0, + + // Basic controls + LABEL, // Used also for: LABELBUTTON + BUTTON, + TOGGLE, // Used also for: TOGGLEGROUP + SLIDER, // Used also for: SLIDERBAR, TOGGLESLIDER + PROGRESSBAR, + CHECKBOX, + COMBOBOX, + DROPDOWNBOX, + TEXTBOX, // Used also for: TEXTBOXMULTI + VALUEBOX, + SPINNER, // Uses: BUTTON, VALUEBOX + LISTVIEW, + COLORPICKER, + SCROLLBAR, + STATUSBAR +} GuiControl; + +// Gui base properties for every control +// NOTE: RAYGUI_MAX_PROPS_BASE properties (by default 16 properties) +typedef enum { + BORDER_COLOR_NORMAL = 0, // Control border color in STATE_NORMAL + BASE_COLOR_NORMAL, // Control base color in STATE_NORMAL + TEXT_COLOR_NORMAL, // Control text color in STATE_NORMAL + BORDER_COLOR_FOCUSED, // Control border color in STATE_FOCUSED + BASE_COLOR_FOCUSED, // Control base color in STATE_FOCUSED + TEXT_COLOR_FOCUSED, // Control text color in STATE_FOCUSED + BORDER_COLOR_PRESSED, // Control border color in STATE_PRESSED + BASE_COLOR_PRESSED, // Control base color in STATE_PRESSED + TEXT_COLOR_PRESSED, // Control text color in STATE_PRESSED + BORDER_COLOR_DISABLED, // Control border color in STATE_DISABLED + BASE_COLOR_DISABLED, // Control base color in STATE_DISABLED + TEXT_COLOR_DISABLED, // Control text color in STATE_DISABLED + BORDER_WIDTH, // Control border size, 0 for no border + //TEXT_SIZE, // Control text size (glyphs max height) -> GLOBAL for all controls + //TEXT_SPACING, // Control text spacing between glyphs -> GLOBAL for all controls + //TEXT_LINE_SPACING // Control text spacing between lines -> GLOBAL for all controls + TEXT_PADDING, // Control text padding, not considering border + TEXT_ALIGNMENT, // Control text horizontal alignment inside control text bound (after border and padding) + //TEXT_WRAP_MODE // Control text wrap-mode inside text bounds -> GLOBAL for all controls +} GuiControlProperty; + +// TODO: Which text styling properties should be global or per-control? +// At this moment TEXT_PADDING and TEXT_ALIGNMENT is configured and saved per control while +// TEXT_SIZE, TEXT_SPACING, TEXT_LINE_SPACING, TEXT_ALIGNMENT_VERTICAL, TEXT_WRAP_MODE are global and +// should be configured by user as needed while defining the UI layout + +// Gui extended properties depend on control +// NOTE: RAYGUI_MAX_PROPS_EXTENDED properties (by default, max 8 properties) +//---------------------------------------------------------------------------------- +// DEFAULT extended properties +// NOTE: Those properties are common to all controls or global +// WARNING: We only have 8 slots for those properties by default!!! -> New global control: TEXT? +typedef enum { + TEXT_SIZE = 16, // Text size (glyphs max height) + TEXT_SPACING, // Text spacing between glyphs + LINE_COLOR, // Line control color + BACKGROUND_COLOR, // Background color + TEXT_LINE_SPACING, // Text spacing between lines + TEXT_ALIGNMENT_VERTICAL, // Text vertical alignment inside text bounds (after border and padding) + TEXT_WRAP_MODE // Text wrap-mode inside text bounds + //TEXT_DECORATION // Text decoration: 0-None, 1-Underline, 2-Line-through, 3-Overline + //TEXT_DECORATION_THICK // Text decoration line thickness +} GuiDefaultProperty; + +// Other possible text properties: +// TEXT_WEIGHT // Normal, Italic, Bold -> Requires specific font change +// TEXT_INDENT // Text indentation -> Now using TEXT_PADDING... + +// Label +//typedef enum { } GuiLabelProperty; + +// Button/Spinner +//typedef enum { } GuiButtonProperty; + +// Toggle/ToggleGroup +typedef enum { + GROUP_PADDING = 16, // ToggleGroup separation between toggles +} GuiToggleProperty; + +// Slider/SliderBar +typedef enum { + SLIDER_WIDTH = 16, // Slider size of internal bar + SLIDER_PADDING // Slider/SliderBar internal bar padding +} GuiSliderProperty; + +// ProgressBar +typedef enum { + PROGRESS_PADDING = 16, // ProgressBar internal padding +} GuiProgressBarProperty; + +// ScrollBar +typedef enum { + ARROWS_SIZE = 16, // ScrollBar arrows size + ARROWS_VISIBLE, // ScrollBar arrows visible + SCROLL_SLIDER_PADDING, // ScrollBar slider internal padding + SCROLL_SLIDER_SIZE, // ScrollBar slider size + SCROLL_PADDING, // ScrollBar scroll padding from arrows + SCROLL_SPEED, // ScrollBar scrolling speed +} GuiScrollBarProperty; + +// CheckBox +typedef enum { + CHECK_PADDING = 16 // CheckBox internal check padding +} GuiCheckBoxProperty; + +// ComboBox +typedef enum { + COMBO_BUTTON_WIDTH = 16, // ComboBox right button width + COMBO_BUTTON_SPACING // ComboBox button separation +} GuiComboBoxProperty; + +// DropdownBox +typedef enum { + ARROW_PADDING = 16, // DropdownBox arrow separation from border and items + DROPDOWN_ITEMS_SPACING, // DropdownBox items separation + DROPDOWN_ARROW_HIDDEN, // DropdownBox arrow hidden + DROPDOWN_ROLL_UP // DropdownBox roll up flag (default rolls down) +} GuiDropdownBoxProperty; + +// TextBox/TextBoxMulti/ValueBox/Spinner +typedef enum { + TEXT_READONLY = 16, // TextBox in read-only mode: 0-text editable, 1-text no-editable +} GuiTextBoxProperty; + +// Spinner +typedef enum { + SPIN_BUTTON_WIDTH = 16, // Spinner left/right buttons width + SPIN_BUTTON_SPACING, // Spinner buttons separation +} GuiSpinnerProperty; + +// ListView +typedef enum { + LIST_ITEMS_HEIGHT = 16, // ListView items height + LIST_ITEMS_SPACING, // ListView items separation + SCROLLBAR_WIDTH, // ListView scrollbar size (usually width) + SCROLLBAR_SIDE, // ListView scrollbar side (0-SCROLLBAR_LEFT_SIDE, 1-SCROLLBAR_RIGHT_SIDE) + LIST_ITEMS_BORDER_WIDTH // ListView items border width +} GuiListViewProperty; + +// ColorPicker +typedef enum { + COLOR_SELECTOR_SIZE = 16, + HUEBAR_WIDTH, // ColorPicker right hue bar width + HUEBAR_PADDING, // ColorPicker right hue bar separation from panel + HUEBAR_SELECTOR_HEIGHT, // ColorPicker right hue bar selector height + HUEBAR_SELECTOR_OVERFLOW // ColorPicker right hue bar selector overflow +} GuiColorPickerProperty; + +#define SCROLLBAR_LEFT_SIDE 0 +#define SCROLLBAR_RIGHT_SIDE 1 + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +// ... + +//---------------------------------------------------------------------------------- +// Module Functions Declaration +//---------------------------------------------------------------------------------- + +#if defined(__cplusplus) +extern "C" { // Prevents name mangling of functions +#endif + +// Global gui state control functions +RAYGUIAPI void GuiEnable(void); // Enable gui controls (global state) +RAYGUIAPI void GuiDisable(void); // Disable gui controls (global state) +RAYGUIAPI void GuiLock(void); // Lock gui controls (global state) +RAYGUIAPI void GuiUnlock(void); // Unlock gui controls (global state) +RAYGUIAPI bool GuiIsLocked(void); // Check if gui is locked (global state) +RAYGUIAPI void GuiSetAlpha(float alpha); // Set gui controls alpha (global state), alpha goes from 0.0f to 1.0f +RAYGUIAPI void GuiSetState(int state); // Set gui state (global state) +RAYGUIAPI int GuiGetState(void); // Get gui state (global state) + +// Font set/get functions +RAYGUIAPI void GuiSetFont(Font font); // Set gui custom font (global state) +RAYGUIAPI Font GuiGetFont(void); // Get gui custom font (global state) + +// Style set/get functions +RAYGUIAPI void GuiSetStyle(int control, int property, int value); // Set one style property +RAYGUIAPI int GuiGetStyle(int control, int property); // Get one style property + +// Styles loading functions +RAYGUIAPI void GuiLoadStyle(const char *fileName); // Load style file over global style variable (.rgs) +RAYGUIAPI void GuiLoadStyleDefault(void); // Load style default over global style + +// Tooltips management functions +RAYGUIAPI void GuiEnableTooltip(void); // Enable gui tooltips (global state) +RAYGUIAPI void GuiDisableTooltip(void); // Disable gui tooltips (global state) +RAYGUIAPI void GuiSetTooltip(const char *tooltip); // Set tooltip string + +// Icons functionality +RAYGUIAPI const char *GuiIconText(int iconId, const char *text); // Get text with icon id prepended (if supported) +#if !defined(RAYGUI_NO_ICONS) +RAYGUIAPI void GuiSetIconScale(int scale); // Set default icon drawing size +RAYGUIAPI unsigned int *GuiGetIcons(void); // Get raygui icons data pointer +RAYGUIAPI char **GuiLoadIcons(const char *fileName, bool loadIconsName); // Load raygui icons file (.rgi) into internal icons data +RAYGUIAPI void GuiDrawIcon(int iconId, int posX, int posY, int pixelSize, Color color); // Draw icon using pixel size at specified position +#endif + +// Controls +//---------------------------------------------------------------------------------------------------------- +// Container/separator controls, useful for controls organization +RAYGUIAPI int GuiWindowBox(Rectangle bounds, const char *title); // Window Box control, shows a window that can be closed +RAYGUIAPI int GuiGroupBox(Rectangle bounds, const char *text); // Group Box control with text name +RAYGUIAPI int GuiLine(Rectangle bounds, const char *text); // Line separator control, could contain text +RAYGUIAPI int GuiPanel(Rectangle bounds, const char *text); // Panel control, useful to group controls +RAYGUIAPI int GuiTabBar(Rectangle bounds, const char **text, int count, int *active); // Tab Bar control, returns TAB to be closed or -1 +RAYGUIAPI int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector2 *scroll, Rectangle *view); // Scroll Panel control + +// Basic controls set +RAYGUIAPI int GuiLabel(Rectangle bounds, const char *text); // Label control +RAYGUIAPI int GuiButton(Rectangle bounds, const char *text); // Button control, returns true when clicked +RAYGUIAPI int GuiLabelButton(Rectangle bounds, const char *text); // Label button control, returns true when clicked +RAYGUIAPI int GuiToggle(Rectangle bounds, const char *text, bool *active); // Toggle Button control +RAYGUIAPI int GuiToggleGroup(Rectangle bounds, const char *text, int *active); // Toggle Group control +RAYGUIAPI int GuiToggleSlider(Rectangle bounds, const char *text, int *active); // Toggle Slider control +RAYGUIAPI int GuiCheckBox(Rectangle bounds, const char *text, bool *checked); // Check Box control, returns true when active +RAYGUIAPI int GuiComboBox(Rectangle bounds, const char *text, int *active); // Combo Box control + +RAYGUIAPI int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMode); // Dropdown Box control +RAYGUIAPI int GuiSpinner(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode); // Spinner control +RAYGUIAPI int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode); // Value Box control, updates input text with numbers +RAYGUIAPI int GuiValueBoxFloat(Rectangle bounds, const char *text, char *textValue, float *value, bool editMode); // Value box control for float values +RAYGUIAPI int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode); // Text Box control, updates input text + +RAYGUIAPI int GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue); // Slider control +RAYGUIAPI int GuiSliderBar(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue); // Slider Bar control +RAYGUIAPI int GuiProgressBar(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue); // Progress Bar control +RAYGUIAPI int GuiStatusBar(Rectangle bounds, const char *text); // Status Bar control, shows info text +RAYGUIAPI int GuiDummyRec(Rectangle bounds, const char *text); // Dummy control for placeholders +RAYGUIAPI int GuiGrid(Rectangle bounds, const char *text, float spacing, int subdivs, Vector2 *mouseCell); // Grid control + +// Advance controls set +RAYGUIAPI int GuiListView(Rectangle bounds, const char *text, int *scrollIndex, int *active); // List View control +RAYGUIAPI int GuiListViewEx(Rectangle bounds, const char **text, int count, int *scrollIndex, int *active, int *focus); // List View with extended parameters +RAYGUIAPI int GuiMessageBox(Rectangle bounds, const char *title, const char *message, const char *buttons); // Message Box control, displays a message +RAYGUIAPI int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, const char *buttons, char *text, int textMaxSize, bool *secretViewActive); // Text Input Box control, ask for text, supports secret +RAYGUIAPI int GuiColorPicker(Rectangle bounds, const char *text, Color *color); // Color Picker control (multiple color controls) +RAYGUIAPI int GuiColorPanel(Rectangle bounds, const char *text, Color *color); // Color Panel control +RAYGUIAPI int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha); // Color Bar Alpha control +RAYGUIAPI int GuiColorBarHue(Rectangle bounds, const char *text, float *value); // Color Bar Hue control +RAYGUIAPI int GuiColorPickerHSV(Rectangle bounds, const char *text, Vector3 *colorHsv); // Color Picker control that avoids conversion to RGB on each call (multiple color controls) +RAYGUIAPI int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv); // Color Panel control that updates Hue-Saturation-Value color value, used by GuiColorPickerHSV() +//---------------------------------------------------------------------------------------------------------- + +#if !defined(RAYGUI_NO_ICONS) + +#if !defined(RAYGUI_CUSTOM_ICONS) +//---------------------------------------------------------------------------------- +// Icons enumeration +//---------------------------------------------------------------------------------- +typedef enum { + ICON_NONE = 0, + ICON_FOLDER_FILE_OPEN = 1, + ICON_FILE_SAVE_CLASSIC = 2, + ICON_FOLDER_OPEN = 3, + ICON_FOLDER_SAVE = 4, + ICON_FILE_OPEN = 5, + ICON_FILE_SAVE = 6, + ICON_FILE_EXPORT = 7, + ICON_FILE_ADD = 8, + ICON_FILE_DELETE = 9, + ICON_FILETYPE_TEXT = 10, + ICON_FILETYPE_AUDIO = 11, + ICON_FILETYPE_IMAGE = 12, + ICON_FILETYPE_PLAY = 13, + ICON_FILETYPE_VIDEO = 14, + ICON_FILETYPE_INFO = 15, + ICON_FILE_COPY = 16, + ICON_FILE_CUT = 17, + ICON_FILE_PASTE = 18, + ICON_CURSOR_HAND = 19, + ICON_CURSOR_POINTER = 20, + ICON_CURSOR_CLASSIC = 21, + ICON_PENCIL = 22, + ICON_PENCIL_BIG = 23, + ICON_BRUSH_CLASSIC = 24, + ICON_BRUSH_PAINTER = 25, + ICON_WATER_DROP = 26, + ICON_COLOR_PICKER = 27, + ICON_RUBBER = 28, + ICON_COLOR_BUCKET = 29, + ICON_TEXT_T = 30, + ICON_TEXT_A = 31, + ICON_SCALE = 32, + ICON_RESIZE = 33, + ICON_FILTER_POINT = 34, + ICON_FILTER_BILINEAR = 35, + ICON_CROP = 36, + ICON_CROP_ALPHA = 37, + ICON_SQUARE_TOGGLE = 38, + ICON_SYMMETRY = 39, + ICON_SYMMETRY_HORIZONTAL = 40, + ICON_SYMMETRY_VERTICAL = 41, + ICON_LENS = 42, + ICON_LENS_BIG = 43, + ICON_EYE_ON = 44, + ICON_EYE_OFF = 45, + ICON_FILTER_TOP = 46, + ICON_FILTER = 47, + ICON_TARGET_POINT = 48, + ICON_TARGET_SMALL = 49, + ICON_TARGET_BIG = 50, + ICON_TARGET_MOVE = 51, + ICON_CURSOR_MOVE = 52, + ICON_CURSOR_SCALE = 53, + ICON_CURSOR_SCALE_RIGHT = 54, + ICON_CURSOR_SCALE_LEFT = 55, + ICON_UNDO = 56, + ICON_REDO = 57, + ICON_REREDO = 58, + ICON_MUTATE = 59, + ICON_ROTATE = 60, + ICON_REPEAT = 61, + ICON_SHUFFLE = 62, + ICON_EMPTYBOX = 63, + ICON_TARGET = 64, + ICON_TARGET_SMALL_FILL = 65, + ICON_TARGET_BIG_FILL = 66, + ICON_TARGET_MOVE_FILL = 67, + ICON_CURSOR_MOVE_FILL = 68, + ICON_CURSOR_SCALE_FILL = 69, + ICON_CURSOR_SCALE_RIGHT_FILL = 70, + ICON_CURSOR_SCALE_LEFT_FILL = 71, + ICON_UNDO_FILL = 72, + ICON_REDO_FILL = 73, + ICON_REREDO_FILL = 74, + ICON_MUTATE_FILL = 75, + ICON_ROTATE_FILL = 76, + ICON_REPEAT_FILL = 77, + ICON_SHUFFLE_FILL = 78, + ICON_EMPTYBOX_SMALL = 79, + ICON_BOX = 80, + ICON_BOX_TOP = 81, + ICON_BOX_TOP_RIGHT = 82, + ICON_BOX_RIGHT = 83, + ICON_BOX_BOTTOM_RIGHT = 84, + ICON_BOX_BOTTOM = 85, + ICON_BOX_BOTTOM_LEFT = 86, + ICON_BOX_LEFT = 87, + ICON_BOX_TOP_LEFT = 88, + ICON_BOX_CENTER = 89, + ICON_BOX_CIRCLE_MASK = 90, + ICON_POT = 91, + ICON_ALPHA_MULTIPLY = 92, + ICON_ALPHA_CLEAR = 93, + ICON_DITHERING = 94, + ICON_MIPMAPS = 95, + ICON_BOX_GRID = 96, + ICON_GRID = 97, + ICON_BOX_CORNERS_SMALL = 98, + ICON_BOX_CORNERS_BIG = 99, + ICON_FOUR_BOXES = 100, + ICON_GRID_FILL = 101, + ICON_BOX_MULTISIZE = 102, + ICON_ZOOM_SMALL = 103, + ICON_ZOOM_MEDIUM = 104, + ICON_ZOOM_BIG = 105, + ICON_ZOOM_ALL = 106, + ICON_ZOOM_CENTER = 107, + ICON_BOX_DOTS_SMALL = 108, + ICON_BOX_DOTS_BIG = 109, + ICON_BOX_CONCENTRIC = 110, + ICON_BOX_GRID_BIG = 111, + ICON_OK_TICK = 112, + ICON_CROSS = 113, + ICON_ARROW_LEFT = 114, + ICON_ARROW_RIGHT = 115, + ICON_ARROW_DOWN = 116, + ICON_ARROW_UP = 117, + ICON_ARROW_LEFT_FILL = 118, + ICON_ARROW_RIGHT_FILL = 119, + ICON_ARROW_DOWN_FILL = 120, + ICON_ARROW_UP_FILL = 121, + ICON_AUDIO = 122, + ICON_FX = 123, + ICON_WAVE = 124, + ICON_WAVE_SINUS = 125, + ICON_WAVE_SQUARE = 126, + ICON_WAVE_TRIANGULAR = 127, + ICON_CROSS_SMALL = 128, + ICON_PLAYER_PREVIOUS = 129, + ICON_PLAYER_PLAY_BACK = 130, + ICON_PLAYER_PLAY = 131, + ICON_PLAYER_PAUSE = 132, + ICON_PLAYER_STOP = 133, + ICON_PLAYER_NEXT = 134, + ICON_PLAYER_RECORD = 135, + ICON_MAGNET = 136, + ICON_LOCK_CLOSE = 137, + ICON_LOCK_OPEN = 138, + ICON_CLOCK = 139, + ICON_TOOLS = 140, + ICON_GEAR = 141, + ICON_GEAR_BIG = 142, + ICON_BIN = 143, + ICON_HAND_POINTER = 144, + ICON_LASER = 145, + ICON_COIN = 146, + ICON_EXPLOSION = 147, + ICON_1UP = 148, + ICON_PLAYER = 149, + ICON_PLAYER_JUMP = 150, + ICON_KEY = 151, + ICON_DEMON = 152, + ICON_TEXT_POPUP = 153, + ICON_GEAR_EX = 154, + ICON_CRACK = 155, + ICON_CRACK_POINTS = 156, + ICON_STAR = 157, + ICON_DOOR = 158, + ICON_EXIT = 159, + ICON_MODE_2D = 160, + ICON_MODE_3D = 161, + ICON_CUBE = 162, + ICON_CUBE_FACE_TOP = 163, + ICON_CUBE_FACE_LEFT = 164, + ICON_CUBE_FACE_FRONT = 165, + ICON_CUBE_FACE_BOTTOM = 166, + ICON_CUBE_FACE_RIGHT = 167, + ICON_CUBE_FACE_BACK = 168, + ICON_CAMERA = 169, + ICON_SPECIAL = 170, + ICON_LINK_NET = 171, + ICON_LINK_BOXES = 172, + ICON_LINK_MULTI = 173, + ICON_LINK = 174, + ICON_LINK_BROKE = 175, + ICON_TEXT_NOTES = 176, + ICON_NOTEBOOK = 177, + ICON_SUITCASE = 178, + ICON_SUITCASE_ZIP = 179, + ICON_MAILBOX = 180, + ICON_MONITOR = 181, + ICON_PRINTER = 182, + ICON_PHOTO_CAMERA = 183, + ICON_PHOTO_CAMERA_FLASH = 184, + ICON_HOUSE = 185, + ICON_HEART = 186, + ICON_CORNER = 187, + ICON_VERTICAL_BARS = 188, + ICON_VERTICAL_BARS_FILL = 189, + ICON_LIFE_BARS = 190, + ICON_INFO = 191, + ICON_CROSSLINE = 192, + ICON_HELP = 193, + ICON_FILETYPE_ALPHA = 194, + ICON_FILETYPE_HOME = 195, + ICON_LAYERS_VISIBLE = 196, + ICON_LAYERS = 197, + ICON_WINDOW = 198, + ICON_HIDPI = 199, + ICON_FILETYPE_BINARY = 200, + ICON_HEX = 201, + ICON_SHIELD = 202, + ICON_FILE_NEW = 203, + ICON_FOLDER_ADD = 204, + ICON_ALARM = 205, + ICON_CPU = 206, + ICON_ROM = 207, + ICON_STEP_OVER = 208, + ICON_STEP_INTO = 209, + ICON_STEP_OUT = 210, + ICON_RESTART = 211, + ICON_BREAKPOINT_ON = 212, + ICON_BREAKPOINT_OFF = 213, + ICON_BURGER_MENU = 214, + ICON_CASE_SENSITIVE = 215, + ICON_REG_EXP = 216, + ICON_FOLDER = 217, + ICON_FILE = 218, + ICON_SAND_TIMER = 219, + ICON_WARNING = 220, + ICON_HELP_BOX = 221, + ICON_INFO_BOX = 222, + ICON_PRIORITY = 223, + ICON_LAYERS_ISO = 224, + ICON_LAYERS2 = 225, + ICON_MLAYERS = 226, + ICON_MAPS = 227, + ICON_HOT = 228, + ICON_229 = 229, + ICON_230 = 230, + ICON_231 = 231, + ICON_232 = 232, + ICON_233 = 233, + ICON_234 = 234, + ICON_235 = 235, + ICON_236 = 236, + ICON_237 = 237, + ICON_238 = 238, + ICON_239 = 239, + ICON_240 = 240, + ICON_241 = 241, + ICON_242 = 242, + ICON_243 = 243, + ICON_244 = 244, + ICON_245 = 245, + ICON_246 = 246, + ICON_247 = 247, + ICON_248 = 248, + ICON_249 = 249, + ICON_250 = 250, + ICON_251 = 251, + ICON_252 = 252, + ICON_253 = 253, + ICON_254 = 254, + ICON_255 = 255, +} GuiIconName; +#endif + +#endif + +#if defined(__cplusplus) +} // Prevents name mangling of functions +#endif + +#endif // RAYGUI_H + +/*********************************************************************************** +* +* RAYGUI IMPLEMENTATION +* +************************************************************************************/ + +#if defined(RAYGUI_IMPLEMENTATION) + +#include // required for: isspace() [GuiTextBox()] +#include // Required for: FILE, fopen(), fclose(), fprintf(), feof(), fscanf(), vsprintf() [GuiLoadStyle(), GuiLoadIcons()] +#include // Required for: malloc(), calloc(), free() [GuiLoadStyle(), GuiLoadIcons()] +#include // Required for: strlen() [GuiTextBox(), GuiValueBox()], memset(), memcpy() +#include // Required for: va_list, va_start(), vfprintf(), va_end() [TextFormat()] +#include // Required for: roundf() [GuiColorPicker()] + +#ifdef __cplusplus + #define RAYGUI_CLITERAL(name) name +#else + #define RAYGUI_CLITERAL(name) (name) +#endif + +// Check if two rectangles are equal, used to validate a slider bounds as an id +#ifndef CHECK_BOUNDS_ID + #define CHECK_BOUNDS_ID(src, dst) ((src.x == dst.x) && (src.y == dst.y) && (src.width == dst.width) && (src.height == dst.height)) +#endif + +#if !defined(RAYGUI_NO_ICONS) && !defined(RAYGUI_CUSTOM_ICONS) + +// Embedded icons, no external file provided +#define RAYGUI_ICON_SIZE 16 // Size of icons in pixels (squared) +#define RAYGUI_ICON_MAX_ICONS 256 // Maximum number of icons +#define RAYGUI_ICON_MAX_NAME_LENGTH 32 // Maximum length of icon name id + +// Icons data is defined by bit array (every bit represents one pixel) +// Those arrays are stored as unsigned int data arrays, so, +// every array element defines 32 pixels (bits) of information +// One icon is defined by 8 int, (8 int * 32 bit = 256 bit = 16*16 pixels) +// NOTE: Number of elemens depend on RAYGUI_ICON_SIZE (by default 16x16 pixels) +#define RAYGUI_ICON_DATA_ELEMENTS (RAYGUI_ICON_SIZE*RAYGUI_ICON_SIZE/32) + +//---------------------------------------------------------------------------------- +// Icons data for all gui possible icons (allocated on data segment by default) +// +// NOTE 1: Every icon is codified in binary form, using 1 bit per pixel, so, +// every 16x16 icon requires 8 integers (16*16/32) to be stored +// +// NOTE 2: A different icon set could be loaded over this array using GuiLoadIcons(), +// but loaded icons set must be same RAYGUI_ICON_SIZE and no more than RAYGUI_ICON_MAX_ICONS +// +// guiIcons size is by default: 256*(16*16/32) = 2048*4 = 8192 bytes = 8 KB +//---------------------------------------------------------------------------------- +static unsigned int guiIcons[RAYGUI_ICON_MAX_ICONS*RAYGUI_ICON_DATA_ELEMENTS] = { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_NONE + 0x3ff80000, 0x2f082008, 0x2042207e, 0x40027fc2, 0x40024002, 0x40024002, 0x40024002, 0x00007ffe, // ICON_FOLDER_FILE_OPEN + 0x3ffe0000, 0x44226422, 0x400247e2, 0x5ffa4002, 0x57ea500a, 0x500a500a, 0x40025ffa, 0x00007ffe, // ICON_FILE_SAVE_CLASSIC + 0x00000000, 0x0042007e, 0x40027fc2, 0x40024002, 0x41024002, 0x44424282, 0x793e4102, 0x00000100, // ICON_FOLDER_OPEN + 0x00000000, 0x0042007e, 0x40027fc2, 0x40024002, 0x41024102, 0x44424102, 0x793e4282, 0x00000000, // ICON_FOLDER_SAVE + 0x3ff00000, 0x201c2010, 0x20042004, 0x21042004, 0x24442284, 0x21042104, 0x20042104, 0x00003ffc, // ICON_FILE_OPEN + 0x3ff00000, 0x201c2010, 0x20042004, 0x21042004, 0x21042104, 0x22842444, 0x20042104, 0x00003ffc, // ICON_FILE_SAVE + 0x3ff00000, 0x201c2010, 0x00042004, 0x20041004, 0x20844784, 0x00841384, 0x20042784, 0x00003ffc, // ICON_FILE_EXPORT + 0x3ff00000, 0x201c2010, 0x20042004, 0x20042004, 0x22042204, 0x22042f84, 0x20042204, 0x00003ffc, // ICON_FILE_ADD + 0x3ff00000, 0x201c2010, 0x20042004, 0x20042004, 0x25042884, 0x25042204, 0x20042884, 0x00003ffc, // ICON_FILE_DELETE + 0x3ff00000, 0x201c2010, 0x20042004, 0x20042ff4, 0x20042ff4, 0x20042ff4, 0x20042004, 0x00003ffc, // ICON_FILETYPE_TEXT + 0x3ff00000, 0x201c2010, 0x27042004, 0x244424c4, 0x26442444, 0x20642664, 0x20042004, 0x00003ffc, // ICON_FILETYPE_AUDIO + 0x3ff00000, 0x201c2010, 0x26042604, 0x20042004, 0x35442884, 0x2414222c, 0x20042004, 0x00003ffc, // ICON_FILETYPE_IMAGE + 0x3ff00000, 0x201c2010, 0x20c42004, 0x22442144, 0x22442444, 0x20c42144, 0x20042004, 0x00003ffc, // ICON_FILETYPE_PLAY + 0x3ff00000, 0x3ffc2ff0, 0x3f3c2ff4, 0x3dbc2eb4, 0x3dbc2bb4, 0x3f3c2eb4, 0x3ffc2ff4, 0x00002ff4, // ICON_FILETYPE_VIDEO + 0x3ff00000, 0x201c2010, 0x21842184, 0x21842004, 0x21842184, 0x21842184, 0x20042184, 0x00003ffc, // ICON_FILETYPE_INFO + 0x0ff00000, 0x381c0810, 0x28042804, 0x28042804, 0x28042804, 0x28042804, 0x20102ffc, 0x00003ff0, // ICON_FILE_COPY + 0x00000000, 0x701c0000, 0x079c1e14, 0x55a000f0, 0x079c00f0, 0x701c1e14, 0x00000000, 0x00000000, // ICON_FILE_CUT + 0x01c00000, 0x13e41bec, 0x3f841004, 0x204420c4, 0x20442044, 0x20442044, 0x207c2044, 0x00003fc0, // ICON_FILE_PASTE + 0x00000000, 0x3aa00fe0, 0x2abc2aa0, 0x2aa42aa4, 0x20042aa4, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_CURSOR_HAND + 0x00000000, 0x003c000c, 0x030800c8, 0x30100c10, 0x10202020, 0x04400840, 0x01800280, 0x00000000, // ICON_CURSOR_POINTER + 0x00000000, 0x00180000, 0x01f00078, 0x03e007f0, 0x07c003e0, 0x04000e40, 0x00000000, 0x00000000, // ICON_CURSOR_CLASSIC + 0x00000000, 0x04000000, 0x11000a00, 0x04400a80, 0x01100220, 0x00580088, 0x00000038, 0x00000000, // ICON_PENCIL + 0x04000000, 0x15000a00, 0x50402880, 0x14102820, 0x05040a08, 0x015c028c, 0x007c00bc, 0x00000000, // ICON_PENCIL_BIG + 0x01c00000, 0x01400140, 0x01400140, 0x0ff80140, 0x0ff80808, 0x0aa80808, 0x0aa80aa8, 0x00000ff8, // ICON_BRUSH_CLASSIC + 0x1ffc0000, 0x5ffc7ffe, 0x40004000, 0x00807f80, 0x01c001c0, 0x01c001c0, 0x01c001c0, 0x00000080, // ICON_BRUSH_PAINTER + 0x00000000, 0x00800000, 0x01c00080, 0x03e001c0, 0x07f003e0, 0x036006f0, 0x000001c0, 0x00000000, // ICON_WATER_DROP + 0x00000000, 0x3e003800, 0x1f803f80, 0x0c201e40, 0x02080c10, 0x00840104, 0x00380044, 0x00000000, // ICON_COLOR_PICKER + 0x00000000, 0x07800300, 0x1fe00fc0, 0x3f883fd0, 0x0e021f04, 0x02040402, 0x00f00108, 0x00000000, // ICON_RUBBER + 0x00c00000, 0x02800140, 0x08200440, 0x20081010, 0x2ffe3004, 0x03f807fc, 0x00e001f0, 0x00000040, // ICON_COLOR_BUCKET + 0x00000000, 0x21843ffc, 0x01800180, 0x01800180, 0x01800180, 0x01800180, 0x03c00180, 0x00000000, // ICON_TEXT_T + 0x00800000, 0x01400180, 0x06200340, 0x0c100620, 0x1ff80c10, 0x380c1808, 0x70067004, 0x0000f80f, // ICON_TEXT_A + 0x78000000, 0x50004000, 0x00004800, 0x03c003c0, 0x03c003c0, 0x00100000, 0x0002000a, 0x0000000e, // ICON_SCALE + 0x75560000, 0x5e004002, 0x54001002, 0x41001202, 0x408200fe, 0x40820082, 0x40820082, 0x00006afe, // ICON_RESIZE + 0x00000000, 0x3f003f00, 0x3f003f00, 0x3f003f00, 0x00400080, 0x001c0020, 0x001c001c, 0x00000000, // ICON_FILTER_POINT + 0x6d800000, 0x00004080, 0x40804080, 0x40800000, 0x00406d80, 0x001c0020, 0x001c001c, 0x00000000, // ICON_FILTER_BILINEAR + 0x40080000, 0x1ffe2008, 0x14081008, 0x11081208, 0x10481088, 0x10081028, 0x10047ff8, 0x00001002, // ICON_CROP + 0x00100000, 0x3ffc0010, 0x2ab03550, 0x22b02550, 0x20b02150, 0x20302050, 0x2000fff0, 0x00002000, // ICON_CROP_ALPHA + 0x40000000, 0x1ff82000, 0x04082808, 0x01082208, 0x00482088, 0x00182028, 0x35542008, 0x00000002, // ICON_SQUARE_TOGGLE + 0x00000000, 0x02800280, 0x06c006c0, 0x0ea00ee0, 0x1e901eb0, 0x3e883e98, 0x7efc7e8c, 0x00000000, // ICON_SYMMETRY + 0x01000000, 0x05600100, 0x1d480d50, 0x7d423d44, 0x3d447d42, 0x0d501d48, 0x01000560, 0x00000100, // ICON_SYMMETRY_HORIZONTAL + 0x01800000, 0x04200240, 0x10080810, 0x00001ff8, 0x00007ffe, 0x0ff01ff8, 0x03c007e0, 0x00000180, // ICON_SYMMETRY_VERTICAL + 0x00000000, 0x010800f0, 0x02040204, 0x02040204, 0x07f00308, 0x1c000e00, 0x30003800, 0x00000000, // ICON_LENS + 0x00000000, 0x061803f0, 0x08240c0c, 0x08040814, 0x0c0c0804, 0x23f01618, 0x18002400, 0x00000000, // ICON_LENS_BIG + 0x00000000, 0x00000000, 0x1c7007c0, 0x638e3398, 0x1c703398, 0x000007c0, 0x00000000, 0x00000000, // ICON_EYE_ON + 0x00000000, 0x10002000, 0x04700fc0, 0x610e3218, 0x1c703098, 0x001007a0, 0x00000008, 0x00000000, // ICON_EYE_OFF + 0x00000000, 0x00007ffc, 0x40047ffc, 0x10102008, 0x04400820, 0x02800280, 0x02800280, 0x00000100, // ICON_FILTER_TOP + 0x00000000, 0x40027ffe, 0x10082004, 0x04200810, 0x02400240, 0x02400240, 0x01400240, 0x000000c0, // ICON_FILTER + 0x00800000, 0x00800080, 0x00000080, 0x3c9e0000, 0x00000000, 0x00800080, 0x00800080, 0x00000000, // ICON_TARGET_POINT + 0x00800000, 0x00800080, 0x00800080, 0x3f7e01c0, 0x008001c0, 0x00800080, 0x00800080, 0x00000000, // ICON_TARGET_SMALL + 0x00800000, 0x00800080, 0x03e00080, 0x3e3e0220, 0x03e00220, 0x00800080, 0x00800080, 0x00000000, // ICON_TARGET_BIG + 0x01000000, 0x04400280, 0x01000100, 0x43842008, 0x43849ab2, 0x01002008, 0x04400100, 0x01000280, // ICON_TARGET_MOVE + 0x01000000, 0x04400280, 0x01000100, 0x41042108, 0x41049ff2, 0x01002108, 0x04400100, 0x01000280, // ICON_CURSOR_MOVE + 0x781e0000, 0x500a4002, 0x04204812, 0x00000240, 0x02400000, 0x48120420, 0x4002500a, 0x0000781e, // ICON_CURSOR_SCALE + 0x00000000, 0x20003c00, 0x24002800, 0x01000200, 0x00400080, 0x00140024, 0x003c0004, 0x00000000, // ICON_CURSOR_SCALE_RIGHT + 0x00000000, 0x0004003c, 0x00240014, 0x00800040, 0x02000100, 0x28002400, 0x3c002000, 0x00000000, // ICON_CURSOR_SCALE_LEFT + 0x00000000, 0x00100020, 0x10101fc8, 0x10001020, 0x10001000, 0x10001000, 0x00001fc0, 0x00000000, // ICON_UNDO + 0x00000000, 0x08000400, 0x080813f8, 0x00080408, 0x00080008, 0x00080008, 0x000003f8, 0x00000000, // ICON_REDO + 0x00000000, 0x3ffc0000, 0x20042004, 0x20002000, 0x20402000, 0x3f902020, 0x00400020, 0x00000000, // ICON_REREDO + 0x00000000, 0x3ffc0000, 0x20042004, 0x27fc2004, 0x20202000, 0x3fc82010, 0x00200010, 0x00000000, // ICON_MUTATE + 0x00000000, 0x0ff00000, 0x10081818, 0x11801008, 0x10001180, 0x18101020, 0x00100fc8, 0x00000020, // ICON_ROTATE + 0x00000000, 0x04000200, 0x240429fc, 0x20042204, 0x20442004, 0x3f942024, 0x00400020, 0x00000000, // ICON_REPEAT + 0x00000000, 0x20001000, 0x22104c0e, 0x00801120, 0x11200040, 0x4c0e2210, 0x10002000, 0x00000000, // ICON_SHUFFLE + 0x7ffe0000, 0x50024002, 0x44024802, 0x41024202, 0x40424082, 0x40124022, 0x4002400a, 0x00007ffe, // ICON_EMPTYBOX + 0x00800000, 0x03e00080, 0x08080490, 0x3c9e0808, 0x08080808, 0x03e00490, 0x00800080, 0x00000000, // ICON_TARGET + 0x00800000, 0x00800080, 0x00800080, 0x3ffe01c0, 0x008001c0, 0x00800080, 0x00800080, 0x00000000, // ICON_TARGET_SMALL_FILL + 0x00800000, 0x00800080, 0x03e00080, 0x3ffe03e0, 0x03e003e0, 0x00800080, 0x00800080, 0x00000000, // ICON_TARGET_BIG_FILL + 0x01000000, 0x07c00380, 0x01000100, 0x638c2008, 0x638cfbbe, 0x01002008, 0x07c00100, 0x01000380, // ICON_TARGET_MOVE_FILL + 0x01000000, 0x07c00380, 0x01000100, 0x610c2108, 0x610cfffe, 0x01002108, 0x07c00100, 0x01000380, // ICON_CURSOR_MOVE_FILL + 0x781e0000, 0x6006700e, 0x04204812, 0x00000240, 0x02400000, 0x48120420, 0x700e6006, 0x0000781e, // ICON_CURSOR_SCALE_FILL + 0x00000000, 0x38003c00, 0x24003000, 0x01000200, 0x00400080, 0x000c0024, 0x003c001c, 0x00000000, // ICON_CURSOR_SCALE_RIGHT_FILL + 0x00000000, 0x001c003c, 0x0024000c, 0x00800040, 0x02000100, 0x30002400, 0x3c003800, 0x00000000, // ICON_CURSOR_SCALE_LEFT_FILL + 0x00000000, 0x00300020, 0x10301ff8, 0x10001020, 0x10001000, 0x10001000, 0x00001fc0, 0x00000000, // ICON_UNDO_FILL + 0x00000000, 0x0c000400, 0x0c081ff8, 0x00080408, 0x00080008, 0x00080008, 0x000003f8, 0x00000000, // ICON_REDO_FILL + 0x00000000, 0x3ffc0000, 0x20042004, 0x20002000, 0x20402000, 0x3ff02060, 0x00400060, 0x00000000, // ICON_REREDO_FILL + 0x00000000, 0x3ffc0000, 0x20042004, 0x27fc2004, 0x20202000, 0x3ff82030, 0x00200030, 0x00000000, // ICON_MUTATE_FILL + 0x00000000, 0x0ff00000, 0x10081818, 0x11801008, 0x10001180, 0x18301020, 0x00300ff8, 0x00000020, // ICON_ROTATE_FILL + 0x00000000, 0x06000200, 0x26042ffc, 0x20042204, 0x20442004, 0x3ff42064, 0x00400060, 0x00000000, // ICON_REPEAT_FILL + 0x00000000, 0x30001000, 0x32107c0e, 0x00801120, 0x11200040, 0x7c0e3210, 0x10003000, 0x00000000, // ICON_SHUFFLE_FILL + 0x00000000, 0x30043ffc, 0x24042804, 0x21042204, 0x20442084, 0x20142024, 0x3ffc200c, 0x00000000, // ICON_EMPTYBOX_SMALL + 0x00000000, 0x20043ffc, 0x20042004, 0x20042004, 0x20042004, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX + 0x00000000, 0x23c43ffc, 0x23c423c4, 0x200423c4, 0x20042004, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX_TOP + 0x00000000, 0x3e043ffc, 0x3e043e04, 0x20043e04, 0x20042004, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX_TOP_RIGHT + 0x00000000, 0x20043ffc, 0x20042004, 0x3e043e04, 0x3e043e04, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX_RIGHT + 0x00000000, 0x20043ffc, 0x20042004, 0x20042004, 0x3e042004, 0x3e043e04, 0x3ffc3e04, 0x00000000, // ICON_BOX_BOTTOM_RIGHT + 0x00000000, 0x20043ffc, 0x20042004, 0x20042004, 0x23c42004, 0x23c423c4, 0x3ffc23c4, 0x00000000, // ICON_BOX_BOTTOM + 0x00000000, 0x20043ffc, 0x20042004, 0x20042004, 0x207c2004, 0x207c207c, 0x3ffc207c, 0x00000000, // ICON_BOX_BOTTOM_LEFT + 0x00000000, 0x20043ffc, 0x20042004, 0x207c207c, 0x207c207c, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX_LEFT + 0x00000000, 0x207c3ffc, 0x207c207c, 0x2004207c, 0x20042004, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX_TOP_LEFT + 0x00000000, 0x20043ffc, 0x20042004, 0x23c423c4, 0x23c423c4, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX_CENTER + 0x7ffe0000, 0x40024002, 0x47e24182, 0x4ff247e2, 0x47e24ff2, 0x418247e2, 0x40024002, 0x00007ffe, // ICON_BOX_CIRCLE_MASK + 0x7fff0000, 0x40014001, 0x40014001, 0x49555ddd, 0x4945495d, 0x400149c5, 0x40014001, 0x00007fff, // ICON_POT + 0x7ffe0000, 0x53327332, 0x44ce4cce, 0x41324332, 0x404e40ce, 0x48125432, 0x4006540e, 0x00007ffe, // ICON_ALPHA_MULTIPLY + 0x7ffe0000, 0x53327332, 0x44ce4cce, 0x41324332, 0x5c4e40ce, 0x44124432, 0x40065c0e, 0x00007ffe, // ICON_ALPHA_CLEAR + 0x7ffe0000, 0x42fe417e, 0x42fe417e, 0x42fe417e, 0x42fe417e, 0x42fe417e, 0x42fe417e, 0x00007ffe, // ICON_DITHERING + 0x07fe0000, 0x1ffa0002, 0x7fea000a, 0x402a402a, 0x5b2a512a, 0x5128552a, 0x40205128, 0x00007fe0, // ICON_MIPMAPS + 0x00000000, 0x1ff80000, 0x12481248, 0x12481ff8, 0x1ff81248, 0x12481248, 0x00001ff8, 0x00000000, // ICON_BOX_GRID + 0x12480000, 0x7ffe1248, 0x12481248, 0x12487ffe, 0x7ffe1248, 0x12481248, 0x12487ffe, 0x00001248, // ICON_GRID + 0x00000000, 0x1c380000, 0x1c3817e8, 0x08100810, 0x08100810, 0x17e81c38, 0x00001c38, 0x00000000, // ICON_BOX_CORNERS_SMALL + 0x700e0000, 0x700e5ffa, 0x20042004, 0x20042004, 0x20042004, 0x20042004, 0x5ffa700e, 0x0000700e, // ICON_BOX_CORNERS_BIG + 0x3f7e0000, 0x21422142, 0x21422142, 0x00003f7e, 0x21423f7e, 0x21422142, 0x3f7e2142, 0x00000000, // ICON_FOUR_BOXES + 0x00000000, 0x3bb80000, 0x3bb83bb8, 0x3bb80000, 0x3bb83bb8, 0x3bb80000, 0x3bb83bb8, 0x00000000, // ICON_GRID_FILL + 0x7ffe0000, 0x7ffe7ffe, 0x77fe7000, 0x77fe77fe, 0x777e7700, 0x777e777e, 0x777e777e, 0x0000777e, // ICON_BOX_MULTISIZE + 0x781e0000, 0x40024002, 0x00004002, 0x01800000, 0x00000180, 0x40020000, 0x40024002, 0x0000781e, // ICON_ZOOM_SMALL + 0x781e0000, 0x40024002, 0x00004002, 0x03c003c0, 0x03c003c0, 0x40020000, 0x40024002, 0x0000781e, // ICON_ZOOM_MEDIUM + 0x781e0000, 0x40024002, 0x07e04002, 0x07e007e0, 0x07e007e0, 0x400207e0, 0x40024002, 0x0000781e, // ICON_ZOOM_BIG + 0x781e0000, 0x5ffa4002, 0x1ff85ffa, 0x1ff81ff8, 0x1ff81ff8, 0x5ffa1ff8, 0x40025ffa, 0x0000781e, // ICON_ZOOM_ALL + 0x00000000, 0x2004381c, 0x00002004, 0x00000000, 0x00000000, 0x20040000, 0x381c2004, 0x00000000, // ICON_ZOOM_CENTER + 0x00000000, 0x1db80000, 0x10081008, 0x10080000, 0x00001008, 0x10081008, 0x00001db8, 0x00000000, // ICON_BOX_DOTS_SMALL + 0x35560000, 0x00002002, 0x00002002, 0x00002002, 0x00002002, 0x00002002, 0x35562002, 0x00000000, // ICON_BOX_DOTS_BIG + 0x7ffe0000, 0x40024002, 0x48124ff2, 0x49924812, 0x48124992, 0x4ff24812, 0x40024002, 0x00007ffe, // ICON_BOX_CONCENTRIC + 0x00000000, 0x10841ffc, 0x10841084, 0x1ffc1084, 0x10841084, 0x10841084, 0x00001ffc, 0x00000000, // ICON_BOX_GRID_BIG + 0x00000000, 0x00000000, 0x10000000, 0x04000800, 0x01040200, 0x00500088, 0x00000020, 0x00000000, // ICON_OK_TICK + 0x00000000, 0x10080000, 0x04200810, 0x01800240, 0x02400180, 0x08100420, 0x00001008, 0x00000000, // ICON_CROSS + 0x00000000, 0x02000000, 0x00800100, 0x00200040, 0x00200010, 0x00800040, 0x02000100, 0x00000000, // ICON_ARROW_LEFT + 0x00000000, 0x00400000, 0x01000080, 0x04000200, 0x04000800, 0x01000200, 0x00400080, 0x00000000, // ICON_ARROW_RIGHT + 0x00000000, 0x00000000, 0x00000000, 0x08081004, 0x02200410, 0x00800140, 0x00000000, 0x00000000, // ICON_ARROW_DOWN + 0x00000000, 0x00000000, 0x01400080, 0x04100220, 0x10040808, 0x00000000, 0x00000000, 0x00000000, // ICON_ARROW_UP + 0x00000000, 0x02000000, 0x03800300, 0x03e003c0, 0x03e003f0, 0x038003c0, 0x02000300, 0x00000000, // ICON_ARROW_LEFT_FILL + 0x00000000, 0x00400000, 0x01c000c0, 0x07c003c0, 0x07c00fc0, 0x01c003c0, 0x004000c0, 0x00000000, // ICON_ARROW_RIGHT_FILL + 0x00000000, 0x00000000, 0x00000000, 0x0ff81ffc, 0x03e007f0, 0x008001c0, 0x00000000, 0x00000000, // ICON_ARROW_DOWN_FILL + 0x00000000, 0x00000000, 0x01c00080, 0x07f003e0, 0x1ffc0ff8, 0x00000000, 0x00000000, 0x00000000, // ICON_ARROW_UP_FILL + 0x00000000, 0x18a008c0, 0x32881290, 0x24822686, 0x26862482, 0x12903288, 0x08c018a0, 0x00000000, // ICON_AUDIO + 0x00000000, 0x04800780, 0x004000c0, 0x662000f0, 0x08103c30, 0x130a0e18, 0x0000318e, 0x00000000, // ICON_FX + 0x00000000, 0x00800000, 0x08880888, 0x2aaa0a8a, 0x0a8a2aaa, 0x08880888, 0x00000080, 0x00000000, // ICON_WAVE + 0x00000000, 0x00600000, 0x01080090, 0x02040108, 0x42044204, 0x24022402, 0x00001800, 0x00000000, // ICON_WAVE_SINUS + 0x00000000, 0x07f80000, 0x04080408, 0x04080408, 0x04080408, 0x7c0e0408, 0x00000000, 0x00000000, // ICON_WAVE_SQUARE + 0x00000000, 0x00000000, 0x00a00040, 0x22084110, 0x08021404, 0x00000000, 0x00000000, 0x00000000, // ICON_WAVE_TRIANGULAR + 0x00000000, 0x00000000, 0x04200000, 0x01800240, 0x02400180, 0x00000420, 0x00000000, 0x00000000, // ICON_CROSS_SMALL + 0x00000000, 0x18380000, 0x12281428, 0x10a81128, 0x112810a8, 0x14281228, 0x00001838, 0x00000000, // ICON_PLAYER_PREVIOUS + 0x00000000, 0x18000000, 0x11801600, 0x10181060, 0x10601018, 0x16001180, 0x00001800, 0x00000000, // ICON_PLAYER_PLAY_BACK + 0x00000000, 0x00180000, 0x01880068, 0x18080608, 0x06081808, 0x00680188, 0x00000018, 0x00000000, // ICON_PLAYER_PLAY + 0x00000000, 0x1e780000, 0x12481248, 0x12481248, 0x12481248, 0x12481248, 0x00001e78, 0x00000000, // ICON_PLAYER_PAUSE + 0x00000000, 0x1ff80000, 0x10081008, 0x10081008, 0x10081008, 0x10081008, 0x00001ff8, 0x00000000, // ICON_PLAYER_STOP + 0x00000000, 0x1c180000, 0x14481428, 0x15081488, 0x14881508, 0x14281448, 0x00001c18, 0x00000000, // ICON_PLAYER_NEXT + 0x00000000, 0x03c00000, 0x08100420, 0x10081008, 0x10081008, 0x04200810, 0x000003c0, 0x00000000, // ICON_PLAYER_RECORD + 0x00000000, 0x0c3007e0, 0x13c81818, 0x14281668, 0x14281428, 0x1c381c38, 0x08102244, 0x00000000, // ICON_MAGNET + 0x07c00000, 0x08200820, 0x3ff80820, 0x23882008, 0x21082388, 0x20082108, 0x1ff02008, 0x00000000, // ICON_LOCK_CLOSE + 0x07c00000, 0x08000800, 0x3ff80800, 0x23882008, 0x21082388, 0x20082108, 0x1ff02008, 0x00000000, // ICON_LOCK_OPEN + 0x01c00000, 0x0c180770, 0x3086188c, 0x60832082, 0x60034781, 0x30062002, 0x0c18180c, 0x01c00770, // ICON_CLOCK + 0x0a200000, 0x1b201b20, 0x04200e20, 0x04200420, 0x04700420, 0x0e700e70, 0x0e700e70, 0x04200e70, // ICON_TOOLS + 0x01800000, 0x3bdc318c, 0x0ff01ff8, 0x7c3e1e78, 0x1e787c3e, 0x1ff80ff0, 0x318c3bdc, 0x00000180, // ICON_GEAR + 0x01800000, 0x3ffc318c, 0x1c381ff8, 0x781e1818, 0x1818781e, 0x1ff81c38, 0x318c3ffc, 0x00000180, // ICON_GEAR_BIG + 0x00000000, 0x08080ff8, 0x08081ffc, 0x0aa80aa8, 0x0aa80aa8, 0x0aa80aa8, 0x08080aa8, 0x00000ff8, // ICON_BIN + 0x00000000, 0x00000000, 0x20043ffc, 0x08043f84, 0x04040f84, 0x04040784, 0x000007fc, 0x00000000, // ICON_HAND_POINTER + 0x00000000, 0x24400400, 0x00001480, 0x6efe0e00, 0x00000e00, 0x24401480, 0x00000400, 0x00000000, // ICON_LASER + 0x00000000, 0x03c00000, 0x08300460, 0x11181118, 0x11181118, 0x04600830, 0x000003c0, 0x00000000, // ICON_COIN + 0x00000000, 0x10880080, 0x06c00810, 0x366c07e0, 0x07e00240, 0x00001768, 0x04200240, 0x00000000, // ICON_EXPLOSION + 0x00000000, 0x3d280000, 0x2528252c, 0x3d282528, 0x05280528, 0x05e80528, 0x00000000, 0x00000000, // ICON_1UP + 0x01800000, 0x03c003c0, 0x018003c0, 0x0ff007e0, 0x0bd00bd0, 0x0a500bd0, 0x02400240, 0x02400240, // ICON_PLAYER + 0x01800000, 0x03c003c0, 0x118013c0, 0x03c81ff8, 0x07c003c8, 0x04400440, 0x0c080478, 0x00000000, // ICON_PLAYER_JUMP + 0x3ff80000, 0x30183ff8, 0x30183018, 0x3ff83ff8, 0x03000300, 0x03c003c0, 0x03e00300, 0x000003e0, // ICON_KEY + 0x3ff80000, 0x3ff83ff8, 0x33983ff8, 0x3ff83398, 0x3ff83ff8, 0x00000540, 0x0fe00aa0, 0x00000fe0, // ICON_DEMON + 0x00000000, 0x0ff00000, 0x20041008, 0x25442004, 0x10082004, 0x06000bf0, 0x00000300, 0x00000000, // ICON_TEXT_POPUP + 0x00000000, 0x11440000, 0x07f00be8, 0x1c1c0e38, 0x1c1c0c18, 0x07f00e38, 0x11440be8, 0x00000000, // ICON_GEAR_EX + 0x00000000, 0x20080000, 0x0c601010, 0x07c00fe0, 0x07c007c0, 0x0c600fe0, 0x20081010, 0x00000000, // ICON_CRACK + 0x00000000, 0x20080000, 0x0c601010, 0x04400fe0, 0x04405554, 0x0c600fe0, 0x20081010, 0x00000000, // ICON_CRACK_POINTS + 0x00000000, 0x00800080, 0x01c001c0, 0x1ffc3ffe, 0x03e007f0, 0x07f003e0, 0x0c180770, 0x00000808, // ICON_STAR + 0x0ff00000, 0x08180810, 0x08100818, 0x0a100810, 0x08180810, 0x08100818, 0x08100810, 0x00001ff8, // ICON_DOOR + 0x0ff00000, 0x08100810, 0x08100810, 0x10100010, 0x4f902010, 0x10102010, 0x08100010, 0x00000ff0, // ICON_EXIT + 0x00040000, 0x001f000e, 0x0ef40004, 0x12f41284, 0x0ef41214, 0x10040004, 0x7ffc3004, 0x10003000, // ICON_MODE_2D + 0x78040000, 0x501f600e, 0x0ef44004, 0x12f41284, 0x0ef41284, 0x10140004, 0x7ffc300c, 0x10003000, // ICON_MODE_3D + 0x7fe00000, 0x50286030, 0x47fe4804, 0x44224402, 0x44224422, 0x241275e2, 0x0c06140a, 0x000007fe, // ICON_CUBE + 0x7fe00000, 0x5ff87ff0, 0x47fe4ffc, 0x44224402, 0x44224422, 0x241275e2, 0x0c06140a, 0x000007fe, // ICON_CUBE_FACE_TOP + 0x7fe00000, 0x50386030, 0x47c2483c, 0x443e443e, 0x443e443e, 0x241e75fe, 0x0c06140e, 0x000007fe, // ICON_CUBE_FACE_LEFT + 0x7fe00000, 0x50286030, 0x47fe4804, 0x47fe47fe, 0x47fe47fe, 0x27fe77fe, 0x0ffe17fe, 0x000007fe, // ICON_CUBE_FACE_FRONT + 0x7fe00000, 0x50286030, 0x47fe4804, 0x44224402, 0x44224422, 0x3bf27be2, 0x0bfe1bfa, 0x000007fe, // ICON_CUBE_FACE_BOTTOM + 0x7fe00000, 0x70286030, 0x7ffe7804, 0x7c227c02, 0x7c227c22, 0x3c127de2, 0x0c061c0a, 0x000007fe, // ICON_CUBE_FACE_RIGHT + 0x7fe00000, 0x6fe85ff0, 0x781e77e4, 0x7be27be2, 0x7be27be2, 0x24127be2, 0x0c06140a, 0x000007fe, // ICON_CUBE_FACE_BACK + 0x00000000, 0x2a0233fe, 0x22022602, 0x22022202, 0x2a022602, 0x00a033fe, 0x02080110, 0x00000000, // ICON_CAMERA + 0x00000000, 0x200c3ffc, 0x000c000c, 0x3ffc000c, 0x30003000, 0x30003000, 0x3ffc3004, 0x00000000, // ICON_SPECIAL + 0x00000000, 0x0022003e, 0x012201e2, 0x0100013e, 0x01000100, 0x79000100, 0x4f004900, 0x00007800, // ICON_LINK_NET + 0x00000000, 0x44007c00, 0x45004600, 0x00627cbe, 0x00620022, 0x45007cbe, 0x44004600, 0x00007c00, // ICON_LINK_BOXES + 0x00000000, 0x0044007c, 0x0010007c, 0x3f100010, 0x3f1021f0, 0x3f100010, 0x3f0021f0, 0x00000000, // ICON_LINK_MULTI + 0x00000000, 0x0044007c, 0x00440044, 0x0010007c, 0x00100010, 0x44107c10, 0x440047f0, 0x00007c00, // ICON_LINK + 0x00000000, 0x0044007c, 0x00440044, 0x0000007c, 0x00000010, 0x44007c10, 0x44004550, 0x00007c00, // ICON_LINK_BROKE + 0x02a00000, 0x22a43ffc, 0x20042004, 0x20042ff4, 0x20042ff4, 0x20042ff4, 0x20042004, 0x00003ffc, // ICON_TEXT_NOTES + 0x3ffc0000, 0x20042004, 0x245e27c4, 0x27c42444, 0x2004201e, 0x201e2004, 0x20042004, 0x00003ffc, // ICON_NOTEBOOK + 0x00000000, 0x07e00000, 0x04200420, 0x24243ffc, 0x24242424, 0x24242424, 0x3ffc2424, 0x00000000, // ICON_SUITCASE + 0x00000000, 0x0fe00000, 0x08200820, 0x40047ffc, 0x7ffc5554, 0x40045554, 0x7ffc4004, 0x00000000, // ICON_SUITCASE_ZIP + 0x00000000, 0x20043ffc, 0x3ffc2004, 0x13c81008, 0x100813c8, 0x10081008, 0x1ff81008, 0x00000000, // ICON_MAILBOX + 0x00000000, 0x40027ffe, 0x5ffa5ffa, 0x5ffa5ffa, 0x40025ffa, 0x03c07ffe, 0x1ff81ff8, 0x00000000, // ICON_MONITOR + 0x0ff00000, 0x6bfe7ffe, 0x7ffe7ffe, 0x68167ffe, 0x08106816, 0x08100810, 0x0ff00810, 0x00000000, // ICON_PRINTER + 0x3ff80000, 0xfffe2008, 0x870a8002, 0x904a888a, 0x904a904a, 0x870a888a, 0xfffe8002, 0x00000000, // ICON_PHOTO_CAMERA + 0x0fc00000, 0xfcfe0cd8, 0x8002fffe, 0x84428382, 0x84428442, 0x80028382, 0xfffe8002, 0x00000000, // ICON_PHOTO_CAMERA_FLASH + 0x00000000, 0x02400180, 0x08100420, 0x20041008, 0x23c42004, 0x22442244, 0x3ffc2244, 0x00000000, // ICON_HOUSE + 0x00000000, 0x1c700000, 0x3ff83ef8, 0x3ff83ff8, 0x0fe01ff0, 0x038007c0, 0x00000100, 0x00000000, // ICON_HEART + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x80000000, 0xe000c000, // ICON_CORNER + 0x00000000, 0x14001c00, 0x15c01400, 0x15401540, 0x155c1540, 0x15541554, 0x1ddc1554, 0x00000000, // ICON_VERTICAL_BARS + 0x00000000, 0x03000300, 0x1b001b00, 0x1b601b60, 0x1b6c1b60, 0x1b6c1b6c, 0x1b6c1b6c, 0x00000000, // ICON_VERTICAL_BARS_FILL + 0x00000000, 0x00000000, 0x403e7ffe, 0x7ffe403e, 0x7ffe0000, 0x43fe43fe, 0x00007ffe, 0x00000000, // ICON_LIFE_BARS + 0x7ffc0000, 0x43844004, 0x43844284, 0x43844004, 0x42844284, 0x42844284, 0x40044384, 0x00007ffc, // ICON_INFO + 0x40008000, 0x10002000, 0x04000800, 0x01000200, 0x00400080, 0x00100020, 0x00040008, 0x00010002, // ICON_CROSSLINE + 0x00000000, 0x1ff01ff0, 0x18301830, 0x1f001830, 0x03001f00, 0x00000300, 0x03000300, 0x00000000, // ICON_HELP + 0x3ff00000, 0x2abc3550, 0x2aac3554, 0x2aac3554, 0x2aac3554, 0x2aac3554, 0x2aac3554, 0x00003ffc, // ICON_FILETYPE_ALPHA + 0x3ff00000, 0x201c2010, 0x22442184, 0x28142424, 0x29942814, 0x2ff42994, 0x20042004, 0x00003ffc, // ICON_FILETYPE_HOME + 0x07fe0000, 0x04020402, 0x7fe20402, 0x44224422, 0x44224422, 0x402047fe, 0x40204020, 0x00007fe0, // ICON_LAYERS_VISIBLE + 0x07fe0000, 0x04020402, 0x7c020402, 0x44024402, 0x44024402, 0x402047fe, 0x40204020, 0x00007fe0, // ICON_LAYERS + 0x00000000, 0x40027ffe, 0x7ffe4002, 0x40024002, 0x40024002, 0x40024002, 0x7ffe4002, 0x00000000, // ICON_WINDOW + 0x09100000, 0x09f00910, 0x09100910, 0x00000910, 0x24a2779e, 0x27a224a2, 0x709e20a2, 0x00000000, // ICON_HIDPI + 0x3ff00000, 0x201c2010, 0x2a842e84, 0x2e842a84, 0x2ba42004, 0x2aa42aa4, 0x20042ba4, 0x00003ffc, // ICON_FILETYPE_BINARY + 0x00000000, 0x00000000, 0x00120012, 0x4a5e4bd2, 0x485233d2, 0x00004bd2, 0x00000000, 0x00000000, // ICON_HEX + 0x01800000, 0x381c0660, 0x23c42004, 0x23c42044, 0x13c82204, 0x08101008, 0x02400420, 0x00000180, // ICON_SHIELD + 0x007e0000, 0x20023fc2, 0x40227fe2, 0x400a403a, 0x400a400a, 0x400a400a, 0x4008400e, 0x00007ff8, // ICON_FILE_NEW + 0x00000000, 0x0042007e, 0x40027fc2, 0x44024002, 0x5f024402, 0x44024402, 0x7ffe4002, 0x00000000, // ICON_FOLDER_ADD + 0x44220000, 0x12482244, 0xf3cf0000, 0x14280420, 0x48122424, 0x08100810, 0x1ff81008, 0x03c00420, // ICON_ALARM + 0x0aa00000, 0x1ff80aa0, 0x1068700e, 0x1008706e, 0x1008700e, 0x1008700e, 0x0aa01ff8, 0x00000aa0, // ICON_CPU + 0x07e00000, 0x04201db8, 0x04a01c38, 0x04a01d38, 0x04a01d38, 0x04a01d38, 0x04201d38, 0x000007e0, // ICON_ROM + 0x00000000, 0x03c00000, 0x3c382ff0, 0x3c04380c, 0x01800000, 0x03c003c0, 0x00000180, 0x00000000, // ICON_STEP_OVER + 0x01800000, 0x01800180, 0x01800180, 0x03c007e0, 0x00000180, 0x01800000, 0x03c003c0, 0x00000180, // ICON_STEP_INTO + 0x01800000, 0x07e003c0, 0x01800180, 0x01800180, 0x00000180, 0x01800000, 0x03c003c0, 0x00000180, // ICON_STEP_OUT + 0x00000000, 0x0ff003c0, 0x181c1c34, 0x303c301c, 0x30003000, 0x1c301800, 0x03c00ff0, 0x00000000, // ICON_RESTART + 0x00000000, 0x00000000, 0x07e003c0, 0x0ff00ff0, 0x0ff00ff0, 0x03c007e0, 0x00000000, 0x00000000, // ICON_BREAKPOINT_ON + 0x00000000, 0x00000000, 0x042003c0, 0x08100810, 0x08100810, 0x03c00420, 0x00000000, 0x00000000, // ICON_BREAKPOINT_OFF + 0x00000000, 0x00000000, 0x1ff81ff8, 0x1ff80000, 0x00001ff8, 0x1ff81ff8, 0x00000000, 0x00000000, // ICON_BURGER_MENU + 0x00000000, 0x00000000, 0x00880070, 0x0c880088, 0x1e8810f8, 0x3e881288, 0x00000000, 0x00000000, // ICON_CASE_SENSITIVE + 0x00000000, 0x02000000, 0x07000a80, 0x07001fc0, 0x02000a80, 0x00300030, 0x00000000, 0x00000000, // ICON_REG_EXP + 0x00000000, 0x0042007e, 0x40027fc2, 0x40024002, 0x40024002, 0x40024002, 0x7ffe4002, 0x00000000, // ICON_FOLDER + 0x3ff00000, 0x201c2010, 0x20042004, 0x20042004, 0x20042004, 0x20042004, 0x20042004, 0x00003ffc, // ICON_FILE + 0x1ff00000, 0x20082008, 0x17d02fe8, 0x05400ba0, 0x09200540, 0x23881010, 0x2fe827c8, 0x00001ff0, // ICON_SAND_TIMER + 0x01800000, 0x02400240, 0x05a00420, 0x09900990, 0x11881188, 0x21842004, 0x40024182, 0x00003ffc, // ICON_WARNING + 0x7ffe0000, 0x4ff24002, 0x4c324ff2, 0x4f824c02, 0x41824f82, 0x41824002, 0x40024182, 0x00007ffe, // ICON_HELP_BOX + 0x7ffe0000, 0x41824002, 0x40024182, 0x41824182, 0x41824182, 0x41824182, 0x40024182, 0x00007ffe, // ICON_INFO_BOX + 0x01800000, 0x04200240, 0x10080810, 0x7bde2004, 0x0a500a50, 0x08500bd0, 0x08100850, 0x00000ff0, // ICON_PRIORITY + 0x01800000, 0x18180660, 0x80016006, 0x98196006, 0x99996666, 0x19986666, 0x01800660, 0x00000000, // ICON_LAYERS_ISO + 0x07fe0000, 0x1c020402, 0x74021402, 0x54025402, 0x54025402, 0x500857fe, 0x40205ff8, 0x00007fe0, // ICON_LAYERS2 + 0x0ffe0000, 0x3ffa0802, 0x7fea200a, 0x402a402a, 0x422a422a, 0x422e422a, 0x40384e28, 0x00007fe0, // ICON_MLAYERS + 0x0ffe0000, 0x3ffa0802, 0x7fea200a, 0x402a402a, 0x5b2a512a, 0x512e552a, 0x40385128, 0x00007fe0, // ICON_MAPS + 0x04200000, 0x1cf00c60, 0x11f019f0, 0x0f3807b8, 0x1e3c0f3c, 0x1c1c1e1c, 0x1e3c1c1c, 0x00000f70, // ICON_HOT + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_229 + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_230 + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_231 + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_232 + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_233 + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_234 + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_235 + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_236 + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_237 + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_238 + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_239 + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_240 + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_241 + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_242 + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_243 + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_244 + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_245 + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_246 + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_247 + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_248 + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_249 + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_250 + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_251 + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_252 + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_253 + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_254 + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_255 +}; + +// NOTE: A pointer to current icons array should be defined +static unsigned int *guiIconsPtr = guiIcons; + +#endif // !RAYGUI_NO_ICONS && !RAYGUI_CUSTOM_ICONS + +#ifndef RAYGUI_ICON_SIZE + #define RAYGUI_ICON_SIZE 0 +#endif + +// WARNING: Those values define the total size of the style data array, +// if changed, previous saved styles could become incompatible +#define RAYGUI_MAX_CONTROLS 16 // Maximum number of controls +#define RAYGUI_MAX_PROPS_BASE 16 // Maximum number of base properties +#define RAYGUI_MAX_PROPS_EXTENDED 8 // Maximum number of extended properties + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- +// Gui control property style color element +typedef enum { BORDER = 0, BASE, TEXT, OTHER } GuiPropertyElement; + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +static GuiState guiState = STATE_NORMAL; // Gui global state, if !STATE_NORMAL, forces defined state + +static Font guiFont = { 0 }; // Gui current font (WARNING: highly coupled to raylib) +static bool guiLocked = false; // Gui lock state (no inputs processed) +static float guiAlpha = 1.0f; // Gui controls transparency + +static unsigned int guiIconScale = 1; // Gui icon default scale (if icons enabled) + +static bool guiTooltip = false; // Tooltip enabled/disabled +static const char *guiTooltipPtr = NULL; // Tooltip string pointer (string provided by user) + +static bool guiControlExclusiveMode = false; // Gui control exclusive mode (no inputs processed except current control) +static Rectangle guiControlExclusiveRec = { 0 }; // Gui control exclusive bounds rectangle, used as an unique identifier + +static int textBoxCursorIndex = 0; // Cursor index, shared by all GuiTextBox*() +//static int blinkCursorFrameCounter = 0; // Frame counter for cursor blinking +static int autoCursorCooldownCounter = 0; // Cooldown frame counter for automatic cursor movement on key-down +static int autoCursorDelayCounter = 0; // Delay frame counter for automatic cursor movement + +//---------------------------------------------------------------------------------- +// Style data array for all gui style properties (allocated on data segment by default) +// +// NOTE 1: First set of BASE properties are generic to all controls but could be individually +// overwritten per control, first set of EXTENDED properties are generic to all controls and +// can not be overwritten individually but custom EXTENDED properties can be used by control +// +// NOTE 2: A new style set could be loaded over this array using GuiLoadStyle(), +// but default gui style could always be recovered with GuiLoadStyleDefault() +// +// guiStyle size is by default: 16*(16 + 8) = 384*4 = 1536 bytes = 1.5 KB +//---------------------------------------------------------------------------------- +static unsigned int guiStyle[RAYGUI_MAX_CONTROLS*(RAYGUI_MAX_PROPS_BASE + RAYGUI_MAX_PROPS_EXTENDED)] = { 0 }; + +static bool guiStyleLoaded = false; // Style loaded flag for lazy style initialization + +//---------------------------------------------------------------------------------- +// Standalone Mode Functions Declaration +// +// NOTE: raygui depend on some raylib input and drawing functions +// To use raygui as standalone library, below functions must be defined by the user +//---------------------------------------------------------------------------------- +#if defined(RAYGUI_STANDALONE) + +#define KEY_RIGHT 262 +#define KEY_LEFT 263 +#define KEY_DOWN 264 +#define KEY_UP 265 +#define KEY_BACKSPACE 259 +#define KEY_ENTER 257 + +#define MOUSE_LEFT_BUTTON 0 + +// Input required functions +//------------------------------------------------------------------------------- +static Vector2 GetMousePosition(void); +static float GetMouseWheelMove(void); +static bool IsMouseButtonDown(int button); +static bool IsMouseButtonPressed(int button); +static bool IsMouseButtonReleased(int button); + +static bool IsKeyDown(int key); +static bool IsKeyPressed(int key); +static int GetCharPressed(void); // -- GuiTextBox(), GuiValueBox() +//------------------------------------------------------------------------------- + +// Drawing required functions +//------------------------------------------------------------------------------- +static void DrawRectangle(int x, int y, int width, int height, Color color); // -- GuiDrawRectangle() +static void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3, Color col4); // -- GuiColorPicker() +//------------------------------------------------------------------------------- + +// Text required functions +//------------------------------------------------------------------------------- +static Font GetFontDefault(void); // -- GuiLoadStyleDefault() +static Font LoadFontEx(const char *fileName, int fontSize, int *codepoints, int codepointCount); // -- GuiLoadStyle(), load font + +static Texture2D LoadTextureFromImage(Image image); // -- GuiLoadStyle(), required to load texture from embedded font atlas image +static void SetShapesTexture(Texture2D tex, Rectangle rec); // -- GuiLoadStyle(), required to set shapes rec to font white rec (optimization) + +static char *LoadFileText(const char *fileName); // -- GuiLoadStyle(), required to load charset data +static void UnloadFileText(char *text); // -- GuiLoadStyle(), required to unload charset data + +static const char *GetDirectoryPath(const char *filePath); // -- GuiLoadStyle(), required to find charset/font file from text .rgs + +static int *LoadCodepoints(const char *text, int *count); // -- GuiLoadStyle(), required to load required font codepoints list +static void UnloadCodepoints(int *codepoints); // -- GuiLoadStyle(), required to unload codepoints list + +static unsigned char *DecompressData(const unsigned char *compData, int compDataSize, int *dataSize); // -- GuiLoadStyle() +//------------------------------------------------------------------------------- + +// raylib functions already implemented in raygui +//------------------------------------------------------------------------------- +static Color GetColor(int hexValue); // Returns a Color struct from hexadecimal value +static int ColorToInt(Color color); // Returns hexadecimal value for a Color +static bool CheckCollisionPointRec(Vector2 point, Rectangle rec); // Check if point is inside rectangle +static const char *TextFormat(const char *text, ...); // Formatting of text with variables to 'embed' +static const char **TextSplit(const char *text, char delimiter, int *count); // Split text into multiple strings +static int TextToInteger(const char *text); // Get integer value from text +static float TextToFloat(const char *text); // Get float value from text + +static int GetCodepointNext(const char *text, int *codepointSize); // Get next codepoint in a UTF-8 encoded text +static const char *CodepointToUTF8(int codepoint, int *byteSize); // Encode codepoint into UTF-8 text (char array size returned as parameter) + +static void DrawRectangleGradientV(int posX, int posY, int width, int height, Color color1, Color color2); // Draw rectangle vertical gradient +//------------------------------------------------------------------------------- + +#endif // RAYGUI_STANDALONE + +//---------------------------------------------------------------------------------- +// Module Internal Functions Declaration +//---------------------------------------------------------------------------------- +static void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize); // Load style from memory (binary only) + +static int GetTextWidth(const char *text); // Gui get text width using gui font and style +static Rectangle GetTextBounds(int control, Rectangle bounds); // Get text bounds considering control bounds +static const char *GetTextIcon(const char *text, int *iconId); // Get text icon if provided and move text cursor + +static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, Color tint); // Gui draw text using default font +static void GuiDrawRectangle(Rectangle rec, int borderWidth, Color borderColor, Color color); // Gui draw rectangle using default raygui style + +static const char **GuiTextSplit(const char *text, char delimiter, int *count, int *textRow); // Split controls text into multiple strings +static Vector3 ConvertHSVtoRGB(Vector3 hsv); // Convert color data from HSV to RGB +static Vector3 ConvertRGBtoHSV(Vector3 rgb); // Convert color data from RGB to HSV + +static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue); // Scroll bar control, used by GuiScrollPanel() +static void GuiTooltip(Rectangle controlRec); // Draw tooltip using control rec position + +static Color GuiFade(Color color, float alpha); // Fade color by an alpha factor + +//---------------------------------------------------------------------------------- +// Gui Setup Functions Definition +//---------------------------------------------------------------------------------- +// Enable gui global state +// NOTE: We check for STATE_DISABLED to avoid messing custom global state setups +void GuiEnable(void) { if (guiState == STATE_DISABLED) guiState = STATE_NORMAL; } + +// Disable gui global state +// NOTE: We check for STATE_NORMAL to avoid messing custom global state setups +void GuiDisable(void) { if (guiState == STATE_NORMAL) guiState = STATE_DISABLED; } + +// Lock gui global state +void GuiLock(void) { guiLocked = true; } + +// Unlock gui global state +void GuiUnlock(void) { guiLocked = false; } + +// Check if gui is locked (global state) +bool GuiIsLocked(void) { return guiLocked; } + +// Set gui controls alpha global state +void GuiSetAlpha(float alpha) +{ + if (alpha < 0.0f) alpha = 0.0f; + else if (alpha > 1.0f) alpha = 1.0f; + + guiAlpha = alpha; +} + +// Set gui state (global state) +void GuiSetState(int state) { guiState = (GuiState)state; } + +// Get gui state (global state) +int GuiGetState(void) { return guiState; } + +// Set custom gui font +// NOTE: Font loading/unloading is external to raygui +void GuiSetFont(Font font) +{ + if (font.texture.id > 0) + { + // NOTE: If we try to setup a font but default style has not been + // lazily loaded before, it will be overwritten, so we need to force + // default style loading first + if (!guiStyleLoaded) GuiLoadStyleDefault(); + + guiFont = font; + } +} + +// Get custom gui font +Font GuiGetFont(void) +{ + return guiFont; +} + +// Set control style property value +void GuiSetStyle(int control, int property, int value) +{ + if (!guiStyleLoaded) GuiLoadStyleDefault(); + guiStyle[control*(RAYGUI_MAX_PROPS_BASE + RAYGUI_MAX_PROPS_EXTENDED) + property] = value; + + // Default properties are propagated to all controls + if ((control == 0) && (property < RAYGUI_MAX_PROPS_BASE)) + { + for (int i = 1; i < RAYGUI_MAX_CONTROLS; i++) guiStyle[i*(RAYGUI_MAX_PROPS_BASE + RAYGUI_MAX_PROPS_EXTENDED) + property] = value; + } +} + +// Get control style property value +int GuiGetStyle(int control, int property) +{ + if (!guiStyleLoaded) GuiLoadStyleDefault(); + return guiStyle[control*(RAYGUI_MAX_PROPS_BASE + RAYGUI_MAX_PROPS_EXTENDED) + property]; +} + +//---------------------------------------------------------------------------------- +// Gui Controls Functions Definition +//---------------------------------------------------------------------------------- + +// Window Box control +int GuiWindowBox(Rectangle bounds, const char *title) +{ + // Window title bar height (including borders) + // NOTE: This define is also used by GuiMessageBox() and GuiTextInputBox() + #if !defined(RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT) + #define RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT 24 + #endif + + int result = 0; + //GuiState state = guiState; + + int statusBarHeight = RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT; + + Rectangle statusBar = { bounds.x, bounds.y, bounds.width, (float)statusBarHeight }; + if (bounds.height < statusBarHeight*2.0f) bounds.height = statusBarHeight*2.0f; + + Rectangle windowPanel = { bounds.x, bounds.y + (float)statusBarHeight - 1, bounds.width, bounds.height - (float)statusBarHeight + 1 }; + Rectangle closeButtonRec = { statusBar.x + statusBar.width - GuiGetStyle(STATUSBAR, BORDER_WIDTH) - 20, + statusBar.y + statusBarHeight/2.0f - 18.0f/2.0f, 18, 18 }; + + // Update control + //-------------------------------------------------------------------- + // NOTE: Logic is directly managed by button + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiStatusBar(statusBar, title); // Draw window header as status bar + GuiPanel(windowPanel, NULL); // Draw window base + + // Draw window close button + int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH); + int tempTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); + GuiSetStyle(BUTTON, BORDER_WIDTH, 1); + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); +#if defined(RAYGUI_NO_ICONS) + result = GuiButton(closeButtonRec, "x"); +#else + result = GuiButton(closeButtonRec, GuiIconText(ICON_CROSS_SMALL, NULL)); +#endif + GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth); + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlignment); + //-------------------------------------------------------------------- + + return result; // Window close button clicked: result = 1 +} + +// Group Box control with text name +int GuiGroupBox(Rectangle bounds, const char *text) +{ + #if !defined(RAYGUI_GROUPBOX_LINE_THICK) + #define RAYGUI_GROUPBOX_LINE_THICK 1 + #endif + + int result = 0; + GuiState state = guiState; + + // Draw control + //-------------------------------------------------------------------- + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, RAYGUI_GROUPBOX_LINE_THICK, bounds.height }, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BORDER_COLOR_DISABLED : (int)LINE_COLOR))); + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height - 1, bounds.width, RAYGUI_GROUPBOX_LINE_THICK }, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BORDER_COLOR_DISABLED : (int)LINE_COLOR))); + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - 1, bounds.y, RAYGUI_GROUPBOX_LINE_THICK, bounds.height }, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BORDER_COLOR_DISABLED : (int)LINE_COLOR))); + + GuiLine(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y - GuiGetStyle(DEFAULT, TEXT_SIZE)/2, bounds.width, (float)GuiGetStyle(DEFAULT, TEXT_SIZE) }, text); + //-------------------------------------------------------------------- + + return result; +} + +// Line control +int GuiLine(Rectangle bounds, const char *text) +{ + #if !defined(RAYGUI_LINE_ORIGIN_SIZE) + #define RAYGUI_LINE_MARGIN_TEXT 12 + #endif + #if !defined(RAYGUI_LINE_TEXT_PADDING) + #define RAYGUI_LINE_TEXT_PADDING 4 + #endif + + int result = 0; + GuiState state = guiState; + + Color color = GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BORDER_COLOR_DISABLED : (int)LINE_COLOR)); + + // Draw control + //-------------------------------------------------------------------- + if (text == NULL) GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height/2, bounds.width, 1 }, 0, BLANK, color); + else + { + Rectangle textBounds = { 0 }; + textBounds.width = (float)GetTextWidth(text) + 2; + textBounds.height = bounds.height; + textBounds.x = bounds.x + RAYGUI_LINE_MARGIN_TEXT; + textBounds.y = bounds.y; + + // Draw line with embedded text label: "--- text --------------" + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height/2, RAYGUI_LINE_MARGIN_TEXT - RAYGUI_LINE_TEXT_PADDING, 1 }, 0, BLANK, color); + GuiDrawText(text, textBounds, TEXT_ALIGN_LEFT, color); + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + 12 + textBounds.width + 4, bounds.y + bounds.height/2, bounds.width - textBounds.width - RAYGUI_LINE_MARGIN_TEXT - RAYGUI_LINE_TEXT_PADDING, 1 }, 0, BLANK, color); + } + //-------------------------------------------------------------------- + + return result; +} + +// Panel control +int GuiPanel(Rectangle bounds, const char *text) +{ + #if !defined(RAYGUI_PANEL_BORDER_WIDTH) + #define RAYGUI_PANEL_BORDER_WIDTH 1 + #endif + + int result = 0; + GuiState state = guiState; + + // Text will be drawn as a header bar (if provided) + Rectangle statusBar = { bounds.x, bounds.y, bounds.width, (float)RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT }; + if ((text != NULL) && (bounds.height < RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT*2.0f)) bounds.height = RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT*2.0f; + + if (text != NULL) + { + // Move panel bounds after the header bar + bounds.y += (float)RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT - 1; + bounds.height -= (float)RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT - 1; + } + + // Draw control + //-------------------------------------------------------------------- + if (text != NULL) GuiStatusBar(statusBar, text); // Draw panel header as status bar + + GuiDrawRectangle(bounds, RAYGUI_PANEL_BORDER_WIDTH, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BORDER_COLOR_DISABLED: (int)LINE_COLOR)), + GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? BASE_COLOR_DISABLED : BACKGROUND_COLOR))); + //-------------------------------------------------------------------- + + return result; +} + +// Tab Bar control +// NOTE: Using GuiToggle() for the TABS +int GuiTabBar(Rectangle bounds, const char **text, int count, int *active) +{ + #define RAYGUI_TABBAR_ITEM_WIDTH 160 + + int result = -1; + //GuiState state = guiState; + + Rectangle tabBounds = { bounds.x, bounds.y, RAYGUI_TABBAR_ITEM_WIDTH, bounds.height }; + + if (*active < 0) *active = 0; + else if (*active > count - 1) *active = count - 1; + + int offsetX = 0; // Required in case tabs go out of screen + offsetX = (*active + 2)*RAYGUI_TABBAR_ITEM_WIDTH - GetScreenWidth(); + if (offsetX < 0) offsetX = 0; + + bool toggle = false; // Required for individual toggles + + // Draw control + //-------------------------------------------------------------------- + for (int i = 0; i < count; i++) + { + tabBounds.x = bounds.x + (RAYGUI_TABBAR_ITEM_WIDTH + 4)*i - offsetX; + + if (tabBounds.x < GetScreenWidth()) + { + // Draw tabs as toggle controls + int textAlignment = GuiGetStyle(TOGGLE, TEXT_ALIGNMENT); + int textPadding = GuiGetStyle(TOGGLE, TEXT_PADDING); + GuiSetStyle(TOGGLE, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); + GuiSetStyle(TOGGLE, TEXT_PADDING, 8); + + if (i == (*active)) + { + toggle = true; + GuiToggle(tabBounds, GuiIconText(12, text[i]), &toggle); + } + else + { + toggle = false; + GuiToggle(tabBounds, GuiIconText(12, text[i]), &toggle); + if (toggle) *active = i; + } + + // Close tab with middle mouse button pressed + if (CheckCollisionPointRec(GetMousePosition(), tabBounds) && IsMouseButtonPressed(MOUSE_MIDDLE_BUTTON)) result = i; + + GuiSetStyle(TOGGLE, TEXT_PADDING, textPadding); + GuiSetStyle(TOGGLE, TEXT_ALIGNMENT, textAlignment); + + // Draw tab close button + // NOTE: Only draw close button for current tab: if (CheckCollisionPointRec(mousePosition, tabBounds)) + int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH); + int tempTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); + GuiSetStyle(BUTTON, BORDER_WIDTH, 1); + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); +#if defined(RAYGUI_NO_ICONS) + if (GuiButton(RAYGUI_CLITERAL(Rectangle){ tabBounds.x + tabBounds.width - 14 - 5, tabBounds.y + 5, 14, 14 }, "x")) result = i; +#else + if (GuiButton(RAYGUI_CLITERAL(Rectangle){ tabBounds.x + tabBounds.width - 14 - 5, tabBounds.y + 5, 14, 14 }, GuiIconText(ICON_CROSS_SMALL, NULL))) result = i; +#endif + GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth); + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlignment); + } + } + + // Draw tab-bar bottom line + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height - 1, bounds.width, 1 }, 0, BLANK, GetColor(GuiGetStyle(TOGGLE, BORDER_COLOR_NORMAL))); + //-------------------------------------------------------------------- + + return result; // Return as result the current TAB closing requested +} + +// Scroll Panel control +int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector2 *scroll, Rectangle *view) +{ + #define RAYGUI_MIN_SCROLLBAR_WIDTH 40 + #define RAYGUI_MIN_SCROLLBAR_HEIGHT 40 + #define RAYGUI_MIN_MOUSE_WHEEL_SPEED 20 + + int result = 0; + GuiState state = guiState; + + Rectangle temp = { 0 }; + if (view == NULL) view = &temp; + + Vector2 scrollPos = { 0.0f, 0.0f }; + if (scroll != NULL) scrollPos = *scroll; + + // Text will be drawn as a header bar (if provided) + Rectangle statusBar = { bounds.x, bounds.y, bounds.width, (float)RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT }; + if (bounds.height < RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT*2.0f) bounds.height = RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT*2.0f; + + if (text != NULL) + { + // Move panel bounds after the header bar + bounds.y += (float)RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT - 1; + bounds.height -= (float)RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT + 1; + } + + bool hasHorizontalScrollBar = (content.width > bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH))? true : false; + bool hasVerticalScrollBar = (content.height > bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH))? true : false; + + // Recheck to account for the other scrollbar being visible + if (!hasHorizontalScrollBar) hasHorizontalScrollBar = (hasVerticalScrollBar && (content.width > (bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH))))? true : false; + if (!hasVerticalScrollBar) hasVerticalScrollBar = (hasHorizontalScrollBar && (content.height > (bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH))))? true : false; + + int horizontalScrollBarWidth = hasHorizontalScrollBar? GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH) : 0; + int verticalScrollBarWidth = hasVerticalScrollBar? GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH) : 0; + Rectangle horizontalScrollBar = { + (float)((GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)bounds.x + verticalScrollBarWidth : (float)bounds.x) + GuiGetStyle(DEFAULT, BORDER_WIDTH), + (float)bounds.y + bounds.height - horizontalScrollBarWidth - GuiGetStyle(DEFAULT, BORDER_WIDTH), + (float)bounds.width - verticalScrollBarWidth - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH), + (float)horizontalScrollBarWidth + }; + Rectangle verticalScrollBar = { + (float)((GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)bounds.x + GuiGetStyle(DEFAULT, BORDER_WIDTH) : (float)bounds.x + bounds.width - verticalScrollBarWidth - GuiGetStyle(DEFAULT, BORDER_WIDTH)), + (float)bounds.y + GuiGetStyle(DEFAULT, BORDER_WIDTH), + (float)verticalScrollBarWidth, + (float)bounds.height - horizontalScrollBarWidth - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) + }; + + // Make sure scroll bars have a minimum width/height + if (horizontalScrollBar.width < RAYGUI_MIN_SCROLLBAR_WIDTH) horizontalScrollBar.width = RAYGUI_MIN_SCROLLBAR_WIDTH; + if (verticalScrollBar.height < RAYGUI_MIN_SCROLLBAR_HEIGHT) verticalScrollBar.height = RAYGUI_MIN_SCROLLBAR_HEIGHT; + + // Calculate view area (area without the scrollbars) + *view = (GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? + RAYGUI_CLITERAL(Rectangle){ bounds.x + verticalScrollBarWidth + GuiGetStyle(DEFAULT, BORDER_WIDTH), bounds.y + GuiGetStyle(DEFAULT, BORDER_WIDTH), bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - verticalScrollBarWidth, bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - horizontalScrollBarWidth } : + RAYGUI_CLITERAL(Rectangle){ bounds.x + GuiGetStyle(DEFAULT, BORDER_WIDTH), bounds.y + GuiGetStyle(DEFAULT, BORDER_WIDTH), bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - verticalScrollBarWidth, bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - horizontalScrollBarWidth }; + + // Clip view area to the actual content size + if (view->width > content.width) view->width = content.width; + if (view->height > content.height) view->height = content.height; + + float horizontalMin = hasHorizontalScrollBar? ((GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)-verticalScrollBarWidth : 0) - (float)GuiGetStyle(DEFAULT, BORDER_WIDTH) : (((float)GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)-verticalScrollBarWidth : 0) - (float)GuiGetStyle(DEFAULT, BORDER_WIDTH); + float horizontalMax = hasHorizontalScrollBar? content.width - bounds.width + (float)verticalScrollBarWidth + GuiGetStyle(DEFAULT, BORDER_WIDTH) - (((float)GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)verticalScrollBarWidth : 0) : (float)-GuiGetStyle(DEFAULT, BORDER_WIDTH); + float verticalMin = hasVerticalScrollBar? 0.0f : -1.0f; + float verticalMax = hasVerticalScrollBar? content.height - bounds.height + (float)horizontalScrollBarWidth + (float)GuiGetStyle(DEFAULT, BORDER_WIDTH) : (float)-GuiGetStyle(DEFAULT, BORDER_WIDTH); + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked) + { + Vector2 mousePoint = GetMousePosition(); + + // Check button state + if (CheckCollisionPointRec(mousePoint, bounds)) + { + if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED; + else state = STATE_FOCUSED; + +#if defined(SUPPORT_SCROLLBAR_KEY_INPUT) + if (hasHorizontalScrollBar) + { + if (IsKeyDown(KEY_RIGHT)) scrollPos.x -= GuiGetStyle(SCROLLBAR, SCROLL_SPEED); + if (IsKeyDown(KEY_LEFT)) scrollPos.x += GuiGetStyle(SCROLLBAR, SCROLL_SPEED); + } + + if (hasVerticalScrollBar) + { + if (IsKeyDown(KEY_DOWN)) scrollPos.y -= GuiGetStyle(SCROLLBAR, SCROLL_SPEED); + if (IsKeyDown(KEY_UP)) scrollPos.y += GuiGetStyle(SCROLLBAR, SCROLL_SPEED); + } +#endif + float wheelMove = GetMouseWheelMove(); + + // Set scrolling speed with mouse wheel based on ratio between bounds and content + Vector2 mouseWheelSpeed = { content.width/bounds.width, content.height/bounds.height }; + if (mouseWheelSpeed.x < RAYGUI_MIN_MOUSE_WHEEL_SPEED) mouseWheelSpeed.x = RAYGUI_MIN_MOUSE_WHEEL_SPEED; + if (mouseWheelSpeed.y < RAYGUI_MIN_MOUSE_WHEEL_SPEED) mouseWheelSpeed.y = RAYGUI_MIN_MOUSE_WHEEL_SPEED; + + // Horizontal and vertical scrolling with mouse wheel + if (hasHorizontalScrollBar && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_LEFT_SHIFT))) scrollPos.x += wheelMove*mouseWheelSpeed.x; + else scrollPos.y += wheelMove*mouseWheelSpeed.y; // Vertical scroll + } + } + + // Normalize scroll values + if (scrollPos.x > -horizontalMin) scrollPos.x = -horizontalMin; + if (scrollPos.x < -horizontalMax) scrollPos.x = -horizontalMax; + if (scrollPos.y > -verticalMin) scrollPos.y = -verticalMin; + if (scrollPos.y < -verticalMax) scrollPos.y = -verticalMax; + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + if (text != NULL) GuiStatusBar(statusBar, text); // Draw panel header as status bar + + GuiDrawRectangle(bounds, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR))); // Draw background + + // Save size of the scrollbar slider + const int slider = GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE); + + // Draw horizontal scrollbar if visible + if (hasHorizontalScrollBar) + { + // Change scrollbar slider size to show the diff in size between the content width and the widget width + GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, (int)(((bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - verticalScrollBarWidth)/(int)content.width)*((int)bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - verticalScrollBarWidth))); + scrollPos.x = (float)-GuiScrollBar(horizontalScrollBar, (int)-scrollPos.x, (int)horizontalMin, (int)horizontalMax); + } + else scrollPos.x = 0.0f; + + // Draw vertical scrollbar if visible + if (hasVerticalScrollBar) + { + // Change scrollbar slider size to show the diff in size between the content height and the widget height + GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, (int)(((bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - horizontalScrollBarWidth)/(int)content.height)*((int)bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - horizontalScrollBarWidth))); + scrollPos.y = (float)-GuiScrollBar(verticalScrollBar, (int)-scrollPos.y, (int)verticalMin, (int)verticalMax); + } + else scrollPos.y = 0.0f; + + // Draw detail corner rectangle if both scroll bars are visible + if (hasHorizontalScrollBar && hasVerticalScrollBar) + { + Rectangle corner = { (GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (bounds.x + GuiGetStyle(DEFAULT, BORDER_WIDTH) + 2) : (horizontalScrollBar.x + horizontalScrollBar.width + 2), verticalScrollBar.y + verticalScrollBar.height + 2, (float)horizontalScrollBarWidth - 4, (float)verticalScrollBarWidth - 4 }; + GuiDrawRectangle(corner, 0, BLANK, GetColor(GuiGetStyle(LISTVIEW, TEXT + (state*3)))); + } + + // Draw scrollbar lines depending on current state + GuiDrawRectangle(bounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER + (state*3))), BLANK); + + // Set scrollbar slider size back to the way it was before + GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, slider); + //-------------------------------------------------------------------- + + if (scroll != NULL) *scroll = scrollPos; + + return result; +} + +// Label control +int GuiLabel(Rectangle bounds, const char *text) +{ + int result = 0; + GuiState state = guiState; + + // Update control + //-------------------------------------------------------------------- + //... + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawText(text, GetTextBounds(LABEL, bounds), GuiGetStyle(LABEL, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); + //-------------------------------------------------------------------- + + return result; +} + +// Button control, returns true when clicked +int GuiButton(Rectangle bounds, const char *text) +{ + int result = 0; + GuiState state = guiState; + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) + { + Vector2 mousePoint = GetMousePosition(); + + // Check button state + if (CheckCollisionPointRec(mousePoint, bounds)) + { + if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED; + else state = STATE_FOCUSED; + + if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) result = 1; + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawRectangle(bounds, GuiGetStyle(BUTTON, BORDER_WIDTH), GetColor(GuiGetStyle(BUTTON, BORDER + (state*3))), GetColor(GuiGetStyle(BUTTON, BASE + (state*3)))); + GuiDrawText(text, GetTextBounds(BUTTON, bounds), GuiGetStyle(BUTTON, TEXT_ALIGNMENT), GetColor(GuiGetStyle(BUTTON, TEXT + (state*3)))); + + if (state == STATE_FOCUSED) GuiTooltip(bounds); + //------------------------------------------------------------------ + + return result; // Button pressed: result = 1 +} + +// Label button control +int GuiLabelButton(Rectangle bounds, const char *text) +{ + GuiState state = guiState; + bool pressed = false; + + // NOTE: We force bounds.width to be all text + float textWidth = (float)GetTextWidth(text); + if ((bounds.width - 2*GuiGetStyle(LABEL, BORDER_WIDTH) - 2*GuiGetStyle(LABEL, TEXT_PADDING)) < textWidth) bounds.width = textWidth + 2*GuiGetStyle(LABEL, BORDER_WIDTH) + 2*GuiGetStyle(LABEL, TEXT_PADDING) + 2; + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) + { + Vector2 mousePoint = GetMousePosition(); + + // Check checkbox state + if (CheckCollisionPointRec(mousePoint, bounds)) + { + if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED; + else state = STATE_FOCUSED; + + if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) pressed = true; + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawText(text, GetTextBounds(LABEL, bounds), GuiGetStyle(LABEL, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); + //-------------------------------------------------------------------- + + return pressed; +} + +// Toggle Button control +int GuiToggle(Rectangle bounds, const char *text, bool *active) +{ + int result = 0; + GuiState state = guiState; + + bool temp = false; + if (active == NULL) active = &temp; + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) + { + Vector2 mousePoint = GetMousePosition(); + + // Check toggle button state + if (CheckCollisionPointRec(mousePoint, bounds)) + { + if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED; + else if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) + { + state = STATE_NORMAL; + *active = !(*active); + } + else state = STATE_FOCUSED; + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + if (state == STATE_NORMAL) + { + GuiDrawRectangle(bounds, GuiGetStyle(TOGGLE, BORDER_WIDTH), GetColor(GuiGetStyle(TOGGLE, ((*active)? BORDER_COLOR_PRESSED : (BORDER + state*3)))), GetColor(GuiGetStyle(TOGGLE, ((*active)? BASE_COLOR_PRESSED : (BASE + state*3))))); + GuiDrawText(text, GetTextBounds(TOGGLE, bounds), GuiGetStyle(TOGGLE, TEXT_ALIGNMENT), GetColor(GuiGetStyle(TOGGLE, ((*active)? TEXT_COLOR_PRESSED : (TEXT + state*3))))); + } + else + { + GuiDrawRectangle(bounds, GuiGetStyle(TOGGLE, BORDER_WIDTH), GetColor(GuiGetStyle(TOGGLE, BORDER + state*3)), GetColor(GuiGetStyle(TOGGLE, BASE + state*3))); + GuiDrawText(text, GetTextBounds(TOGGLE, bounds), GuiGetStyle(TOGGLE, TEXT_ALIGNMENT), GetColor(GuiGetStyle(TOGGLE, TEXT + state*3))); + } + + if (state == STATE_FOCUSED) GuiTooltip(bounds); + //-------------------------------------------------------------------- + + return result; +} + +// Toggle Group control +int GuiToggleGroup(Rectangle bounds, const char *text, int *active) +{ + #if !defined(RAYGUI_TOGGLEGROUP_MAX_ITEMS) + #define RAYGUI_TOGGLEGROUP_MAX_ITEMS 32 + #endif + + int result = 0; + float initBoundsX = bounds.x; + + int temp = 0; + if (active == NULL) active = &temp; + + bool toggle = false; // Required for individual toggles + + // Get substrings items from text (items pointers) + int rows[RAYGUI_TOGGLEGROUP_MAX_ITEMS] = { 0 }; + int itemCount = 0; + const char **items = GuiTextSplit(text, ';', &itemCount, rows); + + int prevRow = rows[0]; + + for (int i = 0; i < itemCount; i++) + { + if (prevRow != rows[i]) + { + bounds.x = initBoundsX; + bounds.y += (bounds.height + GuiGetStyle(TOGGLE, GROUP_PADDING)); + prevRow = rows[i]; + } + + if (i == (*active)) + { + toggle = true; + GuiToggle(bounds, items[i], &toggle); + } + else + { + toggle = false; + GuiToggle(bounds, items[i], &toggle); + if (toggle) *active = i; + } + + bounds.x += (bounds.width + GuiGetStyle(TOGGLE, GROUP_PADDING)); + } + + return result; +} + +// Toggle Slider control extended +int GuiToggleSlider(Rectangle bounds, const char *text, int *active) +{ + int result = 0; + GuiState state = guiState; + + int temp = 0; + if (active == NULL) active = &temp; + + //bool toggle = false; // Required for individual toggles + + // Get substrings items from text (items pointers) + int itemCount = 0; + const char **items = GuiTextSplit(text, ';', &itemCount, NULL); + + Rectangle slider = { + 0, // Calculated later depending on the active toggle + bounds.y + GuiGetStyle(SLIDER, BORDER_WIDTH) + GuiGetStyle(SLIDER, SLIDER_PADDING), + (bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH) - (itemCount + 1)*GuiGetStyle(SLIDER, SLIDER_PADDING))/itemCount, + bounds.height - 2*GuiGetStyle(SLIDER, BORDER_WIDTH) - 2*GuiGetStyle(SLIDER, SLIDER_PADDING) }; + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked) + { + Vector2 mousePoint = GetMousePosition(); + + if (CheckCollisionPointRec(mousePoint, bounds)) + { + if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED; + else if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) + { + state = STATE_PRESSED; + (*active)++; + result = 1; + } + else state = STATE_FOCUSED; + } + + if ((*active) && (state != STATE_FOCUSED)) state = STATE_PRESSED; + } + + if (*active >= itemCount) *active = 0; + slider.x = bounds.x + GuiGetStyle(SLIDER, BORDER_WIDTH) + (*active + 1)*GuiGetStyle(SLIDER, SLIDER_PADDING) + (*active)*slider.width; + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawRectangle(bounds, GuiGetStyle(SLIDER, BORDER_WIDTH), GetColor(GuiGetStyle(TOGGLE, BORDER + (state*3))), + GetColor(GuiGetStyle(TOGGLE, BASE_COLOR_NORMAL))); + + // Draw internal slider + if (state == STATE_NORMAL) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, BASE_COLOR_PRESSED))); + else if (state == STATE_FOCUSED) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, BASE_COLOR_FOCUSED))); + else if (state == STATE_PRESSED) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, BASE_COLOR_PRESSED))); + + // Draw text in slider + if (text != NULL) + { + Rectangle textBounds = { 0 }; + textBounds.width = (float)GetTextWidth(text); + textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); + textBounds.x = slider.x + slider.width/2 - textBounds.width/2; + textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; + + GuiDrawText(items[*active], textBounds, GuiGetStyle(TOGGLE, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(TOGGLE, TEXT + (state*3))), guiAlpha)); + } + //-------------------------------------------------------------------- + + return result; +} + +// Check Box control, returns 1 when state changed +int GuiCheckBox(Rectangle bounds, const char *text, bool *checked) +{ + int result = 0; + GuiState state = guiState; + + bool temp = false; + if (checked == NULL) checked = &temp; + + Rectangle textBounds = { 0 }; + + if (text != NULL) + { + textBounds.width = (float)GetTextWidth(text) + 2; + textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); + textBounds.x = bounds.x + bounds.width + GuiGetStyle(CHECKBOX, TEXT_PADDING); + textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; + if (GuiGetStyle(CHECKBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_LEFT) textBounds.x = bounds.x - textBounds.width - GuiGetStyle(CHECKBOX, TEXT_PADDING); + } + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) + { + Vector2 mousePoint = GetMousePosition(); + + Rectangle totalBounds = { + (GuiGetStyle(CHECKBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_LEFT)? textBounds.x : bounds.x, + bounds.y, + bounds.width + textBounds.width + GuiGetStyle(CHECKBOX, TEXT_PADDING), + bounds.height, + }; + + // Check checkbox state + if (CheckCollisionPointRec(mousePoint, totalBounds)) + { + if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED; + else state = STATE_FOCUSED; + + if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) + { + *checked = !(*checked); + result = 1; + } + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawRectangle(bounds, GuiGetStyle(CHECKBOX, BORDER_WIDTH), GetColor(GuiGetStyle(CHECKBOX, BORDER + (state*3))), BLANK); + + if (*checked) + { + Rectangle check = { bounds.x + GuiGetStyle(CHECKBOX, BORDER_WIDTH) + GuiGetStyle(CHECKBOX, CHECK_PADDING), + bounds.y + GuiGetStyle(CHECKBOX, BORDER_WIDTH) + GuiGetStyle(CHECKBOX, CHECK_PADDING), + bounds.width - 2*(GuiGetStyle(CHECKBOX, BORDER_WIDTH) + GuiGetStyle(CHECKBOX, CHECK_PADDING)), + bounds.height - 2*(GuiGetStyle(CHECKBOX, BORDER_WIDTH) + GuiGetStyle(CHECKBOX, CHECK_PADDING)) }; + GuiDrawRectangle(check, 0, BLANK, GetColor(GuiGetStyle(CHECKBOX, TEXT + state*3))); + } + + GuiDrawText(text, textBounds, (GuiGetStyle(CHECKBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); + //-------------------------------------------------------------------- + + return result; +} + +// Combo Box control +int GuiComboBox(Rectangle bounds, const char *text, int *active) +{ + int result = 0; + GuiState state = guiState; + + int temp = 0; + if (active == NULL) active = &temp; + + bounds.width -= (GuiGetStyle(COMBOBOX, COMBO_BUTTON_WIDTH) + GuiGetStyle(COMBOBOX, COMBO_BUTTON_SPACING)); + + Rectangle selector = { (float)bounds.x + bounds.width + GuiGetStyle(COMBOBOX, COMBO_BUTTON_SPACING), + (float)bounds.y, (float)GuiGetStyle(COMBOBOX, COMBO_BUTTON_WIDTH), (float)bounds.height }; + + // Get substrings items from text (items pointers, lengths and count) + int itemCount = 0; + const char **items = GuiTextSplit(text, ';', &itemCount, NULL); + + if (*active < 0) *active = 0; + else if (*active > (itemCount - 1)) *active = itemCount - 1; + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked && (itemCount > 1) && !guiControlExclusiveMode) + { + Vector2 mousePoint = GetMousePosition(); + + if (CheckCollisionPointRec(mousePoint, bounds) || + CheckCollisionPointRec(mousePoint, selector)) + { + if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) + { + *active += 1; + if (*active >= itemCount) *active = 0; // Cyclic combobox + } + + if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED; + else state = STATE_FOCUSED; + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + // Draw combo box main + GuiDrawRectangle(bounds, GuiGetStyle(COMBOBOX, BORDER_WIDTH), GetColor(GuiGetStyle(COMBOBOX, BORDER + (state*3))), GetColor(GuiGetStyle(COMBOBOX, BASE + (state*3)))); + GuiDrawText(items[*active], GetTextBounds(COMBOBOX, bounds), GuiGetStyle(COMBOBOX, TEXT_ALIGNMENT), GetColor(GuiGetStyle(COMBOBOX, TEXT + (state*3)))); + + // Draw selector using a custom button + // NOTE: BORDER_WIDTH and TEXT_ALIGNMENT forced values + int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH); + int tempTextAlign = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); + GuiSetStyle(BUTTON, BORDER_WIDTH, 1); + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); + + GuiButton(selector, TextFormat("%i/%i", *active + 1, itemCount)); + + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlign); + GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth); + //-------------------------------------------------------------------- + + return result; +} + +// Dropdown Box control +// NOTE: Returns mouse click +int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMode) +{ + int result = 0; + GuiState state = guiState; + + int temp = 0; + if (active == NULL) active = &temp; + + int itemSelected = *active; + int itemFocused = -1; + + int direction = 0; // Dropdown box open direction: down (default) + if (GuiGetStyle(DROPDOWNBOX, DROPDOWN_ROLL_UP) == 1) direction = 1; // Up + + // Get substrings items from text (items pointers, lengths and count) + int itemCount = 0; + const char **items = GuiTextSplit(text, ';', &itemCount, NULL); + + Rectangle boundsOpen = bounds; + boundsOpen.height = (itemCount + 1)*(bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING)); + if (direction == 1) boundsOpen.y -= itemCount*(bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING)) + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING); + + Rectangle itemBounds = bounds; + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && (editMode || !guiLocked) && (itemCount > 1) && !guiControlExclusiveMode) + { + Vector2 mousePoint = GetMousePosition(); + + if (editMode) + { + state = STATE_PRESSED; + + // Check if mouse has been pressed or released outside limits + if (!CheckCollisionPointRec(mousePoint, boundsOpen)) + { + if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON) || IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) result = 1; + } + + // Check if already selected item has been pressed again + if (CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) result = 1; + + // Check focused and selected item + for (int i = 0; i < itemCount; i++) + { + // Update item rectangle y position for next item + if (direction == 0) itemBounds.y += (bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING)); + else itemBounds.y -= (bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING)); + + if (CheckCollisionPointRec(mousePoint, itemBounds)) + { + itemFocused = i; + if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) + { + itemSelected = i; + result = 1; // Item selected + } + break; + } + } + + itemBounds = bounds; + } + else + { + if (CheckCollisionPointRec(mousePoint, bounds)) + { + if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) + { + result = 1; + state = STATE_PRESSED; + } + else state = STATE_FOCUSED; + } + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + if (editMode) GuiPanel(boundsOpen, NULL); + + GuiDrawRectangle(bounds, GuiGetStyle(DROPDOWNBOX, BORDER_WIDTH), GetColor(GuiGetStyle(DROPDOWNBOX, BORDER + state*3)), GetColor(GuiGetStyle(DROPDOWNBOX, BASE + state*3))); + GuiDrawText(items[itemSelected], GetTextBounds(DROPDOWNBOX, bounds), GuiGetStyle(DROPDOWNBOX, TEXT_ALIGNMENT), GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + state*3))); + + if (editMode) + { + // Draw visible items + for (int i = 0; i < itemCount; i++) + { + // Update item rectangle y position for next item + if (direction == 0) itemBounds.y += (bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING)); + else itemBounds.y -= (bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING)); + + if (i == itemSelected) + { + GuiDrawRectangle(itemBounds, GuiGetStyle(DROPDOWNBOX, BORDER_WIDTH), GetColor(GuiGetStyle(DROPDOWNBOX, BORDER_COLOR_PRESSED)), GetColor(GuiGetStyle(DROPDOWNBOX, BASE_COLOR_PRESSED))); + GuiDrawText(items[i], GetTextBounds(DROPDOWNBOX, itemBounds), GuiGetStyle(DROPDOWNBOX, TEXT_ALIGNMENT), GetColor(GuiGetStyle(DROPDOWNBOX, TEXT_COLOR_PRESSED))); + } + else if (i == itemFocused) + { + GuiDrawRectangle(itemBounds, GuiGetStyle(DROPDOWNBOX, BORDER_WIDTH), GetColor(GuiGetStyle(DROPDOWNBOX, BORDER_COLOR_FOCUSED)), GetColor(GuiGetStyle(DROPDOWNBOX, BASE_COLOR_FOCUSED))); + GuiDrawText(items[i], GetTextBounds(DROPDOWNBOX, itemBounds), GuiGetStyle(DROPDOWNBOX, TEXT_ALIGNMENT), GetColor(GuiGetStyle(DROPDOWNBOX, TEXT_COLOR_FOCUSED))); + } + else GuiDrawText(items[i], GetTextBounds(DROPDOWNBOX, itemBounds), GuiGetStyle(DROPDOWNBOX, TEXT_ALIGNMENT), GetColor(GuiGetStyle(DROPDOWNBOX, TEXT_COLOR_NORMAL))); + } + } + + if (!GuiGetStyle(DROPDOWNBOX, DROPDOWN_ARROW_HIDDEN)) + { + // Draw arrows (using icon if available) +#if defined(RAYGUI_NO_ICONS) + GuiDrawText("v", RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_PADDING), bounds.y + bounds.height/2 - 2, 10, 10 }, + TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); +#else + GuiDrawText(direction? "#121#" : "#120#", RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_PADDING), bounds.y + bounds.height/2 - 6, 10, 10 }, + TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); // ICON_ARROW_DOWN_FILL +#endif + } + //-------------------------------------------------------------------- + + *active = itemSelected; + + // TODO: Use result to return more internal states: mouse-press out-of-bounds, mouse-press over selected-item... + return result; // Mouse click: result = 1 +} + +// Text Box control +// NOTE: Returns true on ENTER pressed (useful for data validation) +int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) +{ + #if !defined(RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN) + #define RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN 40 // Frames to wait for autocursor movement + #endif + #if !defined(RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY) + #define RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY 1 // Frames delay for autocursor movement + #endif + + int result = 0; + GuiState state = guiState; + + bool multiline = false; // TODO: Consider multiline text input + int wrapMode = GuiGetStyle(DEFAULT, TEXT_WRAP_MODE); + + Rectangle textBounds = GetTextBounds(TEXTBOX, bounds); + int textLength = (int)strlen(text); // Get current text length + int thisCursorIndex = textBoxCursorIndex; + if (thisCursorIndex > textLength) thisCursorIndex = textLength; + int textWidth = GetTextWidth(text) - GetTextWidth(text + thisCursorIndex); + int textIndexOffset = 0; // Text index offset to start drawing in the box + + // Cursor rectangle + // NOTE: Position X value should be updated + Rectangle cursor = { + textBounds.x + textWidth + GuiGetStyle(DEFAULT, TEXT_SPACING), + textBounds.y + textBounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE), + 2, + (float)GuiGetStyle(DEFAULT, TEXT_SIZE)*2 + }; + + if (cursor.height >= bounds.height) cursor.height = bounds.height - GuiGetStyle(TEXTBOX, BORDER_WIDTH)*2; + if (cursor.y < (bounds.y + GuiGetStyle(TEXTBOX, BORDER_WIDTH))) cursor.y = bounds.y + GuiGetStyle(TEXTBOX, BORDER_WIDTH); + + // Mouse cursor rectangle + // NOTE: Initialized outside of screen + Rectangle mouseCursor = cursor; + mouseCursor.x = -1; + mouseCursor.width = 1; + + // Auto-cursor movement logic + // NOTE: Cursor moves automatically when key down after some time + if (IsKeyDown(KEY_LEFT) || IsKeyDown(KEY_RIGHT) || IsKeyDown(KEY_UP) || IsKeyDown(KEY_DOWN) || IsKeyDown(KEY_BACKSPACE) || IsKeyDown(KEY_DELETE)) autoCursorCooldownCounter++; + else + { + autoCursorCooldownCounter = 0; // GLOBAL: Cursor cooldown counter + autoCursorDelayCounter = 0; // GLOBAL: Cursor delay counter + } + + // Blink-cursor frame counter + //if (!autoCursorMode) blinkCursorFrameCounter++; + //else blinkCursorFrameCounter = 0; + + // Update control + //-------------------------------------------------------------------- + // WARNING: Text editing is only supported under certain conditions: + if ((state != STATE_DISABLED) && // Control not disabled + !GuiGetStyle(TEXTBOX, TEXT_READONLY) && // TextBox not on read-only mode + !guiLocked && // Gui not locked + !guiControlExclusiveMode && // No gui slider on dragging + (wrapMode == TEXT_WRAP_NONE)) // No wrap mode + { + Vector2 mousePosition = GetMousePosition(); + + if (editMode) + { + state = STATE_PRESSED; + + if (textBoxCursorIndex > textLength) textBoxCursorIndex = textLength; + + // If text does not fit in the textbox and current cursor position is out of bounds, + // we add an index offset to text for drawing only what requires depending on cursor + while (textWidth >= textBounds.width) + { + int nextCodepointSize = 0; + GetCodepointNext(text + textIndexOffset, &nextCodepointSize); + + textIndexOffset += nextCodepointSize; + + textWidth = GetTextWidth(text + textIndexOffset) - GetTextWidth(text + textBoxCursorIndex); + } + + int codepoint = GetCharPressed(); // Get Unicode codepoint + if (multiline && IsKeyPressed(KEY_ENTER)) codepoint = (int)'\n'; + + // Encode codepoint as UTF-8 + int codepointSize = 0; + const char *charEncoded = CodepointToUTF8(codepoint, &codepointSize); + + // Add codepoint to text, at current cursor position + // NOTE: Make sure we do not overflow buffer size + if (((multiline && (codepoint == (int)'\n')) || (codepoint >= 32)) && ((textLength + codepointSize) < textSize)) + { + // Move forward data from cursor position + for (int i = (textLength + codepointSize); i > textBoxCursorIndex; i--) text[i] = text[i - codepointSize]; + + // Add new codepoint in current cursor position + for (int i = 0; i < codepointSize; i++) text[textBoxCursorIndex + i] = charEncoded[i]; + + textBoxCursorIndex += codepointSize; + textLength += codepointSize; + + // Make sure text last character is EOL + text[textLength] = '\0'; + } + + // Move cursor to start + if ((textLength > 0) && IsKeyPressed(KEY_HOME)) textBoxCursorIndex = 0; + + // Move cursor to end + if ((textLength > textBoxCursorIndex) && IsKeyPressed(KEY_END)) textBoxCursorIndex = textLength; + + // Delete codepoint from text, after current cursor position + if ((textLength > textBoxCursorIndex) && (IsKeyPressed(KEY_DELETE) || (IsKeyDown(KEY_DELETE) && (autoCursorCooldownCounter >= RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN)))) + { + autoCursorDelayCounter++; + + if (IsKeyPressed(KEY_DELETE) || (autoCursorDelayCounter%RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY) == 0) // Delay every movement some frames + { + int nextCodepointSize = 0; + GetCodepointNext(text + textBoxCursorIndex, &nextCodepointSize); + + // Move backward text from cursor position + for (int i = textBoxCursorIndex; i < textLength; i++) text[i] = text[i + nextCodepointSize]; + + textLength -= codepointSize; + if (textBoxCursorIndex > textLength) textBoxCursorIndex = textLength; + + // Make sure text last character is EOL + text[textLength] = '\0'; + } + } + + // Delete related codepoints from text, before current cursor position + if ((textLength > 0) && IsKeyPressed(KEY_BACKSPACE) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL))) + { + int i = textBoxCursorIndex - 1; + int accCodepointSize = 0; + + // Move cursor to the end of word if on space already + while ((i > 0) && isspace(text[i])) + { + int prevCodepointSize = 0; + GetCodepointPrevious(text + i, &prevCodepointSize); + i -= prevCodepointSize; + accCodepointSize += prevCodepointSize; + } + + // Move cursor to the start of the word + while ((i > 0) && !isspace(text[i])) + { + int prevCodepointSize = 0; + GetCodepointPrevious(text + i, &prevCodepointSize); + i -= prevCodepointSize; + accCodepointSize += prevCodepointSize; + } + + // Move forward text from cursor position + for (int j = (textBoxCursorIndex - accCodepointSize); j < textLength; j++) text[j] = text[j + accCodepointSize]; + + // Prevent cursor index from decrementing past 0 + if (textBoxCursorIndex > 0) + { + textBoxCursorIndex -= accCodepointSize; + textLength -= accCodepointSize; + } + + // Make sure text last character is EOL + text[textLength] = '\0'; + } + else if ((textLength > 0) && (IsKeyPressed(KEY_BACKSPACE) || (IsKeyDown(KEY_BACKSPACE) && (autoCursorCooldownCounter >= RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN)))) + { + autoCursorDelayCounter++; + + if (IsKeyPressed(KEY_BACKSPACE) || (autoCursorDelayCounter%RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY) == 0) // Delay every movement some frames + { + int prevCodepointSize = 0; + + // Prevent cursor index from decrementing past 0 + if (textBoxCursorIndex > 0) + { + GetCodepointPrevious(text + textBoxCursorIndex, &prevCodepointSize); + + // Move backward text from cursor position + for (int i = (textBoxCursorIndex - prevCodepointSize); i < textLength; i++) text[i] = text[i + prevCodepointSize]; + + textBoxCursorIndex -= codepointSize; + textLength -= codepointSize; + } + + // Make sure text last character is EOL + text[textLength] = '\0'; + } + } + + // Move cursor position with keys + if (IsKeyPressed(KEY_LEFT) || (IsKeyDown(KEY_LEFT) && (autoCursorCooldownCounter > RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN))) + { + autoCursorDelayCounter++; + + if (IsKeyPressed(KEY_LEFT) || (autoCursorDelayCounter%RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY) == 0) // Delay every movement some frames + { + int prevCodepointSize = 0; + if (textBoxCursorIndex > 0) GetCodepointPrevious(text + textBoxCursorIndex, &prevCodepointSize); + + if (textBoxCursorIndex >= prevCodepointSize) textBoxCursorIndex -= prevCodepointSize; + } + } + else if (IsKeyPressed(KEY_RIGHT) || (IsKeyDown(KEY_RIGHT) && (autoCursorCooldownCounter > RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN))) + { + autoCursorDelayCounter++; + + if (IsKeyPressed(KEY_RIGHT) || (autoCursorDelayCounter%RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY) == 0) // Delay every movement some frames + { + int nextCodepointSize = 0; + GetCodepointNext(text + textBoxCursorIndex, &nextCodepointSize); + + if ((textBoxCursorIndex + nextCodepointSize) <= textLength) textBoxCursorIndex += nextCodepointSize; + } + } + + // Move cursor position with mouse + if (CheckCollisionPointRec(mousePosition, textBounds)) // Mouse hover text + { + float scaleFactor = (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/(float)guiFont.baseSize; + int codepointIndex = 0; + float glyphWidth = 0.0f; + float widthToMouseX = 0; + int mouseCursorIndex = 0; + + for (int i = textIndexOffset; i < textLength; i++) + { + codepoint = GetCodepointNext(&text[i], &codepointSize); + codepointIndex = GetGlyphIndex(guiFont, codepoint); + + if (guiFont.glyphs[codepointIndex].advanceX == 0) glyphWidth = ((float)guiFont.recs[codepointIndex].width*scaleFactor); + else glyphWidth = ((float)guiFont.glyphs[codepointIndex].advanceX*scaleFactor); + + if (mousePosition.x <= (textBounds.x + (widthToMouseX + glyphWidth/2))) + { + mouseCursor.x = textBounds.x + widthToMouseX; + mouseCursorIndex = i; + break; + } + + widthToMouseX += (glyphWidth + (float)GuiGetStyle(DEFAULT, TEXT_SPACING)); + } + + // Check if mouse cursor is at the last position + int textEndWidth = GetTextWidth(text + textIndexOffset); + if (GetMousePosition().x >= (textBounds.x + textEndWidth - glyphWidth/2)) + { + mouseCursor.x = textBounds.x + textEndWidth; + mouseCursorIndex = textLength; + } + + // Place cursor at required index on mouse click + if ((mouseCursor.x >= 0) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) + { + cursor.x = mouseCursor.x; + textBoxCursorIndex = mouseCursorIndex; + } + } + else mouseCursor.x = -1; + + // Recalculate cursor position.y depending on textBoxCursorIndex + cursor.x = bounds.x + GuiGetStyle(TEXTBOX, TEXT_PADDING) + GetTextWidth(text + textIndexOffset) - GetTextWidth(text + textBoxCursorIndex) + GuiGetStyle(DEFAULT, TEXT_SPACING); + //if (multiline) cursor.y = GetTextLines() + + // Finish text editing on ENTER or mouse click outside bounds + if ((!multiline && IsKeyPressed(KEY_ENTER)) || + (!CheckCollisionPointRec(mousePosition, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON))) + { + textBoxCursorIndex = 0; // GLOBAL: Reset the shared cursor index + result = 1; + } + } + else + { + if (CheckCollisionPointRec(mousePosition, bounds)) + { + state = STATE_FOCUSED; + + if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) + { + textBoxCursorIndex = textLength; // GLOBAL: Place cursor index to the end of current text + result = 1; + } + } + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + if (state == STATE_PRESSED) + { + GuiDrawRectangle(bounds, GuiGetStyle(TEXTBOX, BORDER_WIDTH), GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), GetColor(GuiGetStyle(TEXTBOX, BASE_COLOR_PRESSED))); + } + else if (state == STATE_DISABLED) + { + GuiDrawRectangle(bounds, GuiGetStyle(TEXTBOX, BORDER_WIDTH), GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), GetColor(GuiGetStyle(TEXTBOX, BASE_COLOR_DISABLED))); + } + else GuiDrawRectangle(bounds, GuiGetStyle(TEXTBOX, BORDER_WIDTH), GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), BLANK); + + // Draw text considering index offset if required + // NOTE: Text index offset depends on cursor position + GuiDrawText(text + textIndexOffset, textBounds, GuiGetStyle(TEXTBOX, TEXT_ALIGNMENT), GetColor(GuiGetStyle(TEXTBOX, TEXT + (state*3)))); + + // Draw cursor + if (editMode && !GuiGetStyle(TEXTBOX, TEXT_READONLY)) + { + //if (autoCursorMode || ((blinkCursorFrameCounter/40)%2 == 0)) + GuiDrawRectangle(cursor, 0, BLANK, GetColor(GuiGetStyle(TEXTBOX, BORDER_COLOR_PRESSED))); + + // Draw mouse position cursor (if required) + if (mouseCursor.x >= 0) GuiDrawRectangle(mouseCursor, 0, BLANK, GetColor(GuiGetStyle(TEXTBOX, BORDER_COLOR_PRESSED))); + } + else if (state == STATE_FOCUSED) GuiTooltip(bounds); + //-------------------------------------------------------------------- + + return result; // Mouse button pressed: result = 1 +} + +/* +// Text Box control with multiple lines and word-wrap +// NOTE: This text-box is readonly, no editing supported by default +bool GuiTextBoxMulti(Rectangle bounds, char *text, int textSize, bool editMode) +{ + bool pressed = false; + + GuiSetStyle(TEXTBOX, TEXT_READONLY, 1); + GuiSetStyle(DEFAULT, TEXT_WRAP_MODE, TEXT_WRAP_WORD); // WARNING: If wrap mode enabled, text editing is not supported + GuiSetStyle(DEFAULT, TEXT_ALIGNMENT_VERTICAL, TEXT_ALIGN_TOP); + + // TODO: Implement methods to calculate cursor position properly + pressed = GuiTextBox(bounds, text, textSize, editMode); + + GuiSetStyle(DEFAULT, TEXT_ALIGNMENT_VERTICAL, TEXT_ALIGN_MIDDLE); + GuiSetStyle(DEFAULT, TEXT_WRAP_MODE, TEXT_WRAP_NONE); + GuiSetStyle(TEXTBOX, TEXT_READONLY, 0); + + return pressed; +} +*/ + +// Spinner control, returns selected value +int GuiSpinner(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode) +{ + int result = 1; + GuiState state = guiState; + + int tempValue = *value; + + Rectangle spinner = { bounds.x + GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH) + GuiGetStyle(SPINNER, SPIN_BUTTON_SPACING), bounds.y, + bounds.width - 2*(GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH) + GuiGetStyle(SPINNER, SPIN_BUTTON_SPACING)), bounds.height }; + Rectangle leftButtonBound = { (float)bounds.x, (float)bounds.y, (float)GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH), (float)bounds.height }; + Rectangle rightButtonBound = { (float)bounds.x + bounds.width - GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH), (float)bounds.y, (float)GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH), (float)bounds.height }; + + Rectangle textBounds = { 0 }; + if (text != NULL) + { + textBounds.width = (float)GetTextWidth(text) + 2; + textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); + textBounds.x = bounds.x + bounds.width + GuiGetStyle(SPINNER, TEXT_PADDING); + textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; + if (GuiGetStyle(SPINNER, TEXT_ALIGNMENT) == TEXT_ALIGN_LEFT) textBounds.x = bounds.x - textBounds.width - GuiGetStyle(SPINNER, TEXT_PADDING); + } + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) + { + Vector2 mousePoint = GetMousePosition(); + + // Check spinner state + if (CheckCollisionPointRec(mousePoint, bounds)) + { + if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED; + else state = STATE_FOCUSED; + } + } + +#if defined(RAYGUI_NO_ICONS) + if (GuiButton(leftButtonBound, "<")) tempValue--; + if (GuiButton(rightButtonBound, ">")) tempValue++; +#else + if (GuiButton(leftButtonBound, GuiIconText(ICON_ARROW_LEFT_FILL, NULL))) tempValue--; + if (GuiButton(rightButtonBound, GuiIconText(ICON_ARROW_RIGHT_FILL, NULL))) tempValue++; +#endif + + if (!editMode) + { + if (tempValue < minValue) tempValue = minValue; + if (tempValue > maxValue) tempValue = maxValue; + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + result = GuiValueBox(spinner, NULL, &tempValue, minValue, maxValue, editMode); + + // Draw value selector custom buttons + // NOTE: BORDER_WIDTH and TEXT_ALIGNMENT forced values + int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH); + int tempTextAlign = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); + GuiSetStyle(BUTTON, BORDER_WIDTH, GuiGetStyle(SPINNER, BORDER_WIDTH)); + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); + + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlign); + GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth); + + // Draw text label if provided + GuiDrawText(text, textBounds, (GuiGetStyle(SPINNER, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); + //-------------------------------------------------------------------- + + *value = tempValue; + return result; +} + +// Value Box control, updates input text with numbers +// NOTE: Requires static variables: frameCounter +int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode) +{ + #if !defined(RAYGUI_VALUEBOX_MAX_CHARS) + #define RAYGUI_VALUEBOX_MAX_CHARS 32 + #endif + + int result = 0; + GuiState state = guiState; + + char textValue[RAYGUI_VALUEBOX_MAX_CHARS + 1] = "\0"; + sprintf(textValue, "%i", *value); + + Rectangle textBounds = { 0 }; + if (text != NULL) + { + textBounds.width = (float)GetTextWidth(text) + 2; + textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); + textBounds.x = bounds.x + bounds.width + GuiGetStyle(VALUEBOX, TEXT_PADDING); + textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; + if (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_LEFT) textBounds.x = bounds.x - textBounds.width - GuiGetStyle(VALUEBOX, TEXT_PADDING); + } + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) + { + Vector2 mousePoint = GetMousePosition(); + + bool valueHasChanged = false; + + if (editMode) + { + state = STATE_PRESSED; + + int keyCount = (int)strlen(textValue); + + // Only allow keys in range [48..57] + if (keyCount < RAYGUI_VALUEBOX_MAX_CHARS) + { + if (GetTextWidth(textValue) < bounds.width) + { + int key = GetCharPressed(); + if ((key >= 48) && (key <= 57)) + { + textValue[keyCount] = (char)key; + keyCount++; + valueHasChanged = true; + } + } + } + + // Delete text + if (keyCount > 0) + { + if (IsKeyPressed(KEY_BACKSPACE)) + { + keyCount--; + textValue[keyCount] = '\0'; + valueHasChanged = true; + } + } + + if (valueHasChanged) *value = TextToInteger(textValue); + + // NOTE: We are not clamp values until user input finishes + //if (*value > maxValue) *value = maxValue; + //else if (*value < minValue) *value = minValue; + + if ((IsKeyPressed(KEY_ENTER) || IsKeyPressed(KEY_KP_ENTER)) || (!CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON))) + { + if (*value > maxValue) *value = maxValue; + else if (*value < minValue) *value = minValue; + + result = 1; + } + } + else + { + if (*value > maxValue) *value = maxValue; + else if (*value < minValue) *value = minValue; + + if (CheckCollisionPointRec(mousePoint, bounds)) + { + state = STATE_FOCUSED; + if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) result = 1; + } + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + Color baseColor = BLANK; + if (state == STATE_PRESSED) baseColor = GetColor(GuiGetStyle(VALUEBOX, BASE_COLOR_PRESSED)); + else if (state == STATE_DISABLED) baseColor = GetColor(GuiGetStyle(VALUEBOX, BASE_COLOR_DISABLED)); + + GuiDrawRectangle(bounds, GuiGetStyle(VALUEBOX, BORDER_WIDTH), GetColor(GuiGetStyle(VALUEBOX, BORDER + (state*3))), baseColor); + GuiDrawText(textValue, GetTextBounds(VALUEBOX, bounds), TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(VALUEBOX, TEXT + (state*3)))); + + // Draw cursor + if (editMode) + { + // NOTE: ValueBox internal text is always centered + Rectangle cursor = { bounds.x + GetTextWidth(textValue)/2 + bounds.width/2 + 1, bounds.y + 2*GuiGetStyle(VALUEBOX, BORDER_WIDTH), 4, bounds.height - 4*GuiGetStyle(VALUEBOX, BORDER_WIDTH) }; + GuiDrawRectangle(cursor, 0, BLANK, GetColor(GuiGetStyle(VALUEBOX, BORDER_COLOR_PRESSED))); + } + + // Draw text label if provided + GuiDrawText(text, textBounds, (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); + //-------------------------------------------------------------------- + + return result; +} + +// Floating point Value Box control, updates input val_str with numbers +// NOTE: Requires static variables: frameCounter +int GuiValueBoxFloat(Rectangle bounds, const char *text, char *textValue, float *value, bool editMode) +{ + #if !defined(RAYGUI_VALUEBOX_MAX_CHARS) + #define RAYGUI_VALUEBOX_MAX_CHARS 32 + #endif + + int result = 0; + GuiState state = guiState; + + //char textValue[RAYGUI_VALUEBOX_MAX_CHARS + 1] = "\0"; + //sprintf(textValue, "%2.2f", *value); + + Rectangle textBounds = {0}; + if (text != NULL) + { + textBounds.width = (float)GetTextWidth(text) + 2; + textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); + textBounds.x = bounds.x + bounds.width + GuiGetStyle(VALUEBOX, TEXT_PADDING); + textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; + if (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_LEFT) textBounds.x = bounds.x - textBounds.width - GuiGetStyle(VALUEBOX, TEXT_PADDING); + } + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) + { + Vector2 mousePoint = GetMousePosition(); + + bool valueHasChanged = false; + + if (editMode) + { + state = STATE_PRESSED; + + int keyCount = (int)strlen(textValue); + + // Only allow keys in range [48..57] + if (keyCount < RAYGUI_VALUEBOX_MAX_CHARS) + { + if (GetTextWidth(textValue) < bounds.width) + { + int key = GetCharPressed(); + if (((key >= 48) && (key <= 57)) || + (key == '.') || + ((keyCount == 0) && (key == '+')) || // NOTE: Sign can only be in first position + ((keyCount == 0) && (key == '-'))) + { + textValue[keyCount] = (char)key; + keyCount++; + + valueHasChanged = true; + } + } + } + + // Pressed backspace + if (IsKeyPressed(KEY_BACKSPACE)) + { + if (keyCount > 0) + { + keyCount--; + textValue[keyCount] = '\0'; + valueHasChanged = true; + } + } + + if (valueHasChanged) *value = TextToFloat(textValue); + + if ((IsKeyPressed(KEY_ENTER) || IsKeyPressed(KEY_KP_ENTER)) || (!CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON))) result = 1; + } + else + { + if (CheckCollisionPointRec(mousePoint, bounds)) + { + state = STATE_FOCUSED; + if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) result = 1; + } + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + Color baseColor = BLANK; + if (state == STATE_PRESSED) baseColor = GetColor(GuiGetStyle(VALUEBOX, BASE_COLOR_PRESSED)); + else if (state == STATE_DISABLED) baseColor = GetColor(GuiGetStyle(VALUEBOX, BASE_COLOR_DISABLED)); + + GuiDrawRectangle(bounds, GuiGetStyle(VALUEBOX, BORDER_WIDTH), GetColor(GuiGetStyle(VALUEBOX, BORDER + (state*3))), baseColor); + GuiDrawText(textValue, GetTextBounds(VALUEBOX, bounds), TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(VALUEBOX, TEXT + (state*3)))); + + // Draw cursor + if (editMode) + { + // NOTE: ValueBox internal text is always centered + Rectangle cursor = {bounds.x + GetTextWidth(textValue)/2 + bounds.width/2 + 1, + bounds.y + 2*GuiGetStyle(VALUEBOX, BORDER_WIDTH), 4, + bounds.height - 4*GuiGetStyle(VALUEBOX, BORDER_WIDTH)}; + GuiDrawRectangle(cursor, 0, BLANK, GetColor(GuiGetStyle(VALUEBOX, BORDER_COLOR_PRESSED))); + } + + // Draw text label if provided + GuiDrawText(text, textBounds, + (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, + GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); + //-------------------------------------------------------------------- + + return result; +} + +// Slider control with pro parameters +// NOTE: Other GuiSlider*() controls use this one +int GuiSliderPro(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue, int sliderWidth) +{ + int result = 0; + GuiState state = guiState; + + float temp = (maxValue - minValue)/2.0f; + if (value == NULL) value = &temp; + float oldValue = *value; + + Rectangle slider = { bounds.x, bounds.y + GuiGetStyle(SLIDER, BORDER_WIDTH) + GuiGetStyle(SLIDER, SLIDER_PADDING), + 0, bounds.height - 2*GuiGetStyle(SLIDER, BORDER_WIDTH) - 2*GuiGetStyle(SLIDER, SLIDER_PADDING) }; + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked) + { + Vector2 mousePoint = GetMousePosition(); + + if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds + { + if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) + { + if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec)) + { + state = STATE_PRESSED; + // Get equivalent value and slider position from mousePosition.x + *value = (maxValue - minValue)*((mousePoint.x - bounds.x - sliderWidth/2)/(bounds.width-sliderWidth)) + minValue; + } + } + else + { + guiControlExclusiveMode = false; + guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 }; + } + } + else if (CheckCollisionPointRec(mousePoint, bounds)) + { + if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) + { + state = STATE_PRESSED; + guiControlExclusiveMode = true; + guiControlExclusiveRec = bounds; // Store bounds as an identifier when dragging starts + + if (!CheckCollisionPointRec(mousePoint, slider)) + { + // Get equivalent value and slider position from mousePosition.x + *value = (maxValue - minValue)*((mousePoint.x - bounds.x - sliderWidth/2)/(bounds.width-sliderWidth)) + minValue; + } + } + else state = STATE_FOCUSED; + } + + if (*value > maxValue) *value = maxValue; + else if (*value < minValue) *value = minValue; + } + + // Control value change check + if (oldValue == *value) result = 0; + else result = 1; + + // Slider bar limits check + float sliderValue = (((*value - minValue)/(maxValue - minValue))*(bounds.width - sliderWidth - 2*GuiGetStyle(SLIDER, BORDER_WIDTH))); + if (sliderWidth > 0) // Slider + { + slider.x += sliderValue; + slider.width = (float)sliderWidth; + if (slider.x <= (bounds.x + GuiGetStyle(SLIDER, BORDER_WIDTH))) slider.x = bounds.x + GuiGetStyle(SLIDER, BORDER_WIDTH); + else if ((slider.x + slider.width) >= (bounds.x + bounds.width)) slider.x = bounds.x + bounds.width - slider.width - GuiGetStyle(SLIDER, BORDER_WIDTH); + } + else if (sliderWidth == 0) // SliderBar + { + slider.x += GuiGetStyle(SLIDER, BORDER_WIDTH); + slider.width = sliderValue; + if (slider.width > bounds.width) slider.width = bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH); + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawRectangle(bounds, GuiGetStyle(SLIDER, BORDER_WIDTH), GetColor(GuiGetStyle(SLIDER, BORDER + (state*3))), GetColor(GuiGetStyle(SLIDER, (state != STATE_DISABLED)? BASE_COLOR_NORMAL : BASE_COLOR_DISABLED))); + + // Draw slider internal bar (depends on state) + if (state == STATE_NORMAL) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, BASE_COLOR_PRESSED))); + else if (state == STATE_FOCUSED) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, TEXT_COLOR_FOCUSED))); + else if (state == STATE_PRESSED) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, TEXT_COLOR_PRESSED))); + + // Draw left/right text if provided + if (textLeft != NULL) + { + Rectangle textBounds = { 0 }; + textBounds.width = (float)GetTextWidth(textLeft); + textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); + textBounds.x = bounds.x - textBounds.width - GuiGetStyle(SLIDER, TEXT_PADDING); + textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; + + GuiDrawText(textLeft, textBounds, TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(SLIDER, TEXT + (state*3)))); + } + + if (textRight != NULL) + { + Rectangle textBounds = { 0 }; + textBounds.width = (float)GetTextWidth(textRight); + textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); + textBounds.x = bounds.x + bounds.width + GuiGetStyle(SLIDER, TEXT_PADDING); + textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; + + GuiDrawText(textRight, textBounds, TEXT_ALIGN_LEFT, GetColor(GuiGetStyle(SLIDER, TEXT + (state*3)))); + } + //-------------------------------------------------------------------- + + return result; +} + +// Slider control extended, returns selected value and has text +int GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue) +{ + return GuiSliderPro(bounds, textLeft, textRight, value, minValue, maxValue, GuiGetStyle(SLIDER, SLIDER_WIDTH)); +} + +// Slider Bar control extended, returns selected value +int GuiSliderBar(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue) +{ + return GuiSliderPro(bounds, textLeft, textRight, value, minValue, maxValue, 0); +} + +// Progress Bar control extended, shows current progress value +int GuiProgressBar(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue) +{ + int result = 0; + GuiState state = guiState; + + float temp = (maxValue - minValue)/2.0f; + if (value == NULL) value = &temp; + + // Progress bar + Rectangle progress = { bounds.x + GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), + bounds.y + GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) + GuiGetStyle(PROGRESSBAR, PROGRESS_PADDING), 0, + bounds.height - 2*GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) - 2*GuiGetStyle(PROGRESSBAR, PROGRESS_PADDING) }; + + // Update control + //-------------------------------------------------------------------- + if (*value > maxValue) *value = maxValue; + + // WARNING: Working with floats could lead to rounding issues + if ((state != STATE_DISABLED)) progress.width = (float)(*value/(maxValue - minValue))*bounds.width - ((*value >= maxValue)? (float)(2*GuiGetStyle(PROGRESSBAR, BORDER_WIDTH)) : 0.0f); + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + if (state == STATE_DISABLED) + { + GuiDrawRectangle(bounds, GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), GetColor(GuiGetStyle(PROGRESSBAR, BORDER + (state*3))), BLANK); + } + else + { + if (*value > minValue) + { + // Draw progress bar with colored border, more visual + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, (int)progress.width + (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_FOCUSED))); + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + 1, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.height - 2 }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_FOCUSED))); + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height - 1, (int)progress.width + (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_FOCUSED))); + } + else GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.height }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL))); + + if (*value >= maxValue) GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + progress.width + 1, bounds.y, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.height }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_FOCUSED))); + else + { + // Draw borders not yet reached by value + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + (int)progress.width + 1, bounds.y, bounds.width - (int)progress.width - 1, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL))); + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + (int)progress.width + 1, bounds.y + bounds.height - 1, bounds.width - (int)progress.width - 1, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL))); + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - 1, bounds.y + 1, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.height - 2 }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL))); + } + + // Draw slider internal progress bar (depends on state) + GuiDrawRectangle(progress, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BASE_COLOR_PRESSED))); + } + + // Draw left/right text if provided + if (textLeft != NULL) + { + Rectangle textBounds = { 0 }; + textBounds.width = (float)GetTextWidth(textLeft); + textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); + textBounds.x = bounds.x - textBounds.width - GuiGetStyle(PROGRESSBAR, TEXT_PADDING); + textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; + + GuiDrawText(textLeft, textBounds, TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(PROGRESSBAR, TEXT + (state*3)))); + } + + if (textRight != NULL) + { + Rectangle textBounds = { 0 }; + textBounds.width = (float)GetTextWidth(textRight); + textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); + textBounds.x = bounds.x + bounds.width + GuiGetStyle(PROGRESSBAR, TEXT_PADDING); + textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; + + GuiDrawText(textRight, textBounds, TEXT_ALIGN_LEFT, GetColor(GuiGetStyle(PROGRESSBAR, TEXT + (state*3)))); + } + //-------------------------------------------------------------------- + + return result; +} + +// Status Bar control +int GuiStatusBar(Rectangle bounds, const char *text) +{ + int result = 0; + GuiState state = guiState; + + // Draw control + //-------------------------------------------------------------------- + GuiDrawRectangle(bounds, GuiGetStyle(STATUSBAR, BORDER_WIDTH), GetColor(GuiGetStyle(STATUSBAR, BORDER + (state*3))), GetColor(GuiGetStyle(STATUSBAR, BASE + (state*3)))); + GuiDrawText(text, GetTextBounds(STATUSBAR, bounds), GuiGetStyle(STATUSBAR, TEXT_ALIGNMENT), GetColor(GuiGetStyle(STATUSBAR, TEXT + (state*3)))); + //-------------------------------------------------------------------- + + return result; +} + +// Dummy rectangle control, intended for placeholding +int GuiDummyRec(Rectangle bounds, const char *text) +{ + int result = 0; + GuiState state = guiState; + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) + { + Vector2 mousePoint = GetMousePosition(); + + // Check button state + if (CheckCollisionPointRec(mousePoint, bounds)) + { + if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED; + else state = STATE_FOCUSED; + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawRectangle(bounds, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, (state != STATE_DISABLED)? BASE_COLOR_NORMAL : BASE_COLOR_DISABLED))); + GuiDrawText(text, GetTextBounds(DEFAULT, bounds), TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(BUTTON, (state != STATE_DISABLED)? TEXT_COLOR_NORMAL : TEXT_COLOR_DISABLED))); + //------------------------------------------------------------------ + + return result; +} + +// List View control +int GuiListView(Rectangle bounds, const char *text, int *scrollIndex, int *active) +{ + int result = 0; + int itemCount = 0; + const char **items = NULL; + + if (text != NULL) items = GuiTextSplit(text, ';', &itemCount, NULL); + + result = GuiListViewEx(bounds, items, itemCount, scrollIndex, active, NULL); + + return result; +} + +// List View control with extended parameters +int GuiListViewEx(Rectangle bounds, const char **text, int count, int *scrollIndex, int *active, int *focus) +{ + int result = 0; + GuiState state = guiState; + + int itemFocused = (focus == NULL)? -1 : *focus; + int itemSelected = (active == NULL)? -1 : *active; + + // Check if we need a scroll bar + bool useScrollBar = false; + if ((GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING))*count > bounds.height) useScrollBar = true; + + // Define base item rectangle [0] + Rectangle itemBounds = { 0 }; + itemBounds.x = bounds.x + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING); + itemBounds.y = bounds.y + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING) + GuiGetStyle(DEFAULT, BORDER_WIDTH); + itemBounds.width = bounds.width - 2*GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING) - GuiGetStyle(DEFAULT, BORDER_WIDTH); + itemBounds.height = (float)GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT); + if (useScrollBar) itemBounds.width -= GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH); + + // Get items on the list + int visibleItems = (int)bounds.height/(GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING)); + if (visibleItems > count) visibleItems = count; + + int startIndex = (scrollIndex == NULL)? 0 : *scrollIndex; + if ((startIndex < 0) || (startIndex > (count - visibleItems))) startIndex = 0; + int endIndex = startIndex + visibleItems; + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) + { + Vector2 mousePoint = GetMousePosition(); + + // Check mouse inside list view + if (CheckCollisionPointRec(mousePoint, bounds)) + { + state = STATE_FOCUSED; + + // Check focused and selected item + for (int i = 0; i < visibleItems; i++) + { + if (CheckCollisionPointRec(mousePoint, itemBounds)) + { + itemFocused = startIndex + i; + if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) + { + if (itemSelected == (startIndex + i)) itemSelected = -1; + else itemSelected = startIndex + i; + } + break; + } + + // Update item rectangle y position for next item + itemBounds.y += (GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING)); + } + + if (useScrollBar) + { + int wheelMove = (int)GetMouseWheelMove(); + startIndex -= wheelMove; + + if (startIndex < 0) startIndex = 0; + else if (startIndex > (count - visibleItems)) startIndex = count - visibleItems; + + endIndex = startIndex + visibleItems; + if (endIndex > count) endIndex = count; + } + } + else itemFocused = -1; + + // Reset item rectangle y to [0] + itemBounds.y = bounds.y + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING) + GuiGetStyle(DEFAULT, BORDER_WIDTH); + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawRectangle(bounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER + state*3)), GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR))); // Draw background + + // Draw visible items + for (int i = 0; ((i < visibleItems) && (text != NULL)); i++) + { + GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, LIST_ITEMS_BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_NORMAL)), BLANK); + + if (state == STATE_DISABLED) + { + if ((startIndex + i) == itemSelected) GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_DISABLED)), GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_DISABLED))); + + GuiDrawText(text[startIndex + i], GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_DISABLED))); + } + else + { + if (((startIndex + i) == itemSelected) && (active != NULL)) + { + // Draw item selected + GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_PRESSED)), GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_PRESSED))); + GuiDrawText(text[startIndex + i], GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_PRESSED))); + } + else if (((startIndex + i) == itemFocused)) // && (focus != NULL)) // NOTE: We want items focused, despite not returned! + { + // Draw item focused + GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_FOCUSED)), GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_FOCUSED))); + GuiDrawText(text[startIndex + i], GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_FOCUSED))); + } + else + { + // Draw item normal + GuiDrawText(text[startIndex + i], GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_NORMAL))); + } + } + + // Update item rectangle y position for next item + itemBounds.y += (GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING)); + } + + if (useScrollBar) + { + Rectangle scrollBarBounds = { + bounds.x + bounds.width - GuiGetStyle(LISTVIEW, BORDER_WIDTH) - GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH), + bounds.y + GuiGetStyle(LISTVIEW, BORDER_WIDTH), (float)GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH), + bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) + }; + + // Calculate percentage of visible items and apply same percentage to scrollbar + float percentVisible = (float)(endIndex - startIndex)/count; + float sliderSize = bounds.height*percentVisible; + + int prevSliderSize = GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE); // Save default slider size + int prevScrollSpeed = GuiGetStyle(SCROLLBAR, SCROLL_SPEED); // Save default scroll speed + GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, (int)sliderSize); // Change slider size + GuiSetStyle(SCROLLBAR, SCROLL_SPEED, count - visibleItems); // Change scroll speed + + startIndex = GuiScrollBar(scrollBarBounds, startIndex, 0, count - visibleItems); + + GuiSetStyle(SCROLLBAR, SCROLL_SPEED, prevScrollSpeed); // Reset scroll speed to default + GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, prevSliderSize); // Reset slider size to default + } + //-------------------------------------------------------------------- + + if (active != NULL) *active = itemSelected; + if (focus != NULL) *focus = itemFocused; + if (scrollIndex != NULL) *scrollIndex = startIndex; + + return result; +} + +// Color Panel control - Color (RGBA) variant. +int GuiColorPanel(Rectangle bounds, const char *text, Color *color) +{ + int result = 0; + + Vector3 vcolor = { (float)color->r/255.0f, (float)color->g/255.0f, (float)color->b/255.0f }; + Vector3 hsv = ConvertRGBtoHSV(vcolor); + Vector3 prevHsv = hsv; // workaround to see if GuiColorPanelHSV modifies the hsv. + + GuiColorPanelHSV(bounds, text, &hsv); + + // Check if the hsv was changed, only then change the color. + // This is required, because the Color->HSV->Color conversion has precision errors. + // Thus the assignment from HSV to Color should only be made, if the HSV has a new user-entered value. + // Otherwise GuiColorPanel would often modify it's color without user input. + // TODO: GuiColorPanelHSV could return 1 if the slider was dragged, to simplify this check. + if (hsv.x != prevHsv.x || hsv.y != prevHsv.y || hsv.z != prevHsv.z) + { + Vector3 rgb = ConvertHSVtoRGB(hsv); + + // NOTE: Vector3ToColor() only available on raylib 1.8.1 + *color = RAYGUI_CLITERAL(Color){ (unsigned char)(255.0f*rgb.x), + (unsigned char)(255.0f*rgb.y), + (unsigned char)(255.0f*rgb.z), + color->a }; + } + return result; +} + +// Color Bar Alpha control +// NOTE: Returns alpha value normalized [0..1] +int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha) +{ + #if !defined(RAYGUI_COLORBARALPHA_CHECKED_SIZE) + #define RAYGUI_COLORBARALPHA_CHECKED_SIZE 10 + #endif + + int result = 0; + GuiState state = guiState; + Rectangle selector = { (float)bounds.x + (*alpha)*bounds.width - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT)/2, (float)bounds.y - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW), (float)GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT), (float)bounds.height + GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW)*2 }; + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked) + { + Vector2 mousePoint = GetMousePosition(); + + if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds + { + if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) + { + if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec)) + { + state = STATE_PRESSED; + + *alpha = (mousePoint.x - bounds.x)/bounds.width; + if (*alpha <= 0.0f) *alpha = 0.0f; + if (*alpha >= 1.0f) *alpha = 1.0f; + } + } + else + { + guiControlExclusiveMode = false; + guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 }; + } + } + else if (CheckCollisionPointRec(mousePoint, bounds) || CheckCollisionPointRec(mousePoint, selector)) + { + if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) + { + state = STATE_PRESSED; + guiControlExclusiveMode = true; + guiControlExclusiveRec = bounds; // Store bounds as an identifier when dragging starts + + *alpha = (mousePoint.x - bounds.x)/bounds.width; + if (*alpha <= 0.0f) *alpha = 0.0f; + if (*alpha >= 1.0f) *alpha = 1.0f; + //selector.x = bounds.x + (int)(((alpha - 0)/(100 - 0))*(bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH))) - selector.width/2; + } + else state = STATE_FOCUSED; + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + + // Draw alpha bar: checked background + if (state != STATE_DISABLED) + { + int checksX = (int)bounds.width/RAYGUI_COLORBARALPHA_CHECKED_SIZE; + int checksY = (int)bounds.height/RAYGUI_COLORBARALPHA_CHECKED_SIZE; + + for (int x = 0; x < checksX; x++) + { + for (int y = 0; y < checksY; y++) + { + Rectangle check = { bounds.x + x*RAYGUI_COLORBARALPHA_CHECKED_SIZE, bounds.y + y*RAYGUI_COLORBARALPHA_CHECKED_SIZE, RAYGUI_COLORBARALPHA_CHECKED_SIZE, RAYGUI_COLORBARALPHA_CHECKED_SIZE }; + GuiDrawRectangle(check, 0, BLANK, ((x + y)%2)? Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), 0.4f) : Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.4f)); + } + } + + DrawRectangleGradientEx(bounds, RAYGUI_CLITERAL(Color){ 255, 255, 255, 0 }, RAYGUI_CLITERAL(Color){ 255, 255, 255, 0 }, Fade(RAYGUI_CLITERAL(Color){ 0, 0, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 0, 0, 255 }, guiAlpha)); + } + else DrawRectangleGradientEx(bounds, Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), guiAlpha), Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), guiAlpha)); + + GuiDrawRectangle(bounds, GuiGetStyle(COLORPICKER, BORDER_WIDTH), GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), BLANK); + + // Draw alpha bar: selector + GuiDrawRectangle(selector, 0, BLANK, GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3))); + //-------------------------------------------------------------------- + + return result; +} + +// Color Bar Hue control +// Returns hue value normalized [0..1] +// NOTE: Other similar bars (for reference): +// Color GuiColorBarSat() [WHITE->color] +// Color GuiColorBarValue() [BLACK->color], HSV/HSL +// float GuiColorBarLuminance() [BLACK->WHITE] +int GuiColorBarHue(Rectangle bounds, const char *text, float *hue) +{ + int result = 0; + GuiState state = guiState; + Rectangle selector = { (float)bounds.x - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW), (float)bounds.y + (*hue)/360.0f*bounds.height - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT)/2, (float)bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW)*2, (float)GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT) }; + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked) + { + Vector2 mousePoint = GetMousePosition(); + + if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds + { + if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) + { + if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec)) + { + state = STATE_PRESSED; + + *hue = (mousePoint.y - bounds.y)*360/bounds.height; + if (*hue <= 0.0f) *hue = 0.0f; + if (*hue >= 359.0f) *hue = 359.0f; + } + } + else + { + guiControlExclusiveMode = false; + guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 }; + } + } + else if (CheckCollisionPointRec(mousePoint, bounds) || CheckCollisionPointRec(mousePoint, selector)) + { + if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) + { + state = STATE_PRESSED; + guiControlExclusiveMode = true; + guiControlExclusiveRec = bounds; // Store bounds as an identifier when dragging starts + + *hue = (mousePoint.y - bounds.y)*360/bounds.height; + if (*hue <= 0.0f) *hue = 0.0f; + if (*hue >= 359.0f) *hue = 359.0f; + + } + else state = STATE_FOCUSED; + + /*if (IsKeyDown(KEY_UP)) + { + hue -= 2.0f; + if (hue <= 0.0f) hue = 0.0f; + } + else if (IsKeyDown(KEY_DOWN)) + { + hue += 2.0f; + if (hue >= 360.0f) hue = 360.0f; + }*/ + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + if (state != STATE_DISABLED) + { + // Draw hue bar:color bars + // TODO: Use directly DrawRectangleGradientEx(bounds, color1, color2, color2, color1); + DrawRectangleGradientV((int)bounds.x, (int)(bounds.y), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 255, 0, 255 }, guiAlpha)); + DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + bounds.height/6), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 255, 255, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 0, 255 }, guiAlpha)); + DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + 2*(bounds.height/6)), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 255, 255 }, guiAlpha)); + DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + 3*(bounds.height/6)), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 0, 255, 255 }, guiAlpha)); + DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + 4*(bounds.height/6)), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 0, 0, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 255, 255 }, guiAlpha)); + DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + 5*(bounds.height/6)), (int)bounds.width, (int)(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 0, 255 }, guiAlpha)); + } + else DrawRectangleGradientV((int)bounds.x, (int)bounds.y, (int)bounds.width, (int)bounds.height, Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), guiAlpha), Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), guiAlpha)); + + GuiDrawRectangle(bounds, GuiGetStyle(COLORPICKER, BORDER_WIDTH), GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), BLANK); + + // Draw hue bar: selector + GuiDrawRectangle(selector, 0, BLANK, GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3))); + //-------------------------------------------------------------------- + + return result; +} + +// Color Picker control +// NOTE: It's divided in multiple controls: +// Color GuiColorPanel(Rectangle bounds, Color color) +// float GuiColorBarAlpha(Rectangle bounds, float alpha) +// float GuiColorBarHue(Rectangle bounds, float value) +// NOTE: bounds define GuiColorPanel() size +// NOTE: this picker converts RGB to HSV, which can cause the Hue control to jump. If you have this problem, consider using the HSV variant instead +int GuiColorPicker(Rectangle bounds, const char *text, Color *color) +{ + int result = 0; + + Color temp = { 200, 0, 0, 255 }; + if (color == NULL) color = &temp; + + GuiColorPanel(bounds, NULL, color); + + Rectangle boundsHue = { (float)bounds.x + bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_PADDING), (float)bounds.y, (float)GuiGetStyle(COLORPICKER, HUEBAR_WIDTH), (float)bounds.height }; + //Rectangle boundsAlpha = { bounds.x, bounds.y + bounds.height + GuiGetStyle(COLORPICKER, BARS_PADDING), bounds.width, GuiGetStyle(COLORPICKER, BARS_THICK) }; + + // NOTE: this conversion can cause low hue-resolution, if the r, g and b value are very similar, which causes the hue bar to shift around when only the GuiColorPanel is used. + Vector3 hsv = ConvertRGBtoHSV(RAYGUI_CLITERAL(Vector3){ (*color).r/255.0f, (*color).g/255.0f, (*color).b/255.0f }); + + GuiColorBarHue(boundsHue, NULL, &hsv.x); + + //color.a = (unsigned char)(GuiColorBarAlpha(boundsAlpha, (float)color.a/255.0f)*255.0f); + Vector3 rgb = ConvertHSVtoRGB(hsv); + + *color = RAYGUI_CLITERAL(Color){ (unsigned char)roundf(rgb.x*255.0f), (unsigned char)roundf(rgb.y*255.0f), (unsigned char)roundf(rgb.z*255.0f), (*color).a }; + + return result; +} + +// Color Picker control that avoids conversion to RGB and back to HSV on each call, thus avoiding jittering. +// The user can call ConvertHSVtoRGB() to convert *colorHsv value to RGB. +// NOTE: It's divided in multiple controls: +// int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) +// int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha) +// float GuiColorBarHue(Rectangle bounds, float value) +// NOTE: bounds define GuiColorPanelHSV() size +int GuiColorPickerHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) +{ + int result = 0; + + Vector3 tempHsv = { 0 }; + + if (colorHsv == NULL) + { + const Vector3 tempColor = { 200.0f/255.0f, 0.0f, 0.0f }; + tempHsv = ConvertRGBtoHSV(tempColor); + colorHsv = &tempHsv; + } + + GuiColorPanelHSV(bounds, NULL, colorHsv); + + const Rectangle boundsHue = { (float)bounds.x + bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_PADDING), (float)bounds.y, (float)GuiGetStyle(COLORPICKER, HUEBAR_WIDTH), (float)bounds.height }; + + GuiColorBarHue(boundsHue, NULL, &colorHsv->x); + + return result; +} + +// Color Panel control - HSV variant +int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) +{ + int result = 0; + GuiState state = guiState; + Vector2 pickerSelector = { 0 }; + + const Color colWhite = { 255, 255, 255, 255 }; + const Color colBlack = { 0, 0, 0, 255 }; + + pickerSelector.x = bounds.x + (float)colorHsv->y*bounds.width; // HSV: Saturation + pickerSelector.y = bounds.y + (1.0f - (float)colorHsv->z)*bounds.height; // HSV: Value + + Vector3 maxHue = { colorHsv->x, 1.0f, 1.0f }; + Vector3 rgbHue = ConvertHSVtoRGB(maxHue); + Color maxHueCol = { (unsigned char)(255.0f*rgbHue.x), + (unsigned char)(255.0f*rgbHue.y), + (unsigned char)(255.0f*rgbHue.z), 255 }; + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked) + { + Vector2 mousePoint = GetMousePosition(); + + if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds + { + if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) + { + if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec)) + { + pickerSelector = mousePoint; + + if (pickerSelector.x < bounds.x) pickerSelector.x = bounds.x; + if (pickerSelector.x > bounds.x + bounds.width) pickerSelector.x = bounds.x + bounds.width; + if (pickerSelector.y < bounds.y) pickerSelector.y = bounds.y; + if (pickerSelector.y > bounds.y + bounds.height) pickerSelector.y = bounds.y + bounds.height; + + // Calculate color from picker + Vector2 colorPick = { pickerSelector.x - bounds.x, pickerSelector.y - bounds.y }; + + colorPick.x /= (float)bounds.width; // Get normalized value on x + colorPick.y /= (float)bounds.height; // Get normalized value on y + + colorHsv->y = colorPick.x; + colorHsv->z = 1.0f - colorPick.y; + + } + } + else + { + guiControlExclusiveMode = false; + guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 }; + } + } + else if (CheckCollisionPointRec(mousePoint, bounds)) + { + if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) + { + state = STATE_PRESSED; + guiControlExclusiveMode = true; + guiControlExclusiveRec = bounds; + pickerSelector = mousePoint; + + // Calculate color from picker + Vector2 colorPick = { pickerSelector.x - bounds.x, pickerSelector.y - bounds.y }; + + colorPick.x /= (float)bounds.width; // Get normalized value on x + colorPick.y /= (float)bounds.height; // Get normalized value on y + + colorHsv->y = colorPick.x; + colorHsv->z = 1.0f - colorPick.y; + } + else state = STATE_FOCUSED; + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + if (state != STATE_DISABLED) + { + DrawRectangleGradientEx(bounds, Fade(colWhite, guiAlpha), Fade(colWhite, guiAlpha), Fade(maxHueCol, guiAlpha), Fade(maxHueCol, guiAlpha)); + DrawRectangleGradientEx(bounds, Fade(colBlack, 0), Fade(colBlack, guiAlpha), Fade(colBlack, guiAlpha), Fade(colBlack, 0)); + + // Draw color picker: selector + Rectangle selector = { pickerSelector.x - GuiGetStyle(COLORPICKER, COLOR_SELECTOR_SIZE)/2, pickerSelector.y - GuiGetStyle(COLORPICKER, COLOR_SELECTOR_SIZE)/2, (float)GuiGetStyle(COLORPICKER, COLOR_SELECTOR_SIZE), (float)GuiGetStyle(COLORPICKER, COLOR_SELECTOR_SIZE) }; + GuiDrawRectangle(selector, 0, BLANK, colWhite); + } + else + { + DrawRectangleGradientEx(bounds, Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), guiAlpha), Fade(Fade(colBlack, 0.6f), guiAlpha), Fade(Fade(colBlack, 0.6f), guiAlpha), Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), 0.6f), guiAlpha)); + } + + GuiDrawRectangle(bounds, GuiGetStyle(COLORPICKER, BORDER_WIDTH), GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), BLANK); + //-------------------------------------------------------------------- + + return result; +} + +// Message Box control +int GuiMessageBox(Rectangle bounds, const char *title, const char *message, const char *buttons) +{ + #if !defined(RAYGUI_MESSAGEBOX_BUTTON_HEIGHT) + #define RAYGUI_MESSAGEBOX_BUTTON_HEIGHT 24 + #endif + #if !defined(RAYGUI_MESSAGEBOX_BUTTON_PADDING) + #define RAYGUI_MESSAGEBOX_BUTTON_PADDING 12 + #endif + + int result = -1; // Returns clicked button from buttons list, 0 refers to closed window button + + int buttonCount = 0; + const char **buttonsText = GuiTextSplit(buttons, ';', &buttonCount, NULL); + Rectangle buttonBounds = { 0 }; + buttonBounds.x = bounds.x + RAYGUI_MESSAGEBOX_BUTTON_PADDING; + buttonBounds.y = bounds.y + bounds.height - RAYGUI_MESSAGEBOX_BUTTON_HEIGHT - RAYGUI_MESSAGEBOX_BUTTON_PADDING; + buttonBounds.width = (bounds.width - RAYGUI_MESSAGEBOX_BUTTON_PADDING*(buttonCount + 1))/buttonCount; + buttonBounds.height = RAYGUI_MESSAGEBOX_BUTTON_HEIGHT; + + //int textWidth = GetTextWidth(message) + 2; + + Rectangle textBounds = { 0 }; + textBounds.x = bounds.x + RAYGUI_MESSAGEBOX_BUTTON_PADDING; + textBounds.y = bounds.y + RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT + RAYGUI_MESSAGEBOX_BUTTON_PADDING; + textBounds.width = bounds.width - RAYGUI_MESSAGEBOX_BUTTON_PADDING*2; + textBounds.height = bounds.height - RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT - 3*RAYGUI_MESSAGEBOX_BUTTON_PADDING - RAYGUI_MESSAGEBOX_BUTTON_HEIGHT; + + // Draw control + //-------------------------------------------------------------------- + if (GuiWindowBox(bounds, title)) result = 0; + + int prevTextAlignment = GuiGetStyle(LABEL, TEXT_ALIGNMENT); + GuiSetStyle(LABEL, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); + GuiLabel(textBounds, message); + GuiSetStyle(LABEL, TEXT_ALIGNMENT, prevTextAlignment); + + prevTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); + + for (int i = 0; i < buttonCount; i++) + { + if (GuiButton(buttonBounds, buttonsText[i])) result = i + 1; + buttonBounds.x += (buttonBounds.width + RAYGUI_MESSAGEBOX_BUTTON_PADDING); + } + + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, prevTextAlignment); + //-------------------------------------------------------------------- + + return result; +} + +// Text Input Box control, ask for text +int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, const char *buttons, char *text, int textMaxSize, bool *secretViewActive) +{ + #if !defined(RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT) + #define RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT 24 + #endif + #if !defined(RAYGUI_TEXTINPUTBOX_BUTTON_PADDING) + #define RAYGUI_TEXTINPUTBOX_BUTTON_PADDING 12 + #endif + #if !defined(RAYGUI_TEXTINPUTBOX_HEIGHT) + #define RAYGUI_TEXTINPUTBOX_HEIGHT 26 + #endif + + // Used to enable text edit mode + // WARNING: No more than one GuiTextInputBox() should be open at the same time + static bool textEditMode = false; + + int result = -1; + + int buttonCount = 0; + const char **buttonsText = GuiTextSplit(buttons, ';', &buttonCount, NULL); + Rectangle buttonBounds = { 0 }; + buttonBounds.x = bounds.x + RAYGUI_TEXTINPUTBOX_BUTTON_PADDING; + buttonBounds.y = bounds.y + bounds.height - RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT - RAYGUI_TEXTINPUTBOX_BUTTON_PADDING; + buttonBounds.width = (bounds.width - RAYGUI_TEXTINPUTBOX_BUTTON_PADDING*(buttonCount + 1))/buttonCount; + buttonBounds.height = RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT; + + int messageInputHeight = (int)bounds.height - RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT - GuiGetStyle(STATUSBAR, BORDER_WIDTH) - RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT - 2*RAYGUI_TEXTINPUTBOX_BUTTON_PADDING; + + Rectangle textBounds = { 0 }; + if (message != NULL) + { + int textSize = GetTextWidth(message) + 2; + + textBounds.x = bounds.x + bounds.width/2 - textSize/2; + textBounds.y = bounds.y + RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT + messageInputHeight/4 - (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/2; + textBounds.width = (float)textSize; + textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); + } + + Rectangle textBoxBounds = { 0 }; + textBoxBounds.x = bounds.x + RAYGUI_TEXTINPUTBOX_BUTTON_PADDING; + textBoxBounds.y = bounds.y + RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT - RAYGUI_TEXTINPUTBOX_HEIGHT/2; + if (message == NULL) textBoxBounds.y = bounds.y + 24 + RAYGUI_TEXTINPUTBOX_BUTTON_PADDING; + else textBoxBounds.y += (messageInputHeight/2 + messageInputHeight/4); + textBoxBounds.width = bounds.width - RAYGUI_TEXTINPUTBOX_BUTTON_PADDING*2; + textBoxBounds.height = RAYGUI_TEXTINPUTBOX_HEIGHT; + + // Draw control + //-------------------------------------------------------------------- + if (GuiWindowBox(bounds, title)) result = 0; + + // Draw message if available + if (message != NULL) + { + int prevTextAlignment = GuiGetStyle(LABEL, TEXT_ALIGNMENT); + GuiSetStyle(LABEL, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); + GuiLabel(textBounds, message); + GuiSetStyle(LABEL, TEXT_ALIGNMENT, prevTextAlignment); + } + + if (secretViewActive != NULL) + { + static char stars[] = "****************"; + if (GuiTextBox(RAYGUI_CLITERAL(Rectangle){ textBoxBounds.x, textBoxBounds.y, textBoxBounds.width - 4 - RAYGUI_TEXTINPUTBOX_HEIGHT, textBoxBounds.height }, + ((*secretViewActive == 1) || textEditMode)? text : stars, textMaxSize, textEditMode)) textEditMode = !textEditMode; + + GuiToggle(RAYGUI_CLITERAL(Rectangle){ textBoxBounds.x + textBoxBounds.width - RAYGUI_TEXTINPUTBOX_HEIGHT, textBoxBounds.y, RAYGUI_TEXTINPUTBOX_HEIGHT, RAYGUI_TEXTINPUTBOX_HEIGHT }, (*secretViewActive == 1)? "#44#" : "#45#", secretViewActive); + } + else + { + if (GuiTextBox(textBoxBounds, text, textMaxSize, textEditMode)) textEditMode = !textEditMode; + } + + int prevBtnTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); + + for (int i = 0; i < buttonCount; i++) + { + if (GuiButton(buttonBounds, buttonsText[i])) result = i + 1; + buttonBounds.x += (buttonBounds.width + RAYGUI_MESSAGEBOX_BUTTON_PADDING); + } + + if (result >= 0) textEditMode = false; + + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, prevBtnTextAlignment); + //-------------------------------------------------------------------- + + return result; // Result is the pressed button index +} + +// Grid control +// NOTE: Returns grid mouse-hover selected cell +// About drawing lines at subpixel spacing, simple put, not easy solution: +// https://stackoverflow.com/questions/4435450/2d-opengl-drawing-lines-that-dont-exactly-fit-pixel-raster +int GuiGrid(Rectangle bounds, const char *text, float spacing, int subdivs, Vector2 *mouseCell) +{ + // Grid lines alpha amount + #if !defined(RAYGUI_GRID_ALPHA) + #define RAYGUI_GRID_ALPHA 0.15f + #endif + + int result = 0; + GuiState state = guiState; + + Vector2 mousePoint = GetMousePosition(); + Vector2 currentMouseCell = { -1, -1 }; + + float spaceWidth = spacing/(float)subdivs; + int linesV = (int)(bounds.width/spaceWidth) + 1; + int linesH = (int)(bounds.height/spaceWidth) + 1; + + int color = GuiGetStyle(DEFAULT, LINE_COLOR); + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) + { + if (CheckCollisionPointRec(mousePoint, bounds)) + { + // NOTE: Cell values must be the upper left of the cell the mouse is in + currentMouseCell.x = floorf((mousePoint.x - bounds.x)/spacing); + currentMouseCell.y = floorf((mousePoint.y - bounds.y)/spacing); + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + if (state == STATE_DISABLED) color = GuiGetStyle(DEFAULT, BORDER_COLOR_DISABLED); + + if (subdivs > 0) + { + // Draw vertical grid lines + for (int i = 0; i < linesV; i++) + { + Rectangle lineV = { bounds.x + spacing*i/subdivs, bounds.y, 1, bounds.height + 1 }; + GuiDrawRectangle(lineV, 0, BLANK, ((i%subdivs) == 0)? GuiFade(GetColor(color), RAYGUI_GRID_ALPHA*4) : GuiFade(GetColor(color), RAYGUI_GRID_ALPHA)); + } + + // Draw horizontal grid lines + for (int i = 0; i < linesH; i++) + { + Rectangle lineH = { bounds.x, bounds.y + spacing*i/subdivs, bounds.width + 1, 1 }; + GuiDrawRectangle(lineH, 0, BLANK, ((i%subdivs) == 0)? GuiFade(GetColor(color), RAYGUI_GRID_ALPHA*4) : GuiFade(GetColor(color), RAYGUI_GRID_ALPHA)); + } + } + + if (mouseCell != NULL) *mouseCell = currentMouseCell; + return result; +} + +//---------------------------------------------------------------------------------- +// Tooltip management functions +// NOTE: Tooltips requires some global variables: tooltipPtr +//---------------------------------------------------------------------------------- +// Enable gui tooltips (global state) +void GuiEnableTooltip(void) { guiTooltip = true; } + +// Disable gui tooltips (global state) +void GuiDisableTooltip(void) { guiTooltip = false; } + +// Set tooltip string +void GuiSetTooltip(const char *tooltip) { guiTooltipPtr = tooltip; } + +//---------------------------------------------------------------------------------- +// Styles loading functions +//---------------------------------------------------------------------------------- + +// Load raygui style file (.rgs) +// NOTE: By default a binary file is expected, that file could contain a custom font, +// in that case, custom font image atlas is GRAY+ALPHA and pixel data can be compressed (DEFLATE) +void GuiLoadStyle(const char *fileName) +{ + #define MAX_LINE_BUFFER_SIZE 256 + + bool tryBinary = false; + if (!guiStyleLoaded) GuiLoadStyleDefault(); + + // Try reading the files as text file first + FILE *rgsFile = fopen(fileName, "rt"); + + if (rgsFile != NULL) + { + char buffer[MAX_LINE_BUFFER_SIZE] = { 0 }; + fgets(buffer, MAX_LINE_BUFFER_SIZE, rgsFile); + + if (buffer[0] == '#') + { + int controlId = 0; + int propertyId = 0; + unsigned int propertyValue = 0; + + while (!feof(rgsFile)) + { + switch (buffer[0]) + { + case 'p': + { + // Style property: p + + sscanf(buffer, "p %d %d 0x%x", &controlId, &propertyId, &propertyValue); + GuiSetStyle(controlId, propertyId, (int)propertyValue); + + } break; + case 'f': + { + // Style font: f + + int fontSize = 0; + char charmapFileName[256] = { 0 }; + char fontFileName[256] = { 0 }; + sscanf(buffer, "f %d %s %[^\r\n]s", &fontSize, charmapFileName, fontFileName); + + Font font = { 0 }; + int *codepoints = NULL; + int codepointCount = 0; + + if (charmapFileName[0] != '0') + { + // Load text data from file + // NOTE: Expected an UTF-8 array of codepoints, no separation + char *textData = LoadFileText(TextFormat("%s/%s", GetDirectoryPath(fileName), charmapFileName)); + codepoints = LoadCodepoints(textData, &codepointCount); + UnloadFileText(textData); + } + + if (fontFileName[0] != '\0') + { + // In case a font is already loaded and it is not default internal font, unload it + if (font.texture.id != GetFontDefault().texture.id) UnloadTexture(font.texture); + + if (codepointCount > 0) font = LoadFontEx(TextFormat("%s/%s", GetDirectoryPath(fileName), fontFileName), fontSize, codepoints, codepointCount); + else font = LoadFontEx(TextFormat("%s/%s", GetDirectoryPath(fileName), fontFileName), fontSize, NULL, 0); // Default to 95 standard codepoints + } + + // If font texture not properly loaded, revert to default font and size/spacing + if (font.texture.id == 0) + { + font = GetFontDefault(); + GuiSetStyle(DEFAULT, TEXT_SIZE, 10); + GuiSetStyle(DEFAULT, TEXT_SPACING, 1); + } + + UnloadCodepoints(codepoints); + + if ((font.texture.id > 0) && (font.glyphCount > 0)) GuiSetFont(font); + + } break; + default: break; + } + + fgets(buffer, MAX_LINE_BUFFER_SIZE, rgsFile); + } + } + else tryBinary = true; + + fclose(rgsFile); + } + + if (tryBinary) + { + rgsFile = fopen(fileName, "rb"); + + if (rgsFile != NULL) + { + fseek(rgsFile, 0, SEEK_END); + int fileDataSize = ftell(rgsFile); + fseek(rgsFile, 0, SEEK_SET); + + if (fileDataSize > 0) + { + unsigned char *fileData = (unsigned char *)RAYGUI_MALLOC(fileDataSize*sizeof(unsigned char)); + fread(fileData, sizeof(unsigned char), fileDataSize, rgsFile); + + GuiLoadStyleFromMemory(fileData, fileDataSize); + + RAYGUI_FREE(fileData); + } + + fclose(rgsFile); + } + } +} + +// Load style default over global style +void GuiLoadStyleDefault(void) +{ + // We set this variable first to avoid cyclic function calls + // when calling GuiSetStyle() and GuiGetStyle() + guiStyleLoaded = true; + + // Initialize default LIGHT style property values + // WARNING: Default value are applied to all controls on set but + // they can be overwritten later on for every custom control + GuiSetStyle(DEFAULT, BORDER_COLOR_NORMAL, 0x838383ff); + GuiSetStyle(DEFAULT, BASE_COLOR_NORMAL, 0xc9c9c9ff); + GuiSetStyle(DEFAULT, TEXT_COLOR_NORMAL, 0x686868ff); + GuiSetStyle(DEFAULT, BORDER_COLOR_FOCUSED, 0x5bb2d9ff); + GuiSetStyle(DEFAULT, BASE_COLOR_FOCUSED, 0xc9effeff); + GuiSetStyle(DEFAULT, TEXT_COLOR_FOCUSED, 0x6c9bbcff); + GuiSetStyle(DEFAULT, BORDER_COLOR_PRESSED, 0x0492c7ff); + GuiSetStyle(DEFAULT, BASE_COLOR_PRESSED, 0x97e8ffff); + GuiSetStyle(DEFAULT, TEXT_COLOR_PRESSED, 0x368bafff); + GuiSetStyle(DEFAULT, BORDER_COLOR_DISABLED, 0xb5c1c2ff); + GuiSetStyle(DEFAULT, BASE_COLOR_DISABLED, 0xe6e9e9ff); + GuiSetStyle(DEFAULT, TEXT_COLOR_DISABLED, 0xaeb7b8ff); + GuiSetStyle(DEFAULT, BORDER_WIDTH, 1); + GuiSetStyle(DEFAULT, TEXT_PADDING, 0); + GuiSetStyle(DEFAULT, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); + + // Initialize default extended property values + // NOTE: By default, extended property values are initialized to 0 + GuiSetStyle(DEFAULT, TEXT_SIZE, 10); // DEFAULT, shared by all controls + GuiSetStyle(DEFAULT, TEXT_SPACING, 1); // DEFAULT, shared by all controls + GuiSetStyle(DEFAULT, LINE_COLOR, 0x90abb5ff); // DEFAULT specific property + GuiSetStyle(DEFAULT, BACKGROUND_COLOR, 0xf5f5f5ff); // DEFAULT specific property + GuiSetStyle(DEFAULT, TEXT_LINE_SPACING, 15); // DEFAULT, 15 pixels between lines + GuiSetStyle(DEFAULT, TEXT_ALIGNMENT_VERTICAL, TEXT_ALIGN_MIDDLE); // DEFAULT, text aligned vertically to middle of text-bounds + + // Initialize control-specific property values + // NOTE: Those properties are in default list but require specific values by control type + GuiSetStyle(LABEL, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); + GuiSetStyle(BUTTON, BORDER_WIDTH, 2); + GuiSetStyle(SLIDER, TEXT_PADDING, 4); + GuiSetStyle(PROGRESSBAR, TEXT_PADDING, 4); + GuiSetStyle(CHECKBOX, TEXT_PADDING, 4); + GuiSetStyle(CHECKBOX, TEXT_ALIGNMENT, TEXT_ALIGN_RIGHT); + GuiSetStyle(DROPDOWNBOX, TEXT_PADDING, 0); + GuiSetStyle(DROPDOWNBOX, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); + GuiSetStyle(TEXTBOX, TEXT_PADDING, 4); + GuiSetStyle(TEXTBOX, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); + GuiSetStyle(VALUEBOX, TEXT_PADDING, 0); + GuiSetStyle(VALUEBOX, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); + GuiSetStyle(SPINNER, TEXT_PADDING, 0); + GuiSetStyle(SPINNER, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); + GuiSetStyle(STATUSBAR, TEXT_PADDING, 8); + GuiSetStyle(STATUSBAR, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); + + // Initialize extended property values + // NOTE: By default, extended property values are initialized to 0 + GuiSetStyle(TOGGLE, GROUP_PADDING, 2); + GuiSetStyle(SLIDER, SLIDER_WIDTH, 16); + GuiSetStyle(SLIDER, SLIDER_PADDING, 1); + GuiSetStyle(PROGRESSBAR, PROGRESS_PADDING, 1); + GuiSetStyle(CHECKBOX, CHECK_PADDING, 1); + GuiSetStyle(COMBOBOX, COMBO_BUTTON_WIDTH, 32); + GuiSetStyle(COMBOBOX, COMBO_BUTTON_SPACING, 2); + GuiSetStyle(DROPDOWNBOX, ARROW_PADDING, 16); + GuiSetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING, 2); + GuiSetStyle(SPINNER, SPIN_BUTTON_WIDTH, 24); + GuiSetStyle(SPINNER, SPIN_BUTTON_SPACING, 2); + GuiSetStyle(SCROLLBAR, BORDER_WIDTH, 0); + GuiSetStyle(SCROLLBAR, ARROWS_VISIBLE, 0); + GuiSetStyle(SCROLLBAR, ARROWS_SIZE, 6); + GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING, 0); + GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, 16); + GuiSetStyle(SCROLLBAR, SCROLL_PADDING, 0); + GuiSetStyle(SCROLLBAR, SCROLL_SPEED, 12); + GuiSetStyle(LISTVIEW, LIST_ITEMS_HEIGHT, 28); + GuiSetStyle(LISTVIEW, LIST_ITEMS_SPACING, 2); + GuiSetStyle(LISTVIEW, SCROLLBAR_WIDTH, 12); + GuiSetStyle(LISTVIEW, SCROLLBAR_SIDE, SCROLLBAR_RIGHT_SIDE); + GuiSetStyle(COLORPICKER, COLOR_SELECTOR_SIZE, 8); + GuiSetStyle(COLORPICKER, HUEBAR_WIDTH, 16); + GuiSetStyle(COLORPICKER, HUEBAR_PADDING, 8); + GuiSetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT, 8); + GuiSetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW, 2); + + if (guiFont.texture.id != GetFontDefault().texture.id) + { + // Unload previous font texture + UnloadTexture(guiFont.texture); + RL_FREE(guiFont.recs); + RL_FREE(guiFont.glyphs); + guiFont.recs = NULL; + guiFont.glyphs = NULL; + + // Setup default raylib font + guiFont = GetFontDefault(); + + // NOTE: Default raylib font character 95 is a white square + Rectangle whiteChar = guiFont.recs[95]; + + // NOTE: We set up a 1px padding on char rectangle to avoid pixel bleeding on MSAA filtering + SetShapesTexture(guiFont.texture, RAYGUI_CLITERAL(Rectangle){ whiteChar.x + 1, whiteChar.y + 1, whiteChar.width - 2, whiteChar.height - 2 }); + } +} + +// Get text with icon id prepended +// NOTE: Useful to add icons by name id (enum) instead of +// a number that can change between ricon versions +const char *GuiIconText(int iconId, const char *text) +{ +#if defined(RAYGUI_NO_ICONS) + return NULL; +#else + static char buffer[1024] = { 0 }; + static char iconBuffer[16] = { 0 }; + + if (text != NULL) + { + memset(buffer, 0, 1024); + sprintf(buffer, "#%03i#", iconId); + + for (int i = 5; i < 1024; i++) + { + buffer[i] = text[i - 5]; + if (text[i - 5] == '\0') break; + } + + return buffer; + } + else + { + sprintf(iconBuffer, "#%03i#", iconId); + + return iconBuffer; + } +#endif +} + +#if !defined(RAYGUI_NO_ICONS) +// Get full icons data pointer +unsigned int *GuiGetIcons(void) { return guiIconsPtr; } + +// Load raygui icons file (.rgi) +// NOTE: In case nameIds are required, they can be requested with loadIconsName, +// they are returned as a guiIconsName[iconCount][RAYGUI_ICON_MAX_NAME_LENGTH], +// WARNING: guiIconsName[]][] memory should be manually freed! +char **GuiLoadIcons(const char *fileName, bool loadIconsName) +{ + // Style File Structure (.rgi) + // ------------------------------------------------------ + // Offset | Size | Type | Description + // ------------------------------------------------------ + // 0 | 4 | char | Signature: "rGI " + // 4 | 2 | short | Version: 100 + // 6 | 2 | short | reserved + + // 8 | 2 | short | Num icons (N) + // 10 | 2 | short | Icons size (Options: 16, 32, 64) (S) + + // Icons name id (32 bytes per name id) + // foreach (icon) + // { + // 12+32*i | 32 | char | Icon NameId + // } + + // Icons data: One bit per pixel, stored as unsigned int array (depends on icon size) + // S*S pixels/32bit per unsigned int = K unsigned int per icon + // foreach (icon) + // { + // ... | K | unsigned int | Icon Data + // } + + FILE *rgiFile = fopen(fileName, "rb"); + + char **guiIconsName = NULL; + + if (rgiFile != NULL) + { + char signature[5] = { 0 }; + short version = 0; + short reserved = 0; + short iconCount = 0; + short iconSize = 0; + + fread(signature, 1, 4, rgiFile); + fread(&version, sizeof(short), 1, rgiFile); + fread(&reserved, sizeof(short), 1, rgiFile); + fread(&iconCount, sizeof(short), 1, rgiFile); + fread(&iconSize, sizeof(short), 1, rgiFile); + + if ((signature[0] == 'r') && + (signature[1] == 'G') && + (signature[2] == 'I') && + (signature[3] == ' ')) + { + if (loadIconsName) + { + guiIconsName = (char **)RAYGUI_MALLOC(iconCount*sizeof(char **)); + for (int i = 0; i < iconCount; i++) + { + guiIconsName[i] = (char *)RAYGUI_MALLOC(RAYGUI_ICON_MAX_NAME_LENGTH); + fread(guiIconsName[i], 1, RAYGUI_ICON_MAX_NAME_LENGTH, rgiFile); + } + } + else fseek(rgiFile, iconCount*RAYGUI_ICON_MAX_NAME_LENGTH, SEEK_CUR); + + // Read icons data directly over internal icons array + fread(guiIconsPtr, sizeof(unsigned int), iconCount*(iconSize*iconSize/32), rgiFile); + } + + fclose(rgiFile); + } + + return guiIconsName; +} + +// Draw selected icon using rectangles pixel-by-pixel +void GuiDrawIcon(int iconId, int posX, int posY, int pixelSize, Color color) +{ + #define BIT_CHECK(a,b) ((a) & (1u<<(b))) + + for (int i = 0, y = 0; i < RAYGUI_ICON_SIZE*RAYGUI_ICON_SIZE/32; i++) + { + for (int k = 0; k < 32; k++) + { + if (BIT_CHECK(guiIconsPtr[iconId*RAYGUI_ICON_DATA_ELEMENTS + i], k)) + { + #if !defined(RAYGUI_STANDALONE) + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ (float)posX + (k%RAYGUI_ICON_SIZE)*pixelSize, (float)posY + y*pixelSize, (float)pixelSize, (float)pixelSize }, 0, BLANK, color); + #endif + } + + if ((k == 15) || (k == 31)) y++; + } + } +} + +// Set icon drawing size +void GuiSetIconScale(int scale) +{ + if (scale >= 1) guiIconScale = scale; +} + +#endif // !RAYGUI_NO_ICONS + +//---------------------------------------------------------------------------------- +// Module Internal Functions Definition +//---------------------------------------------------------------------------------- + +// Load style from memory +// WARNING: Binary files only +static void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize) +{ + unsigned char *fileDataPtr = (unsigned char *)fileData; + + char signature[5] = { 0 }; + short version = 0; + short reserved = 0; + int propertyCount = 0; + + memcpy(signature, fileDataPtr, 4); + memcpy(&version, fileDataPtr + 4, sizeof(short)); + memcpy(&reserved, fileDataPtr + 4 + 2, sizeof(short)); + memcpy(&propertyCount, fileDataPtr + 4 + 2 + 2, sizeof(int)); + fileDataPtr += 12; + + if ((signature[0] == 'r') && + (signature[1] == 'G') && + (signature[2] == 'S') && + (signature[3] == ' ')) + { + short controlId = 0; + short propertyId = 0; + unsigned int propertyValue = 0; + + for (int i = 0; i < propertyCount; i++) + { + memcpy(&controlId, fileDataPtr, sizeof(short)); + memcpy(&propertyId, fileDataPtr + 2, sizeof(short)); + memcpy(&propertyValue, fileDataPtr + 2 + 2, sizeof(unsigned int)); + fileDataPtr += 8; + + if (controlId == 0) // DEFAULT control + { + // If a DEFAULT property is loaded, it is propagated to all controls + // NOTE: All DEFAULT properties should be defined first in the file + GuiSetStyle(0, (int)propertyId, propertyValue); + + if (propertyId < RAYGUI_MAX_PROPS_BASE) for (int j = 1; j < RAYGUI_MAX_CONTROLS; j++) GuiSetStyle(j, (int)propertyId, propertyValue); + } + else GuiSetStyle((int)controlId, (int)propertyId, propertyValue); + } + + // Font loading is highly dependant on raylib API to load font data and image + +#if !defined(RAYGUI_STANDALONE) + // Load custom font if available + int fontDataSize = 0; + memcpy(&fontDataSize, fileDataPtr, sizeof(int)); + fileDataPtr += 4; + + if (fontDataSize > 0) + { + Font font = { 0 }; + int fontType = 0; // 0-Normal, 1-SDF + + memcpy(&font.baseSize, fileDataPtr, sizeof(int)); + memcpy(&font.glyphCount, fileDataPtr + 4, sizeof(int)); + memcpy(&fontType, fileDataPtr + 4 + 4, sizeof(int)); + fileDataPtr += 12; + + // Load font white rectangle + Rectangle fontWhiteRec = { 0 }; + memcpy(&fontWhiteRec, fileDataPtr, sizeof(Rectangle)); + fileDataPtr += 16; + + // Load font image parameters + int fontImageUncompSize = 0; + int fontImageCompSize = 0; + memcpy(&fontImageUncompSize, fileDataPtr, sizeof(int)); + memcpy(&fontImageCompSize, fileDataPtr + 4, sizeof(int)); + fileDataPtr += 8; + + Image imFont = { 0 }; + imFont.mipmaps = 1; + memcpy(&imFont.width, fileDataPtr, sizeof(int)); + memcpy(&imFont.height, fileDataPtr + 4, sizeof(int)); + memcpy(&imFont.format, fileDataPtr + 4 + 4, sizeof(int)); + fileDataPtr += 12; + + if ((fontImageCompSize > 0) && (fontImageCompSize != fontImageUncompSize)) + { + // Compressed font atlas image data (DEFLATE), it requires DecompressData() + int dataUncompSize = 0; + unsigned char *compData = (unsigned char *)RAYGUI_MALLOC(fontImageCompSize); + memcpy(compData, fileDataPtr, fontImageCompSize); + fileDataPtr += fontImageCompSize; + + imFont.data = DecompressData(compData, fontImageCompSize, &dataUncompSize); + + // Security check, dataUncompSize must match the provided fontImageUncompSize + if (dataUncompSize != fontImageUncompSize) RAYGUI_LOG("WARNING: Uncompressed font atlas image data could be corrupted"); + + RAYGUI_FREE(compData); + } + else + { + // Font atlas image data is not compressed + imFont.data = (unsigned char *)RAYGUI_MALLOC(fontImageUncompSize); + memcpy(imFont.data, fileDataPtr, fontImageUncompSize); + fileDataPtr += fontImageUncompSize; + } + + if (font.texture.id != GetFontDefault().texture.id) UnloadTexture(font.texture); + font.texture = LoadTextureFromImage(imFont); + + RAYGUI_FREE(imFont.data); + + // Validate font atlas texture was loaded correctly + if (font.texture.id != 0) + { + // Load font recs data + int recsDataSize = font.glyphCount*sizeof(Rectangle); + int recsDataCompressedSize = 0; + + // WARNING: Version 400 adds the compression size parameter + if (version >= 400) + { + // RGS files version 400 support compressed recs data + memcpy(&recsDataCompressedSize, fileDataPtr, sizeof(int)); + fileDataPtr += sizeof(int); + } + + if ((recsDataCompressedSize > 0) && (recsDataCompressedSize != recsDataSize)) + { + // Recs data is compressed, uncompress it + unsigned char *recsDataCompressed = (unsigned char *)RAYGUI_MALLOC(recsDataCompressedSize); + + memcpy(recsDataCompressed, fileDataPtr, recsDataCompressedSize); + fileDataPtr += recsDataCompressedSize; + + int recsDataUncompSize = 0; + font.recs = (Rectangle *)DecompressData(recsDataCompressed, recsDataCompressedSize, &recsDataUncompSize); + + // Security check, data uncompressed size must match the expected original data size + if (recsDataUncompSize != recsDataSize) RAYGUI_LOG("WARNING: Uncompressed font recs data could be corrupted"); + + RAYGUI_FREE(recsDataCompressed); + } + else + { + // Recs data is uncompressed + font.recs = (Rectangle *)RAYGUI_CALLOC(font.glyphCount, sizeof(Rectangle)); + for (int i = 0; i < font.glyphCount; i++) + { + memcpy(&font.recs[i], fileDataPtr, sizeof(Rectangle)); + fileDataPtr += sizeof(Rectangle); + } + } + + // Load font glyphs info data + int glyphsDataSize = font.glyphCount*16; // 16 bytes data per glyph + int glyphsDataCompressedSize = 0; + + // WARNING: Version 400 adds the compression size parameter + if (version >= 400) + { + // RGS files version 400 support compressed glyphs data + memcpy(&glyphsDataCompressedSize, fileDataPtr, sizeof(int)); + fileDataPtr += sizeof(int); + } + + // Allocate required glyphs space to fill with data + font.glyphs = (GlyphInfo *)RAYGUI_CALLOC(font.glyphCount, sizeof(GlyphInfo)); + + if ((glyphsDataCompressedSize > 0) && (glyphsDataCompressedSize != glyphsDataSize)) + { + // Glyphs data is compressed, uncompress it + unsigned char *glypsDataCompressed = (unsigned char *)RAYGUI_MALLOC(glyphsDataCompressedSize); + + memcpy(glypsDataCompressed, fileDataPtr, glyphsDataCompressedSize); + fileDataPtr += glyphsDataCompressedSize; + + int glyphsDataUncompSize = 0; + unsigned char *glyphsDataUncomp = DecompressData(glypsDataCompressed, glyphsDataCompressedSize, &glyphsDataUncompSize); + + // Security check, data uncompressed size must match the expected original data size + if (glyphsDataUncompSize != glyphsDataSize) RAYGUI_LOG("WARNING: Uncompressed font glyphs data could be corrupted"); + + unsigned char *glyphsDataUncompPtr = glyphsDataUncomp; + + for (int i = 0; i < font.glyphCount; i++) + { + memcpy(&font.glyphs[i].value, glyphsDataUncompPtr, sizeof(int)); + memcpy(&font.glyphs[i].offsetX, glyphsDataUncompPtr + 4, sizeof(int)); + memcpy(&font.glyphs[i].offsetY, glyphsDataUncompPtr + 8, sizeof(int)); + memcpy(&font.glyphs[i].advanceX, glyphsDataUncompPtr + 12, sizeof(int)); + glyphsDataUncompPtr += 16; + } + + RAYGUI_FREE(glypsDataCompressed); + RAYGUI_FREE(glyphsDataUncomp); + } + else + { + // Glyphs data is uncompressed + for (int i = 0; i < font.glyphCount; i++) + { + memcpy(&font.glyphs[i].value, fileDataPtr, sizeof(int)); + memcpy(&font.glyphs[i].offsetX, fileDataPtr + 4, sizeof(int)); + memcpy(&font.glyphs[i].offsetY, fileDataPtr + 8, sizeof(int)); + memcpy(&font.glyphs[i].advanceX, fileDataPtr + 12, sizeof(int)); + fileDataPtr += 16; + } + } + } + else font = GetFontDefault(); // Fallback in case of errors loading font atlas texture + + GuiSetFont(font); + + // Set font texture source rectangle to be used as white texture to draw shapes + // NOTE: It makes possible to draw shapes and text (full UI) in a single draw call + if ((fontWhiteRec.x > 0) && + (fontWhiteRec.y > 0) && + (fontWhiteRec.width > 0) && + (fontWhiteRec.height > 0)) SetShapesTexture(font.texture, fontWhiteRec); + } +#endif + } +} + +// Gui get text width considering icon +static int GetTextWidth(const char *text) +{ + #if !defined(ICON_TEXT_PADDING) + #define ICON_TEXT_PADDING 4 + #endif + + Vector2 textSize = { 0 }; + int textIconOffset = 0; + + if ((text != NULL) && (text[0] != '\0')) + { + if (text[0] == '#') + { + for (int i = 1; (i < 5) && (text[i] != '\0'); i++) + { + if (text[i] == '#') + { + textIconOffset = i; + break; + } + } + } + + text += textIconOffset; + + // Make sure guiFont is set, GuiGetStyle() initializes it lazynessly + float fontSize = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); + + // Custom MeasureText() implementation + if ((guiFont.texture.id > 0) && (text != NULL)) + { + // Get size in bytes of text, considering end of line and line break + int size = 0; + for (int i = 0; i < MAX_LINE_BUFFER_SIZE; i++) + { + if ((text[i] != '\0') && (text[i] != '\n')) size++; + else break; + } + + float scaleFactor = fontSize/(float)guiFont.baseSize; + textSize.y = (float)guiFont.baseSize*scaleFactor; + float glyphWidth = 0.0f; + + for (int i = 0, codepointSize = 0; i < size; i += codepointSize) + { + int codepoint = GetCodepointNext(&text[i], &codepointSize); + int codepointIndex = GetGlyphIndex(guiFont, codepoint); + + if (guiFont.glyphs[codepointIndex].advanceX == 0) glyphWidth = ((float)guiFont.recs[codepointIndex].width*scaleFactor); + else glyphWidth = ((float)guiFont.glyphs[codepointIndex].advanceX*scaleFactor); + + textSize.x += (glyphWidth + (float)GuiGetStyle(DEFAULT, TEXT_SPACING)); + } + } + + if (textIconOffset > 0) textSize.x += (RAYGUI_ICON_SIZE + ICON_TEXT_PADDING); + } + + return (int)textSize.x; +} + +// Get text bounds considering control bounds +static Rectangle GetTextBounds(int control, Rectangle bounds) +{ + Rectangle textBounds = bounds; + + textBounds.x = bounds.x + GuiGetStyle(control, BORDER_WIDTH); + textBounds.y = bounds.y + GuiGetStyle(control, BORDER_WIDTH) + GuiGetStyle(control, TEXT_PADDING); + textBounds.width = bounds.width - 2*GuiGetStyle(control, BORDER_WIDTH) - 2*GuiGetStyle(control, TEXT_PADDING); + textBounds.height = bounds.height - 2*GuiGetStyle(control, BORDER_WIDTH) - 2*GuiGetStyle(control, TEXT_PADDING); // NOTE: Text is processed line per line! + + // Depending on control, TEXT_PADDING and TEXT_ALIGNMENT properties could affect the text-bounds + switch (control) + { + case COMBOBOX: + case DROPDOWNBOX: + case LISTVIEW: + // TODO: Special cases (no label): COMBOBOX, DROPDOWNBOX, LISTVIEW + case SLIDER: + case CHECKBOX: + case VALUEBOX: + case SPINNER: + // TODO: More special cases (label on side): SLIDER, CHECKBOX, VALUEBOX, SPINNER + default: + { + // TODO: WARNING: TEXT_ALIGNMENT is already considered in GuiDrawText() + if (GuiGetStyle(control, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT) textBounds.x -= GuiGetStyle(control, TEXT_PADDING); + else textBounds.x += GuiGetStyle(control, TEXT_PADDING); + } + break; + } + + return textBounds; +} + +// Get text icon if provided and move text cursor +// NOTE: We support up to 999 values for iconId +static const char *GetTextIcon(const char *text, int *iconId) +{ +#if !defined(RAYGUI_NO_ICONS) + *iconId = -1; + if (text[0] == '#') // Maybe we have an icon! + { + char iconValue[4] = { 0 }; // Maximum length for icon value: 3 digits + '\0' + + int pos = 1; + while ((pos < 4) && (text[pos] >= '0') && (text[pos] <= '9')) + { + iconValue[pos - 1] = text[pos]; + pos++; + } + + if (text[pos] == '#') + { + *iconId = TextToInteger(iconValue); + + // Move text pointer after icon + // WARNING: If only icon provided, it could point to EOL character: '\0' + if (*iconId >= 0) text += (pos + 1); + } + } +#endif + + return text; +} + +// Get text divided into lines (by line-breaks '\n') +const char **GetTextLines(const char *text, int *count) +{ + #define RAYGUI_MAX_TEXT_LINES 128 + + static const char *lines[RAYGUI_MAX_TEXT_LINES] = { 0 }; + for (int i = 0; i < RAYGUI_MAX_TEXT_LINES; i++) lines[i] = NULL; // Init NULL pointers to substrings + + int textSize = (int)strlen(text); + + lines[0] = text; + int len = 0; + *count = 1; + //int lineSize = 0; // Stores current line size, not returned + + for (int i = 0, k = 0; (i < textSize) && (*count < RAYGUI_MAX_TEXT_LINES); i++) + { + if (text[i] == '\n') + { + //lineSize = len; + k++; + lines[k] = &text[i + 1]; // WARNING: next value is valid? + len = 0; + *count += 1; + } + else len++; + } + + //lines[*count - 1].size = len; + + return lines; +} + +// Get text width to next space for provided string +static float GetNextSpaceWidth(const char *text, int *nextSpaceIndex) +{ + float width = 0; + int codepointByteCount = 0; + int codepoint = 0; + int index = 0; + float glyphWidth = 0; + float scaleFactor = (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/guiFont.baseSize; + + for (int i = 0; text[i] != '\0'; i++) + { + if (text[i] != ' ') + { + codepoint = GetCodepoint(&text[i], &codepointByteCount); + index = GetGlyphIndex(guiFont, codepoint); + glyphWidth = (guiFont.glyphs[index].advanceX == 0)? guiFont.recs[index].width*scaleFactor : guiFont.glyphs[index].advanceX*scaleFactor; + width += (glyphWidth + (float)GuiGetStyle(DEFAULT, TEXT_SPACING)); + } + else + { + *nextSpaceIndex = i; + break; + } + } + + return width; +} + +// Gui draw text using default font +static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, Color tint) +{ + #define TEXT_VALIGN_PIXEL_OFFSET(h) ((int)h%2) // Vertical alignment for pixel perfect + + #if !defined(ICON_TEXT_PADDING) + #define ICON_TEXT_PADDING 4 + #endif + + if ((text == NULL) || (text[0] == '\0')) return; // Security check + + // PROCEDURE: + // - Text is processed line per line + // - For every line, horizontal alignment is defined + // - For all text, vertical alignment is defined (multiline text only) + // - For every line, wordwrap mode is checked (useful for GuitextBox(), read-only) + + // Get text lines (using '\n' as delimiter) to be processed individually + // WARNING: We can't use GuiTextSplit() function because it can be already used + // before the GuiDrawText() call and its buffer is static, it would be overriden :( + int lineCount = 0; + const char **lines = GetTextLines(text, &lineCount); + + // Text style variables + //int alignment = GuiGetStyle(DEFAULT, TEXT_ALIGNMENT); + int alignmentVertical = GuiGetStyle(DEFAULT, TEXT_ALIGNMENT_VERTICAL); + int wrapMode = GuiGetStyle(DEFAULT, TEXT_WRAP_MODE); // Wrap-mode only available in read-only mode, no for text editing + + // TODO: WARNING: This totalHeight is not valid for vertical alignment in case of word-wrap + float totalHeight = (float)(lineCount*GuiGetStyle(DEFAULT, TEXT_SIZE) + (lineCount - 1)*GuiGetStyle(DEFAULT, TEXT_SIZE)/2); + float posOffsetY = 0.0f; + + for (int i = 0; i < lineCount; i++) + { + int iconId = 0; + lines[i] = GetTextIcon(lines[i], &iconId); // Check text for icon and move cursor + + // Get text position depending on alignment and iconId + //--------------------------------------------------------------------------------- + Vector2 textBoundsPosition = { textBounds.x, textBounds.y }; + float textBoundsWidthOffset = 0.0f; + + // NOTE: We get text size after icon has been processed + // WARNING: GetTextWidth() also processes text icon to get width! -> Really needed? + int textSizeX = GetTextWidth(lines[i]); + + // If text requires an icon, add size to measure + if (iconId >= 0) + { + textSizeX += RAYGUI_ICON_SIZE*guiIconScale; + + // WARNING: If only icon provided, text could be pointing to EOF character: '\0' +#if !defined(RAYGUI_NO_ICONS) + if ((lines[i] != NULL) && (lines[i][0] != '\0')) textSizeX += ICON_TEXT_PADDING; +#endif + } + + // Check guiTextAlign global variables + switch (alignment) + { + case TEXT_ALIGN_LEFT: textBoundsPosition.x = textBounds.x; break; + case TEXT_ALIGN_CENTER: textBoundsPosition.x = textBounds.x + textBounds.width/2 - textSizeX/2; break; + case TEXT_ALIGN_RIGHT: textBoundsPosition.x = textBounds.x + textBounds.width - textSizeX; break; + default: break; + } + + if (textSizeX > textBounds.width && (lines[i] != NULL) && (lines[i][0] != '\0')) textBoundsPosition.x = textBounds.x; + + switch (alignmentVertical) + { + // Only valid in case of wordWrap = 0; + case TEXT_ALIGN_TOP: textBoundsPosition.y = textBounds.y + posOffsetY; break; + case TEXT_ALIGN_MIDDLE: textBoundsPosition.y = textBounds.y + posOffsetY + textBounds.height/2 - totalHeight/2 + TEXT_VALIGN_PIXEL_OFFSET(textBounds.height); break; + case TEXT_ALIGN_BOTTOM: textBoundsPosition.y = textBounds.y + posOffsetY + textBounds.height - totalHeight + TEXT_VALIGN_PIXEL_OFFSET(textBounds.height); break; + default: break; + } + + // NOTE: Make sure we get pixel-perfect coordinates, + // In case of decimals we got weird text positioning + textBoundsPosition.x = (float)((int)textBoundsPosition.x); + textBoundsPosition.y = (float)((int)textBoundsPosition.y); + //--------------------------------------------------------------------------------- + + // Draw text (with icon if available) + //--------------------------------------------------------------------------------- +#if !defined(RAYGUI_NO_ICONS) + if (iconId >= 0) + { + // NOTE: We consider icon height, probably different than text size + GuiDrawIcon(iconId, (int)textBoundsPosition.x, (int)(textBounds.y + textBounds.height/2 - RAYGUI_ICON_SIZE*guiIconScale/2 + TEXT_VALIGN_PIXEL_OFFSET(textBounds.height)), guiIconScale, tint); + textBoundsPosition.x += (float)(RAYGUI_ICON_SIZE*guiIconScale + ICON_TEXT_PADDING); + textBoundsWidthOffset = (float)(RAYGUI_ICON_SIZE*guiIconScale + ICON_TEXT_PADDING); + } +#endif + // Get size in bytes of text, + // considering end of line and line break + int lineSize = 0; + for (int c = 0; (lines[i][c] != '\0') && (lines[i][c] != '\n') && (lines[i][c] != '\r'); c++, lineSize++){ } + float scaleFactor = (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/guiFont.baseSize; + + int lastSpaceIndex = 0; + bool tempWrapCharMode = false; + + int textOffsetY = 0; + float textOffsetX = 0.0f; + float glyphWidth = 0; + + int ellipsisWidth = GetTextWidth("..."); + bool textOverflow = false; + for (int c = 0, codepointSize = 0; c < lineSize; c += codepointSize) + { + int codepoint = GetCodepointNext(&lines[i][c], &codepointSize); + int index = GetGlyphIndex(guiFont, codepoint); + + // NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f) + // but we need to draw all of the bad bytes using the '?' symbol moving one byte + if (codepoint == 0x3f) codepointSize = 1; // TODO: Review not recognized codepoints size + + // Get glyph width to check if it goes out of bounds + if (guiFont.glyphs[index].advanceX == 0) glyphWidth = ((float)guiFont.recs[index].width*scaleFactor); + else glyphWidth = (float)guiFont.glyphs[index].advanceX*scaleFactor; + + // Wrap mode text measuring, to validate if + // it can be drawn or a new line is required + if (wrapMode == TEXT_WRAP_CHAR) + { + // Jump to next line if current character reach end of the box limits + if ((textOffsetX + glyphWidth) > textBounds.width - textBoundsWidthOffset) + { + textOffsetX = 0.0f; + textOffsetY += GuiGetStyle(DEFAULT, TEXT_LINE_SPACING); + + if (tempWrapCharMode) // Wrap at char level when too long words + { + wrapMode = TEXT_WRAP_WORD; + tempWrapCharMode = false; + } + } + } + else if (wrapMode == TEXT_WRAP_WORD) + { + if (codepoint == 32) lastSpaceIndex = c; + + // Get width to next space in line + int nextSpaceIndex = 0; + float nextSpaceWidth = GetNextSpaceWidth(lines[i] + c, &nextSpaceIndex); + + int nextSpaceIndex2 = 0; + float nextWordSize = GetNextSpaceWidth(lines[i] + lastSpaceIndex + 1, &nextSpaceIndex2); + + if (nextWordSize > textBounds.width - textBoundsWidthOffset) + { + // Considering the case the next word is longer than bounds + tempWrapCharMode = true; + wrapMode = TEXT_WRAP_CHAR; + } + else if ((textOffsetX + nextSpaceWidth) > textBounds.width - textBoundsWidthOffset) + { + textOffsetX = 0.0f; + textOffsetY += GuiGetStyle(DEFAULT, TEXT_LINE_SPACING); + } + } + + if (codepoint == '\n') break; // WARNING: Lines are already processed manually, no need to keep drawing after this codepoint + else + { + // TODO: There are multiple types of spaces in Unicode, + // maybe it's a good idea to add support for more: http://jkorpela.fi/chars/spaces.html + if ((codepoint != ' ') && (codepoint != '\t')) // Do not draw codepoints with no glyph + { + if (wrapMode == TEXT_WRAP_NONE) + { + // Draw only required text glyphs fitting the textBounds.width + if (textSizeX > textBounds.width) + { + if (textOffsetX <= (textBounds.width - glyphWidth - textBoundsWidthOffset - ellipsisWidth)) + { + DrawTextCodepoint(guiFont, codepoint, RAYGUI_CLITERAL(Vector2){ textBoundsPosition.x + textOffsetX, textBoundsPosition.y + textOffsetY }, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), GuiFade(tint, guiAlpha)); + } + else if (!textOverflow) + { + textOverflow = true; + + for (int j = 0; j < ellipsisWidth; j += ellipsisWidth/3) + { + DrawTextCodepoint(guiFont, '.', RAYGUI_CLITERAL(Vector2){ textBoundsPosition.x + textOffsetX + j, textBoundsPosition.y + textOffsetY }, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), GuiFade(tint, guiAlpha)); + } + } + } + else + { + DrawTextCodepoint(guiFont, codepoint, RAYGUI_CLITERAL(Vector2){ textBoundsPosition.x + textOffsetX, textBoundsPosition.y + textOffsetY }, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), GuiFade(tint, guiAlpha)); + } + } + else if ((wrapMode == TEXT_WRAP_CHAR) || (wrapMode == TEXT_WRAP_WORD)) + { + // Draw only glyphs inside the bounds + if ((textBoundsPosition.y + textOffsetY) <= (textBounds.y + textBounds.height - GuiGetStyle(DEFAULT, TEXT_SIZE))) + { + DrawTextCodepoint(guiFont, codepoint, RAYGUI_CLITERAL(Vector2){ textBoundsPosition.x + textOffsetX, textBoundsPosition.y + textOffsetY }, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), GuiFade(tint, guiAlpha)); + } + } + } + + if (guiFont.glyphs[index].advanceX == 0) textOffsetX += ((float)guiFont.recs[index].width*scaleFactor + (float)GuiGetStyle(DEFAULT, TEXT_SPACING)); + else textOffsetX += ((float)guiFont.glyphs[index].advanceX*scaleFactor + (float)GuiGetStyle(DEFAULT, TEXT_SPACING)); + } + } + + if (wrapMode == TEXT_WRAP_NONE) posOffsetY += (float)GuiGetStyle(DEFAULT, TEXT_LINE_SPACING); + else if ((wrapMode == TEXT_WRAP_CHAR) || (wrapMode == TEXT_WRAP_WORD)) posOffsetY += (textOffsetY + (float)GuiGetStyle(DEFAULT, TEXT_LINE_SPACING)); + //--------------------------------------------------------------------------------- + } + +#if defined(RAYGUI_DEBUG_TEXT_BOUNDS) + GuiDrawRectangle(textBounds, 0, WHITE, Fade(BLUE, 0.4f)); +#endif +} + +// Gui draw rectangle using default raygui plain style with borders +static void GuiDrawRectangle(Rectangle rec, int borderWidth, Color borderColor, Color color) +{ + if (color.a > 0) + { + // Draw rectangle filled with color + DrawRectangle((int)rec.x, (int)rec.y, (int)rec.width, (int)rec.height, GuiFade(color, guiAlpha)); + } + + if (borderWidth > 0) + { + // Draw rectangle border lines with color + DrawRectangle((int)rec.x, (int)rec.y, (int)rec.width, borderWidth, GuiFade(borderColor, guiAlpha)); + DrawRectangle((int)rec.x, (int)rec.y + borderWidth, borderWidth, (int)rec.height - 2*borderWidth, GuiFade(borderColor, guiAlpha)); + DrawRectangle((int)rec.x + (int)rec.width - borderWidth, (int)rec.y + borderWidth, borderWidth, (int)rec.height - 2*borderWidth, GuiFade(borderColor, guiAlpha)); + DrawRectangle((int)rec.x, (int)rec.y + (int)rec.height - borderWidth, (int)rec.width, borderWidth, GuiFade(borderColor, guiAlpha)); + } + +#if defined(RAYGUI_DEBUG_RECS_BOUNDS) + DrawRectangle((int)rec.x, (int)rec.y, (int)rec.width, (int)rec.height, Fade(RED, 0.4f)); +#endif +} + +// Draw tooltip using control bounds +static void GuiTooltip(Rectangle controlRec) +{ + if (!guiLocked && guiTooltip && (guiTooltipPtr != NULL) && !guiControlExclusiveMode) + { + Vector2 textSize = MeasureTextEx(GuiGetFont(), guiTooltipPtr, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), (float)GuiGetStyle(DEFAULT, TEXT_SPACING)); + + if ((controlRec.x + textSize.x + 16) > GetScreenWidth()) controlRec.x -= (textSize.x + 16 - controlRec.width); + + GuiPanel(RAYGUI_CLITERAL(Rectangle){ controlRec.x, controlRec.y + controlRec.height + 4, textSize.x + 16, GuiGetStyle(DEFAULT, TEXT_SIZE) + 8.f }, NULL); + + int textPadding = GuiGetStyle(LABEL, TEXT_PADDING); + int textAlignment = GuiGetStyle(LABEL, TEXT_ALIGNMENT); + GuiSetStyle(LABEL, TEXT_PADDING, 0); + GuiSetStyle(LABEL, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); + GuiLabel(RAYGUI_CLITERAL(Rectangle){ controlRec.x, controlRec.y + controlRec.height + 4, textSize.x + 16, GuiGetStyle(DEFAULT, TEXT_SIZE) + 8.f }, guiTooltipPtr); + GuiSetStyle(LABEL, TEXT_ALIGNMENT, textAlignment); + GuiSetStyle(LABEL, TEXT_PADDING, textPadding); + } +} + +// Split controls text into multiple strings +// Also check for multiple columns (required by GuiToggleGroup()) +static const char **GuiTextSplit(const char *text, char delimiter, int *count, int *textRow) +{ + // NOTE: Current implementation returns a copy of the provided string with '\0' (string end delimiter) + // inserted between strings defined by "delimiter" parameter. No memory is dynamically allocated, + // all used memory is static... it has some limitations: + // 1. Maximum number of possible split strings is set by RAYGUI_TEXTSPLIT_MAX_ITEMS + // 2. Maximum size of text to split is RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE + // NOTE: Those definitions could be externally provided if required + + // TODO: HACK: GuiTextSplit() - Review how textRows are returned to user + // textRow is an externally provided array of integers that stores row number for every splitted string + + #if !defined(RAYGUI_TEXTSPLIT_MAX_ITEMS) + #define RAYGUI_TEXTSPLIT_MAX_ITEMS 128 + #endif + #if !defined(RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE) + #define RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE 1024 + #endif + + static const char *result[RAYGUI_TEXTSPLIT_MAX_ITEMS] = { NULL }; // String pointers array (points to buffer data) + static char buffer[RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE] = { 0 }; // Buffer data (text input copy with '\0' added) + memset(buffer, 0, RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE); + + result[0] = buffer; + int counter = 1; + + if (textRow != NULL) textRow[0] = 0; + + // Count how many substrings we have on text and point to every one + for (int i = 0; i < RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE; i++) + { + buffer[i] = text[i]; + if (buffer[i] == '\0') break; + else if ((buffer[i] == delimiter) || (buffer[i] == '\n')) + { + result[counter] = buffer + i + 1; + + if (textRow != NULL) + { + if (buffer[i] == '\n') textRow[counter] = textRow[counter - 1] + 1; + else textRow[counter] = textRow[counter - 1]; + } + + buffer[i] = '\0'; // Set an end of string at this point + + counter++; + if (counter > RAYGUI_TEXTSPLIT_MAX_ITEMS) break; + } + } + + *count = counter; + + return result; +} + +// Convert color data from RGB to HSV +// NOTE: Color data should be passed normalized +static Vector3 ConvertRGBtoHSV(Vector3 rgb) +{ + Vector3 hsv = { 0 }; + float min = 0.0f; + float max = 0.0f; + float delta = 0.0f; + + min = (rgb.x < rgb.y)? rgb.x : rgb.y; + min = (min < rgb.z)? min : rgb.z; + + max = (rgb.x > rgb.y)? rgb.x : rgb.y; + max = (max > rgb.z)? max : rgb.z; + + hsv.z = max; // Value + delta = max - min; + + if (delta < 0.00001f) + { + hsv.y = 0.0f; + hsv.x = 0.0f; // Undefined, maybe NAN? + return hsv; + } + + if (max > 0.0f) + { + // NOTE: If max is 0, this divide would cause a crash + hsv.y = (delta/max); // Saturation + } + else + { + // NOTE: If max is 0, then r = g = b = 0, s = 0, h is undefined + hsv.y = 0.0f; + hsv.x = 0.0f; // Undefined, maybe NAN? + return hsv; + } + + // NOTE: Comparing float values could not work properly + if (rgb.x >= max) hsv.x = (rgb.y - rgb.z)/delta; // Between yellow & magenta + else + { + if (rgb.y >= max) hsv.x = 2.0f + (rgb.z - rgb.x)/delta; // Between cyan & yellow + else hsv.x = 4.0f + (rgb.x - rgb.y)/delta; // Between magenta & cyan + } + + hsv.x *= 60.0f; // Convert to degrees + + if (hsv.x < 0.0f) hsv.x += 360.0f; + + return hsv; +} + +// Convert color data from HSV to RGB +// NOTE: Color data should be passed normalized +static Vector3 ConvertHSVtoRGB(Vector3 hsv) +{ + Vector3 rgb = { 0 }; + float hh = 0.0f, p = 0.0f, q = 0.0f, t = 0.0f, ff = 0.0f; + long i = 0; + + // NOTE: Comparing float values could not work properly + if (hsv.y <= 0.0f) + { + rgb.x = hsv.z; + rgb.y = hsv.z; + rgb.z = hsv.z; + return rgb; + } + + hh = hsv.x; + if (hh >= 360.0f) hh = 0.0f; + hh /= 60.0f; + + i = (long)hh; + ff = hh - i; + p = hsv.z*(1.0f - hsv.y); + q = hsv.z*(1.0f - (hsv.y*ff)); + t = hsv.z*(1.0f - (hsv.y*(1.0f - ff))); + + switch (i) + { + case 0: + { + rgb.x = hsv.z; + rgb.y = t; + rgb.z = p; + } break; + case 1: + { + rgb.x = q; + rgb.y = hsv.z; + rgb.z = p; + } break; + case 2: + { + rgb.x = p; + rgb.y = hsv.z; + rgb.z = t; + } break; + case 3: + { + rgb.x = p; + rgb.y = q; + rgb.z = hsv.z; + } break; + case 4: + { + rgb.x = t; + rgb.y = p; + rgb.z = hsv.z; + } break; + case 5: + default: + { + rgb.x = hsv.z; + rgb.y = p; + rgb.z = q; + } break; + } + + return rgb; +} + +// Scroll bar control (used by GuiScrollPanel()) +static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue) +{ + GuiState state = guiState; + + // Is the scrollbar horizontal or vertical? + bool isVertical = (bounds.width > bounds.height)? false : true; + + // The size (width or height depending on scrollbar type) of the spinner buttons + const int spinnerSize = GuiGetStyle(SCROLLBAR, ARROWS_VISIBLE)? + (isVertical? (int)bounds.width - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH) : + (int)bounds.height - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH)) : 0; + + // Arrow buttons [<] [>] [∧] [∨] + Rectangle arrowUpLeft = { 0 }; + Rectangle arrowDownRight = { 0 }; + + // Actual area of the scrollbar excluding the arrow buttons + Rectangle scrollbar = { 0 }; + + // Slider bar that moves --[///]----- + Rectangle slider = { 0 }; + + // Normalize value + if (value > maxValue) value = maxValue; + if (value < minValue) value = minValue; + + int valueRange = maxValue - minValue; + if (valueRange <= 0) valueRange = 1; + + int sliderSize = GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE); + if (sliderSize < 1) sliderSize = 1; // TODO: Consider a minimum slider size + + // Calculate rectangles for all of the components + arrowUpLeft = RAYGUI_CLITERAL(Rectangle){ + (float)bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), + (float)bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), + (float)spinnerSize, (float)spinnerSize }; + + if (isVertical) + { + arrowDownRight = RAYGUI_CLITERAL(Rectangle){ (float)bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)bounds.y + bounds.height - spinnerSize - GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)spinnerSize, (float)spinnerSize }; + scrollbar = RAYGUI_CLITERAL(Rectangle){ bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING), arrowUpLeft.y + arrowUpLeft.height, bounds.width - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING)), bounds.height - arrowUpLeft.height - arrowDownRight.height - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH) }; + + // Make sure the slider won't get outside of the scrollbar + sliderSize = (sliderSize >= scrollbar.height)? ((int)scrollbar.height - 2) : sliderSize; + slider = RAYGUI_CLITERAL(Rectangle){ + bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING), + scrollbar.y + (int)(((float)(value - minValue)/valueRange)*(scrollbar.height - sliderSize)), + bounds.width - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING)), + (float)sliderSize }; + } + else // horizontal + { + arrowDownRight = RAYGUI_CLITERAL(Rectangle){ (float)bounds.x + bounds.width - spinnerSize - GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)spinnerSize, (float)spinnerSize }; + scrollbar = RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x + arrowUpLeft.width, bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING), bounds.width - arrowUpLeft.width - arrowDownRight.width - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH), bounds.height - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING)) }; + + // Make sure the slider won't get outside of the scrollbar + sliderSize = (sliderSize >= scrollbar.width)? ((int)scrollbar.width - 2) : sliderSize; + slider = RAYGUI_CLITERAL(Rectangle){ + scrollbar.x + (int)(((float)(value - minValue)/valueRange)*(scrollbar.width - sliderSize)), + bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING), + (float)sliderSize, + bounds.height - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING)) }; + } + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked) + { + Vector2 mousePoint = GetMousePosition(); + + if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds + { + if (IsMouseButtonDown(MOUSE_LEFT_BUTTON) && + !CheckCollisionPointRec(mousePoint, arrowUpLeft) && + !CheckCollisionPointRec(mousePoint, arrowDownRight)) + { + if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec)) + { + state = STATE_PRESSED; + + if (isVertical) value = (int)(((float)(mousePoint.y - scrollbar.y - slider.height/2)*valueRange)/(scrollbar.height - slider.height) + minValue); + else value = (int)(((float)(mousePoint.x - scrollbar.x - slider.width/2)*valueRange)/(scrollbar.width - slider.width) + minValue); + } + } + else + { + guiControlExclusiveMode = false; + guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 }; + } + } + else if (CheckCollisionPointRec(mousePoint, bounds)) + { + state = STATE_FOCUSED; + + // Handle mouse wheel + int wheel = (int)GetMouseWheelMove(); + if (wheel != 0) value += wheel; + + // Handle mouse button down + if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) + { + guiControlExclusiveMode = true; + guiControlExclusiveRec = bounds; // Store bounds as an identifier when dragging starts + + // Check arrows click + if (CheckCollisionPointRec(mousePoint, arrowUpLeft)) value -= valueRange/GuiGetStyle(SCROLLBAR, SCROLL_SPEED); + else if (CheckCollisionPointRec(mousePoint, arrowDownRight)) value += valueRange/GuiGetStyle(SCROLLBAR, SCROLL_SPEED); + else if (!CheckCollisionPointRec(mousePoint, slider)) + { + // If click on scrollbar position but not on slider, place slider directly on that position + if (isVertical) value = (int)(((float)(mousePoint.y - scrollbar.y - slider.height/2)*valueRange)/(scrollbar.height - slider.height) + minValue); + else value = (int)(((float)(mousePoint.x - scrollbar.x - slider.width/2)*valueRange)/(scrollbar.width - slider.width) + minValue); + } + + state = STATE_PRESSED; + } + + // Keyboard control on mouse hover scrollbar + /* + if (isVertical) + { + if (IsKeyDown(KEY_DOWN)) value += 5; + else if (IsKeyDown(KEY_UP)) value -= 5; + } + else + { + if (IsKeyDown(KEY_RIGHT)) value += 5; + else if (IsKeyDown(KEY_LEFT)) value -= 5; + } + */ + } + + // Normalize value + if (value > maxValue) value = maxValue; + if (value < minValue) value = minValue; + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawRectangle(bounds, GuiGetStyle(SCROLLBAR, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER + state*3)), GetColor(GuiGetStyle(DEFAULT, BORDER_COLOR_DISABLED))); // Draw the background + + GuiDrawRectangle(scrollbar, 0, BLANK, GetColor(GuiGetStyle(BUTTON, BASE_COLOR_NORMAL))); // Draw the scrollbar active area background + GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, BORDER + state*3))); // Draw the slider bar + + // Draw arrows (using icon if available) + if (GuiGetStyle(SCROLLBAR, ARROWS_VISIBLE)) + { +#if defined(RAYGUI_NO_ICONS) + GuiDrawText(isVertical? "^" : "<", + RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x, arrowUpLeft.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, + TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); + GuiDrawText(isVertical? "v" : ">", + RAYGUI_CLITERAL(Rectangle){ arrowDownRight.x, arrowDownRight.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, + TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); +#else + GuiDrawText(isVertical? "#121#" : "#118#", + RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x, arrowUpLeft.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, + TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(SCROLLBAR, TEXT + state*3))); // ICON_ARROW_UP_FILL / ICON_ARROW_LEFT_FILL + GuiDrawText(isVertical? "#120#" : "#119#", + RAYGUI_CLITERAL(Rectangle){ arrowDownRight.x, arrowDownRight.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, + TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(SCROLLBAR, TEXT + state*3))); // ICON_ARROW_DOWN_FILL / ICON_ARROW_RIGHT_FILL +#endif + } + //-------------------------------------------------------------------- + + return value; +} + +// Color fade-in or fade-out, alpha goes from 0.0f to 1.0f +// WARNING: It multiplies current alpha by alpha scale factor +static Color GuiFade(Color color, float alpha) +{ + if (alpha < 0.0f) alpha = 0.0f; + else if (alpha > 1.0f) alpha = 1.0f; + + Color result = { color.r, color.g, color.b, (unsigned char)(color.a*alpha) }; + + return result; +} + +#if defined(RAYGUI_STANDALONE) +// Returns a Color struct from hexadecimal value +static Color GetColor(int hexValue) +{ + Color color; + + color.r = (unsigned char)(hexValue >> 24) & 0xFF; + color.g = (unsigned char)(hexValue >> 16) & 0xFF; + color.b = (unsigned char)(hexValue >> 8) & 0xFF; + color.a = (unsigned char)hexValue & 0xFF; + + return color; +} + +// Returns hexadecimal value for a Color +static int ColorToInt(Color color) +{ + return (((int)color.r << 24) | ((int)color.g << 16) | ((int)color.b << 8) | (int)color.a); +} + +// Check if point is inside rectangle +static bool CheckCollisionPointRec(Vector2 point, Rectangle rec) +{ + bool collision = false; + + if ((point.x >= rec.x) && (point.x <= (rec.x + rec.width)) && + (point.y >= rec.y) && (point.y <= (rec.y + rec.height))) collision = true; + + return collision; +} + +// Formatting of text with variables to 'embed' +static const char *TextFormat(const char *text, ...) +{ + #if !defined(RAYGUI_TEXTFORMAT_MAX_SIZE) + #define RAYGUI_TEXTFORMAT_MAX_SIZE 256 + #endif + + static char buffer[RAYGUI_TEXTFORMAT_MAX_SIZE]; + + va_list args; + va_start(args, text); + vsprintf(buffer, text, args); + va_end(args); + + return buffer; +} + +// Draw rectangle with vertical gradient fill color +// NOTE: This function is only used by GuiColorPicker() +static void DrawRectangleGradientV(int posX, int posY, int width, int height, Color color1, Color color2) +{ + Rectangle bounds = { (float)posX, (float)posY, (float)width, (float)height }; + DrawRectangleGradientEx(bounds, color1, color2, color2, color1); +} + +// Split string into multiple strings +const char **TextSplit(const char *text, char delimiter, int *count) +{ + // NOTE: Current implementation returns a copy of the provided string with '\0' (string end delimiter) + // inserted between strings defined by "delimiter" parameter. No memory is dynamically allocated, + // all used memory is static... it has some limitations: + // 1. Maximum number of possible split strings is set by RAYGUI_TEXTSPLIT_MAX_ITEMS + // 2. Maximum size of text to split is RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE + + #if !defined(RAYGUI_TEXTSPLIT_MAX_ITEMS) + #define RAYGUI_TEXTSPLIT_MAX_ITEMS 128 + #endif + #if !defined(RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE) + #define RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE 1024 + #endif + + static const char *result[RAYGUI_TEXTSPLIT_MAX_ITEMS] = { NULL }; + static char buffer[RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE] = { 0 }; + memset(buffer, 0, RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE); + + result[0] = buffer; + int counter = 0; + + if (text != NULL) + { + counter = 1; + + // Count how many substrings we have on text and point to every one + for (int i = 0; i < RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE; i++) + { + buffer[i] = text[i]; + if (buffer[i] == '\0') break; + else if (buffer[i] == delimiter) + { + buffer[i] = '\0'; // Set an end of string at this point + result[counter] = buffer + i + 1; + counter++; + + if (counter == RAYGUI_TEXTSPLIT_MAX_ITEMS) break; + } + } + } + + *count = counter; + return result; +} + +// Get integer value from text +// NOTE: This function replaces atoi() [stdlib.h] +static int TextToInteger(const char *text) +{ + int value = 0; + int sign = 1; + + if ((text[0] == '+') || (text[0] == '-')) + { + if (text[0] == '-') sign = -1; + text++; + } + + for (int i = 0; ((text[i] >= '0') && (text[i] <= '9')); ++i) value = value*10 + (int)(text[i] - '0'); + + return value*sign; +} + +// Get float value from text +// NOTE: This function replaces atof() [stdlib.h] +// WARNING: Only '.' character is understood as decimal point +static float TextToFloat(const char *text) +{ + float value = 0.0f; + float sign = 1.0f; + + if ((text[0] == '+') || (text[0] == '-')) + { + if (text[0] == '-') sign = -1.0f; + text++; + } + + int i = 0; + for (; ((text[i] >= '0') && (text[i] <= '9')); i++) value = value*10.0f + (float)(text[i] - '0'); + + if (text[i++] != '.') value *= sign; + else + { + float divisor = 10.0f; + for (; ((text[i] >= '0') && (text[i] <= '9')); i++) + { + value += ((float)(text[i] - '0'))/divisor; + divisor = divisor*10.0f; + } + } + + return value; +} + +// Encode codepoint into UTF-8 text (char array size returned as parameter) +static const char *CodepointToUTF8(int codepoint, int *byteSize) +{ + static char utf8[6] = { 0 }; + int size = 0; + + if (codepoint <= 0x7f) + { + utf8[0] = (char)codepoint; + size = 1; + } + else if (codepoint <= 0x7ff) + { + utf8[0] = (char)(((codepoint >> 6) & 0x1f) | 0xc0); + utf8[1] = (char)((codepoint & 0x3f) | 0x80); + size = 2; + } + else if (codepoint <= 0xffff) + { + utf8[0] = (char)(((codepoint >> 12) & 0x0f) | 0xe0); + utf8[1] = (char)(((codepoint >> 6) & 0x3f) | 0x80); + utf8[2] = (char)((codepoint & 0x3f) | 0x80); + size = 3; + } + else if (codepoint <= 0x10ffff) + { + utf8[0] = (char)(((codepoint >> 18) & 0x07) | 0xf0); + utf8[1] = (char)(((codepoint >> 12) & 0x3f) | 0x80); + utf8[2] = (char)(((codepoint >> 6) & 0x3f) | 0x80); + utf8[3] = (char)((codepoint & 0x3f) | 0x80); + size = 4; + } + + *byteSize = size; + + return utf8; +} + +// Get next codepoint in a UTF-8 encoded text, scanning until '\0' is found +// When a invalid UTF-8 byte is encountered we exit as soon as possible and a '?'(0x3f) codepoint is returned +// Total number of bytes processed are returned as a parameter +// NOTE: the standard says U+FFFD should be returned in case of errors +// but that character is not supported by the default font in raylib +static int GetCodepointNext(const char *text, int *codepointSize) +{ + const char *ptr = text; + int codepoint = 0x3f; // Codepoint (defaults to '?') + *codepointSize = 1; + + // Get current codepoint and bytes processed + if (0xf0 == (0xf8 & ptr[0])) + { + // 4 byte UTF-8 codepoint + if (((ptr[1] & 0xC0) ^ 0x80) || ((ptr[2] & 0xC0) ^ 0x80) || ((ptr[3] & 0xC0) ^ 0x80)) { return codepoint; } //10xxxxxx checks + codepoint = ((0x07 & ptr[0]) << 18) | ((0x3f & ptr[1]) << 12) | ((0x3f & ptr[2]) << 6) | (0x3f & ptr[3]); + *codepointSize = 4; + } + else if (0xe0 == (0xf0 & ptr[0])) + { + // 3 byte UTF-8 codepoint */ + if (((ptr[1] & 0xC0) ^ 0x80) || ((ptr[2] & 0xC0) ^ 0x80)) { return codepoint; } //10xxxxxx checks + codepoint = ((0x0f & ptr[0]) << 12) | ((0x3f & ptr[1]) << 6) | (0x3f & ptr[2]); + *codepointSize = 3; + } + else if (0xc0 == (0xe0 & ptr[0])) + { + // 2 byte UTF-8 codepoint + if ((ptr[1] & 0xC0) ^ 0x80) { return codepoint; } //10xxxxxx checks + codepoint = ((0x1f & ptr[0]) << 6) | (0x3f & ptr[1]); + *codepointSize = 2; + } + else if (0x00 == (0x80 & ptr[0])) + { + // 1 byte UTF-8 codepoint + codepoint = ptr[0]; + *codepointSize = 1; + } + + return codepoint; +} +#endif // RAYGUI_STANDALONE + +#endif // RAYGUI_IMPLEMENTATION diff --git a/projects/VS2022/examples/core_directory_files.vcxproj b/projects/VS2022/examples/core_directory_files.vcxproj index 24dd573f8..426fbfca8 100644 --- a/projects/VS2022/examples/core_directory_files.vcxproj +++ b/projects/VS2022/examples/core_directory_files.vcxproj @@ -51,7 +51,7 @@ - {6B1A933E-71B8-4C1F-9E79-02D98830E671} + {7467E9AE-844F-444D-8A3F-17397544BA21} Win32Proj core_directory_files 10.0 diff --git a/projects/VS2022/examples/shapes_pie_chart.vcxproj b/projects/VS2022/examples/shapes_pie_chart.vcxproj index 058a9b577..ad1cf93d1 100644 --- a/projects/VS2022/examples/shapes_pie_chart.vcxproj +++ b/projects/VS2022/examples/shapes_pie_chart.vcxproj @@ -51,7 +51,7 @@ - {6B1A933E-71B8-4C1F-9E79-02D98830E671} + {61997220-5383-4AE5-ABD4-5F45AE1B0F2A} Win32Proj shapes_pie_chart 10.0 diff --git a/projects/VS2022/raylib.sln b/projects/VS2022/raylib.sln index 48f3762dd..d17c569c5 100644 --- a/projects/VS2022/raylib.sln +++ b/projects/VS2022/raylib.sln @@ -371,25 +371,11 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_recursive_tree", "ex EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_triangle_strip", "examples\shapes_triangle_strip.vcxproj", "{BB58A5FB-1A35-4471-86D0-A5189EC541B3}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "web", "web", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_pie_chart", "examples\shapes_pie_chart.vcxproj", "{61997220-5383-4AE5-ABD4-5F45AE1B0F2A}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_pie_chart", "examples\shapes_pie_chart.vcxproj", "{6B1A933E-71B8-4C1F-9E79-02D98830E671}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_directory_files", "examples\core_directory_files.vcxproj", "{7467E9AE-844F-444D-8A3F-17397544BA21}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_kaleidoscope", "examples\shapes_kaleidoscope.vcxproj", "{6B1A933E-71B8-4C1F-9E79-02D98830E671}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_recursive_tree", "examples\shapes_recursive_tree.vcxproj", "{6B1A933E-71B8-4C1F-9E79-02D98830E671}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_triangle_strip", "examples\shapes_triangle_strip.vcxproj", "{2CCCD9E4-9058-4291-BD89-39C979F0CA1E}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_directory_files", "examples\core_directory_files.vcxproj", "{6B1A933E-71B8-4C1F-9E79-02D98830E671}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_kaleidoscope", "examples\shapes_kaleidoscope.vcxproj", "{6B1A933E-71B8-4C1F-9E79-02D98830E671}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_recursive_tree", "examples\shapes_recursive_tree.vcxproj", "{6B1A933E-71B8-4C1F-9E79-02D98830E671}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_triangle_strip", "examples\shapes_triangle_strip.vcxproj", "{2CCCD9E4-9058-4291-BD89-39C979F0CA1E}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_simple_particles", "examples\shapes_simple_particles.vcxproj", "{6B1A933E-71B8-4C1F-9E79-02D98830E671}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_simple_particles", "examples\shapes_simple_particles.vcxproj", "{497FDF54-9762-4048-A833-61CC3980A0FB}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -4413,222 +4399,270 @@ Global {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release|x64.Build.0 = Release|x64 {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release|x86.ActiveCfg = Release|Win32 {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.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 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug|ARM64.Build.0 = Debug|ARM64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug|x64.ActiveCfg = Debug|x64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug|x64.Build.0 = Debug|x64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug|x86.ActiveCfg = Debug|Win32 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug|x86.Build.0 = Debug|Win32 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release.DLL|x64.Build.0 = Release.DLL|x64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release.DLL|x86.Build.0 = Release.DLL|Win32 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release|ARM64.ActiveCfg = Release|ARM64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release|ARM64.Build.0 = Release|ARM64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release|x64.ActiveCfg = Release|x64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release|x64.Build.0 = Release|x64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release|x86.ActiveCfg = Release|Win32 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release|x86.Build.0 = Release|Win32 - {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 - {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 - {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 - {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 - {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 - {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 - {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug|ARM64.Build.0 = Debug|ARM64 - {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug|x64.ActiveCfg = Debug|x64 - {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug|x64.Build.0 = Debug|x64 - {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug|x86.ActiveCfg = Debug|Win32 - {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug|x86.Build.0 = Debug|Win32 - {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 - {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 - {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 - {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release.DLL|x64.Build.0 = Release.DLL|x64 - {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 - {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release.DLL|x86.Build.0 = Release.DLL|Win32 - {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release|ARM64.ActiveCfg = Release|ARM64 - {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release|ARM64.Build.0 = Release|ARM64 - {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release|x64.ActiveCfg = Release|x64 - {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release|x64.Build.0 = Release|x64 - {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release|x86.ActiveCfg = Release|Win32 - {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release|x86.Build.0 = Release|Win32 - {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 - {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 - {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 - {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 - {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 - {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 - {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug|ARM64.Build.0 = Debug|ARM64 - {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug|x64.ActiveCfg = Debug|x64 - {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug|x64.Build.0 = Debug|x64 - {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug|x86.ActiveCfg = Debug|Win32 - {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug|x86.Build.0 = Debug|Win32 - {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 - {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 - {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 - {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release.DLL|x64.Build.0 = Release.DLL|x64 - {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 - {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release.DLL|x86.Build.0 = Release.DLL|Win32 - {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release|ARM64.ActiveCfg = Release|ARM64 - {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release|ARM64.Build.0 = Release|ARM64 - {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release|x64.ActiveCfg = Release|x64 - {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release|x64.Build.0 = Release|x64 - {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release|x86.ActiveCfg = Release|Win32 - {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.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 - {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 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug|ARM64.Build.0 = Debug|ARM64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug|x64.ActiveCfg = Debug|x64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug|x64.Build.0 = Debug|x64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug|x86.ActiveCfg = Debug|Win32 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug|x86.Build.0 = Debug|Win32 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release.DLL|x64.Build.0 = Release.DLL|x64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release.DLL|x86.Build.0 = Release.DLL|Win32 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release|ARM64.ActiveCfg = Release|ARM64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release|ARM64.Build.0 = Release|ARM64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release|x64.ActiveCfg = Release|x64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release|x64.Build.0 = Release|x64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release|x86.ActiveCfg = Release|Win32 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.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 + {8E132D5A-2C00-48D0-8747-97E41356F26F}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 + {8E132D5A-2C00-48D0-8747-97E41356F26F}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 + {8E132D5A-2C00-48D0-8747-97E41356F26F}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {8E132D5A-2C00-48D0-8747-97E41356F26F}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {8E132D5A-2C00-48D0-8747-97E41356F26F}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {8E132D5A-2C00-48D0-8747-97E41356F26F}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {8E132D5A-2C00-48D0-8747-97E41356F26F}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {8E132D5A-2C00-48D0-8747-97E41356F26F}.Debug|ARM64.Build.0 = Debug|ARM64 + {8E132D5A-2C00-48D0-8747-97E41356F26F}.Debug|x64.ActiveCfg = Debug|x64 + {8E132D5A-2C00-48D0-8747-97E41356F26F}.Debug|x64.Build.0 = Debug|x64 + {8E132D5A-2C00-48D0-8747-97E41356F26F}.Debug|x86.ActiveCfg = Debug|Win32 + {8E132D5A-2C00-48D0-8747-97E41356F26F}.Debug|x86.Build.0 = Debug|Win32 + {8E132D5A-2C00-48D0-8747-97E41356F26F}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 + {8E132D5A-2C00-48D0-8747-97E41356F26F}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 + {8E132D5A-2C00-48D0-8747-97E41356F26F}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {8E132D5A-2C00-48D0-8747-97E41356F26F}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {8E132D5A-2C00-48D0-8747-97E41356F26F}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {8E132D5A-2C00-48D0-8747-97E41356F26F}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {8E132D5A-2C00-48D0-8747-97E41356F26F}.Release|ARM64.ActiveCfg = Release|ARM64 + {8E132D5A-2C00-48D0-8747-97E41356F26F}.Release|ARM64.Build.0 = Release|ARM64 + {8E132D5A-2C00-48D0-8747-97E41356F26F}.Release|x64.ActiveCfg = Release|x64 + {8E132D5A-2C00-48D0-8747-97E41356F26F}.Release|x64.Build.0 = Release|x64 + {8E132D5A-2C00-48D0-8747-97E41356F26F}.Release|x86.ActiveCfg = Release|Win32 + {8E132D5A-2C00-48D0-8747-97E41356F26F}.Release|x86.Build.0 = Release|Win32 + {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 + {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 + {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Debug|ARM64.Build.0 = Debug|ARM64 + {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Debug|x64.ActiveCfg = Debug|x64 + {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Debug|x64.Build.0 = Debug|x64 + {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Debug|x86.ActiveCfg = Debug|Win32 + {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Debug|x86.Build.0 = Debug|Win32 + {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 + {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 + {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Release|ARM64.ActiveCfg = Release|ARM64 + {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Release|ARM64.Build.0 = Release|ARM64 + {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Release|x64.ActiveCfg = Release|x64 + {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Release|x64.Build.0 = Release|x64 + {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Release|x86.ActiveCfg = Release|Win32 + {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Release|x86.Build.0 = Release|Win32 + {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 + {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 + {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Debug|ARM64.Build.0 = Debug|ARM64 + {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Debug|x64.ActiveCfg = Debug|x64 + {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Debug|x64.Build.0 = Debug|x64 + {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Debug|x86.ActiveCfg = Debug|Win32 + {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Debug|x86.Build.0 = Debug|Win32 + {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 + {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 + {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Release|ARM64.ActiveCfg = Release|ARM64 + {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Release|ARM64.Build.0 = Release|ARM64 + {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Release|x64.ActiveCfg = Release|x64 + {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Release|x64.Build.0 = Release|x64 + {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Release|x86.ActiveCfg = Release|Win32 + {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Release|x86.Build.0 = Release|Win32 + {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 + {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 + {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Debug|ARM64.Build.0 = Debug|ARM64 + {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Debug|x64.ActiveCfg = Debug|x64 + {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Debug|x64.Build.0 = Debug|x64 + {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Debug|x86.ActiveCfg = Debug|Win32 + {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Debug|x86.Build.0 = Debug|Win32 + {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 + {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 + {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Release|ARM64.ActiveCfg = Release|ARM64 + {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Release|ARM64.Build.0 = Release|ARM64 + {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Release|x64.ActiveCfg = Release|x64 + {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Release|x64.Build.0 = Release|x64 + {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Release|x86.ActiveCfg = Release|Win32 + {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Release|x86.Build.0 = Release|Win32 + {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 + {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 + {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Debug|ARM64.Build.0 = Debug|ARM64 + {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Debug|x64.ActiveCfg = Debug|x64 + {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Debug|x64.Build.0 = Debug|x64 + {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Debug|x86.ActiveCfg = Debug|Win32 + {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Debug|x86.Build.0 = Debug|Win32 + {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 + {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 + {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Release|ARM64.ActiveCfg = Release|ARM64 + {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Release|ARM64.Build.0 = Release|ARM64 + {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Release|x64.ActiveCfg = Release|x64 + {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Release|x64.Build.0 = Release|x64 + {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Release|x86.ActiveCfg = Release|Win32 + {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Release|x86.Build.0 = Release|Win32 + {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 + {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 + {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Debug|ARM64.Build.0 = Debug|ARM64 + {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Debug|x64.ActiveCfg = Debug|x64 + {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Debug|x64.Build.0 = Debug|x64 + {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Debug|x86.ActiveCfg = Debug|Win32 + {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Debug|x86.Build.0 = Debug|Win32 + {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 + {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 + {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Release|ARM64.ActiveCfg = Release|ARM64 + {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Release|ARM64.Build.0 = Release|ARM64 + {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Release|x64.ActiveCfg = Release|x64 + {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Release|x64.Build.0 = Release|x64 + {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Release|x86.ActiveCfg = Release|Win32 + {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Release|x86.Build.0 = Release|Win32 + {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 + {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 + {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Debug|ARM64.Build.0 = Debug|ARM64 + {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Debug|x64.ActiveCfg = Debug|x64 + {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Debug|x64.Build.0 = Debug|x64 + {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Debug|x86.ActiveCfg = Debug|Win32 + {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Debug|x86.Build.0 = Debug|Win32 + {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 + {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 + {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Release|ARM64.ActiveCfg = Release|ARM64 + {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Release|ARM64.Build.0 = Release|ARM64 + {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Release|x64.ActiveCfg = Release|x64 + {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Release|x64.Build.0 = Release|x64 + {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Release|x86.ActiveCfg = Release|Win32 + {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Release|x86.Build.0 = Release|Win32 + {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 + {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 + {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Debug|ARM64.Build.0 = Debug|ARM64 + {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Debug|x64.ActiveCfg = Debug|x64 + {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Debug|x64.Build.0 = Debug|x64 + {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Debug|x86.ActiveCfg = Debug|Win32 + {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Debug|x86.Build.0 = Debug|Win32 + {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 + {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 + {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Release|ARM64.ActiveCfg = Release|ARM64 + {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Release|ARM64.Build.0 = Release|ARM64 + {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Release|x64.ActiveCfg = Release|x64 + {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Release|x64.Build.0 = Release|x64 + {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Release|x86.ActiveCfg = Release|Win32 + {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Release|x86.Build.0 = Release|Win32 + {61997220-5383-4AE5-ABD4-5F45AE1B0F2A}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 + {61997220-5383-4AE5-ABD4-5F45AE1B0F2A}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 + {61997220-5383-4AE5-ABD4-5F45AE1B0F2A}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {61997220-5383-4AE5-ABD4-5F45AE1B0F2A}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {61997220-5383-4AE5-ABD4-5F45AE1B0F2A}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {61997220-5383-4AE5-ABD4-5F45AE1B0F2A}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {61997220-5383-4AE5-ABD4-5F45AE1B0F2A}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {61997220-5383-4AE5-ABD4-5F45AE1B0F2A}.Debug|ARM64.Build.0 = Debug|ARM64 + {61997220-5383-4AE5-ABD4-5F45AE1B0F2A}.Debug|x64.ActiveCfg = Debug|x64 + {61997220-5383-4AE5-ABD4-5F45AE1B0F2A}.Debug|x64.Build.0 = Debug|x64 + {61997220-5383-4AE5-ABD4-5F45AE1B0F2A}.Debug|x86.ActiveCfg = Debug|Win32 + {61997220-5383-4AE5-ABD4-5F45AE1B0F2A}.Debug|x86.Build.0 = Debug|Win32 + {61997220-5383-4AE5-ABD4-5F45AE1B0F2A}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 + {61997220-5383-4AE5-ABD4-5F45AE1B0F2A}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 + {61997220-5383-4AE5-ABD4-5F45AE1B0F2A}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {61997220-5383-4AE5-ABD4-5F45AE1B0F2A}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {61997220-5383-4AE5-ABD4-5F45AE1B0F2A}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {61997220-5383-4AE5-ABD4-5F45AE1B0F2A}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {61997220-5383-4AE5-ABD4-5F45AE1B0F2A}.Release|ARM64.ActiveCfg = Release|ARM64 + {61997220-5383-4AE5-ABD4-5F45AE1B0F2A}.Release|ARM64.Build.0 = Release|ARM64 + {61997220-5383-4AE5-ABD4-5F45AE1B0F2A}.Release|x64.ActiveCfg = Release|x64 + {61997220-5383-4AE5-ABD4-5F45AE1B0F2A}.Release|x64.Build.0 = Release|x64 + {61997220-5383-4AE5-ABD4-5F45AE1B0F2A}.Release|x86.ActiveCfg = Release|Win32 + {61997220-5383-4AE5-ABD4-5F45AE1B0F2A}.Release|x86.Build.0 = Release|Win32 + {7467E9AE-844F-444D-8A3F-17397544BA21}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 + {7467E9AE-844F-444D-8A3F-17397544BA21}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 + {7467E9AE-844F-444D-8A3F-17397544BA21}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {7467E9AE-844F-444D-8A3F-17397544BA21}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {7467E9AE-844F-444D-8A3F-17397544BA21}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {7467E9AE-844F-444D-8A3F-17397544BA21}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {7467E9AE-844F-444D-8A3F-17397544BA21}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {7467E9AE-844F-444D-8A3F-17397544BA21}.Debug|ARM64.Build.0 = Debug|ARM64 + {7467E9AE-844F-444D-8A3F-17397544BA21}.Debug|x64.ActiveCfg = Debug|x64 + {7467E9AE-844F-444D-8A3F-17397544BA21}.Debug|x64.Build.0 = Debug|x64 + {7467E9AE-844F-444D-8A3F-17397544BA21}.Debug|x86.ActiveCfg = Debug|Win32 + {7467E9AE-844F-444D-8A3F-17397544BA21}.Debug|x86.Build.0 = Debug|Win32 + {7467E9AE-844F-444D-8A3F-17397544BA21}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 + {7467E9AE-844F-444D-8A3F-17397544BA21}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 + {7467E9AE-844F-444D-8A3F-17397544BA21}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {7467E9AE-844F-444D-8A3F-17397544BA21}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {7467E9AE-844F-444D-8A3F-17397544BA21}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {7467E9AE-844F-444D-8A3F-17397544BA21}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {7467E9AE-844F-444D-8A3F-17397544BA21}.Release|ARM64.ActiveCfg = Release|ARM64 + {7467E9AE-844F-444D-8A3F-17397544BA21}.Release|ARM64.Build.0 = Release|ARM64 + {7467E9AE-844F-444D-8A3F-17397544BA21}.Release|x64.ActiveCfg = Release|x64 + {7467E9AE-844F-444D-8A3F-17397544BA21}.Release|x64.Build.0 = Release|x64 + {7467E9AE-844F-444D-8A3F-17397544BA21}.Release|x86.ActiveCfg = Release|Win32 + {7467E9AE-844F-444D-8A3F-17397544BA21}.Release|x86.Build.0 = Release|Win32 + {497FDF54-9762-4048-A833-61CC3980A0FB}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 + {497FDF54-9762-4048-A833-61CC3980A0FB}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 + {497FDF54-9762-4048-A833-61CC3980A0FB}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {497FDF54-9762-4048-A833-61CC3980A0FB}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {497FDF54-9762-4048-A833-61CC3980A0FB}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {497FDF54-9762-4048-A833-61CC3980A0FB}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {497FDF54-9762-4048-A833-61CC3980A0FB}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {497FDF54-9762-4048-A833-61CC3980A0FB}.Debug|ARM64.Build.0 = Debug|ARM64 + {497FDF54-9762-4048-A833-61CC3980A0FB}.Debug|x64.ActiveCfg = Debug|x64 + {497FDF54-9762-4048-A833-61CC3980A0FB}.Debug|x64.Build.0 = Debug|x64 + {497FDF54-9762-4048-A833-61CC3980A0FB}.Debug|x86.ActiveCfg = Debug|Win32 + {497FDF54-9762-4048-A833-61CC3980A0FB}.Debug|x86.Build.0 = Debug|Win32 + {497FDF54-9762-4048-A833-61CC3980A0FB}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 + {497FDF54-9762-4048-A833-61CC3980A0FB}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 + {497FDF54-9762-4048-A833-61CC3980A0FB}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {497FDF54-9762-4048-A833-61CC3980A0FB}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {497FDF54-9762-4048-A833-61CC3980A0FB}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {497FDF54-9762-4048-A833-61CC3980A0FB}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {497FDF54-9762-4048-A833-61CC3980A0FB}.Release|ARM64.ActiveCfg = Release|ARM64 + {497FDF54-9762-4048-A833-61CC3980A0FB}.Release|ARM64.Build.0 = Release|ARM64 + {497FDF54-9762-4048-A833-61CC3980A0FB}.Release|x64.ActiveCfg = Release|x64 + {497FDF54-9762-4048-A833-61CC3980A0FB}.Release|x64.Build.0 = Release|x64 + {497FDF54-9762-4048-A833-61CC3980A0FB}.Release|x86.ActiveCfg = Release|Win32 + {497FDF54-9762-4048-A833-61CC3980A0FB}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -4796,7 +4830,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} = {278D8859-20B1-428F-8448-064F46E1F021} + {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} @@ -4808,10 +4842,17 @@ Global {2CCCD9E4-9058-4291-BD89-39C979F0CA1E} = {278D8859-20B1-428F-8448-064F46E1F021} {9DB1F875-6E65-4195-B23F-ED8095C0B99C} = {5317807F-61D4-4E0F-B6DC-2D9F12621ED9} {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} - {6B1A933E-71B8-4C1F-9E79-02D98830E671} = {278D8859-20B1-428F-8448-064F46E1F021} - {6B1A933E-71B8-4C1F-9E79-02D98830E671} = {278D8859-20B1-428F-8448-064F46E1F021} - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E} = {278D8859-20B1-428F-8448-064F46E1F021} - {6B1A933E-71B8-4C1F-9E79-02D98830E671} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} + {8E132D5A-2C00-48D0-8747-97E41356F26F} = {278D8859-20B1-428F-8448-064F46E1F021} + {A4662163-83E7-4309-8CAA-B0BF13655FE6} = {AF5BEC5C-1F2B-4DA8-B12D-D09FE569237C} + {5F4B766F-DD52-4B53-B6C3-BC7611E17F20} = {278D8859-20B1-428F-8448-064F46E1F021} + {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} + {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC} = {E9D708A5-9C1F-4B84-A795-C5F191801762} + {0C442799-B09C-4CD1-9538-711B6E85E9BF} = {278D8859-20B1-428F-8448-064F46E1F021} + {DFB40A10-F8B7-412A-BCC3-5EE49294D816} = {278D8859-20B1-428F-8448-064F46E1F021} + {BB58A5FB-1A35-4471-86D0-A5189EC541B3} = {278D8859-20B1-428F-8448-064F46E1F021} + {61997220-5383-4AE5-ABD4-5F45AE1B0F2A} = {278D8859-20B1-428F-8448-064F46E1F021} + {7467E9AE-844F-444D-8A3F-17397544BA21} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} + {497FDF54-9762-4048-A833-61CC3980A0FB} = {278D8859-20B1-428F-8448-064F46E1F021} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {E926C768-6307-4423-A1EC-57E95B1FAB29} From 8e052b81b45e33eb33b57d501424221480c6e872 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 15 Oct 2025 19:59:28 +0200 Subject: [PATCH 122/167] REVIEWED: New examples on VS project --- examples/Makefile | 8 +- examples/Makefile.Web | 26 +- examples/README.md | 15 +- examples/core/core_clipboard_text.c | 4 +- examples/examples_list.txt | 5 + examples/shapes/shapes_clock_of_clocks.c | 2 +- examples/shapes/shapes_mouse_trail.c | 2 +- examples/shapes/shapes_pie_chart.c | 6 +- examples/shapes/shapes_recursive_tree.c | 6 +- examples/shapes/shapes_simple_particles.c | 93 ++- examples/shapes/shapes_starfield.c | 4 +- examples/shapes/shapes_triangle_strip.c | 2 +- examples/text/text_words_alignment.c | 6 +- .../examples/core_clipboard_text.vcxproj | 569 ++++++++++++++++++ .../examples/shapes_clock_of_clocks.vcxproj | 569 ++++++++++++++++++ .../examples/shapes_mouse_trail.vcxproj | 569 ++++++++++++++++++ .../VS2022/examples/shapes_starfield.vcxproj | 569 ++++++++++++++++++ .../examples/text_words_alignment.vcxproj | 569 ++++++++++++++++++ projects/VS2022/raylib.sln | 143 ++++- tools/rexm/examples_report.md | 7 + 20 files changed, 3098 insertions(+), 76 deletions(-) create mode 100644 projects/VS2022/examples/core_clipboard_text.vcxproj create mode 100644 projects/VS2022/examples/shapes_clock_of_clocks.vcxproj create mode 100644 projects/VS2022/examples/shapes_mouse_trail.vcxproj create mode 100644 projects/VS2022/examples/shapes_starfield.vcxproj create mode 100644 projects/VS2022/examples/text_words_alignment.vcxproj diff --git a/examples/Makefile b/examples/Makefile index 523339d06..eb6725756 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -512,6 +512,7 @@ CORE = \ core/core_automation_events \ core/core_basic_screen_manager \ core/core_basic_window \ + core/core_clipboard_text \ core/core_custom_frame_control \ core/core_custom_logging \ core/core_delta_time \ @@ -546,6 +547,7 @@ SHAPES = \ shapes/shapes_bouncing_ball \ shapes/shapes_bullet_hell \ shapes/shapes_circle_sector_drawing \ + shapes/shapes_clock_of_clocks \ shapes/shapes_collision_area \ shapes/shapes_colors_palette \ shapes/shapes_dashed_line \ @@ -559,12 +561,14 @@ SHAPES = \ shapes/shapes_lines_bezier \ shapes/shapes_logo_raylib \ shapes/shapes_logo_raylib_anim \ + shapes/shapes_mouse_trail \ shapes/shapes_pie_chart \ shapes/shapes_rectangle_advanced \ shapes/shapes_rectangle_scaling \ shapes/shapes_recursive_tree \ shapes/shapes_ring_drawing \ shapes/shapes_rounded_rectangle_drawing \ + shapes/shapes_simple_particles \ shapes/shapes_splines_drawing \ shapes/shapes_starfield \ shapes/shapes_top_down_lights \ @@ -613,8 +617,8 @@ TEXT = \ text/text_sprite_fonts \ text/text_unicode_emojis \ text/text_unicode_ranges \ - text/text_writing_anim \ - text/text_words_alignment + text/text_words_alignment \ + text/text_writing_anim MODELS = \ models/models_animation_gpu_skinning \ diff --git a/examples/Makefile.Web b/examples/Makefile.Web index c5e9138f5..e365a5fee 100644 --- a/examples/Makefile.Web +++ b/examples/Makefile.Web @@ -512,6 +512,7 @@ CORE = \ core/core_automation_events \ core/core_basic_screen_manager \ core/core_basic_window \ + core/core_clipboard_text \ core/core_custom_frame_control \ core/core_custom_logging \ core/core_delta_time \ @@ -546,6 +547,7 @@ SHAPES = \ shapes/shapes_bouncing_ball \ shapes/shapes_bullet_hell \ shapes/shapes_circle_sector_drawing \ + shapes/shapes_clock_of_clocks \ shapes/shapes_collision_area \ shapes/shapes_colors_palette \ shapes/shapes_dashed_line \ @@ -559,12 +561,14 @@ SHAPES = \ shapes/shapes_lines_bezier \ shapes/shapes_logo_raylib \ shapes/shapes_logo_raylib_anim \ + shapes/shapes_mouse_trail \ shapes/shapes_pie_chart \ shapes/shapes_rectangle_advanced \ shapes/shapes_rectangle_scaling \ shapes/shapes_recursive_tree \ shapes/shapes_ring_drawing \ shapes/shapes_rounded_rectangle_drawing \ + shapes/shapes_simple_particles \ shapes/shapes_splines_drawing \ shapes/shapes_starfield \ shapes/shapes_top_down_lights \ @@ -613,8 +617,8 @@ TEXT = \ text/text_sprite_fonts \ text/text_unicode_emojis \ text/text_unicode_ranges \ - text/text_writing_anim \ - text/text_words_alignment + text/text_words_alignment \ + text/text_writing_anim MODELS = \ models/models_animation_gpu_skinning \ @@ -736,6 +740,9 @@ core/core_basic_screen_manager: core/core_basic_screen_manager.c core/core_basic_window: core/core_basic_window.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) +core/core_clipboard_text: core/core_clipboard_text.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) + core/core_custom_frame_control: core/core_custom_frame_control.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) @@ -836,6 +843,9 @@ shapes/shapes_bullet_hell: shapes/shapes_bullet_hell.c shapes/shapes_circle_sector_drawing: shapes/shapes_circle_sector_drawing.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) +shapes/shapes_clock_of_clocks: shapes/shapes_clock_of_clocks.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) + shapes/shapes_collision_area: shapes/shapes_collision_area.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) @@ -875,6 +885,9 @@ shapes/shapes_logo_raylib: shapes/shapes_logo_raylib.c shapes/shapes_logo_raylib_anim: shapes/shapes_logo_raylib_anim.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) +shapes/shapes_mouse_trail: shapes/shapes_mouse_trail.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) + shapes/shapes_pie_chart: shapes/shapes_pie_chart.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) @@ -893,9 +906,15 @@ shapes/shapes_ring_drawing: shapes/shapes_ring_drawing.c shapes/shapes_rounded_rectangle_drawing: shapes/shapes_rounded_rectangle_drawing.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) +shapes/shapes_simple_particles: shapes/shapes_simple_particles.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) + 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 + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) + shapes/shapes_top_down_lights: shapes/shapes_top_down_lights.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) @@ -1078,6 +1097,9 @@ text/text_unicode_ranges: text/text_unicode_ranges.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \ --preload-file text/resources/NotoSansTC-Regular.ttf@resources/NotoSansTC-Regular.ttf +text/text_words_alignment: text/text_words_alignment.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) + text/text_writing_anim: text/text_writing_anim.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) diff --git a/examples/README.md b/examples/README.md index 16e44aa2b..e8b6ba4bf 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: 176] +## EXAMPLES COLLECTION [TOTAL: 183] -### category: core [41] +### category: core [42] Examples using raylib[core](../src/rcore.c) platform functionality like window creation, inputs, drawing modes and system functionality. @@ -66,8 +66,9 @@ 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_clipboard_text](core/core_clipboard_text.c) | core_clipboard_text | ⭐☆☆☆ | 5.6-dev | 5.6-dev | [Robin](https://github.com/RobinsAviary) | -### category: shapes [27] +### category: shapes [31] Examples using raylib shapes drawing functionality, provided by raylib [shapes](../src/rshapes.c) module. @@ -93,13 +94,17 @@ Examples using raylib shapes drawing functionality, provided by raylib [shapes]( | [shapes_top_down_lights](shapes/shapes_top_down_lights.c) | shapes_top_down_lights | ⭐⭐⭐⭐️ | 4.2 | 4.2 | [Jeffery Myers](https://github.com/JeffM2501) | | [shapes_rectangle_advanced](shapes/shapes_rectangle_advanced.c) | shapes_rectangle_advanced | ⭐⭐⭐⭐️ | 5.5 | 5.5 | [Everton Jr.](https://github.com/evertonse) | | [shapes_splines_drawing](shapes/shapes_splines_drawing.c) | shapes_splines_drawing | ⭐⭐⭐☆ | 5.0 | 5.0 | [Ramon Santamaria](https://github.com/raysan5) | -| [shapes_starfield](shapes/shapes_starfield.c) | shapes_starfield | ⭐⭐⭐☆ | 5.5 | 5.5 | [JP Mortiboys](https://github.com/themushroompirates) | | [shapes_digital_clock](shapes/shapes_digital_clock.c) | shapes_digital_clock | ⭐⭐⭐⭐️ | 5.5 | 5.6 | [Hamza RAHAL](https://github.com/hmz-rhl) | | [shapes_double_pendulum](shapes/shapes_double_pendulum.c) | shapes_double_pendulum | ⭐⭐☆☆ | 5.5 | 5.5 | [JoeCheong](https://github.com/Joecheong2006) | | [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_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) | ### category: textures [26] @@ -154,7 +159,7 @@ Examples using raylib text functionality, including sprite fonts loading/generat | [text_3d_drawing](text/text_3d_drawing.c) | text_3d_drawing | ⭐⭐⭐⭐️ | 3.5 | 4.0 | [Vlad Adrian](https://github.com/demizdor) | | [text_codepoints_loading](text/text_codepoints_loading.c) | text_codepoints_loading | ⭐⭐⭐☆ | 4.2 | 4.2 | [Ramon Santamaria](https://github.com/raysan5) | | [text_inline_styling](text/text_inline_styling.c) | text_inline_styling | ⭐⭐⭐☆ | 5.6-dev | 5.6-dev | [Wagner Barongello](https://github.com/SultansOfCode) | -| [text_words_alignment](text/text_words_alignment.c) | text_words_alignment | ⭐⭐⭐☆ | 5.6-dev | 5.6-dev | [JP Mortiboys](https://github.com/themushroompirates) | +| [text_words_alignment](text/text_words_alignment.c) | text_words_alignment | ⭐☆☆☆ | 5.6-dev | 5.6-dev | [JP Mortiboys](https://github.com/themushroompirates) | ### category: models [25] diff --git a/examples/core/core_clipboard_text.c b/examples/core/core_clipboard_text.c index 973163cb5..2be64154b 100644 --- a/examples/core/core_clipboard_text.c +++ b/examples/core/core_clipboard_text.c @@ -4,14 +4,14 @@ * * Example complexity rating: [★☆☆☆] 1/4 * -* Example originally created with raylib 5.6-dev +* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev * * 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) +* Copyright (c) 2025 Robin (@RobinsAviary) * ********************************************************************************************/ diff --git a/examples/examples_list.txt b/examples/examples_list.txt index 9770975fb..b86a4bc02 100644 --- a/examples/examples_list.txt +++ b/examples/examples_list.txt @@ -185,3 +185,8 @@ others;raylib_opengl_interop;★★★★;3.8;4.0;2021;2025;"Stephan Soller";@ar 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_clock_of_clocks.c b/examples/shapes/shapes_clock_of_clocks.c index 0418255e4..493e53b5e 100644 --- a/examples/shapes/shapes_clock_of_clocks.c +++ b/examples/shapes/shapes_clock_of_clocks.c @@ -4,7 +4,7 @@ * * Example complexity rating: [★★☆☆] 2/4 * -* Example originally created with raylib 5.5 +* Example originally created with raylib 5.5, last time updated with raylib 5.6-dev * * Example contributed by JP Mortiboys (@themushroompirates) and reviewed by Ramon Santamaria (@raysan5) * diff --git a/examples/shapes/shapes_mouse_trail.c b/examples/shapes/shapes_mouse_trail.c index b1cb706f2..88a7c0ce5 100644 --- a/examples/shapes/shapes_mouse_trail.c +++ b/examples/shapes/shapes_mouse_trail.c @@ -31,7 +31,7 @@ int main(void) const int screenWidth = 800; const int screenHeight = 450; - InitWindow(screenWidth, screenHeight, "raylib [shapes] example - Draw a mouse trail"); + InitWindow(screenWidth, screenHeight, "raylib [shapes] example - mouse trail"); // Array to store the history of mouse positions (our fixed-size queue) Vector2 trailPositions[MAX_TRAIL_LENGTH] = { 0 }; diff --git a/examples/shapes/shapes_pie_chart.c b/examples/shapes/shapes_pie_chart.c index 68993ed01..35250c5be 100644 --- a/examples/shapes/shapes_pie_chart.c +++ b/examples/shapes/shapes_pie_chart.c @@ -2,9 +2,9 @@ * * raylib [shapes] example - pie chart * -* Example complexity rating: [★★☆☆] 2/4 +* Example complexity rating: [★☆☆☆] 1/4 * -* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev +* Example originally created with raylib 5.5, last time updated with raylib 5.6 * * Example contributed by Gideon Serfontein (@GideonSerf) and reviewed by Ramon Santamaria (@raysan5) * @@ -32,7 +32,7 @@ int main(void) const int screenWidth = 800; const int screenHeight = 450; - InitWindow(screenWidth, screenHeight, "raylib [shapes] example - interactive pie chart"); + InitWindow(screenWidth, screenHeight, "raylib [shapes] example - pie chart"); #define MAX_SLICES 10 int sliceCount = 7; diff --git a/examples/shapes/shapes_recursive_tree.c b/examples/shapes/shapes_recursive_tree.c index 7ed02e5c2..4d0042419 100644 --- a/examples/shapes/shapes_recursive_tree.c +++ b/examples/shapes/shapes_recursive_tree.c @@ -1,6 +1,6 @@ /******************************************************************************************* * -* raylib [shapes] example - shapes recursive tree +* raylib [shapes] example - recursive tree * * Example complexity rating: [★★★☆] 3/4 * @@ -11,7 +11,7 @@ * 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) 2018-2025 Jopestpe (@jopestpe) +* Copyright (c) 2025 Jopestpe (@jopestpe) * ********************************************************************************************/ @@ -46,7 +46,7 @@ int main(void) const int screenWidth = 800; const int screenHeight = 450; - InitWindow(screenWidth, screenHeight, "raylib [shapes] example - shapes recursive tree"); + InitWindow(screenWidth, screenHeight, "raylib [shapes] example - recursive tree"); Vector2 start = { (screenWidth/2.0f) - 125.0f, (float)screenHeight }; float angle = 40.0f; diff --git a/examples/shapes/shapes_simple_particles.c b/examples/shapes/shapes_simple_particles.c index aae85f35d..5bef0917a 100644 --- a/examples/shapes/shapes_simple_particles.c +++ b/examples/shapes/shapes_simple_particles.c @@ -31,16 +31,17 @@ typedef enum ParticleType { FIRE } ParticleType; -static const char particleTypesChar[3][10] = { "WATER", "SMOKE", "FIRE" }; +static const char particleTypeNames[3][10] = { "WATER", "SMOKE", "FIRE" }; typedef struct Particle { + ParticleType type; // Particle type (WATER, SMOKE, FIRE) Vector2 position; // Particle position on screen Vector2 velocity; // Particle current speed and direction - bool alive; // Particle alive: inside screen and life time - float lifeTime; // Particle life time - ParticleType type; // Particle type (WATER, SMOKE, FIRE) float radius; // Particle radius Color color; // Particle color + + float lifeTime; // Particle life time + bool alive; // Particle alive: inside screen and life time } Particle; typedef struct CircularBuffer { @@ -68,7 +69,7 @@ int main(void) const int screenWidth = 800; const int screenHeight = 450; - InitWindow(screenWidth, screenHeight, "raylib [shapes] example - particles"); + InitWindow(screenWidth, screenHeight, "raylib [shapes] example - simple particles"); // Definition of particles Particle *particles = (Particle*)RL_CALLOC(MAX_PARTICLES, sizeof(Particle)); // Particle array @@ -90,13 +91,11 @@ int main(void) // Emit new particles: when emissionRate is 1, emit every frame if (emissionRate < 0) { - if (rand()%(-emissionRate) == 0) - EmitParticle(&circularBuffer, emitterPosition, currentType); + if (rand()%(-emissionRate) == 0) EmitParticle(&circularBuffer, emitterPosition, currentType); } else { - for (int i = 0; i <= emissionRate; ++i) - EmitParticle(&circularBuffer, emitterPosition, currentType); + for (int i = 0; i <= emissionRate; ++i) EmitParticle(&circularBuffer, emitterPosition, currentType); } // Update the parameters of each particle @@ -105,43 +104,37 @@ int main(void) UpdateCircularBuffer(&circularBuffer); // Change Particle Emission Rate (UP/DOWN arrows) - if (IsKeyPressed(KEY_UP)) - ++emissionRate; - if (IsKeyPressed(KEY_DOWN)) - --emissionRate; + if (IsKeyPressed(KEY_UP)) emissionRate++; + if (IsKeyPressed(KEY_DOWN)) emissionRate--; // Change Particle Type (LEFT/RIGHT arrows) - if (IsKeyPressed(KEY_RIGHT)) - (currentType == FIRE) ? (currentType = WATER) : ++currentType; - if (IsKeyPressed(KEY_LEFT)) - (currentType == WATER) ? (currentType = FIRE) : --currentType; + if (IsKeyPressed(KEY_RIGHT)) (currentType == FIRE)? (currentType = WATER) : currentType++; + if (IsKeyPressed(KEY_LEFT)) (currentType == WATER)? (currentType = FIRE) : currentType--; - if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) - emitterPosition = GetMousePosition(); + if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) emitterPosition = GetMousePosition(); + //---------------------------------------------------------------------------------- // Draw //---------------------------------------------------------------------------------- BeginDrawing(); - ClearBackground(RAYWHITE); + ClearBackground(RAYWHITE); - // Call the function with a loop to draw all particles - DrawParticles(&circularBuffer); + // Call the function with a loop to draw all particles + DrawParticles(&circularBuffer); - // Draw UI and Instructions - DrawRectangle(5, 5, 315, 75, Fade(SKYBLUE, 0.5f)); - DrawRectangleLines(5, 5, 315, 75, BLUE); + // Draw UI and Instructions + DrawRectangle(5, 5, 315, 75, Fade(SKYBLUE, 0.5f)); + DrawRectangleLines(5, 5, 315, 75, BLUE); - DrawText("CONTROLS:", 15, 15, 10, BLACK); - DrawText("UP/DOWN: Change Particle Emission Rate", 15, 35, 10, BLACK); - DrawText("LEFT/RIGHT: Change Particle Type (Water, Smoke, Fire)", 15, 55, 10, BLACK); + DrawText("CONTROLS:", 15, 15, 10, BLACK); + DrawText("UP/DOWN: Change Particle Emission Rate", 15, 35, 10, BLACK); + DrawText("LEFT/RIGHT: Change Particle Type (Water, Smoke, Fire)", 15, 55, 10, BLACK); - if (emissionRate < 0) - DrawText(TextFormat("Particles every %d frames | Type: %s", -emissionRate, particleTypesChar[currentType]), 15, 95, 10, DARKGRAY); - else - DrawText(TextFormat("%d Particles per frame | Type: %s", emissionRate + 1, particleTypesChar[currentType]), 15, 95, 10, DARKGRAY); + if (emissionRate < 0) DrawText(TextFormat("Particles every %d frames | Type: %s", -emissionRate, particleTypeNames[currentType]), 15, 95, 10, DARKGRAY); + else DrawText(TextFormat("%d Particles per frame | Type: %s", emissionRate + 1, particleTypeNames[currentType]), 15, 95, 10, DARKGRAY); - DrawFPS(screenWidth - 80, 10); + DrawFPS(screenWidth - 80, 10); EndDrawing(); //---------------------------------------------------------------------------------- @@ -163,6 +156,7 @@ int main(void) static void EmitParticle(CircularBuffer *circularBuffer, Vector2 emitterPosition, ParticleType type) { Particle *newParticle = AddToCircularBuffer(circularBuffer); + // If buffer is full, newParticle is NULL if (newParticle != NULL) { @@ -174,21 +168,25 @@ static void EmitParticle(CircularBuffer *circularBuffer, Vector2 emitterPosition float speed = (float)(rand()%10)/5.0f; switch (type) { - case WATER: - newParticle->radius = 5.0f; - newParticle->color = BLUE; - break; - case SMOKE: - newParticle->radius = 7.0f; - newParticle->color = GRAY; - break; - case FIRE: - newParticle->radius = 10.0f; - newParticle->color = YELLOW; - speed /= 10.0f; - break; - default: break; + case WATER: + { + newParticle->radius = 5.0f; + newParticle->color = BLUE; + } break; + case SMOKE: + { + newParticle->radius = 7.0f; + newParticle->color = GRAY; + } break; + case FIRE: + { + newParticle->radius = 10.0f; + newParticle->color = YELLOW; + speed /= 10.0f; + } break; + default: break; } + float direction = (float)(rand()%360); newParticle->velocity = (Vector2){ speed*cosf(direction*DEG2RAD), speed*sinf(direction*DEG2RAD) }; } @@ -253,6 +251,7 @@ static void UpdateParticles(CircularBuffer *circularBuffer, int screenWidth, int circularBuffer->buffer[i].alive = false; } } + static void UpdateCircularBuffer(CircularBuffer *circularBuffer) { // Update circular buffer: advance tail over dead particles diff --git a/examples/shapes/shapes_starfield.c b/examples/shapes/shapes_starfield.c index 457912dec..df543d066 100644 --- a/examples/shapes/shapes_starfield.c +++ b/examples/shapes/shapes_starfield.c @@ -1,10 +1,10 @@ /******************************************************************************************* * -* raylib [shapes] example - simple starfield +* raylib [shapes] example - starfield * * Example complexity rating: [★☆☆☆] 1/4 * -* Example originally created with raylib 5.5 +* Example originally created with raylib 5.5, last time updated with raylib 5.6-dev * * Example contributed by JP Mortiboys (@themushroompirates) and reviewed by Ramon Santamaria (@raysan5) * diff --git a/examples/shapes/shapes_triangle_strip.c b/examples/shapes/shapes_triangle_strip.c index ee4556d25..d8b5faeea 100644 --- a/examples/shapes/shapes_triangle_strip.c +++ b/examples/shapes/shapes_triangle_strip.c @@ -11,7 +11,7 @@ * 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) 2018-2025 Jopestpe (@jopestpe) +* Copyright (c) 2025 Jopestpe (@jopestpe) * ********************************************************************************************/ diff --git a/examples/text/text_words_alignment.c b/examples/text/text_words_alignment.c index 0f012ab75..352b3cd37 100644 --- a/examples/text/text_words_alignment.c +++ b/examples/text/text_words_alignment.c @@ -1,10 +1,10 @@ /******************************************************************************************* * -* raylib [text] example - text alignment +* raylib [text] example - words alignment * * Example complexity rating: [★☆☆☆] 1/4 * -* Example originally created with raylib 5.0, last time updated with raylib 5.5 +* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev * * Example contributed by JP Mortiboys (@themushroompirates) and reviewed by Ramon Santamaria (@raysan5) * @@ -38,7 +38,7 @@ int main(void) const int screenWidth = 800; const int screenHeight = 450; - InitWindow(screenWidth, screenHeight, "raylib [text] example - text alignment"); + InitWindow(screenWidth, screenHeight, "raylib [text] example - words alignment"); // Define the rectangle we will draw the text in Rectangle textContainerRect = (Rectangle){ screenWidth/2-screenWidth/4, screenHeight/2-screenHeight/3, screenWidth/2, screenHeight*2/3 }; diff --git a/projects/VS2022/examples/core_clipboard_text.vcxproj b/projects/VS2022/examples/core_clipboard_text.vcxproj new file mode 100644 index 000000000..5b0b3e16f --- /dev/null +++ b/projects/VS2022/examples/core_clipboard_text.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 + + + + {124935CC-73BB-489E-92E8-4F922A85DB5D} + Win32Proj + core_clipboard_text + 10.0 + core_clipboard_text + + + + 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/shapes_clock_of_clocks.vcxproj b/projects/VS2022/examples/shapes_clock_of_clocks.vcxproj new file mode 100644 index 000000000..94b1713ec --- /dev/null +++ b/projects/VS2022/examples/shapes_clock_of_clocks.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 + + + + {AC215730-2B5F-4498-B7F5-5DB80AEFCA5F} + Win32Proj + shapes_clock_of_clocks + 10.0 + shapes_clock_of_clocks + + + + 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\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + 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/shapes_mouse_trail.vcxproj b/projects/VS2022/examples/shapes_mouse_trail.vcxproj new file mode 100644 index 000000000..edc65c027 --- /dev/null +++ b/projects/VS2022/examples/shapes_mouse_trail.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 + + + + {0835E6BF-0170-4E99-A55C-E06E1EF4C3B2} + Win32Proj + shapes_mouse_trail + 10.0 + shapes_mouse_trail + + + + 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\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + 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/shapes_starfield.vcxproj b/projects/VS2022/examples/shapes_starfield.vcxproj new file mode 100644 index 000000000..5cfc0a6d3 --- /dev/null +++ b/projects/VS2022/examples/shapes_starfield.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 + + + + {EA4AD5A7-DB95-43C0-9A67-2D94146BCF91} + Win32Proj + shapes_starfield + 10.0 + shapes_starfield + + + + 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\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + 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/text_words_alignment.vcxproj b/projects/VS2022/examples/text_words_alignment.vcxproj new file mode 100644 index 000000000..be9c1614e --- /dev/null +++ b/projects/VS2022/examples/text_words_alignment.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 + + + + {29B00F47-BE91-4A1F-B87D-B1302F038316} + Win32Proj + text_words_alignment + 10.0 + text_words_alignment + + + + 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\text + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\text + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\text + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\text + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\text + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\text + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\text + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\text + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\text + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\text + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\text + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\text + 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 d17c569c5..5a784adbe 100644 --- a/projects/VS2022/raylib.sln +++ b/projects/VS2022/raylib.sln @@ -377,6 +377,16 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_directory_files", "exa EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_simple_particles", "examples\shapes_simple_particles.vcxproj", "{497FDF54-9762-4048-A833-61CC3980A0FB}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "text_words_alignment", "examples\text_words_alignment.vcxproj", "{29B00F47-BE91-4A1F-B87D-B1302F038316}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_clipboard_text", "examples\core_clipboard_text.vcxproj", "{124935CC-73BB-489E-92E8-4F922A85DB5D}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_clock_of_clocks", "examples\shapes_clock_of_clocks.vcxproj", "{AC215730-2B5F-4498-B7F5-5DB80AEFCA5F}" +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}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug.DLL|ARM64 = Debug.DLL|ARM64 @@ -4663,6 +4673,126 @@ Global {497FDF54-9762-4048-A833-61CC3980A0FB}.Release|x64.Build.0 = Release|x64 {497FDF54-9762-4048-A833-61CC3980A0FB}.Release|x86.ActiveCfg = Release|Win32 {497FDF54-9762-4048-A833-61CC3980A0FB}.Release|x86.Build.0 = Release|Win32 + {29B00F47-BE91-4A1F-B87D-B1302F038316}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 + {29B00F47-BE91-4A1F-B87D-B1302F038316}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 + {29B00F47-BE91-4A1F-B87D-B1302F038316}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {29B00F47-BE91-4A1F-B87D-B1302F038316}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {29B00F47-BE91-4A1F-B87D-B1302F038316}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {29B00F47-BE91-4A1F-B87D-B1302F038316}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {29B00F47-BE91-4A1F-B87D-B1302F038316}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {29B00F47-BE91-4A1F-B87D-B1302F038316}.Debug|ARM64.Build.0 = Debug|ARM64 + {29B00F47-BE91-4A1F-B87D-B1302F038316}.Debug|x64.ActiveCfg = Debug|x64 + {29B00F47-BE91-4A1F-B87D-B1302F038316}.Debug|x64.Build.0 = Debug|x64 + {29B00F47-BE91-4A1F-B87D-B1302F038316}.Debug|x86.ActiveCfg = Debug|Win32 + {29B00F47-BE91-4A1F-B87D-B1302F038316}.Debug|x86.Build.0 = Debug|Win32 + {29B00F47-BE91-4A1F-B87D-B1302F038316}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 + {29B00F47-BE91-4A1F-B87D-B1302F038316}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 + {29B00F47-BE91-4A1F-B87D-B1302F038316}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {29B00F47-BE91-4A1F-B87D-B1302F038316}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {29B00F47-BE91-4A1F-B87D-B1302F038316}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {29B00F47-BE91-4A1F-B87D-B1302F038316}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {29B00F47-BE91-4A1F-B87D-B1302F038316}.Release|ARM64.ActiveCfg = Release|ARM64 + {29B00F47-BE91-4A1F-B87D-B1302F038316}.Release|ARM64.Build.0 = Release|ARM64 + {29B00F47-BE91-4A1F-B87D-B1302F038316}.Release|x64.ActiveCfg = Release|x64 + {29B00F47-BE91-4A1F-B87D-B1302F038316}.Release|x64.Build.0 = Release|x64 + {29B00F47-BE91-4A1F-B87D-B1302F038316}.Release|x86.ActiveCfg = Release|Win32 + {29B00F47-BE91-4A1F-B87D-B1302F038316}.Release|x86.Build.0 = Release|Win32 + {124935CC-73BB-489E-92E8-4F922A85DB5D}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 + {124935CC-73BB-489E-92E8-4F922A85DB5D}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 + {124935CC-73BB-489E-92E8-4F922A85DB5D}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {124935CC-73BB-489E-92E8-4F922A85DB5D}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {124935CC-73BB-489E-92E8-4F922A85DB5D}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {124935CC-73BB-489E-92E8-4F922A85DB5D}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {124935CC-73BB-489E-92E8-4F922A85DB5D}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {124935CC-73BB-489E-92E8-4F922A85DB5D}.Debug|ARM64.Build.0 = Debug|ARM64 + {124935CC-73BB-489E-92E8-4F922A85DB5D}.Debug|x64.ActiveCfg = Debug|x64 + {124935CC-73BB-489E-92E8-4F922A85DB5D}.Debug|x64.Build.0 = Debug|x64 + {124935CC-73BB-489E-92E8-4F922A85DB5D}.Debug|x86.ActiveCfg = Debug|Win32 + {124935CC-73BB-489E-92E8-4F922A85DB5D}.Debug|x86.Build.0 = Debug|Win32 + {124935CC-73BB-489E-92E8-4F922A85DB5D}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 + {124935CC-73BB-489E-92E8-4F922A85DB5D}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 + {124935CC-73BB-489E-92E8-4F922A85DB5D}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {124935CC-73BB-489E-92E8-4F922A85DB5D}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {124935CC-73BB-489E-92E8-4F922A85DB5D}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {124935CC-73BB-489E-92E8-4F922A85DB5D}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {124935CC-73BB-489E-92E8-4F922A85DB5D}.Release|ARM64.ActiveCfg = Release|ARM64 + {124935CC-73BB-489E-92E8-4F922A85DB5D}.Release|ARM64.Build.0 = Release|ARM64 + {124935CC-73BB-489E-92E8-4F922A85DB5D}.Release|x64.ActiveCfg = Release|x64 + {124935CC-73BB-489E-92E8-4F922A85DB5D}.Release|x64.Build.0 = Release|x64 + {124935CC-73BB-489E-92E8-4F922A85DB5D}.Release|x86.ActiveCfg = Release|Win32 + {124935CC-73BB-489E-92E8-4F922A85DB5D}.Release|x86.Build.0 = Release|Win32 + {AC215730-2B5F-4498-B7F5-5DB80AEFCA5F}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 + {AC215730-2B5F-4498-B7F5-5DB80AEFCA5F}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 + {AC215730-2B5F-4498-B7F5-5DB80AEFCA5F}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {AC215730-2B5F-4498-B7F5-5DB80AEFCA5F}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {AC215730-2B5F-4498-B7F5-5DB80AEFCA5F}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {AC215730-2B5F-4498-B7F5-5DB80AEFCA5F}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {AC215730-2B5F-4498-B7F5-5DB80AEFCA5F}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {AC215730-2B5F-4498-B7F5-5DB80AEFCA5F}.Debug|ARM64.Build.0 = Debug|ARM64 + {AC215730-2B5F-4498-B7F5-5DB80AEFCA5F}.Debug|x64.ActiveCfg = Debug|x64 + {AC215730-2B5F-4498-B7F5-5DB80AEFCA5F}.Debug|x64.Build.0 = Debug|x64 + {AC215730-2B5F-4498-B7F5-5DB80AEFCA5F}.Debug|x86.ActiveCfg = Debug|Win32 + {AC215730-2B5F-4498-B7F5-5DB80AEFCA5F}.Debug|x86.Build.0 = Debug|Win32 + {AC215730-2B5F-4498-B7F5-5DB80AEFCA5F}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 + {AC215730-2B5F-4498-B7F5-5DB80AEFCA5F}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 + {AC215730-2B5F-4498-B7F5-5DB80AEFCA5F}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {AC215730-2B5F-4498-B7F5-5DB80AEFCA5F}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {AC215730-2B5F-4498-B7F5-5DB80AEFCA5F}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {AC215730-2B5F-4498-B7F5-5DB80AEFCA5F}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {AC215730-2B5F-4498-B7F5-5DB80AEFCA5F}.Release|ARM64.ActiveCfg = Release|ARM64 + {AC215730-2B5F-4498-B7F5-5DB80AEFCA5F}.Release|ARM64.Build.0 = Release|ARM64 + {AC215730-2B5F-4498-B7F5-5DB80AEFCA5F}.Release|x64.ActiveCfg = Release|x64 + {AC215730-2B5F-4498-B7F5-5DB80AEFCA5F}.Release|x64.Build.0 = Release|x64 + {AC215730-2B5F-4498-B7F5-5DB80AEFCA5F}.Release|x86.ActiveCfg = Release|Win32 + {AC215730-2B5F-4498-B7F5-5DB80AEFCA5F}.Release|x86.Build.0 = Release|Win32 + {0835E6BF-0170-4E99-A55C-E06E1EF4C3B2}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 + {0835E6BF-0170-4E99-A55C-E06E1EF4C3B2}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 + {0835E6BF-0170-4E99-A55C-E06E1EF4C3B2}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {0835E6BF-0170-4E99-A55C-E06E1EF4C3B2}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {0835E6BF-0170-4E99-A55C-E06E1EF4C3B2}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {0835E6BF-0170-4E99-A55C-E06E1EF4C3B2}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {0835E6BF-0170-4E99-A55C-E06E1EF4C3B2}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {0835E6BF-0170-4E99-A55C-E06E1EF4C3B2}.Debug|ARM64.Build.0 = Debug|ARM64 + {0835E6BF-0170-4E99-A55C-E06E1EF4C3B2}.Debug|x64.ActiveCfg = Debug|x64 + {0835E6BF-0170-4E99-A55C-E06E1EF4C3B2}.Debug|x64.Build.0 = Debug|x64 + {0835E6BF-0170-4E99-A55C-E06E1EF4C3B2}.Debug|x86.ActiveCfg = Debug|Win32 + {0835E6BF-0170-4E99-A55C-E06E1EF4C3B2}.Debug|x86.Build.0 = Debug|Win32 + {0835E6BF-0170-4E99-A55C-E06E1EF4C3B2}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 + {0835E6BF-0170-4E99-A55C-E06E1EF4C3B2}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 + {0835E6BF-0170-4E99-A55C-E06E1EF4C3B2}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {0835E6BF-0170-4E99-A55C-E06E1EF4C3B2}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {0835E6BF-0170-4E99-A55C-E06E1EF4C3B2}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {0835E6BF-0170-4E99-A55C-E06E1EF4C3B2}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {0835E6BF-0170-4E99-A55C-E06E1EF4C3B2}.Release|ARM64.ActiveCfg = Release|ARM64 + {0835E6BF-0170-4E99-A55C-E06E1EF4C3B2}.Release|ARM64.Build.0 = Release|ARM64 + {0835E6BF-0170-4E99-A55C-E06E1EF4C3B2}.Release|x64.ActiveCfg = Release|x64 + {0835E6BF-0170-4E99-A55C-E06E1EF4C3B2}.Release|x64.Build.0 = Release|x64 + {0835E6BF-0170-4E99-A55C-E06E1EF4C3B2}.Release|x86.ActiveCfg = Release|Win32 + {0835E6BF-0170-4E99-A55C-E06E1EF4C3B2}.Release|x86.Build.0 = Release|Win32 + {EA4AD5A7-DB95-43C0-9A67-2D94146BCF91}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 + {EA4AD5A7-DB95-43C0-9A67-2D94146BCF91}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 + {EA4AD5A7-DB95-43C0-9A67-2D94146BCF91}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {EA4AD5A7-DB95-43C0-9A67-2D94146BCF91}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {EA4AD5A7-DB95-43C0-9A67-2D94146BCF91}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {EA4AD5A7-DB95-43C0-9A67-2D94146BCF91}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {EA4AD5A7-DB95-43C0-9A67-2D94146BCF91}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {EA4AD5A7-DB95-43C0-9A67-2D94146BCF91}.Debug|ARM64.Build.0 = Debug|ARM64 + {EA4AD5A7-DB95-43C0-9A67-2D94146BCF91}.Debug|x64.ActiveCfg = Debug|x64 + {EA4AD5A7-DB95-43C0-9A67-2D94146BCF91}.Debug|x64.Build.0 = Debug|x64 + {EA4AD5A7-DB95-43C0-9A67-2D94146BCF91}.Debug|x86.ActiveCfg = Debug|Win32 + {EA4AD5A7-DB95-43C0-9A67-2D94146BCF91}.Debug|x86.Build.0 = Debug|Win32 + {EA4AD5A7-DB95-43C0-9A67-2D94146BCF91}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 + {EA4AD5A7-DB95-43C0-9A67-2D94146BCF91}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 + {EA4AD5A7-DB95-43C0-9A67-2D94146BCF91}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {EA4AD5A7-DB95-43C0-9A67-2D94146BCF91}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {EA4AD5A7-DB95-43C0-9A67-2D94146BCF91}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {EA4AD5A7-DB95-43C0-9A67-2D94146BCF91}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {EA4AD5A7-DB95-43C0-9A67-2D94146BCF91}.Release|ARM64.ActiveCfg = Release|ARM64 + {EA4AD5A7-DB95-43C0-9A67-2D94146BCF91}.Release|ARM64.Build.0 = Release|ARM64 + {EA4AD5A7-DB95-43C0-9A67-2D94146BCF91}.Release|x64.ActiveCfg = Release|x64 + {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 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -4830,7 +4960,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} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} + {6B1A933E-71B8-4C1F-9E79-02D98830E671} = {8D3C83B7-F1E0-4C2E-9E34-EE5F6AB2502A} {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} @@ -4839,9 +4969,9 @@ Global {3B27F358-2679-4F38-B297-17B536F580BB} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} {718FCBD0-591D-448C-B7D5-9F1CA8544E7B} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} {19CA0070-B4B2-4394-90B7-D0C259AA35BA} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E} = {278D8859-20B1-428F-8448-064F46E1F021} - {9DB1F875-6E65-4195-B23F-ED8095C0B99C} = {5317807F-61D4-4E0F-B6DC-2D9F12621ED9} - {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} + {9DB1F875-6E65-4195-B23F-ED8095C0B99C} = {278D8859-20B1-428F-8448-064F46E1F021} + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F} = {278D8859-20B1-428F-8448-064F46E1F021} {8E132D5A-2C00-48D0-8747-97E41356F26F} = {278D8859-20B1-428F-8448-064F46E1F021} {A4662163-83E7-4309-8CAA-B0BF13655FE6} = {AF5BEC5C-1F2B-4DA8-B12D-D09FE569237C} {5F4B766F-DD52-4B53-B6C3-BC7611E17F20} = {278D8859-20B1-428F-8448-064F46E1F021} @@ -4853,6 +4983,11 @@ Global {61997220-5383-4AE5-ABD4-5F45AE1B0F2A} = {278D8859-20B1-428F-8448-064F46E1F021} {7467E9AE-844F-444D-8A3F-17397544BA21} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} {497FDF54-9762-4048-A833-61CC3980A0FB} = {278D8859-20B1-428F-8448-064F46E1F021} + {29B00F47-BE91-4A1F-B87D-B1302F038316} = {8D3C83B7-F1E0-4C2E-9E34-EE5F6AB2502A} + {124935CC-73BB-489E-92E8-4F922A85DB5D} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} + {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} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {E926C768-6307-4423-A1EC-57E95B1FAB29} diff --git a/tools/rexm/examples_report.md b/tools/rexm/examples_report.md index e9a70930b..e55610a30 100644 --- a/tools/rexm/examples_report.md +++ b/tools/rexm/examples_report.md @@ -86,6 +86,7 @@ Example elements validated: | shapes_dashed_line | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shapes_triangle_strip | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shapes_vector_angle | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| shapes_pie_chart | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | textures_logo_raylib | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | textures_srcrec_dstrec | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | textures_image_drawing | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | @@ -126,6 +127,7 @@ Example elements validated: | text_3d_drawing | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | text_codepoints_loading | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | text_inline_styling | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| text_words_alignment | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | models_animation_playing | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | models_billboard_rendering | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | models_box_collisions | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | @@ -196,3 +198,8 @@ Example elements validated: | embedded_files_loading | ✔ | ❌ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | web_basic_window | ✔ | ❌ | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shapes_kaleidoscope | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| core_clipboard_text | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| shapes_clock_of_clocks | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| shapes_mouse_trail | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| shapes_simple_particles | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| shapes_starfield | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | From af068ec020f2c57f0b4de228e8c2721c20aa6a94 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 15 Oct 2025 20:18:44 +0200 Subject: [PATCH 123/167] Reviewed dynamic library building #5270 --- src/Makefile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Makefile b/src/Makefile index e767d21d0..0d4ca9ac7 100644 --- a/src/Makefile +++ b/src/Makefile @@ -519,7 +519,7 @@ endif #------------------------------------------------------------------------------------------------ LDFLAGS = $(CUSTOM_LDFLAGS) -L. -L$(RAYLIB_RELEASE_PATH) -ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW) +ifeq ($(TARGET_PLATFORM),$(filter $(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW PLATFORM_DESKTOP_SDL PLATFORM_DESKTOP_RGFW)) ifeq ($(PLATFORM_OS),WINDOWS) ifneq ($(CC), tcc) LDFLAGS += -Wl,--out-implib,$(RAYLIB_RELEASE_PATH)/lib$(RAYLIB_LIB_NAME)dll.a @@ -536,7 +536,6 @@ ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW) endif endif ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_SDL) - LDFLAGS += -Wl,-soname,lib$(RAYLIB_LIB_NAME).so.$(RAYLIB_API_VERSION) LDFLAGS += -L$(SDL_LIBRARY_PATH) endif ifeq ($(TARGET_PLATFORM),$(filter $(TARGET_PLATFORM),PLATFORM_WEB PLATFORM_WEB_RGFW)) From c6f9f76afb0543d0091dedfbb1b549f1b45397e3 Mon Sep 17 00:00:00 2001 From: GideonSerf Date: Thu, 16 Oct 2025 09:53:55 +0200 Subject: [PATCH 124/167] [examples] Added donut pie charts to `shapes_pie_chart` (#5277) * Added donut chart option to pie chart example * Increased example description buffer size * Testing mouse trail building * Removed unused variable --------- Co-authored-by: Gideon Serfontein --- examples/shapes/shapes_mouse_trail.c | 6 +++--- examples/shapes/shapes_pie_chart.c | 26 +++++++++++++++++++++++--- examples/shapes/shapes_pie_chart.png | Bin 17457 -> 15301 bytes 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/examples/shapes/shapes_mouse_trail.c b/examples/shapes/shapes_mouse_trail.c index 88a7c0ce5..ad1166548 100644 --- a/examples/shapes/shapes_mouse_trail.c +++ b/examples/shapes/shapes_mouse_trail.c @@ -1,6 +1,3 @@ -#include "raylib.h" -#include "raymath.h" - /******************************************************************************************* * * raylib [shapes] example - Draw a mouse trail (position history) @@ -18,6 +15,9 @@ * ********************************************************************************************/ +#include "raylib.h" +#include "raymath.h" + // Define the maximum number of positions to store in the trail #define MAX_TRAIL_LENGTH 30 diff --git a/examples/shapes/shapes_pie_chart.c b/examples/shapes/shapes_pie_chart.c index 35250c5be..1fa938905 100644 --- a/examples/shapes/shapes_pie_chart.c +++ b/examples/shapes/shapes_pie_chart.c @@ -36,6 +36,7 @@ int main(void) #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}; @@ -45,6 +46,7 @@ int main(void) bool showValues = true; bool showPercentages = false; + bool showDonut = false; int hoveredSlice = -1; Rectangle scrollPanelBounds = {0}; Vector2 scrollContentOffset = {0}; @@ -72,7 +74,7 @@ int main(void) const Rectangle panelRect = { panelPos.x, panelPos.y, (float)panelWidth, - (float)screenHeight - 2.0f*panelMargin + (float)screenHeight - 2.0f*panelMargin }; // Pie chart geometry @@ -159,6 +161,12 @@ int main(void) DrawText(labelText, (int)labelPos.x, (int)labelPos.y, 18, WHITE); } + if(showDonut) + { + // Draw inner circle to create donut effect + DrawCircle(center.x, center.y, donutInnerRadius, RAYWHITE); + } + startAngle += sweepAngle; } //------------------------------------------------------------------------------ @@ -177,17 +185,29 @@ int main(void) currentY += 30; GuiCheckBox((Rectangle){ panelPos.x + 20, (float)currentY, 20, 20 }, "Show Percentages", &showPercentages); - currentY += 40; + currentY += 30; + + GuiCheckBox((Rectangle){ panelPos.x + 20, (float)currentY, 20, 20 }, "Make Donut", &showDonut); + currentY += 30; + + if(showDonut) + { + GuiSliderBar((Rectangle){ panelPos.x + 80, (float)currentY, panelRect.width - 100, 30 }, + "Inner Radius", NULL, &donutInnerRadius, 5.0f, radius - 10.0f); + currentY += 40; + } GuiLine((Rectangle){ panelPos.x + 10, (float)currentY, panelRect.width - 20, 1 }, NULL); currentY += 20; + + // 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; GuiScrollPanel(scrollPanelBounds, NULL, - (Rectangle){ 0, 0, panelRect.width - 20, (float)contentHeight }, + (Rectangle){ 0, 0, panelRect.width - 25, (float)contentHeight }, &scrollContentOffset, &view); const float contentX = view.x + scrollContentOffset.x; // left of content diff --git a/examples/shapes/shapes_pie_chart.png b/examples/shapes/shapes_pie_chart.png index bad7960f476c0d66e32df5d38b7aded5a81b5a75..afc0a8c2d930a695661611746b3fb83083dc7eff 100644 GIT binary patch literal 15301 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 YRBozKYo7$4-m>W(I;Nd<&_3k<0K(vKCjbBd literal 17457 zcmbWf2{_d2|2{r5m?oK+vdu_Dr$mcow4gE43~h`S``$8x3Y8GUh^AsJb+l(4ODB7B zh%7}?N5*m@9cvUKOQtZw|9Q`-%sKr&-|PCH>zb>}nfLoyU(ai~@B5j{6f+aFI8Gb} zgQ0hs?%WT9i73Nh@TVvw_&;)ovueOU@YDNEcEGahRt$hYM5#vmj9{?5=q2A=#K7N+ zy-aOR!(dA*p%47I=e;8^m~r*4okj=!96z;hfAHH2%TLoy$bLjk;&lYtU;U}&0OB<) z9!d9mt6L&YUSzgBhPW=j1>Rfyr@GCS!;%TJT8I62PI9Lt^Air8^o=eUFY1eu4}Dzt z(R^;Eb8bc-^a*S0HrIpxg;^yrpnr=LoGn^YYggc|4rvt+fh>B1I0tO?1ue*$(N0dNwqlpX{j1f&C!u-GoR$&6#G=SRe zQk9m1tpp#~C`KFwlLQ~wBxs7U=zlb4(AVM=T>7^|Cv}nUr)#s=OPA(*^p9dTwMKQC zly3=YEG@noG;(RakC?v4#sdj+-}?T*4-GF1%t;RLd46jr84h2@>vIY!iJM&s8wy2y zzFYEic;k}^^F?8>w(ZteWfMtka_E+iXQJWu7ysKp*D+gl1N@On z6Aq$c1$IeIOUsRc?Y{Qu6Ln|S43!0$>!p34i0-L1s(oH5)MZ#P(W0BzFPYO4tEt>f z*xla?82xW*+K#hbCO$dDp0Rg(YyQ!fQVPw}J=WfIz^-LU3C_#pe74M4D^ywWBHowZ&*a!rPklWun4Y37 zEIutnp3`8cL9_&2GOG)F+NN6yzEG=Qo4$F?@o&)GT{$fN#A3Wb6aR2zXXSd=Cc_dUUOJ|) zO=f;Xf^Bow$2I$=z-0sK4gVra|KfWET%&K=6PbVp!+$D1g7*C{HfF3Sj}G$umJ;Ce z+e`<>f+!Ww9AA%r=xWHLDq72cHNu%uO9rQhy0S|f4Mm^_t|LDm$7i}a@u*7H!1q8d zpqnPe*=?-;HQjJYg}T6Jpo~TQ&f?6jT%0`)GY8fST#K_m?(tYCbAK<}P^032;4$ml z%#+_zT%@-Ra3n@W1+L|Kii^T#G`nU`Fq5Hg!S_YE(&#s|CMofLjv zZ`!j09bXY4E43T-y^Sn9vF9|7aOIAyWUArs6%qo+*G3N2`A`oFZ+qxv&804%lom|< zMpFgr5uTy4X#;LMFJJsFNidF7{QAQLbW+W(zn-bh+!Ct;ZWYYGYZ>mUw<0>ZW>>_8 z8?zE3EAyAsm6{Tu^lf$Q&*MpyVC#21?B zv-pQn2BZW`%?4L^-s8SApK6L`55y@N)(zTv?DJS*EhZ-FfIE}727Uj{@3J9l2l5gA zU~JbXcoT-DJv{S>I>qwl&XOfyQ|Ev_ zSs8Tt3MHE+?c$|HI5E*fIIq0T=!`cJ$hm9%`65$0zt6Yl?c42HW3nERLCm1pn%fQD zU2f7+H}P$*bewgb9C{|Bfr>hH*^&q|h(Me_kF={w43U|x&n;J{Usr}=BlwgxP$I1H zMXr)Ku2mXGx|b+ec_n;}${KX`C3BG=X&&oIhu{>b?O6Y=aWwo5F6 zu1bS%7AZXwv<7@Oqq&#?okan~_ZhXCHe zQeU-87_c`AVyjo7v))87ZT_n9c~-1be(`oQZbqUsGp{8z;q*5HMg1UVRPgS~>5W{Q zFuEX9xZ02#K0~|tMUVN>vVxF*^2p;YTZ*f18%DhjaO`*fvXwwGy? zXYu&@bBe}38qNteTeLgwC^#H`rSv@WFWVOF;yPoI=_qb%*red;UBEob{@+iZj75Hl z8_*HY6F7=x^^EXRw|ght97?AqeC*Q`I&UjH;;tMFQuKUfcR1evy+da*e7gwUa@9uu zKGl4{-*pYf9k;W!@|>kBwhZ(YejslweO~PJ+-|)2Ce_iurI5Cjvm?Rg(q;axJkUa? z)fiW1J*V9xWP7wX-Oj*1N-wOwU09vzJ=hqKIbGLCiH{_dNJ;WN#E}Cy(<>23`{)J= z-M*zbUDrzIl(}c5u4kl8Pjl*o^+a51h=D4dxk^?r944NnqJ%D5$xh-GW&4Y;hyrM~w%y6f+la0T4I}FA*+rO&WUaH$1cp}p` zr=Z%lFBQHbHs;Pahx2gcB(NkgPg6=;y?VyKvv#|=)=vAv-KT| z(5JA2#<>`;SJJZk)N>(>L&DOy|ruQ{zp| ziK`S&@M3#=qW=9wySG4@fmweN=sN|P-+A?b$h*JAGJsD$*x&pGvDs^~K7P~>s$ zK)&Q4IJsxqy=SHq@&_jLf;j00Gc#A@#8%%+_WE1?$(cjXDedBKsLheAi4Wu!>+$D# zZ*x2bH!{MxP`m_d#+ z3D?8LUMd)}Bp&p%A8FxaMn(tzS?vC8GGM>X^AI_4QzGe!yo>1HuUGu~aF~f`#=v`s{56 zJ$k5y#s$^T(3D9@TPsn2nA3iqt&B*)8bK!|GP^~YMWtN=X>IGJJ`3W@;QMd=JcjR& zHIE#6?(X5yqstzQ5fNK`DcLmeDeAt)R$*`P;{dsX;1q<5*Sbhh9m}MN?QBtODWCJV zw<}54&35m};@oRzdqfXj`?9UzOY@r{@2(4oWjifY2uH(Sr~hl^?G85=`3!7trt9LE z-kZ>`Zki-q@w0r0IL|4aklPCEoM^G~nD&mr15ruEGP#^g1?HQ&LFNtp0*m?y==FD?coCt$*a zJ>CheVxkowHbtxpuV`WsK_FY*qldfXZAedh2UUS9rDHBgcL&Rm?~&HyVzm;GE(RtE zSw$-aL&uQ%ogy*rn2XG#wW)AcW^c>Lj&=u+zl!f9``z+F~`dnsMOoXXn> zHrKdvV>6p$Z!cK!&xtC3n;Z#q$lO(_Lx2+WM(U;yf;`mV9%|eI>moPU0E^_%YMvEy zTO+3CyIQv+@C>=@nJq{H4bVl_34~BBIsUAA;UvG#3z&0xOVJHmO+q)ktEXyxNaE*p z28pO)eXaArB^lxRX!l4fc6HWMC3#54{Kt3B*m#kJu8Z4dT`xn&j?(b$Z^3!$Y~(9hEqUFSwW6NS`L{cv~Hz7WPB^1>zqU8 zZku^jNFi>t4D080E#(lJY9k`y|zz#y9v(RYxChV~@1 zj|!$>e-G7`i(Q3nX-JH`iaa>9@8>rus8*WJd2no86n;bBdy_z@>=xv!k4!PS4b-rs zwdpPjoor96p?g7DglAmvtXRn-L9cKf7}@w!tD)NR!QgW5<5bDxxl>}<4J5(>hE zzqF$Ghf&)Glja?TxvdqA^rR3*LkUe<%`BJq%u0p42ba8*aB3-ceyTU72Q!M4kar`A} zYWH%#2CBhZ!Q%cd?SgI5JddwyP>#RCH0#=zFh&!s&R$B`5&OSTO`}bk@sUU~;z0gN zA3?)#%M^!E8P!smS*b$oHzZqI+-A>P6kTw4)Ha7F6HF}w#Z4nZzdYly#sfX?_X>y(lyD}K=Lk*JD&C=yzRjoYYf`SI8TdECH zIYF_Rh|hE1a^_$R!~XFQ#Hsz5z`UiZw8}I%or+UW&_3mmH(WcClvY4CJlyM^1)>yv z?(L)mZ)t^Z0U~)2)@uyEbq@uOJ?2k~#+Wi4bgVfR{enGc>z-htp!B+AZfmEVNBd#A zgTi=i@QzOSBv_Y3CPLc+GpFJziRHF4~bw zFn&(0_l1>#<-eE2*t=iUA@dcgV{%s|?YU#aR9{i1fWBg`@W^10Oqdt~Gb;SB)$r8749`Z-Qs=XO zLcK3MC|S@C1^7UhFwfW!`dXZ_mF6k`=E%U|)=uMnp0B)vdK;&|k(sx3|x8Si5*r)}t#v1!Em;{kMAp zJwEl@e{yd>Ekj@1b+KLiQdClJYkJFD!?`IAs_JyvcIlYK;lv0(mQ?&L=2r)r7pqG? z(axnYY>^^_FrH73Q7 z?8%_^51n3$$CJG!>a#T4Z!6eXDL{dATU}wZ?P=A+JRi@%&Gan{#MLWQuxMj`b%g** zOH!#)*{sTa@`s_Twe6(hYw-D}>DS-ZK^3A1V{0#d3 zF@{f3FwS|4RAZ@ZI6)g70W$FUpvqtG?f1{VZXTFC&O2G5E7n`+6m)C1VfnFRqi=65 z=siT`q3b5H8fT|*;6a?U_lD9lvrEnC!E}=&Cj6=X=!%H3&QnsoNlh{$sG~0zU3b(A zzL;KCUZ(nh&FJlET`O*C5I_DYi4mBH%6RiTrcS3`S?LOLXV-3CR817(YV^-Of#L7Z z+oGB{VpbWr6DJjtF;JqSBW_BFrzbP2dbV}06tCGuB0igCK{h_#K+_Z*P8GAc%X#@W9rt}) zcPU}}dk=?wQFP0V-eJ7TYb~96IgMw(Fq4yky9MfsB0Z>xP~@?aLs$k)J>aEb6_VF+;5+!P!WOY@J)mVAH~5y;a{SvDsD=zEvAN1KP@Lu43t_fdD4z|X1{_=S}I+| z58+8>bcP^j4!OZZ<5NbWSZ6mW^9p63mzUN%wKNx2Z^(KiV?BM)7=HQr{3~Y=CS*pm zS?Fvy{u|u9$=8HjA}1AVFun8pBNtVUBXr3z(Yq`8k7(5Unr@bk2^4zb2x0^IX0&PL ztUI0y&-m37&WP>g#Avd}+;03RT%+L^ZP+7JSrnzq%-L(SE)mP*k(lGcTOS%uS?nkO zgs==ft5Ki3DATm_w_6nA=dq#XVyjnjroK{$NSTmjquS@`(zw}#v{jPU*UI*2Cka`p zg!u~i2K>60`gtpZEoKcJsDMpmw687zy8{F?I(!lvBZ{v$F zA#2u7L`7Ffkn5eUU1zLys}QkFABkNrJYbRVE>x{+*o=(ZV!v>tzA}QIe#B_rkwD0c zV9e4cRrzR+cc>t~p9+TVWTcrTw`^Wi*FF~Z6q$* z$sV~bA@JFXB%hv;KTUAt_hveQ;Ay|lY?19s>jk=rR6rq^DAE0xsh-xf~-Eg)8TZDFGf zNK2kx!&ktsfEGf3cwpO^k-g3*_#OiB%hpy2xxn$u{uHZqWTkwg=YX#(9fn*(uLlWYHcKQCx?7VFznU!hAN9N59DOdH$%u zN42N)QG;%&zlX!8MxPDr!A8ySr-vSHtxa5oesitN<1ASy68xct=vb`U;vLtKbDBL! z=GW2Z#^ZfT{T&8v63$!5W+%RPL89F%vVYa>u$la$s6lQ}oPvV@?`pa;kvaHk(3Zo) zvz}_+xqi{yjVN+9ZRB>GkUN){A>P}C|?K_XK$@dCcRsardAB|=TS4^G}!6Ltqvf!w7*yoR}MZEkt)o$3*P?9&1C zcc-NuuI#%*W3^J>v7GOlSqQL~ftFHlc@|=9-G=2xeFg8~TJr~6q=-UsD>d$-(n&0~Bl z+@`H<&0T#^K-<|Z{H4LextV-`2 z3K#Ogu4?CTxf*P1R^zD#_9}^*-JRP?l7+mze0U6Us8&r*^`Y}a8camH35-M7MKe_r z;Uzla{#Y&GDH#z3{!l{csSJGvb$!8(_cj2Lu%spd&fP2pERjf(OIE6YG?54`6TjV}k+)=*|{)eC_}d z?+m{;-x<#nu_JESA+qD5Ja+{EW5EuIC59sqll}Tss}dP0MdKGxn$7FHRq>Xe>T1y{ z5R`Gr^0{%(@^7>MY=V&oz>|De&b7^$yD&z>CyvzdQyF9I16bgMp4wD&V0N5?@g6( zA#Og}P2s6*5=W6lHGholNAhHht!7BPylTPTGY8i3Y#MmUKE>BW- zuDpvx4f(&u{E~qjN?R|>=8DZ)#zxAjLTCB=S}f?Vnc)z7;i<7x$9*;2cJfw{v%gvd znuv-9@KC&We@crT4#U(l;-FEL$i?L3Y-$P^E;1Y0Zd}gEdGaq|i*_E6y<|QR z@z4I)C6cQ5;QEcgh_t1p6cujWc^@^>eRP3ilQ?=)Bv~z@Qi9i*y$+moOf#chFkmR7 zF71z;U}cy5z92)^icMN-ZDS*Utm($tJr?S9nmZJ7mw*jYH-<>DsKGOP4b#6A)D2A7 zUKV-_E@^FHBb}YNX(&E<~m+GFpCMRB!u@vs?tn(LSmLcoE7onO6G zQIOl6WsVvZT`kKrk^b%70Ww2GMc^X7XbrB+$)9j=JCo4ip<8dlhSPodIg9+u`b7qR ztVjAb-1u@SnON&83MEf{L+%rZAx=LsG4ZDCCEDm_Potdld#fy zs+gySHp8g zT-UBOVW+yJC8G>pp~5QSelNgDJNEVBZ2p~B(EQwx0Qeha2qqQpppn@iCS z3z(%#m~odoG`y2yqKD6nxN`|riG6;uVkyZI2{nI6d@89=_PVArnNtlC?n6+-j{_O= zBQ<68QF+qRqt=~QWG`e$hXj+zl&Tp3B(?HCP_oOHa{Dj`e~l&%w<&>JcK!4xcsQ zr}A!UmFizDkmKtgu4qd_O=9HXr$|3pP;&NLy_w90k<^}ietIee1C=UM`=QF8+AJ#j zS=UBVQFImRs>KQs9}W9?lG5gYLd$g2pnC!}av;$2)mo5$m&A!*n!UrIqz72BCsrZ1 zKhKAz%^(>ZMRE2^lx8D|ZP#v0!uQ&Km z`=JsA!V#dl;lZRh{!GtWer=`q(mBHCT9Sex4ePf9^FdVy@uA7K#oKYDX+HbCqN{qN zgFW%lFVeU4Vws(GqEPy9CU%wF;5v~lWlh?nVJcN7)UevM1=&51JJRP9U{w!5m70va z9>a~CljN6B5K8pD;2%%}fINkH{LMp@K`LsrMDytf^{9|ynQQ^k;@@oTJ~1HRXLO(% zNkjY+p_7oB;H0DD_o;SaJE5E650w!q>A!Wk0TBK&Mla#4#NSz7^kYy0T$f+Hzr_4` z)}E2P;XAuPP4=&vICho%gt`+zn8d)_w9ZJ3LBbiKx05FZTAKY%?DHI64rm2#8}!`$EXH_*AI(WaeQ1@3%S<==?plKd&|ze4Tx!A} zPB|3|(tio{P<-_@NxHo;aEal>_$wHQ0Jw2v2YhPQW9H7)j-p2InR8+bs*WQR?EMBS z!Vn;tcp4fAe@n9SGe-bF>;f5;KL;@HH-pRu2YWzPZJxg%rw)DTg|?ewJl~G*&B;W) zYsCWjQau zMJfdP#UsY>Kca0W{NhSScJl*bcd!_)c9vnWhAkeRP35!28CH4F?zRko!)H9GOYFh=tH~&icmmZbk zqy&2P_~SmRu0w3u4al<4 zUv{l@m?Bp5@HHlf!aP_yJ2o{Z0pLuyP*@wgig5e$D%Mtfm5C)ptUQt92;jkmL2~&^ zqLR^67s&wE#nwRR)@khkZ1o5$6I31Mx3G`Te)x%(-lZ_7uU%Uu>+QzqGy;4~Jj7iA zY?352(QSW7@HEzi0+CBsS%k{Y9v!lBHJ$5l1uImf^rmQYa}p)8-h?v0#!16*r{y8$ z$(MBOd!7uJ^AG^mDcau*QzbIqL^Hp(OLt?(eXBz)$`J=Ck4f1zI9H1EW;emY2m)so;-L>uvJOD0fCRq~<$&Ep}TgdOkKR}njT(2Hpn5)ZY{$;h-$j=A~x1Jw9b58}*{-IwsLO9)h^x z6cYe#+pHj1Fe$yMAmt(vtGBZ>(S{Iqj!29GnE8X9cP*Iay=mPBp@8*qgjgT?7Uvv9 z^4uEbzXyJnIyIt4ljK1V?;?fz%aW7<3k0}7Au3=25Vet5y7s3QrtFsQF74H&u z{O()b=pdjn_Cg5aah@!p7FC9%rZgAPA(TfDcy!C^bcI zbRD_}D+AbH9R!ez@R<)jT#gdknII`0vs`WEWGr)x6+Rl_Bj2qc9djL&zf-|O)2yJN zSG8RQI#3C!rpyaWWZX>&Stg%qWRR~i>AHc8;_T*AJOX50T8d7f5X~AXi&>3Q@iu(M z2T%$lu)uj3|NDU4?un9VFitiKh&nMZbsG4T&%yyo(uzcF@qv}#B;CQ(>eN#Wch3W6 z04xWz)n_>RCNYBP`Hd20pUFWD=r{f6iB;%Z43hDdAoZsk-f2GNodiVOKf{np?=LO{ ze*|#qM|1{HQ~8L&4tPVK2p~{!cz9}vLZ?iUY@R&8(g6XtK>*t1XHV9)@;x+#$ekj> zr(&4;|-OR>dFO_&!>&)O!sjLwv1*Igo!U>YsGe;J%MS3;+#Q(GA5bT)t6=r?9 zq6n9E^JG@WyznJzJgWe-=X0V~2k5{Q=p-6wE(YlK{$zVjAkJTf*cyRNt!b3vJv_`< ziEhgBDR}f20@_}AmlZVIrt@*ebiDQ9y?`28t2&xPPWaS6pWn}0_X|9WFd(03QhCP1 z;lxiu4S=JmgSO-rMYns^MJo4PJ;|d^A$<0Ep*62*BA&a^{Q6F?({pI%Kl}bu*VmqX zSXVV69mrhmF_b(*Hq2mO!hpQ7z-P|ex?DZw+{OR-zHbUp5Rr(arDTlXc|I+^u>XyT zPq^#YaK8R*!QcgK;5i@{x~pp+UYq0FC zvd7yFG})cLs{|y2hf3TBfzk}9N329C6>4amfqaD^A(wDU3!QlnLfgBhW^s45OfZCy zEo_6p-9RgGkss6@J#@QV1z^7c(OBanM56nZl_ROO7GY*YEPz=d$;7`!e)njh&n?z)x}W^)J*LjI__bpqzvz|NOM_J;W3LJ z%D+!GNobe^(ggrw^%~(^F~0+GQ99}tG1>y}&c#M@fNm2+qLpbbvUxOObwRk-VwSe} zqW3+vKx_c&ATdbA0`x#xDhClO$zzFu_SE$M#uxe{hXO!X3ke<`q&%Vm1jGA_bExly zD<<$RMDAyfG!^p|r7fK19FHGT2di|BW34cGY!kzD%rr6vIgrbPbeXGmr-6ZWG}$%X zDQq6t&UZrPD)bNUaKghEa~pkz!;AK8!>I+>u6m^F`(AGZs5*c06qd<+mD56Q`GFd` z97wmF4fco}HP={O_yG{&rRjxfTRgKe9EzbzQ=MxQF(_Oz$fm6VN}|ySU0UvOESQ+> zxk1|-*#*N*-X04y2$o44Yx@YHB=vzN`l%li>6B?ydGxQE_ckq!b}hwcvV0Pv?8ZSs znUjzTd8tBidi6Wo{{vH7Z&s-}oSGyzSnuWEtVQIYny7@sK=KMC44x+(|S^Oy2Bu$PUvLEZhtEIBqpffy@m6b;@&S~DB(MVMv zHsaSM|3q{Y-H*(vT2RP{CPBF(q(ZMZ=#fvPh7IT>XaR{XaQ20kHiJHU%ZDR#b|j=0 zng8!P#Ryz_DZux;?!#^704;;iKn^vZQ-p|-jC$(2;rsx2p7qg6TvI@7cHVGHj+G{# z#`tQLvdTb*pJE{zVpxN;`e(QC$K!#d0$S0i!Az&ZjWd~V`)s42C1$%@orsIdAtodh z$$_gt;C>BzkUJ>Dg4hfuAY4(LS_l)4amK3wX%r|9kaZIC=gOo%fBD2erHuYg+ZA(P zcLY1wb>ggw)BYUZwV+sAEsy@|<{pua&FN20`$FQN_}N)iZtLY~Ku!Uu;s@i5Xsicn zJxCXC0H+^&hZVNuMEq88mEt%i6iQk78p?$>yX+>Cb~imq)|&<+Ir3Ol06AHxbO>>S zG*#}H2&6@C3da=Cz(OzIMY>J8-2|1!&MVObg)sx+!W)UFRGL(-f7bxgZ0@Z~y26IP zIVlNum@mXnsWDEtVEz0Tuv;Xp2#BA60RM^fG$i=lAyk*NUP2y!=*9rf*euVGj&$81 zJn>hw8sJ+l*{+{ha_dV|vs1$y@{`CkU# zzP1IDdERWn7zW&Qkfi_V0*To`L=c5UY%X7xLr%~mE2Ew5ep(53udyY>!~vDglqfN zX^?cxbOet}j2^U|`1^yqfXtq1F6N7-hLe(Hwfe!e2*B3OPTlBCYvknos{&u0{)8^~ zznVzxmi1_&E`KMCT_>UdE-Y30j}|f7p4!a6L9neZ+WuVheTM=cz2Q`#hHIoQ`zlb3 zea8ZyC;{9cb(J)oFEpH-#huDqLzi_?5;`_g-<)tCR2!wj36L7gDliybY#mJq%>~l) z1tKYMvxca28A&0E0Gxuea!8PBeP_qPZ5%-61|o3h@{sfo&gTC|_^C+g4)Vbngz%;P z1drStL6|xAs3*X0A$@Vst;XpZq|^i&{#1_qP$c5>Obf42u5>KE!N+$Y2i)ISQI12$ zRa{{@x0xrbt68;>yzzMjkgA34N;K4$i=*!_8Z}t~1NoxjBJ! z=f?)F6)1l-__0BAZ{=JQo`#SGO6_QZam*6F_wVufTBaeOvVrnRiu00B2o}*61M$wj zisU5uiF)dy&#l5ve+28`yLN%F0I_8Q!n_`&k5DAz-U_+`9@& zY3?=#*X*e9QDN=H6TGeLu_oeTKblu{A9OQK7{bzwlf8(=??pJ`;=SW%Yei&*N47CZ z?A-y}8u%tixgFdba$7^Z=D@#{EJdvAm-6wZ2&&snX7nseMA)HA*_$o7a1m+RwH$X( ziyWL5f)O^{wjB}A)X*^%Yw^}>^Wf_t7W}UPLHiwe5-n^1Bz-pqU>+V12RNEtd3Nw8 z@(WZ$Pd+`QS>v}N@@X~XUBSmfbmp1qE{yHgSSHz77X8npS+HdY2$GQK)Gt<6^5vrJ zv=9Zue$JZFb$liTwbBF*cE~UEbBKo^!OxX=xo9{UZlE!P6+I@9o;t6?Nrz~F`YOeINnFt-vFXO>g&y^uqKuzxrPGjf`M_(x>e<2%vQw)tO;)J~+$|Mx%)0ki4 z`oVS3FtAU6_5SA|Z%X%HT7j?>mt~`k^<_(DY~b<2q1lLrQ-@2UN3INTkl-eukn8v} z@yRmzq*Vl!85@|TK#KOmLs{aT5gUO2X)v6w04uyO6?p?rQ6f2X<|CJ*m#hA-CevJ& zQ*fhJslk7Sy#7C=JLjeGXAqv?LLeL1h?;;l*56}zpxkkxP|`>pM}VWhWz-8U`OcHY z8j2uQbY6fu$6N=AQEKWd5q=>(G1O7FAp_@rbcaff=VT$g|-V!~V`|AX> z-ZveP!+a;hm`h5M_NT2XikQWUp54Jm%(?w~0MF+`<^Y+*^|Sd>B2i5m@ma@1dHY>+ znedXg!Vcy?S*0kgJ~5o`W^r@h+;Mmb$Uzf(e*(g=P<*cICR_Pq^@hg8HNxksOB9`R z$^5TM8y;1xMpy-d2s8}^D7{K|Qt%oeE74w%oH8zh0#$Z{?1pn+A%XY8N)jg5;1%)3 z?FHprHSDACW>@S3HQ#pWrOtvd|6N*#8ij!yWFn~|H~appZb9Y3&`*n^?2j`mhOpSYMbLRv__#)Z_rTGx}ekw3PE{+#A8q926da z!!^OZlnNz0x6>$C6807RgadTB7Y1t*fXv{>8_w`EH}I1UngR+H{O-eE0W#+jp zW(S1FLcb7U4Sx0k9FqV1FhsOFd@5&-m*Wb$B|`Twti^g?Z=dCk%*~EG0|Q{3yRaBG zTHjZb5%6umY3_?t#9|ou@8&0`+4oLCb4}n!E;{FCmFAw5S1N%2U*Y2z*E2FZJOaLg zo}QbHo|}w*27b2!yz~C`w%Lz4vmYl6XWoO?M}nsdgQuUvf|o;IJEvJa_w$J?pSn{% zH3LSVro1Vqe6jz`wVJ^>hvvb#)2O+#>!D_-kBh4^4m>V?mT~y;?1!FBv+p*|_AAaU Yx?Iq Date: Thu, 16 Oct 2025 04:18:42 -0400 Subject: [PATCH 125/167] Fix DrawBillboardPro so that flipped images that are sampling from part of a larger texture still draw from the same source rectangle (#5276) Co-authored-by: Violently --- src/rmodels.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rmodels.c b/src/rmodels.c index 3a5cc9004..3c904c396 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -3904,14 +3904,14 @@ void DrawBillboardPro(Camera camera, Texture2D texture, Rectangle source, Vector // Flip the content of the billboard while maintaining the counterclockwise edge rendering order if (size.x < 0.0f) { - source.x += size.x; + source.x -= size.x; source.width *= -1.0; right = Vector3Negate(right); origin.x *= -1.0f; } if (size.y < 0.0f) { - source.y += size.y; + source.y -= size.y; source.height *= -1.0; up = Vector3Negate(up); origin.y *= -1.0f; 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 126/167] 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 127/167] 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 128/167] 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 129/167] 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 130/167] 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 131/167] 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 132/167] 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 133/167] 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 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 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 134/167] 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 135/167] 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 136/167] 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 137/167] 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 138/167] 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 139/167] [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 140/167] 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 141/167] 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 142/167] [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 143/167] 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 144/167] 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 145/167] 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 146/167] [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 147/167] 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 148/167] 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 149/167] 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 150/167] 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 151/167] [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 152/167] 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 153/167] 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 154/167] 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 155/167] [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 ""; From 428421f21a565b301e24e624fd2ffb4e1727258a Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 22 Oct 2025 11:03:19 +0200 Subject: [PATCH 156/167] Update examples_list.txt --- examples/examples_list.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/examples_list.txt b/examples/examples_list.txt index 2a1b9c0b7..71cda6c1a 100644 --- a/examples/examples_list.txt +++ b/examples/examples_list.txt @@ -51,6 +51,7 @@ core;core_directory_files;★☆☆☆;5.5;5.6;2025;2025;"Hugo ARNAL";@hugoarnal 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 +core;core_text_file_loading;★☆☆☆;5.5;5.6;0;0;"Aanjishnu Bhattacharyya";@NimComPoo-04 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 @@ -160,6 +161,7 @@ shaders;shaders_texture_rendering;★★☆☆;2.0;3.7;2019;2025;"Michał Ciesie shaders;shaders_texture_outline;★★★☆;4.0;4.0;2021;2025;"Serenity Skiff";@GoldenThumbs shaders;shaders_texture_waves;★★☆☆;2.5;3.7;2019;2025;"Anata";@anatagawa shaders;shaders_julia_set;★★★☆;2.5;4.0;2019;2025;"Josh Colclough";@joshcol9232 +shaders;shaders_mandelbrot_set;★★★☆;5.6;5.6;2025;2025;"Jordi Santonja";@JordSant shaders;shaders_eratosthenes_sieve;★★★☆;2.5;4.0;2019;2025;"ProfJski";@ProfJski shaders;shaders_fog_rendering;★★★☆;2.5;3.7;2019;2025;"Chris Camacho";@chriscamacho shaders;shaders_simple_mask;★★☆☆;2.5;3.7;2019;2025;"Chris Camacho";@chriscamacho @@ -192,5 +194,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 -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 From 780a7df760d45b8bd386be425ab5c2da0b1a48f6 Mon Sep 17 00:00:00 2001 From: Jeffery Myers Date: Thu, 23 Oct 2025 04:25:23 -0700 Subject: [PATCH 157/167] Fix warnings in more examples. (#5292) --- examples/core/core_text_file_loading.c | 16 ++++++++-------- examples/shapes/shapes_clock_of_clocks.c | 3 +++ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/examples/core/core_text_file_loading.c b/examples/core/core_text_file_loading.c index 033fd4dc6..ed48f7d36 100644 --- a/examples/core/core_text_file_loading.c +++ b/examples/core/core_text_file_loading.c @@ -88,16 +88,16 @@ int main(void) for (int i = 0; i < lineCount; i++) { - Vector2 size = MeasureTextEx(GetFontDefault(), lines[i], fontSize, 2); - textHeight += size.y + 10; + Vector2 size = MeasureTextEx(GetFontDefault(), lines[i], (float)fontSize, 2); + textHeight += (int)size.y + 10; } // A simple scrollbar on the side to show how far we have red into the file Rectangle scrollBar = { - .x = screenWidth - 5, + .x = (float)screenWidth - 5, .y = 0, .width = 5, - .height = screenHeight*100/(textHeight - screenHeight) // Scrollbar height is just a percentage + .height = screenHeight*100.0f/(textHeight - screenHeight) // Scrollbar height is just a percentage }; SetTargetFPS(60); @@ -115,10 +115,10 @@ int main(void) // Ensuring that the camera does not scroll past all text if (cam.target.y > textHeight - screenHeight + textTop) - cam.target.y = textHeight - screenHeight + textTop; + cam.target.y = (float)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)); + scrollBar.y = Lerp((float)textTop, (float)screenHeight - scrollBar.height, (float)(cam.target.y - textTop)/(textHeight - screenHeight)); //---------------------------------------------------------------------------------- // Draw @@ -132,13 +132,13 @@ int main(void) 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(GetFontDefault(), lines[i], fontSize, 2); + Vector2 size = MeasureTextEx(GetFontDefault(), lines[i], (float)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; + t += (int)size.y + 10; } EndMode2D(); diff --git a/examples/shapes/shapes_clock_of_clocks.c b/examples/shapes/shapes_clock_of_clocks.c index 493e53b5e..3fc24aa92 100644 --- a/examples/shapes/shapes_clock_of_clocks.c +++ b/examples/shapes/shapes_clock_of_clocks.c @@ -14,6 +14,9 @@ * Copyright (c) 2025 JP Mortiboys (@themushroompirates) * ********************************************************************************************/ +#if defined(WIN32) +#define _CRT_SECURE_NO_WARNINGS +#endif #include "raylib.h" From 04930c5132f900be39b21a6b89685f0f75f2d0e5 Mon Sep 17 00:00:00 2001 From: Diogo Hartuiq Debarba <35925088+diogohartuiqdebarba@users.noreply.github.com> Date: Thu, 23 Oct 2025 08:27:28 -0300 Subject: [PATCH 158/167] Fix typo in RPI cross-compiler variable name (#5295) --- src/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Makefile b/src/Makefile index 0d4ca9ac7..4369d8084 100644 --- a/src/Makefile +++ b/src/Makefile @@ -283,7 +283,7 @@ ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW) endif endif ifeq ($(TARGET_PLATFORM),PLATFORM_DRM) - ifeq ($(USE_RPI_CROSS_COMPILER),TRUE) + ifeq ($(USE_RPI_CROSSCOMPILER),TRUE) # Define RPI cross-compiler #CC = armv6j-hardfloat-linux-gnueabi-gcc CC = $(RPI_TOOLCHAIN)/bin/$(RPI_TOOLCHAIN_NAME)-gcc From 93c5dc3b5f67b5c221cd93f379f9b31ba15b8c94 Mon Sep 17 00:00:00 2001 From: alexgb0 Date: Thu, 23 Oct 2025 17:28:00 +0200 Subject: [PATCH 159/167] [rlsw] c++ support (#5291) * rlsw c++ support * rslw formatting fixes --- src/external/rlsw.h | 141 ++++++++++++++++++++++++-------------------- 1 file changed, 77 insertions(+), 64 deletions(-) diff --git a/src/external/rlsw.h b/src/external/rlsw.h index 904bf1210..aa4803265 100644 --- a/src/external/rlsw.h +++ b/src/external/rlsw.h @@ -156,6 +156,12 @@ #define SW_CLIP_EPSILON 1e-4f #endif +#ifdef __cplusplus + #define CURLY_INIT(name) name +#else + #define CURLY_INIT(name) (name) +#endif + //---------------------------------------------------------------------------------- // OpenGL Compatibility Types //---------------------------------------------------------------------------------- @@ -1699,7 +1705,7 @@ static inline void sw_framebuffer_blit_to_##name( int xSrc, int ySrc, int wSrc, int hSrc, \ DST_PTR_T *dst) \ { \ - const uint8_t *srcBase = RLSW.framebuffer.color; \ + const uint8_t *srcBase = (uint8_t*)RLSW.framebuffer.color; \ int fbWidth = RLSW.framebuffer.width; \ \ uint32_t xScale = ((uint32_t)wSrc << 16)/(uint32_t)wDst; \ @@ -1722,7 +1728,7 @@ static inline void sw_framebuffer_blit_to_##name( int xSrc, int ySrc, int wSrc, int hSrc, \ DST_PTR_T *dst) \ { \ - const uint8_t *srcBase = RLSW.framebuffer.color; \ + const uint8_t *srcBase = (uint8_t *)RLSW.framebuffer.color; \ int fbWidth = RLSW.framebuffer.width; \ \ uint32_t xScale = ((uint32_t)wSrc << 16)/(uint32_t)wDst; \ @@ -2583,6 +2589,15 @@ static inline void FUNC_NAME(const sw_texture_t *tex, const sw_vertex_t *start, /* Scanline rasterization */ \ for (int x = xStart; x < xEnd; x++) \ { \ + /* Pixel color computation */ \ + float wRcp = 1.0f/w; \ + float srcColor[4] = { \ + color[0]*wRcp, \ + color[1]*wRcp, \ + color[2]*wRcp, \ + color[3]*wRcp \ + }; \ + \ /* Test and write depth */ \ if (ENABLE_DEPTH_TEST) \ { \ @@ -2593,15 +2608,6 @@ static inline void FUNC_NAME(const sw_texture_t *tex, const sw_vertex_t *start, \ sw_framebuffer_write_depth(dptr, z); \ \ - /* Pixel color computation */ \ - float wRcp = 1.0f/w; \ - float srcColor[4] = { \ - color[0]*wRcp, \ - color[1]*wRcp, \ - color[2]*wRcp, \ - color[3]*wRcp \ - }; \ - \ if (ENABLE_TEXTURE) \ { \ float texColor[4]; \ @@ -3063,6 +3069,14 @@ static inline void FUNC_NAME(void) /* Scanline rasterization */ \ for (int x = xMin; x < xMax; x++) \ { \ + /* Pixel color computation */ \ + float srcColor[4] = { \ + color[0], \ + color[1], \ + color[2], \ + color[3] \ + }; \ + \ /* Test and write depth */ \ if (ENABLE_DEPTH_TEST) \ { \ @@ -3073,14 +3087,6 @@ static inline void FUNC_NAME(void) \ sw_framebuffer_write_depth(dptr, z); \ \ - /* Pixel color computation */ \ - float srcColor[4] = { \ - color[0], \ - color[1], \ - color[2], \ - color[3] \ - }; \ - \ if (ENABLE_TEXTURE) \ { \ float texColor[4]; \ @@ -3361,6 +3367,7 @@ static inline void FUNC_NAME(const sw_vertex_t *v0, const sw_vertex_t *v1) \ { \ int offset = (y1 + i)*fbWidth + (x1 + (j >> 16)); \ void *dptr = sw_framebuffer_get_depth_addr(dBuffer, offset); \ + void *cptr; \ \ if (ENABLE_DEPTH_TEST) \ { \ @@ -3370,7 +3377,7 @@ static inline void FUNC_NAME(const sw_vertex_t *v0, const sw_vertex_t *v1) \ \ sw_framebuffer_write_depth(dptr, z); \ \ - void *cptr = sw_framebuffer_get_color_addr(cBuffer, offset); \ + cptr = sw_framebuffer_get_color_addr(cBuffer, offset); \ \ if (ENABLE_COLOR_BLEND) \ { \ @@ -3397,6 +3404,7 @@ static inline void FUNC_NAME(const sw_vertex_t *v0, const sw_vertex_t *v1) \ { \ int offset = (y1 + (j >> 16))*fbWidth + (x1 + i); \ void *dptr = sw_framebuffer_get_depth_addr(dBuffer, offset); \ + void *cptr; \ \ if (ENABLE_DEPTH_TEST) \ { \ @@ -3406,7 +3414,7 @@ static inline void FUNC_NAME(const sw_vertex_t *v0, const sw_vertex_t *v1) \ \ sw_framebuffer_write_depth(dptr, z); \ \ - void *cptr = sw_framebuffer_get_color_addr(cBuffer, offset); \ + cptr = sw_framebuffer_get_color_addr(cBuffer, offset); \ \ if (ENABLE_COLOR_BLEND) \ { \ @@ -3687,9 +3695,14 @@ static inline void sw_poly_line_render(void) const sw_vertex_t *vertices = RLSW.vertexBuffer; int cm1 = RLSW.vertexCounter - 1; - for (int i = 0; i < cm1; i++) sw_line_render((sw_vertex_t[2]){ vertices[i], vertices[i + 1] }); + for (int i = 0; i < cm1; i++) + { + sw_vertex_t verts[2] = { vertices[i], vertices[i + 1] }; + sw_line_render(verts); + } - sw_line_render((sw_vertex_t[2]){ vertices[cm1], vertices[0] }); + sw_vertex_t verts[2] = { vertices[cm1], vertices[0] }; + sw_line_render(verts); } static inline void sw_poly_fill_render(void) @@ -3817,10 +3830,10 @@ bool swInit(int w, int h) swViewport(0, 0, w, h); swScissor(0, 0, w, h); - RLSW.loadedTextures = SW_MALLOC(SW_MAX_TEXTURES*sizeof(sw_texture_t)); + RLSW.loadedTextures = (sw_texture_t *)SW_MALLOC(SW_MAX_TEXTURES*sizeof(sw_texture_t)); if (RLSW.loadedTextures == NULL) { swClose(); return false; } - RLSW.freeTextureIds = SW_MALLOC(SW_MAX_TEXTURES*sizeof(uint32_t)); + RLSW.freeTextureIds = (uint32_t *)SW_MALLOC(SW_MAX_TEXTURES*sizeof(uint32_t)); if (RLSW.loadedTextures == NULL) { swClose(); return false; } RLSW.clearColor[0] = 0.0f; @@ -3898,7 +3911,7 @@ void swClose(void) SW_FREE(RLSW.loadedTextures); SW_FREE(RLSW.freeTextureIds); - RLSW = (sw_context_t) { 0 }; + RLSW = CURLY_INIT(sw_context_t) { 0 }; } bool swResizeFramebuffer(int w, int h) @@ -3908,7 +3921,7 @@ bool swResizeFramebuffer(int w, int h) void swCopyFramebuffer(int x, int y, int w, int h, SWformat format, SWtype type, void *pixels) { - sw_pixelformat_t pFormat = sw_get_pixel_format(format, type); + sw_pixelformat_t pFormat = (sw_pixelformat_t)sw_get_pixel_format(format, type); if (w <= 0) { @@ -3930,26 +3943,26 @@ void swCopyFramebuffer(int x, int y, int w, int h, SWformat format, SWtype type, switch (pFormat) { - case SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: sw_framebuffer_copy_to_GRAYALPHA(x, y, w, h, pixels); break; - case SW_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: sw_framebuffer_copy_to_GRAYALPHA(x, y, w, h, pixels); break; - case SW_PIXELFORMAT_UNCOMPRESSED_R5G6B5: sw_framebuffer_copy_to_R5G6B5(x, y, w, h, pixels); break; - case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8: sw_framebuffer_copy_to_R8G8B8(x, y, w, h, pixels); break; - case SW_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: sw_framebuffer_copy_to_R5G5B5A1(x, y, w, h, pixels); break; - case SW_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: sw_framebuffer_copy_to_R4G4B4A4(x, y, w, h, pixels); break; - case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: sw_framebuffer_copy_to_R8G8B8A8(x, y, w, h, pixels); break; - case SW_PIXELFORMAT_UNCOMPRESSED_R32: sw_framebuffer_copy_to_R32(x, y, w, h, pixels); break; - case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32: sw_framebuffer_copy_to_R32G32B32(x, y, w, h, pixels); break; - case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: sw_framebuffer_copy_to_R32G32B32A32(x, y, w, h, pixels); break; - case SW_PIXELFORMAT_UNCOMPRESSED_R16: sw_framebuffer_copy_to_R16(x, y, w, h, pixels); break; - case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16: sw_framebuffer_copy_to_R16G16B16(x, y, w, h, pixels); break; - case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: sw_framebuffer_copy_to_R16G16B16A16(x, y, w, h, pixels); break; + case SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: sw_framebuffer_copy_to_GRAYALPHA(x, y, w, h, (uint8_t *)pixels); break; + case SW_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: sw_framebuffer_copy_to_GRAYALPHA(x, y, w, h, (uint8_t *)pixels); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R5G6B5: sw_framebuffer_copy_to_R5G6B5(x, y, w, h, (uint16_t *)pixels); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8: sw_framebuffer_copy_to_R8G8B8(x, y, w, h, (uint8_t *)pixels); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: sw_framebuffer_copy_to_R5G5B5A1(x, y, w, h, (uint16_t *)pixels); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: sw_framebuffer_copy_to_R4G4B4A4(x, y, w, h, (uint16_t *)pixels); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: sw_framebuffer_copy_to_R8G8B8A8(x, y, w, h, (uint8_t *)pixels); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R32: sw_framebuffer_copy_to_R32(x, y, w, h, (float *)pixels); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32: sw_framebuffer_copy_to_R32G32B32(x, y, w, h, (float *)pixels); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: sw_framebuffer_copy_to_R32G32B32A32(x, y, w, h, (float *)pixels); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R16: sw_framebuffer_copy_to_R16(x, y, w, h, (sw_half_t *)pixels); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16: sw_framebuffer_copy_to_R16G16B16(x, y, w, h, (sw_half_t *)pixels); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: sw_framebuffer_copy_to_R16G16B16A16(x, y, w, h, (sw_half_t *)pixels); break; default: RLSW.errCode = SW_INVALID_ENUM; break; } } void swBlitFramebuffer(int xDst, int yDst, int wDst, int hDst, int xSrc, int ySrc, int wSrc, int hSrc, SWformat format, SWtype type, void *pixels) { - sw_pixelformat_t pFormat = sw_get_pixel_format(format, type); + sw_pixelformat_t pFormat = (sw_pixelformat_t)sw_get_pixel_format(format, type); if (wSrc <= 0) { @@ -3971,19 +3984,19 @@ void swBlitFramebuffer(int xDst, int yDst, int wDst, int hDst, int xSrc, int ySr switch (pFormat) { - case SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: sw_framebuffer_blit_to_GRAYALPHA(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break; - case SW_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: sw_framebuffer_blit_to_GRAYALPHA(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break; - case SW_PIXELFORMAT_UNCOMPRESSED_R5G6B5: sw_framebuffer_blit_to_R5G6B5(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break; - case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8: sw_framebuffer_blit_to_R8G8B8(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break; - case SW_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: sw_framebuffer_blit_to_R5G5B5A1(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break; - case SW_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: sw_framebuffer_blit_to_R4G4B4A4(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break; - case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: sw_framebuffer_blit_to_R8G8B8A8(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break; - case SW_PIXELFORMAT_UNCOMPRESSED_R32: sw_framebuffer_blit_to_R32(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break; - case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32: sw_framebuffer_blit_to_R32G32B32(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break; - case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: sw_framebuffer_blit_to_R32G32B32A32(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break; - case SW_PIXELFORMAT_UNCOMPRESSED_R16: sw_framebuffer_blit_to_R16(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break; - case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16: sw_framebuffer_blit_to_R16G16B16(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break; - case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: sw_framebuffer_blit_to_R16G16B16A16(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break; + case SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: sw_framebuffer_blit_to_GRAYALPHA(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (uint8_t *)pixels); break; + case SW_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: sw_framebuffer_blit_to_GRAYALPHA(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (uint8_t *)pixels); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R5G6B5: sw_framebuffer_blit_to_R5G6B5(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (uint16_t *)pixels); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8: sw_framebuffer_blit_to_R8G8B8(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (uint8_t *)pixels); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: sw_framebuffer_blit_to_R5G5B5A1(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (uint16_t *)pixels); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: sw_framebuffer_blit_to_R4G4B4A4(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (uint16_t *)pixels); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: sw_framebuffer_blit_to_R8G8B8A8(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (uint8_t *)pixels); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R32: sw_framebuffer_blit_to_R32(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (uint8_t *)pixels); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32: sw_framebuffer_blit_to_R32G32B32(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (float *)pixels); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: sw_framebuffer_blit_to_R32G32B32A32(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (float*)pixels); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R16: sw_framebuffer_blit_to_R16(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (sw_half_t *)pixels); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16: sw_framebuffer_blit_to_R16G16B16(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (sw_half_t *)pixels); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: sw_framebuffer_blit_to_R16G16B16A16(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (sw_half_t *)pixels); break; default: RLSW.errCode = SW_INVALID_ENUM; break; } } @@ -4553,7 +4566,7 @@ void swBegin(SWdraw mode) void swEnd(void) { - RLSW.drawMode = 0; + RLSW.drawMode = (SWdraw)0; } void swVertex2i(int x, int y) @@ -4738,9 +4751,9 @@ void swBindArray(SWarray type, void *buffer) { switch (type) { - case SW_VERTEX_ARRAY: RLSW.array.positions = buffer; break; - case SW_TEXTURE_COORD_ARRAY: RLSW.array.texcoords = buffer; break; - case SW_COLOR_ARRAY: RLSW.array.colors = buffer; break; + case SW_VERTEX_ARRAY: RLSW.array.positions = (float *)buffer; break; + case SW_TEXTURE_COORD_ARRAY: RLSW.array.texcoords = (float *)buffer; break; + case SW_COLOR_ARRAY: RLSW.array.colors = (uint8_t *)buffer; break; default: break; } } @@ -4833,7 +4846,7 @@ void swTexImage2D(int width, int height, SWformat format, SWtype type, bool copy if (copy) { - int bytes = sw_get_pixel_bytes(pixelFormat); + int bytes = sw_get_pixel_bytes((sw_pixelformat_t)pixelFormat); int size = bytes*width*height; texture->pixels.ptr = SW_MALLOC(size); @@ -4854,7 +4867,7 @@ void swTexImage2D(int width, int height, SWformat format, SWtype type, bool copy texture->height = height; texture->wMinus1 = width - 1; texture->hMinus1 = height - 1; - texture->format = pixelFormat; + texture->format = (sw_pixelformat_t)pixelFormat; texture->tx = 1.0f/width; texture->ty = 1.0f/height; texture->copy = copy; @@ -4882,7 +4895,7 @@ void swTexParameteri(int param, int value) return; } - texture->minFilter = value; + texture->minFilter = (SWfilter)value; } break; case SW_TEXTURE_MAG_FILTER: { @@ -4892,7 +4905,7 @@ void swTexParameteri(int param, int value) return; } - texture->magFilter = value; + texture->magFilter = (SWfilter)value; } break; case SW_TEXTURE_WRAP_S: { @@ -4902,7 +4915,7 @@ void swTexParameteri(int param, int value) return; } - texture->sWrap = value; + texture->sWrap = (SWwrap)value; } break; case SW_TEXTURE_WRAP_T: { @@ -4912,7 +4925,7 @@ void swTexParameteri(int param, int value) return; } - texture->tWrap = value; + texture->tWrap = (SWwrap)value; } break; default: RLSW.errCode = SW_INVALID_ENUM; break; } From 12dc0d66758970212eaa323c2e398d8645a229e4 Mon Sep 17 00:00:00 2001 From: Jeffery Myers Date: Thu, 23 Oct 2025 08:45:33 -0700 Subject: [PATCH 160/167] Revert undesired change to rcore and restore correct win32 ifdef and max path (#5297) Fixes #5293 also add comment for win32 platform. --- src/rcore.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/rcore.c b/src/rcore.c index 350490ad1..e4628e77c 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -26,7 +26,8 @@ * - Linux DRM subsystem (KMS mode) * > PLATFORM_ANDROID: * - Android (ARM, ARM64) -* +* > PLATFORM_DESKTOP_WIN32 (Native Win32): +* - Windows (Win32, Win64) * CONFIGURATION: * #define SUPPORT_DEFAULT_FONT (default) * Default font is loaded on window initialization to be available for the user to render simple text. @@ -161,7 +162,10 @@ #endif // Platform specific defines to handle GetApplicationDirectory() -#if (defined(_WIN32) && !defined(PLATFORM_DESKTOP_RGFW)) || (defined(_MSC_VER) && defined(PLATFORM_DESKTOP_RGFW)) +#if defined(_WIN32) + #if !defined(MAX_PATH) + #define MAX_PATH 260 + #endif struct HINSTANCE__; #if defined(__cplusplus) From 39242dba2303cd321e594908c814e08f976d31b4 Mon Sep 17 00:00:00 2001 From: Le Juez Victor <90587919+Bigfoot71@users.noreply.github.com> Date: Fri, 24 Oct 2025 18:29:01 +0200 Subject: [PATCH 161/167] [rlsw] Smarter texture management (#5296) * simplified framebuffer management * convert texture to rgba32 * remove float copy/blit * adding SIMD framebuffer read/write This adds SIMD framebuffer read/write, and also texel fetch. This supports SSE2/SSE41 and SISD fallback (also includes ARM NEON support, conceptually identical but still needs testing). * consistency * tweaks * review of `sw_texture_sample_linear` * better quad sorting unrelated to the PR, but at least it's done * ignore some pipeline state in certains context * convention tweaks --------- Co-authored-by: Ray --- src/external/rlsw.h | 1723 ++++++++++++++++++------------------------- 1 file changed, 724 insertions(+), 999 deletions(-) diff --git a/src/external/rlsw.h b/src/external/rlsw.h index aa4803265..626cb2cc5 100644 --- a/src/external/rlsw.h +++ b/src/external/rlsw.h @@ -115,16 +115,12 @@ #define SW_GL_FRAMEBUFFER_COPY_BGRA true #endif -#ifndef SW_GL_BINDING_COPY_TEXTURE - #define SW_GL_BINDING_COPY_TEXTURE true -#endif - #ifndef SW_COLOR_BUFFER_BITS - #define SW_COLOR_BUFFER_BITS 24 + #define SW_COLOR_BUFFER_BITS 32 //< 32 (rgba), 16 (rgb packed) or 8 (rgb packed) #endif #ifndef SW_DEPTH_BUFFER_BITS - #define SW_DEPTH_BUFFER_BITS 16 + #define SW_DEPTH_BUFFER_BITS 16 //< 24, 16 or 8 #endif #ifndef SW_MAX_PROJECTION_STACK_SIZE @@ -382,7 +378,7 @@ typedef double GLclampd; #define glDrawArrays(m, o, c) swDrawArrays((m), (o), (c)) #define glGenTextures(c, v) swGenTextures((c), (v)) #define glDeleteTextures(c, v) swDeleteTextures((c), (v)) -#define glTexImage2D(tr, l, if, w, h, b, f, t, p) swTexImage2D((w), (h), (f), (t), SW_GL_BINDING_COPY_TEXTURE, (p)) +#define glTexImage2D(tr, l, if, w, h, b, f, t, p) swTexImage2D((w), (h), (f), (t), (p)) #define glTexParameteri(tr, pname, param) swTexParameteri((pname), (param)) #define glBindTexture(tr, id) swBindTexture((id)) @@ -597,7 +593,7 @@ SWAPI void swDrawArrays(SWdraw mode, int offset, int count); SWAPI void swGenTextures(int count, uint32_t *textures); SWAPI void swDeleteTextures(int count, uint32_t *textures); -SWAPI void swTexImage2D(int width, int height, SWformat format, SWtype type, bool copy, const void *data); +SWAPI void swTexImage2D(int width, int height, SWformat format, SWtype type, const void *data); SWAPI void swTexParameteri(int param, int value); SWAPI void swBindTexture(uint32_t id); @@ -615,6 +611,65 @@ SWAPI void swBindTexture(uint32_t id); #include #include // Required for: floorf(), fabsf() +#if defined(__FMA__) && defined(__AVX2__) +# define SW_HAS_FMA_AVX2 +# include +#endif + +#if defined(__FMA__) && defined(__AVX__) +# define SW_HAS_FMA_AVX +# include +#endif + +#if defined(__AVX2__) +# define SW_HAS_AVX2 +# include +#endif + +#if defined(__AVX__) +# define SW_HAS_AVX +# include +#endif + +#if defined(__SSE4_2__) +# define SW_HAS_SSE42 +# include +#endif + +#if defined(__SSE4_1__) +# define SW_HAS_SSE41 +# include +#endif + +#if defined(__SSSE3__) +# define SW_HAS_SSSE3 +# include +#endif + +#if defined(__SSE3__) +# define SW_HAS_SSE3 +# include +#endif + +#if defined(__SSE2__) +# define SW_HAS_SSE2 +# include +#endif + +#if defined(__SSE__) +# define SW_HAS_SSE +# include +#endif + +#if defined(__ARM_NEON) || defined(__aarch64__) +# if defined(__ARM_FEATURE_FMA) +# define SW_HAS_NEON_FMA +# else +# define SW_HAS_NEON +# endif +# include +#endif + //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- @@ -625,7 +680,69 @@ SWAPI void swBindTexture(uint32_t id); #define SW_COLOR_PIXEL_SIZE (SW_COLOR_BUFFER_BITS/8) #define SW_DEPTH_PIXEL_SIZE (SW_DEPTH_BUFFER_BITS/8) -#define SW_STATE_CHECK(flags) ((RLSW.stateFlags & (flags)) == (flags)) +#if (SW_COLOR_BUFFER_BITS == 8) + #define COLOR_TYPE uint8_t + #define COLOR_IS_PACKED 1 + #define PACK_COLOR(r,g,b) ((((uint8_t)((r)*7+0.5f))&0x07)<<5 | (((uint8_t)((g)*7+0.5f))&0x07)<<2 | ((uint8_t)((b)*3+0.5f))&0x03) + #define UNPACK_R(p) (((p)>>5)&0x07) + #define UNPACK_G(p) (((p)>>2)&0x07) + #define UNPACK_B(p) ((p)&0x03) + #define SCALE_R(v) ((v)*255+3)/7 + #define SCALE_G(v) ((v)*255+3)/7 + #define SCALE_B(v) ((v)*255+1)/3 + #define TO_FLOAT_R(v) ((v)*(1.0f/7.0f)) + #define TO_FLOAT_G(v) ((v)*(1.0f/7.0f)) + #define TO_FLOAT_B(v) ((v)*(1.0f/3.0f)) +#elif (SW_COLOR_BUFFER_BITS == 16) + #define COLOR_TYPE uint16_t + #define COLOR_IS_PACKED 1 + #define PACK_COLOR(r,g,b) ((((uint16_t)((r)*31+0.5f))&0x1F)<<11 | (((uint16_t)((g)*63+0.5f))&0x3F)<<5 | ((uint16_t)((b)*31+0.5f))&0x1F) + #define UNPACK_R(p) (((p)>>11)&0x1F) + #define UNPACK_G(p) (((p)>>5)&0x3F) + #define UNPACK_B(p) ((p)&0x1F) + #define SCALE_R(v) ((v)*255+15)/31 + #define SCALE_G(v) ((v)*255+31)/63 + #define SCALE_B(v) ((v)*255+15)/31 + #define TO_FLOAT_R(v) ((v)*(1.0f/31.0f)) + #define TO_FLOAT_G(v) ((v)*(1.0f/63.0f)) + #define TO_FLOAT_B(v) ((v)*(1.0f/31.0f)) +#else // 32 bits + #define COLOR_TYPE uint8_t + #define COLOR_IS_PACKED 0 +#endif + +#if (SW_DEPTH_BUFFER_BITS == 8) + #define DEPTH_TYPE uint8_t + #define DEPTH_IS_PACKED 1 + #define DEPTH_MAX UINT8_MAX + #define DEPTH_SCALE (1.0f/UINT8_MAX) + #define PACK_DEPTH(d) ((DEPTH_TYPE)((d)*DEPTH_MAX)) + #define UNPACK_DEPTH(p) (p) +#elif (SW_DEPTH_BUFFER_BITS == 16) + #define DEPTH_TYPE uint16_t + #define DEPTH_IS_PACKED 1 + #define DEPTH_MAX UINT16_MAX + #define DEPTH_SCALE (1.0f/UINT16_MAX) + #define PACK_DEPTH(d) ((DEPTH_TYPE)((d)*DEPTH_MAX)) + #define UNPACK_DEPTH(p) (p) +#else // 24 bits + #define DEPTH_TYPE uint8_t + #define DEPTH_IS_PACKED 0 + #define DEPTH_MAX 0xFFFFFF + #define DEPTH_SCALE (1.0f/0xFFFFFF) + #define PACK_DEPTH_0(d) (((uint32_t)((d)*DEPTH_MAX)>>16)&0xFF) + #define PACK_DEPTH_1(d) (((uint32_t)((d)*DEPTH_MAX)>>8)&0xFF) + #define PACK_DEPTH_2(d) ((uint32_t)((d)*DEPTH_MAX)&0xFF) + #define UNPACK_DEPTH(p) (((p)[0]<<16)|((p)[1]<<8)|(p)[2]) +#endif + +#define GET_COLOR_PTR(ptr, offset) ((void*)((uint8_t*)(ptr) + (offset)*SW_COLOR_PIXEL_SIZE)) +#define GET_DEPTH_PTR(ptr, offset) ((void*)((uint8_t*)(ptr) + (offset)*SW_DEPTH_PIXEL_SIZE)) +#define INC_COLOR_PTR(ptr) ((ptr) = (void*)((uint8_t*)(ptr) + SW_COLOR_PIXEL_SIZE)) +#define INC_DEPTH_PTR(ptr) ((ptr) = (void*)((uint8_t*)(ptr) + SW_DEPTH_PIXEL_SIZE)) + +#define SW_STATE_CHECK(flags) (SW_STATE_CHECK_EX(RLSW.stateFlags, (flags))) +#define SW_STATE_CHECK_EX(state, flags) (((state) & (flags)) == (flags)) #define SW_STATE_SCISSOR_TEST (1 << 0) #define SW_STATE_TEXTURE_2D (1 << 1) @@ -674,16 +791,11 @@ typedef struct { } sw_vertex_t; typedef struct { - // Dirty hack for copied data - // TODO: Rework copied image handling - union { - const void *cptr; // NOTE: Is used for all data reads - void *ptr; // WARNING: Should only be used to allocate and free data - } pixels; + + uint8_t* pixels; // Texture pixels (RGBA32) int width, height; // Dimensions of the texture int wMinus1, hMinus1; // Dimensions minus one - sw_pixelformat_t format; // Pixel format (internal representation) SWfilter minFilter; // Minification filter SWfilter magFilter; // Magnification filter @@ -694,8 +806,6 @@ typedef struct { float tx; // Texel width float ty; // Texel height - bool copy; // Flag indicating whether memory has been allocated - } sw_texture_t; typedef struct { @@ -943,8 +1053,89 @@ static inline void sw_add_vertex_grad_PTCH( out->homogeneous[3] += gradients->homogeneous[3]; } -// Half floating point management functions -static inline uint32_t sw_f16_to_f32_ui(uint16_t h) +static inline void sw_float_to_unorm8_simd(uint8_t dst[4], const float src[4]) +{ +#if defined(SW_HAS_NEON) + float32x4_t values = vld1q_f32(src); + float32x4_t scaled = vmulq_n_f32(values, 255.0f); + scaled = vminq_f32(vmaxq_f32(scaled, vdupq_n_f32(0.0f)), vdupq_n_f32(255.0f)); + uint32x4_t clamped = vcvtq_u32_f32(scaled); + + uint16x4_t narrow16 = vmovn_u32(clamped); + uint8x8_t narrow8 = vmovn_u16(vcombine_u16(narrow16, narrow16)); + + vst1_lane_u32((uint32_t*)dst, vreinterpret_u32_u8(narrow8), 0); + +#elif defined(SW_HAS_SSE41) + __m128 values = _mm_loadu_ps(src); + __m128 scaled = _mm_mul_ps(values, _mm_set1_ps(255.0f)); + scaled = _mm_max_ps(_mm_min_ps(scaled, _mm_set1_ps(255.0f)), _mm_setzero_ps()); + __m128i clamped = _mm_cvtps_epi32(scaled); + + clamped = _mm_packus_epi32(clamped, clamped); + clamped = _mm_packus_epi16(clamped, clamped); + *(uint32_t*)dst = _mm_cvtsi128_si32(clamped); + +#elif defined(SW_HAS_SSE2) + __m128 values = _mm_loadu_ps(src); + __m128 scaled = _mm_mul_ps(values, _mm_set1_ps(255.0f)); + scaled = _mm_max_ps(_mm_min_ps(scaled, _mm_set1_ps(255.0f)), _mm_setzero_ps()); + __m128i clamped = _mm_cvtps_epi32(scaled); + + clamped = _mm_packs_epi32(clamped, clamped); + clamped = _mm_packus_epi16(clamped, clamped); + *(uint32_t*)dst = _mm_cvtsi128_si32(clamped); + +#else + for (int i = 0; i < 4; i++) + { + float val = src[i]*255.0f; + val = (val > 255.0f)? 255.0f : val; + val = (val < 0.0f)? 0.0f : val; + dst[i] = (uint8_t)(val + 0.5f); + } +#endif +} + +static inline void sw_float_from_unorm8_simd(float dst[4], const uint8_t src[4]) +{ +#if defined(SW_HAS_NEON) + uint32x4_t bytes = vdupq_n_u32(0); + bytes = vld1q_lane_u32((const uint32_t*)src, bytes, 0); + + uint8x8_t bytes8 = vreinterpret_u8_u32(vget_low_u32(bytes)); + uint16x8_t bytes16 = vmovl_u8(bytes8); + uint32x4_t ints = vmovl_u16(vget_low_u16(bytes16)); + + float32x4_t floats = vcvtq_f32_u32(ints); + floats = vmulq_n_f32(floats, 1.0f/255.0f); + vst1q_f32(dst, floats); + +#elif defined(SW_HAS_SSE41) + __m128i bytes = _mm_cvtsi32_si128(*(const uint32_t*)src); + __m128i ints = _mm_cvtepu8_epi32(bytes); + __m128 floats = _mm_cvtepi32_ps(ints); + floats = _mm_mul_ps(floats, _mm_set1_ps(1.0f/255.0f)); + _mm_storeu_ps(dst, floats); + +#elif defined(SW_HAS_SSE2) + __m128i bytes = _mm_cvtsi32_si128(*(const uint32_t*)src); + bytes = _mm_unpacklo_epi8(bytes, _mm_setzero_si128()); + __m128i ints = _mm_unpacklo_epi16(bytes, _mm_setzero_si128()); + __m128 floats = _mm_cvtepi32_ps(ints); + floats = _mm_mul_ps(floats, _mm_set1_ps(1.0f/255.0f)); + _mm_storeu_ps(dst, floats); + +#else + dst[0] = (float)src[0]/255.0f; + dst[1] = (float)src[1]/255.0f; + dst[2] = (float)src[2]/255.0f; + dst[3] = (float)src[3]/255.0f; +#endif +} + +// Half conversion functions +static inline uint32_t sw_half_to_float_ui(uint16_t h) { uint32_t s = (uint32_t)(h & 0x8000) << 16; int32_t em = h & 0x7fff; @@ -962,14 +1153,14 @@ static inline uint32_t sw_f16_to_f32_ui(uint16_t h) return s | r; } -static inline float sw_f16_to_f32(sw_half_t y) +static inline float sw_half_to_float(sw_half_t y) { - union { float f; uint32_t i; } v = { .i = sw_f16_to_f32_ui(y) }; + union { float f; uint32_t i; } v = { .i = sw_half_to_float_ui(y) }; return v.f; } -static inline uint16_t sw_f16_from_f32_ui(uint32_t ui) +static inline uint16_t sw_half_from_float_ui(uint32_t ui) { int32_t s = (ui >> 16) & 0x8000; int32_t em = ui & 0x7fffffff; @@ -989,14 +1180,15 @@ static inline uint16_t sw_f16_from_f32_ui(uint32_t ui) return (uint16_t)(s | h); } -static inline sw_half_t sw_f16_from_f32(float i) +static inline sw_half_t sw_half_from_float(float i) { union { float f; uint32_t i; } v; v.f = i; - return sw_f16_from_f32_ui(v.i); + return sw_half_from_float_ui(v.i); } // Framebuffer management functions + static inline bool sw_framebuffer_load(int w, int h) { int size = w*h; @@ -1005,7 +1197,11 @@ static inline bool sw_framebuffer_load(int w, int h) if (RLSW.framebuffer.color == NULL) return false; RLSW.framebuffer.depth = SW_MALLOC(SW_DEPTH_PIXEL_SIZE*size); - if (RLSW.framebuffer.depth == NULL) return false; + if (RLSW.framebuffer.depth == NULL) + { + SW_FREE(RLSW.framebuffer.color); + return false; + } RLSW.framebuffer.width = w; RLSW.framebuffer.height = h; @@ -1025,11 +1221,15 @@ static inline bool sw_framebuffer_resize(int w, int h) return true; } - void *newColor = SW_REALLOC(RLSW.framebuffer.color, newSize); + void *newColor = SW_REALLOC(RLSW.framebuffer.color, SW_COLOR_PIXEL_SIZE*newSize); if (newColor == NULL) return false; - void *newDepth = SW_REALLOC(RLSW.framebuffer.depth, newSize); - if (newDepth == NULL) return false; + void *newDepth = SW_REALLOC(RLSW.framebuffer.depth, SW_DEPTH_PIXEL_SIZE*newSize); + if (newDepth == NULL) + { + SW_FREE(newColor); + return false; + } RLSW.framebuffer.color = newColor; RLSW.framebuffer.depth = newDepth; @@ -1041,314 +1241,221 @@ static inline bool sw_framebuffer_resize(int w, int h) return true; } -static inline void *sw_framebuffer_get_color_addr(const void *ptr, uint32_t offset) -{ - return (uint8_t *)ptr + offset*SW_COLOR_PIXEL_SIZE; -} - -static inline void sw_framebuffer_inc_color_addr(void **ptr) -{ - *ptr = (void *)(((uint8_t *)*ptr) + SW_COLOR_PIXEL_SIZE); -} - -static inline void sw_framebuffer_inc_const_color_addr(const void **ptr) -{ - *ptr = (const void *)(((const uint8_t *)*ptr) + SW_COLOR_PIXEL_SIZE); -} - -static inline void *sw_framebuffer_get_depth_addr(const void *ptr, uint32_t offset) -{ - return (uint8_t *)ptr + offset*SW_DEPTH_PIXEL_SIZE; -} - -static inline void sw_framebuffer_inc_depth_addr(void* *ptr) -{ - *ptr = (void*)(((uint8_t *)*ptr) + SW_DEPTH_PIXEL_SIZE); -} - -#if (SW_COLOR_BUFFER_BITS == 8) // RGB - (3:3:2) static inline void sw_framebuffer_read_color(float dst[4], const void *src) { - uint8_t pixel = ((uint8_t *)src)[0]; - - dst[0] = ((pixel >> 5) & 0x07)*(1.0f/7.0f); - dst[1] = ((pixel >> 2) & 0x07)*(1.0f/7.0f); - dst[2] = (pixel & 0x03)*(1.0f/3.0f); +#if COLOR_IS_PACKED + COLOR_TYPE pixel = ((COLOR_TYPE*)src)[0]; + dst[0] = TO_FLOAT_R(UNPACK_R(pixel)); + dst[1] = TO_FLOAT_G(UNPACK_G(pixel)); + dst[2] = TO_FLOAT_B(UNPACK_B(pixel)); dst[3] = 1.0f; +#else + sw_float_from_unorm8_simd(dst, src); +#endif } static inline void sw_framebuffer_read_color8(uint8_t dst[4], const void *src) { - uint8_t pixel = ((const uint8_t *)src)[0]; - - uint8_t r = (pixel >> 5) & 0x07; - uint8_t g = (pixel >> 2) & 0x07; - uint8_t b = pixel & 0x03; - - dst[0] = (r*255 + 3)/7; - dst[1] = (g*255 + 3)/7; - dst[2] = (b*255 + 1)/3; +#if COLOR_IS_PACKED + COLOR_TYPE pixel = ((COLOR_TYPE*)src)[0]; + dst[0] = SCALE_R(UNPACK_R(pixel)); + dst[1] = SCALE_G(UNPACK_G(pixel)); + dst[2] = SCALE_B(UNPACK_B(pixel)); dst[3] = 255; +#else + const COLOR_TYPE *p = (const COLOR_TYPE*)src; + dst[0] = p[0]; + dst[1] = p[1]; + dst[2] = p[2]; + dst[3] = p[3]; +#endif } -static inline void sw_framebuffer_write_color(void *dst, const float color[3]) +static inline void sw_framebuffer_write_color(void *dst, const float src[4]) { - uint8_t r = ((uint8_t)(color[0]*UINT8_MAX) >> 5) & 0x07; - uint8_t g = ((uint8_t)(color[1]*UINT8_MAX) >> 5) & 0x07; - uint8_t b = ((uint8_t)(color[2]*UINT8_MAX) >> 6) & 0x03; - - ((uint8_t *)dst)[0] = (r << 5) | (g << 2) | b; +#if COLOR_IS_PACKED + ((COLOR_TYPE*)dst)[0] = PACK_COLOR(src[0], src[1], src[2]); +#else + sw_float_to_unorm8_simd(dst, src); +#endif } -static inline void sw_framebuffer_fill_color(void *ptr, int size, const float color[3]) +static inline void sw_framebuffer_fill_color(void *ptr, int size, const float color[4]) { - uint8_t r8 = (uint8_t)(color[0]*7.0f + 0.5f); - uint8_t g8 = (uint8_t)(color[1]*7.0f + 0.5f); - uint8_t b8 = (uint8_t)(color[2]*3.0f + 0.5f); - - uint8_t packedColor = ((r8 & 0x07) << 5) | ((g8 & 0x07) << 2) | (b8 & 0x03); - - uint8_t *p = (uint8_t *)ptr; - +#if COLOR_IS_PACKED + COLOR_TYPE packed = PACK_COLOR(color[0], color[1], color[2]); + COLOR_TYPE *p = (COLOR_TYPE*)ptr; +#else + COLOR_TYPE r = sw_clampi(color[0]*255, 0, 255); + COLOR_TYPE g = sw_clampi(color[1]*255, 0, 255); + COLOR_TYPE b = sw_clampi(color[2]*255, 0, 255); + COLOR_TYPE a = sw_clampi(color[3]*255, 0, 255); + COLOR_TYPE *p = (COLOR_TYPE*)ptr; +#endif + if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST) { - int wScissor = RLSW.scMax[0] - RLSW.scMin[0] + 1; + int w = RLSW.scMax[0] - RLSW.scMin[0] + 1; for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++) { - uint8_t *curPtr = p + y*RLSW.framebuffer.width + RLSW.scMin[0]; - for (int xCount = 0; xCount < wScissor; xCount++) *curPtr++ = packedColor; - } - } - else - { - for (int i = 0; i < size; i++) *p++ = packedColor; - } -} - -#elif (SW_COLOR_BUFFER_BITS == 16) // RGB - (5:6:5) - -static inline void sw_framebuffer_read_color(float dst[4], const void *src) -{ - uint16_t pixel = ((uint16_t *)src)[0]; - - dst[0] = ((pixel >> 11) & 0x1F)*(1.0f/31.0f); - dst[1] = ((pixel >> 5) & 0x3F)*(1.0f/63.0f); - dst[2] = (pixel & 0x1F)*(1.0f/31.0f); - dst[3] = 1.0f; -} - -static inline void sw_framebuffer_read_color8(uint8_t dst[4], const void *src) -{ - uint16_t pixel = ((const uint16_t *)src)[0]; - - uint8_t r = (pixel >> 11) & 0x1F; - uint8_t g = (pixel >> 5) & 0x3F; - uint8_t b = pixel & 0x1F; - - dst[0] = (r*255 + 15)/31; - dst[1] = (g*255 + 31)/63; - dst[2] = (b*255 + 15)/31; - dst[3] = 255; -} - -static inline void sw_framebuffer_write_color(void *dst, const float color[3]) -{ - uint8_t r = (uint8_t)(color[0]*31.0f + 0.5f) & 0x1F; - uint8_t g = (uint8_t)(color[1]*63.0f + 0.5f) & 0x3F; - uint8_t b = (uint8_t)(color[2]*31.0f + 0.5f) & 0x1F; - - ((uint16_t *)dst)[0] = (r << 11) | (g << 5) | b; -} - -static inline void sw_framebuffer_fill_color(void *ptr, int size, const float color[3]) -{ - uint16_t r16 = (uint16_t)(color[0]*31.0f + 0.5f); - uint16_t g_16 = (uint16_t)(color[1]*63.0f + 0.5f); - uint16_t b_16 = (uint16_t)(color[2]*31.0f + 0.5f); - - uint16_t packedColor = ((r16 & 0x1F) << 11) | ((g_16 & 0x3F) << 5) | (b_16 & 0x1F); - - uint16_t *p = (uint16_t *)ptr; - - if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST) - { - int wScissor = RLSW.scMax[0] - RLSW.scMin[0] + 1; - for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++) - { - uint16_t *curPtr = p + y*RLSW.framebuffer.width + RLSW.scMin[0]; - for (int xCount = 0; xCount < wScissor; xCount++) *curPtr++ = packedColor; - } - } - else - { - for (int i = 0; i < size; i++) *p++ = packedColor; - } -} - -#elif (SW_COLOR_BUFFER_BITS == 24) // RGB - (8:8:8) - -static inline void sw_framebuffer_read_color(float dst[4], const void *src) -{ - dst[0] = ((uint8_t *)src)[0]*(1.0f/255.0f); - dst[1] = ((uint8_t *)src)[1]*(1.0f/255.0f); - dst[2] = ((uint8_t *)src)[2]*(1.0f/255.0f); - dst[3] = 1.0f; -} - -static inline void sw_framebuffer_read_color8(uint8_t dst[4], const void *src) -{ - dst[0] = ((uint8_t *)src)[0]; - dst[1] = ((uint8_t *)src)[1]; - dst[2] = ((uint8_t *)src)[2]; - dst[3] = 255; -} - -static inline void sw_framebuffer_write_color(void *dst, const float color[3]) -{ - ((uint8_t *)dst)[0] = (uint8_t)(color[0]*UINT8_MAX); - ((uint8_t *)dst)[1] = (uint8_t)(color[1]*UINT8_MAX); - ((uint8_t *)dst)[2] = (uint8_t)(color[2]*UINT8_MAX); -} - -static inline void sw_framebuffer_fill_color(void *ptr, int size, const float color[3]) -{ - uint8_t r = (uint8_t)(color[0]*255.0f); - uint8_t g = (uint8_t)(color[1]*255.0f); - uint8_t b = (uint8_t)(color[2]*255.0f); - - uint8_t *p = (uint8_t *)ptr; - - if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST) - { - int wScissor = RLSW.scMax[0] - RLSW.scMin[0] + 1; - for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++) - { - uint8_t *curPtr = p + 3*(y*RLSW.framebuffer.width + RLSW.scMin[0]); - for (int xCount = 0; xCount < wScissor; xCount++) +#if COLOR_IS_PACKED + COLOR_TYPE *row = p + y*RLSW.framebuffer.width + RLSW.scMin[0]; + for (int x = 0; x < w; x++) *row++ = packed; +#else + COLOR_TYPE *row = p + 3*(y*RLSW.framebuffer.width + RLSW.scMin[0]); + for (int x = 0; x < w; x++) { - *curPtr++ = r; - *curPtr++ = g; - *curPtr++ = b; + *row++ = r; + *row++ = g; + *row++ = b; + *row++ = a; } +#endif } } else { +#if COLOR_IS_PACKED + for (int i = 0; i < size; i++) *p++ = packed; +#else for (int i = 0; i < size; i++) { *p++ = r; *p++ = g; *p++ = b; + *p++ = a; } +#endif } } -#endif // SW_COLOR_BUFFER_BITS - -#if (SW_DEPTH_BUFFER_BITS == 8) - static inline float sw_framebuffer_read_depth(const void *src) { - return (float)((uint8_t *)src)[0]*(1.0f/UINT8_MAX); +#if DEPTH_IS_PACKED + return ((DEPTH_TYPE*)src)[0]*DEPTH_SCALE; +#else + const DEPTH_TYPE *p = (const DEPTH_TYPE*)src; + uint32_t d = UNPACK_DEPTH(p); + return d*DEPTH_SCALE; +#endif } static inline void sw_framebuffer_write_depth(void *dst, float depth) { - ((uint8_t *)dst)[0] = (uint8_t)(depth*UINT8_MAX); +#if DEPTH_IS_PACKED + ((DEPTH_TYPE*)dst)[0] = PACK_DEPTH(depth); +#else + DEPTH_TYPE *p = (DEPTH_TYPE*)dst; + p[0] = PACK_DEPTH_0(depth); + p[1] = PACK_DEPTH_1(depth); + p[2] = PACK_DEPTH_2(depth); +#endif } static inline void sw_framebuffer_fill_depth(void *ptr, int size, float value) { - uint8_t d8 = (uint8_t)(value*UINT8_MAX); - uint8_t *p = (uint8_t *)ptr; - +#if DEPTH_IS_PACKED + DEPTH_TYPE d = PACK_DEPTH(value); + DEPTH_TYPE *p = (DEPTH_TYPE*)ptr; +#else + DEPTH_TYPE d0 = PACK_DEPTH_0(value); + DEPTH_TYPE d1 = PACK_DEPTH_1(value); + DEPTH_TYPE d2 = PACK_DEPTH_2(value); + DEPTH_TYPE *p = (DEPTH_TYPE*)ptr; +#endif + if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST) { - int wScissor = RLSW.scMax[0] - RLSW.scMin[0] + 1; + int w = RLSW.scMax[0] - RLSW.scMin[0] + 1; for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++) { - uint8_t *curPtr = p + y*RLSW.framebuffer.width + RLSW.scMin[0]; - for (int xCount = 0; xCount < wScissor; xCount++) *curPtr++ = d8; - } - } - else - { - for (int i = 0; i < size; i++) *p++ = d8; - } -} - -#elif (SW_DEPTH_BUFFER_BITS == 16) - -static inline float sw_framebuffer_read_depth(const void *src) -{ - return (float)((uint16_t *)src)[0]*(1.0f/UINT16_MAX); -} - -static inline void sw_framebuffer_write_depth(void *dst, float depth) -{ - ((uint16_t *)dst)[0] = (uint16_t)(depth*UINT16_MAX); -} - -static inline void sw_framebuffer_fill_depth(void *ptr, int size, float value) -{ - uint16_t d16 = (uint16_t)(value*UINT16_MAX); - uint16_t *p = (uint16_t *)ptr; - - if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST) - { - int wScissor = RLSW.scMax[0] - RLSW.scMin[0] + 1; - for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++) - { - uint16_t *curPtr = p + y*RLSW.framebuffer.width + RLSW.scMin[0]; - for (int xCount = 0; xCount < wScissor; xCount++) *curPtr++ = d16; - } - } - else - { - for (int i = 0; i < size; i++) *p++ = d16; - } -} - -#elif (SW_DEPTH_BUFFER_BITS == 24) - -static inline float sw_framebuffer_read_depth(const void *src) -{ - uint32_t depth24 = (((uint8_t *)src)[0] << 16) | - (((uint8_t *)src)[1] << 8) | - ((uint8_t *)src)[2]; - - return depth24/(float)0xFFFFFF; -} - -static inline void sw_framebuffer_write_depth(void *dst, float depth) -{ - uint32_t depth24 = (uint32_t)(depth*0xFFFFFF); - - ((uint8_t *)dst)[0] = (depth24 >> 16) & 0xFF; - ((uint8_t *)dst)[1] = (depth24 >> 8) & 0xFF; - ((uint8_t *)dst)[2] = depth24 & 0xFF; -} - -static inline void sw_framebuffer_fill_depth(void *ptr, int size, float value) -{ - uint32_t d32 = (uint32_t)(value*UINT32_MAX); - uint8_t d_byte0 = (uint8_t)((d32 >> 16) & 0xFF); - uint8_t d_byte1 = (uint8_t)((d32 >> 8) & 0xFF); - uint8_t d_byte2 = (uint8_t)(d32 & 0xFF); - - uint8_t *p = (uint8_t *)ptr; - - if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST) - { - int wScissor = RLSW.scMax[0] - RLSW.scMin[0] + 1; - for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++) - { - uint8_t *curPtr = p + 3*(y*RLSW.framebuffer.width + RLSW.scMin[0]); - for (int xCount = 0; xCount < wScissor; xCount++) +#if DEPTH_IS_PACKED + DEPTH_TYPE *row = p + y*RLSW.framebuffer.width + RLSW.scMin[0]; + for (int x = 0; x < w; x++) *row++ = d; +#else + DEPTH_TYPE *row = p + 3*(y*RLSW.framebuffer.width + RLSW.scMin[0]); + for (int x = 0; x < w; x++) { - *curPtr++ = d_byte0; - *curPtr++ = d_byte1; - *curPtr++ = d_byte2; + *row++ = d0; + *row++ = d1; + *row++ = d2; + } +#endif + } + } + else + { +#if DEPTH_IS_PACKED + for (int i = 0; i < size; i++) *p++ = d; +#else + for (int i = 0; i < size; i++) + { + *p++ = d0; + *p++ = d1; + *p++ = d2; + } +#endif + } +} + +static inline void sw_framebuffer_fill(void *colorPtr, void *depthPtr, int size, float color[4], float depth) +{ +#if COLOR_IS_PACKED + COLOR_TYPE packedColor = PACK_COLOR(color[0], color[1], color[2]); + COLOR_TYPE *pColor = (COLOR_TYPE*)colorPtr; +#else + COLOR_TYPE r = sw_clampi(color[0]*255, 0, 255); + COLOR_TYPE g = sw_clampi(color[1]*255, 0, 255); + COLOR_TYPE b = sw_clampi(color[2]*255, 0, 255); + COLOR_TYPE a = sw_clampi(color[3]*255, 0, 255); + COLOR_TYPE *pColor = (COLOR_TYPE*)colorPtr; +#endif + +#if DEPTH_IS_PACKED + DEPTH_TYPE d = PACK_DEPTH(depth); + DEPTH_TYPE *pDepth = (DEPTH_TYPE*)depthPtr; +#else + DEPTH_TYPE d0 = PACK_DEPTH_0(depth); + DEPTH_TYPE d1 = PACK_DEPTH_1(depth); + DEPTH_TYPE d2 = PACK_DEPTH_2(depth); + DEPTH_TYPE *pDepth = (DEPTH_TYPE*)depthPtr; +#endif + + if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST) + { + int w = RLSW.scMax[0] - RLSW.scMin[0] + 1; + for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++) + { +#if COLOR_IS_PACKED + COLOR_TYPE *rowColor = pColor + y*RLSW.framebuffer.width + RLSW.scMin[0]; +#else + COLOR_TYPE *rowColor = pColor + 3*(y*RLSW.framebuffer.width + RLSW.scMin[0]); +#endif + +#if DEPTH_IS_PACKED + DEPTH_TYPE *rowDepth = pDepth + y*RLSW.framebuffer.width + RLSW.scMin[0]; +#else + DEPTH_TYPE *rowDepth = pDepth + 3*(y*RLSW.framebuffer.width + RLSW.scMin[0]); +#endif + + for (int x = 0; x < w; x++) + { +#if COLOR_IS_PACKED + *rowColor++ = packedColor; +#else + *rowColor++ = r; + *rowColor++ = g; + *rowColor++ = b; + *rowColor++ = a; +#endif + +#if DEPTH_IS_PACKED + *rowDepth++ = d; +#else + *rowDepth++ = d0; + *rowDepth++ = d1; + *rowDepth++ = d2; +#endif } } } @@ -1356,140 +1463,27 @@ static inline void sw_framebuffer_fill_depth(void *ptr, int size, float value) { for (int i = 0; i < size; i++) { - *p++ = d_byte0; - *p++ = d_byte1; - *p++ = d_byte2; +#if COLOR_IS_PACKED + *pColor++ = packedColor; +#else + *pColor++ = r; + *pColor++ = g; + *pColor++ = b; + *pColor++ = a; +#endif + +#if DEPTH_IS_PACKED + *pDepth++ = d; +#else + *pDepth++ = d0; + *pDepth++ = d1; + *pDepth++ = d2; +#endif } } } -#endif // SW_DEPTH_BUFFER_BITS - -static inline void sw_framebuffer_fill(void *colorPtr, void *depthPtr, int size, float color[4], float depth_value) -{ -#if (SW_COLOR_BUFFER_BITS == 8) - // Calculate and pack 3:3:2 color - // Scale color components to the max value for each bit depth and round - uint8_t r8 = (uint8_t)(color[0]*7.0f + 0.5f); - uint8_t g8 = (uint8_t)(color[1]*7.0f + 0.5f); - uint8_t b8 = (uint8_t)(color[2]*3.0f + 0.5f); - // Pack the components into a single byte - uint8_t packedColor = ((r8 & 0x07) << 5) | ((g8 & 0x07) << 2) | (b8 & 0x03); - uint8_t *cptr = (uint8_t *)colorPtr; -#elif (SW_COLOR_BUFFER_BITS == 16) - // Calculate and pack 5:6:5 color - // Scale color components to the max value for each bit depth and round - uint16_t r16 = (uint16_t)(color[0]*31.0f + 0.5f); - uint16_t g16 = (uint16_t)(color[1]*63.0f + 0.5f); - uint16_t b16 = (uint16_t)(color[2]*31.0f + 0.5f); - // Pack the components into a 16-bit value - uint16_t packedColor = ((r16 & 0x1F) << 11) | ((g16 & 0x3F) << 5) | (b16 & 0x1F); - uint16_t *cptr = (uint16_t *)colorPtr; -#elif (SW_COLOR_BUFFER_BITS == 24) - // Calculate 8:8:8 color components - uint8_t r24 = (uint8_t)(color[0]*255.0f); - uint8_t g24 = (uint8_t)(color[1]*255.0f); - uint8_t b24 = (uint8_t)(color[2]*255.0f); - uint8_t *cptr = (uint8_t *)colorPtr; -#endif - -#if (SW_DEPTH_BUFFER_BITS == 8) - // Calculate 8-bit depth - uint8_t d8 = (uint8_t)(depth_value*UINT8_MAX); - uint8_t *dptr = (uint8_t *)depthPtr; -#elif (SW_DEPTH_BUFFER_BITS == 16) - // Calculate 16-bit depth - uint16_t d16 = (uint16_t)(depth_value*UINT16_MAX); - uint16_t *dptr = (uint16_t *)depthPtr; -#elif (SW_DEPTH_BUFFER_BITS == 24) - // Calculate 24-bit depth and pre-calculate bytes - uint32_t d32 = (uint32_t)(depth_value*UINT32_MAX); - uint8_t dByte0 = (uint8_t)((d32 >> 16) & 0xFF); - uint8_t dByte1 = (uint8_t)((d32 >> 8) & 0xFF); - uint8_t dByte2 = (uint8_t)(d32 & 0xFF); - uint8_t *dptr = (uint8_t *)depthPtr; -#endif - - if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST) - { - int wScissor = RLSW.scMax[0] - RLSW.scMin[0] + 1; - for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++) - { - int rowStartIdx = y*RLSW.framebuffer.width + RLSW.scMin[0]; - - // Calculate starting pointers for the current row within the scissor rectangle - #if (SW_COLOR_BUFFER_BITS == 8) - uint8_t *curCPtr = cptr + rowStartIdx; - #elif (SW_COLOR_BUFFER_BITS == 16) - uint16_t *curCPtr = cptr + rowStartIdx; - #elif (SW_COLOR_BUFFER_BITS == 24) - uint8_t *curCPtr = cptr + 3*rowStartIdx; - #endif - - #if (SW_DEPTH_BUFFER_BITS == 8) - uint8_t *curDPtr = dptr + rowStartIdx; - #elif (SW_DEPTH_BUFFER_BITS == 16) - uint16_t *curDPtr = dptr + rowStartIdx; - #elif (SW_DEPTH_BUFFER_BITS == 24) - uint8_t *curDPtr = dptr + 3*rowStartIdx; - #endif - - // Fill the current row within the scissor rectangle - for (int xCount = 0; xCount < wScissor; xCount++) - { - // Write color - #if (SW_COLOR_BUFFER_BITS == 8) - *curCPtr++ = packedColor; - #elif (SW_COLOR_BUFFER_BITS == 16) - *curCPtr++ = packedColor; - #elif (SW_COLOR_BUFFER_BITS == 24) - *curCPtr++ = r24; - *curCPtr++ = g24; - *curCPtr++ = b24; - #endif - - // Write depth - #if (SW_DEPTH_BUFFER_BITS == 8) - *curDPtr++ = d8; - #elif (SW_DEPTH_BUFFER_BITS == 16) - *curDPtr++ = d16; - #elif (SW_DEPTH_BUFFER_BITS == 24) - *curDPtr++ = dByte0; - *curDPtr++ = dByte1; - *curDPtr++ = dByte2; - #endif - } - } - return; - } - - for (int i = 0; i < size; i++) - { - // Write color - #if (SW_COLOR_BUFFER_BITS == 8) - *cptr++ = packedColor; - #elif (SW_COLOR_BUFFER_BITS == 16) - *cptr++ = packedColor; - #elif (SW_COLOR_BUFFER_BITS == 24) - *cptr++ = r24; - *cptr++ = g24; - *cptr++ = b24; - #endif - - // Write depth - #if (SW_DEPTH_BUFFER_BITS == 8) - *dptr++ = d8; - #elif (SW_DEPTH_BUFFER_BITS == 16) - *dptr++ = d16; - #elif (SW_DEPTH_BUFFER_BITS == 24) - *dptr++ = dByte0; - *dptr++ = dByte1; - *dptr++ = dByte2; - #endif - } -} - -#define DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(name, DST_PTR_T) \ +#define DEFINE_FRAMEBUFFER_COPY_BEGIN(name, DST_PTR_T) \ static inline void sw_framebuffer_copy_to_##name(int x, int y, int w, int h, DST_PTR_T *dst) \ { \ const void *src = RLSW.framebuffer.color; \ @@ -1499,23 +1493,13 @@ static inline void sw_framebuffer_copy_to_##name(int x, int y, int w, int h, DST uint8_t color[4]; \ sw_framebuffer_read_color8(color, src); \ -#define DEFINE_FRAMEBUFFER_COPY_F32_BEGIN(name, DST_PTR_T) \ -static inline void sw_framebuffer_copy_to_##name(int x, int y, int w, int h, DST_PTR_T *dst) \ -{ \ - const void *src = RLSW.framebuffer.color; \ - \ - for (int iy = y; iy < h; iy++) { \ - for (int ix = x; ix < w; ix++) { \ - float color[4]; \ - sw_framebuffer_read_color(color, src); \ - #define DEFINE_FRAMEBUFFER_COPY_END() \ - sw_framebuffer_inc_const_color_addr(&src); \ + INC_COLOR_PTR(src); \ } \ } \ } -DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(GRAYSCALE, uint8_t) +DEFINE_FRAMEBUFFER_COPY_BEGIN(GRAYSCALE, uint8_t) { // NTSC grayscale conversion: Y = 0.299R + 0.587G + 0.114B uint8_t gray = (uint8_t)((color[0]*299 + color[1]*587 + color[2]*114 + 500)/1000); @@ -1523,7 +1507,7 @@ DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(GRAYSCALE, uint8_t) } DEFINE_FRAMEBUFFER_COPY_END() -DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(GRAYALPHA, uint8_t) +DEFINE_FRAMEBUFFER_COPY_BEGIN(GRAYALPHA, uint8_t) { // Convert RGB to grayscale using NTSC formula uint8_t gray = (uint8_t)((color[0]*299 + color[1]*587 + color[2]*114 + 500)/1000); @@ -1535,7 +1519,7 @@ DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(GRAYALPHA, uint8_t) } DEFINE_FRAMEBUFFER_COPY_END() -DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(R5G6B5, uint16_t) +DEFINE_FRAMEBUFFER_COPY_BEGIN(R5G6B5, uint16_t) { // Convert 8-bit RGB to 5:6:5 format uint8_t r5 = (color[0]*31 + 127)/255; @@ -1552,7 +1536,7 @@ DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(R5G6B5, uint16_t) } DEFINE_FRAMEBUFFER_COPY_END() -DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(R8G8B8, uint8_t) +DEFINE_FRAMEBUFFER_COPY_BEGIN(R8G8B8, uint8_t) { #if SW_GL_FRAMEBUFFER_COPY_BGRA dst[0] = color[2]; @@ -1568,7 +1552,7 @@ DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(R8G8B8, uint8_t) } DEFINE_FRAMEBUFFER_COPY_END() -DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(R5G5B5A1, uint16_t) +DEFINE_FRAMEBUFFER_COPY_BEGIN(R5G5B5A1, uint16_t) { uint8_t r5 = (color[0]*31 + 127)/255; uint8_t g5 = (color[1]*31 + 127)/255; @@ -1585,7 +1569,7 @@ DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(R5G5B5A1, uint16_t) } DEFINE_FRAMEBUFFER_COPY_END() -DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(R4G4B4A4, uint16_t) +DEFINE_FRAMEBUFFER_COPY_BEGIN(R4G4B4A4, uint16_t) { uint8_t r4 = (color[0]*15 + 127)/255; uint8_t g4 = (color[1]*15 + 127)/255; @@ -1602,7 +1586,7 @@ DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(R4G4B4A4, uint16_t) } DEFINE_FRAMEBUFFER_COPY_END() -DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(R8G8B8A8, uint8_t) +DEFINE_FRAMEBUFFER_COPY_BEGIN(R8G8B8A8, uint8_t) { #if SW_GL_FRAMEBUFFER_COPY_BGRA dst[0] = color[2]; @@ -1619,87 +1603,7 @@ DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(R8G8B8A8, uint8_t) } DEFINE_FRAMEBUFFER_COPY_END() -DEFINE_FRAMEBUFFER_COPY_F32_BEGIN(R32, float) -{ - dst[0] = color[0]; - dst++; -} -DEFINE_FRAMEBUFFER_COPY_END() - -DEFINE_FRAMEBUFFER_COPY_F32_BEGIN(R32G32B32, float) -{ -#if SW_GL_FRAMEBUFFER_COPY_BGRA - dst[0] = color[2]; - dst[1] = color[1]; - dst[2] = color[0]; -#else // RGBA - dst[0] = color[0]; - dst[1] = color[1]; - dst[2] = color[2]; -#endif - - dst += 3; -} -DEFINE_FRAMEBUFFER_COPY_END() - -DEFINE_FRAMEBUFFER_COPY_F32_BEGIN(R32G32B32A32, float) -{ -#if SW_GL_FRAMEBUFFER_COPY_BGRA - dst[0] = color[2]; - dst[1] = color[1]; - dst[2] = color[0]; -#else // RGBA - dst[0] = color[0]; - dst[1] = color[1]; - dst[2] = color[2]; -#endif - dst[3] = color[3]; - - dst += 4; -} -DEFINE_FRAMEBUFFER_COPY_END() - -DEFINE_FRAMEBUFFER_COPY_F32_BEGIN(R16, sw_half_t) -{ - dst[0] = sw_f16_from_f32(color[0]); - dst++; -} -DEFINE_FRAMEBUFFER_COPY_END() - -DEFINE_FRAMEBUFFER_COPY_F32_BEGIN(R16G16B16, sw_half_t) -{ -#if SW_GL_FRAMEBUFFER_COPY_BGRA - dst[0] = sw_f16_from_f32(color[2]); - dst[1] = sw_f16_from_f32(color[1]); - dst[2] = sw_f16_from_f32(color[0]); -#else // RGBA - dst[0] = sw_f16_from_f32(color[0]); - dst[1] = sw_f16_from_f32(color[1]); - dst[2] = sw_f16_from_f32(color[2]); -#endif - - dst += 3; -} -DEFINE_FRAMEBUFFER_COPY_END() - -DEFINE_FRAMEBUFFER_COPY_F32_BEGIN(R16G16B16A16, sw_half_t) -{ -#if SW_GL_FRAMEBUFFER_COPY_BGRA - dst[0] = sw_f16_from_f32(color[2]); - dst[1] = sw_f16_from_f32(color[1]); - dst[2] = sw_f16_from_f32(color[0]); -#else // RGBA - dst[0] = sw_f16_from_f32(color[0]); - dst[1] = sw_f16_from_f32(color[1]); - dst[2] = sw_f16_from_f32(color[2]); -#endif - dst[3] = sw_f16_from_f32(color[3]); - - dst += 4; -} -DEFINE_FRAMEBUFFER_COPY_END() - -#define DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(name, DST_PTR_T) \ +#define DEFINE_FRAMEBUFFER_BLIT_BEGIN(name, DST_PTR_T) \ static inline void sw_framebuffer_blit_to_##name( \ int xDst, int yDst, int wDst, int hDst, \ int xSrc, int ySrc, int wSrc, int hSrc, \ @@ -1708,56 +1612,33 @@ static inline void sw_framebuffer_blit_to_##name( const uint8_t *srcBase = (uint8_t*)RLSW.framebuffer.color; \ int fbWidth = RLSW.framebuffer.width; \ \ - uint32_t xScale = ((uint32_t)wSrc << 16)/(uint32_t)wDst; \ - uint32_t yScale = ((uint32_t)hSrc << 16)/(uint32_t)hDst; \ + uint32_t xScale = ((uint32_t)wSrc << 16)/(uint32_t)wDst; \ + uint32_t yScale = ((uint32_t)hSrc << 16)/(uint32_t)hDst; \ \ for (int dy = 0; dy < hDst; dy++) { \ - uint32_t yFix = ((uint32_t)ySrc << 16) + dy*yScale; \ + uint32_t yFix = ((uint32_t)ySrc << 16) + dy*yScale; \ int sy = yFix >> 16; \ \ for (int dx = 0; dx < wDst; dx++) { \ - uint32_t xFix = dx*xScale; \ + uint32_t xFix = dx*xScale; \ int sx = xFix >> 16; \ - const void *srcPtr = sw_framebuffer_get_color_addr(srcBase, sy*fbWidth + sx); \ + const void *srcPtr = GET_COLOR_PTR(srcBase, sy*fbWidth + sx); \ uint8_t color[4]; \ sw_framebuffer_read_color8(color, srcPtr); \ -#define DEFINE_FRAMEBUFFER_BLIT_F32_BEGIN(name, DST_PTR_T) \ -static inline void sw_framebuffer_blit_to_##name( \ - int xDst, int yDst, int wDst, int hDst, \ - int xSrc, int ySrc, int wSrc, int hSrc, \ - DST_PTR_T *dst) \ -{ \ - const uint8_t *srcBase = (uint8_t *)RLSW.framebuffer.color; \ - int fbWidth = RLSW.framebuffer.width; \ - \ - uint32_t xScale = ((uint32_t)wSrc << 16)/(uint32_t)wDst; \ - uint32_t yScale = ((uint32_t)hSrc << 16)/(uint32_t)hDst; \ - \ - for (int dy = 0; dy < hDst; dy++) { \ - uint32_t yFix = ((uint32_t)ySrc << 16) + dy*yScale; \ - int sy = yFix >> 16; \ - \ - for (int dx = 0; dx < wDst; dx++) { \ - uint32_t xFix = dx*xScale; \ - int sx = xFix >> 16; \ - const void *srcPtr = sw_framebuffer_get_color_addr(srcBase, sy*fbWidth + sx); \ - float color[4]; \ - sw_framebuffer_read_color(color, srcPtr); \ - #define DEFINE_FRAMEBUFFER_BLIT_END() \ } \ } \ } -DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(GRAYSCALE, uint8_t) +DEFINE_FRAMEBUFFER_BLIT_BEGIN(GRAYSCALE, uint8_t) { uint8_t gray = (uint8_t)((color[0]*299 + color[1]*587 + color[2]*114 + 500)/1000); *dst++ = gray; } DEFINE_FRAMEBUFFER_BLIT_END() -DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(GRAYALPHA, uint8_t) +DEFINE_FRAMEBUFFER_BLIT_BEGIN(GRAYALPHA, uint8_t) { uint8_t gray = (uint8_t)((color[0]*299 + color[1]*587 + color[2]*114 + 500)/1000); @@ -1768,7 +1649,7 @@ DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(GRAYALPHA, uint8_t) } DEFINE_FRAMEBUFFER_BLIT_END() -DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(R5G6B5, uint16_t) +DEFINE_FRAMEBUFFER_BLIT_BEGIN(R5G6B5, uint16_t) { uint8_t r5 = (color[0]*31 + 127)/255; uint8_t g6 = (color[1]*63 + 127)/255; @@ -1784,7 +1665,7 @@ DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(R5G6B5, uint16_t) } DEFINE_FRAMEBUFFER_BLIT_END() -DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(R8G8B8, uint8_t) +DEFINE_FRAMEBUFFER_BLIT_BEGIN(R8G8B8, uint8_t) { #if SW_GL_FRAMEBUFFER_COPY_BGRA dst[0] = color[2]; @@ -1800,7 +1681,7 @@ DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(R8G8B8, uint8_t) } DEFINE_FRAMEBUFFER_BLIT_END() -DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(R5G5B5A1, uint16_t) +DEFINE_FRAMEBUFFER_BLIT_BEGIN(R5G5B5A1, uint16_t) { uint8_t r5 = (color[0]*31 + 127)/255; uint8_t g5 = (color[1]*31 + 127)/255; @@ -1817,7 +1698,7 @@ DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(R5G5B5A1, uint16_t) } DEFINE_FRAMEBUFFER_BLIT_END() -DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(R4G4B4A4, uint16_t) +DEFINE_FRAMEBUFFER_BLIT_BEGIN(R4G4B4A4, uint16_t) { uint8_t r4 = (color[0]*15 + 127)/255; uint8_t g4 = (color[1]*15 + 127)/255; @@ -1834,7 +1715,7 @@ DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(R4G4B4A4, uint16_t) } DEFINE_FRAMEBUFFER_BLIT_END() -DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(R8G8B8A8, uint8_t) +DEFINE_FRAMEBUFFER_BLIT_BEGIN(R8G8B8A8, uint8_t) { #if SW_GL_FRAMEBUFFER_COPY_BGRA dst[0] = color[2]; @@ -1851,86 +1732,6 @@ DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(R8G8B8A8, uint8_t) } DEFINE_FRAMEBUFFER_BLIT_END() -DEFINE_FRAMEBUFFER_BLIT_F32_BEGIN(R32, uint8_t) -{ - dst[0] = color[0]; - dst++; -} -DEFINE_FRAMEBUFFER_BLIT_END() - -DEFINE_FRAMEBUFFER_BLIT_F32_BEGIN(R32G32B32, float) -{ -#if SW_GL_FRAMEBUFFER_COPY_BGRA - dst[0] = color[2]; - dst[1] = color[1]; - dst[2] = color[0]; -#else // RGBA - dst[0] = color[0]; - dst[1] = color[1]; - dst[2] = color[2]; -#endif - - dst += 3; -} -DEFINE_FRAMEBUFFER_BLIT_END() - -DEFINE_FRAMEBUFFER_BLIT_F32_BEGIN(R32G32B32A32, float) -{ -#if SW_GL_FRAMEBUFFER_COPY_BGRA - dst[0] = color[2]; - dst[1] = color[1]; - dst[2] = color[0]; -#else // RGBA - dst[0] = color[0]; - dst[1] = color[1]; - dst[2] = color[2]; -#endif - dst[3] = color[3]; - - dst += 4; -} -DEFINE_FRAMEBUFFER_BLIT_END() - -DEFINE_FRAMEBUFFER_BLIT_F32_BEGIN(R16, sw_half_t) -{ - dst[0] = sw_f16_from_f32(color[0]); - dst++; -} -DEFINE_FRAMEBUFFER_BLIT_END() - -DEFINE_FRAMEBUFFER_BLIT_F32_BEGIN(R16G16B16, sw_half_t) -{ -#if SW_GL_FRAMEBUFFER_COPY_BGRA - dst[0] = sw_f16_from_f32(color[2]); - dst[1] = sw_f16_from_f32(color[1]); - dst[2] = sw_f16_from_f32(color[0]); -#else // RGBA - dst[0] = sw_f16_from_f32(color[0]); - dst[1] = sw_f16_from_f32(color[1]); - dst[2] = sw_f16_from_f32(color[2]); -#endif - - dst += 3; -} -DEFINE_FRAMEBUFFER_BLIT_END() - -DEFINE_FRAMEBUFFER_BLIT_F32_BEGIN(R16G16B16A16, sw_half_t) -{ -#if SW_GL_FRAMEBUFFER_COPY_BGRA - dst[0] = sw_f16_from_f32(color[2]); - dst[1] = sw_f16_from_f32(color[1]); - dst[2] = sw_f16_from_f32(color[0]); -#else // RGBA - dst[0] = sw_f16_from_f32(color[0]); - dst[1] = sw_f16_from_f32(color[1]); - dst[2] = sw_f16_from_f32(color[2]); -#endif - dst[3] = sw_f16_from_f32(color[3]); - - dst += 4; -} -DEFINE_FRAMEBUFFER_BLIT_END() - // Pixel format management functions static inline int sw_get_pixel_format(SWformat format, SWtype type) @@ -1985,210 +1786,178 @@ static inline int sw_get_pixel_format(SWformat format, SWtype type) return SW_PIXELFORMAT_UNKNOWN; } -int sw_get_pixel_bytes(sw_pixelformat_t format) +static inline void sw_get_pixel(uint8_t *color, const void *pixels, uint32_t offset, sw_pixelformat_t format) { - int bpp = 0; - switch (format) { - case SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: bpp = 1; break; + case SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: + { + uint8_t gray = ((const uint8_t*)pixels)[offset]; + color[0] = gray; + color[1] = gray; + color[2] = gray; + color[3] = 255; + break; + } case SW_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: + { + const uint8_t *src = &((const uint8_t*)pixels)[offset*2]; + color[0] = src[0]; + color[1] = src[0]; + color[2] = src[0]; + color[3] = src[1]; + break; + } case SW_PIXELFORMAT_UNCOMPRESSED_R5G6B5: + { + uint16_t pixel = ((const uint16_t*)pixels)[offset]; + color[0] = ((pixel >> 11) & 0x1F)*255/31; // R (5 bits) + color[1] = ((pixel >> 5) & 0x3F)*255/63; // G (6 bits) + color[2] = (pixel & 0x1F)*255/31; // B (5 bits) + color[3] = 255; + break; + } + case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8: + { + const uint8_t *src = &((const uint8_t*)pixels)[offset*3]; + color[0] = src[0]; + color[1] = src[1]; + color[2] = src[2]; + color[3] = 255; + break; + } case SW_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: - case SW_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: bpp = 2; break; - case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: bpp = 4; break; - case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8: bpp = 3; break; - case SW_PIXELFORMAT_UNCOMPRESSED_R32: bpp = 4; break; - case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32: bpp = 4*3; break; - case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: bpp = 4*4; break; - case SW_PIXELFORMAT_UNCOMPRESSED_R16: bpp = 2; break; - case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16: bpp = 2*3; break; - case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: bpp = 2*4; break; - default: break; - } - - return bpp; -} - -static inline void sw_get_pixel_grayscale(float *color, const void *pixels, uint32_t offset) -{ - float gray = (float)((uint8_t *)pixels)[offset]*(1.0f/255); - - color[0] = gray; - color[1] = gray; - color[2] = gray; - color[3] = 1.0f; -} - -static inline void sw_get_pixel_red_16(float *color, const void *pixels, uint32_t offset) -{ - float value = sw_f16_to_f32(((sw_half_t *)pixels)[offset]); - - color[0] = value; - color[1] = value; - color[2] = value; - color[3] = 1.0f; -} - -static inline void sw_get_pixel_red_32(float *color, const void *pixels, uint32_t offset) -{ - float value = ((float *)pixels)[offset]; - - color[0] = value; - color[1] = value; - color[2] = value; - color[3] = 1.0f; -} - -static inline void sw_get_pixel_grayscale_alpha(float *color, const void *pixels, uint32_t offset) -{ - const uint8_t *pixelData = (const uint8_t *)pixels + 2*offset; - - color[0] = color[1] = color[2] = (float)pixelData[0]*(1.0f/255); - color[3] = (float)pixelData[1]*(1.0f/255); -} - -static inline void sw_get_pixel_rgb_565(float *color, const void *pixels, uint32_t offset) -{ - uint16_t pixel = ((uint16_t *)pixels)[offset]; - - color[0] = (float)((pixel & 0xF800) >> 11)/31; - color[1] = (float)((pixel & 0x7E0) >> 5)/63; - color[2] = (float)(pixel & 0x1F)/31; - color[3] = 1.0f; -} - -static inline void sw_get_pixel_rgb_888(float *color, const void *pixels, uint32_t offset) -{ - const uint8_t *pixel = (const uint8_t *)pixels + 3*offset; - - color[0] = (float)pixel[0]*(1.0f/255); - color[1] = (float)pixel[1]*(1.0f/255); - color[2] = (float)pixel[2]*(1.0f/255); - color[3] = 1.0f; -} - -static inline void sw_get_pixel_rgb_161616(float *color, const void *pixels, uint32_t offset) -{ - const sw_half_t *pixel = (sw_half_t *)pixels + 3*offset; - - color[0] = sw_f16_to_f32(pixel[0]); - color[1] = sw_f16_to_f32(pixel[1]); - color[2] = sw_f16_to_f32(pixel[2]); - color[3] = 1.0f; -} - -static inline void sw_get_pixel_rgb_323232(float *color, const void *pixels, uint32_t offset) -{ - const float *pixel = (float *)pixels + 3*offset; - - color[0] = pixel[0]; - color[1] = pixel[1]; - color[2] = pixel[2]; - color[3] = 1.0f; -} - -static inline void sw_get_pixel_rgba_5551(float *color, const void *pixels, uint32_t offset) -{ - uint16_t pixel = ((uint16_t *)pixels)[offset]; - - color[0] = (float)((pixel & 0xF800) >> 11)/31; - color[1] = (float)((pixel & 0x7C0) >> 6)/31; - color[2] = (float)((pixel & 0x3E) >> 1)/31; - color[3] = (float)(pixel & 0x1); -} - -static inline void sw_get_pixel_rgba_4444(float *color, const void *pixels, uint32_t offset) -{ - uint16_t pixel = ((uint16_t *)pixels)[offset]; - - color[0] = (float)((pixel & 0xF000) >> 12)/15; - color[1] = (float)((pixel & 0xF00) >> 8)/15; - color[2] = (float)((pixel & 0xF0) >> 4)/15; - color[3] = (float)(pixel & 0xF)/15; -} - -static inline void sw_get_pixel_rgba_8888(float *color, const void *pixels, uint32_t offset) -{ - const uint8_t *pixel = (uint8_t *)pixels + 4*offset; - - color[0] = (float)pixel[0]*(1.0f/255); - color[1] = (float)pixel[1]*(1.0f/255); - color[2] = (float)pixel[2]*(1.0f/255); - color[3] = (float)pixel[3]*(1.0f/255); -} - -static inline void sw_get_pixel_rgba_16161616(float *color, const void *pixels, uint32_t offset) -{ - const sw_half_t *pixel = (sw_half_t *)pixels + 4*offset; - - color[0] = sw_f16_to_f32(pixel[0]); - color[1] = sw_f16_to_f32(pixel[1]); - color[2] = sw_f16_to_f32(pixel[2]); - color[3] = sw_f16_to_f32(pixel[3]); -} - -static inline void sw_get_pixel_rgba_32323232(float *color, const void *pixels, uint32_t offset) -{ - const float *pixel = (float *)pixels + 4*offset; - - color[0] = pixel[0]; - color[1] = pixel[1]; - color[2] = pixel[2]; - color[3] = pixel[3]; -} - -static inline void sw_get_pixel(float *color, const void *pixels, uint32_t offset, sw_pixelformat_t format) -{ - switch (format) - { - case SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: sw_get_pixel_grayscale(color, pixels, offset); break; - case SW_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: sw_get_pixel_grayscale_alpha(color, pixels, offset); break; - case SW_PIXELFORMAT_UNCOMPRESSED_R5G6B5: sw_get_pixel_rgb_565(color, pixels, offset); break; - case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8: sw_get_pixel_rgb_888(color, pixels, offset); break; - case SW_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: sw_get_pixel_rgba_5551(color, pixels, offset); break; - case SW_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: sw_get_pixel_rgba_4444(color, pixels, offset); break; - case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: sw_get_pixel_rgba_8888(color, pixels, offset); break; - case SW_PIXELFORMAT_UNCOMPRESSED_R32: sw_get_pixel_red_32(color, pixels, offset); break; - case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32: sw_get_pixel_rgb_323232(color, pixels, offset); break; - case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: sw_get_pixel_rgba_32323232(color, pixels, offset); break; - case SW_PIXELFORMAT_UNCOMPRESSED_R16: sw_get_pixel_red_16(color, pixels, offset); break; - case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16: sw_get_pixel_rgb_161616(color, pixels, offset); break; - case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: sw_get_pixel_rgba_16161616(color, pixels, offset); break; - case SW_PIXELFORMAT_UNKNOWN: break; - default: break; + { + uint16_t pixel = ((const uint16_t*)pixels)[offset]; + color[0] = ((pixel >> 11) & 0x1F)*255/31; // R (5 bits) + color[1] = ((pixel >> 6) & 0x1F)*255/31; // G (5 bits) + color[2] = ((pixel >> 1) & 0x1F)*255/31; // B (5 bits) + color[3] = (pixel & 0x01)*255; // A (1 bit) + break; + } + case SW_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: + { + uint16_t pixel = ((const uint16_t*)pixels)[offset]; + color[0] = ((pixel >> 12) & 0x0F)*255/15; // R (4 bits) + color[1] = ((pixel >> 8) & 0x0F)*255/15; // G (4 bits) + color[2] = ((pixel >> 4) & 0x0F)*255/15; // B (4 bits) + color[3] = (pixel & 0x0F)*255/15; // A (4 bits) + break; + } + case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: + { + const uint8_t *src = &((const uint8_t*)pixels)[offset*4]; + color[0] = src[0]; + color[1] = src[1]; + color[2] = src[2]; + color[3] = src[3]; + break; + } + case SW_PIXELFORMAT_UNCOMPRESSED_R32: + { + float val = ((const float*)pixels)[offset]; + uint8_t gray = (uint8_t)(val*255.0f); + color[0] = gray; + color[1] = gray; + color[2] = gray; + color[3] = 255; + break; + } + case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32: + { + const float *src = &((const float*)pixels)[offset*3]; + color[0] = (uint8_t)(src[0]*255.0f); + color[1] = (uint8_t)(src[1]*255.0f); + color[2] = (uint8_t)(src[2]*255.0f); + color[3] = 255; + break; + } + case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: + { + const float *src = &((const float*)pixels)[offset*4]; + color[0] = (uint8_t)(src[0]*255.0f); + color[1] = (uint8_t)(src[1]*255.0f); + color[2] = (uint8_t)(src[2]*255.0f); + color[3] = (uint8_t)(src[3]*255.0f); + break; + } + case SW_PIXELFORMAT_UNCOMPRESSED_R16: + { + uint16_t val = ((const uint16_t*)pixels)[offset]; + uint8_t gray = sw_half_to_float(val)/255.0f; + color[0] = gray; + color[1] = gray; + color[2] = gray; + color[3] = 255; + break; + } + case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16: + { + const uint16_t *src = &((const uint16_t*)pixels)[offset*3]; + color[0] = sw_half_to_float(src[0])/255.0f; + color[1] = sw_half_to_float(src[1])/255.0f; + color[2] = sw_half_to_float(src[2])/255.0f; + color[3] = 255; + break; + } + case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: + { + const uint16_t *src = &((const uint16_t*)pixels)[offset*4]; + color[0] = sw_half_to_float(src[0])/255.0f; + color[1] = sw_half_to_float(src[1])/255.0f; + color[2] = sw_half_to_float(src[2])/255.0f; + color[3] = sw_half_to_float(src[3])/255.0f; + break; + } + case SW_PIXELFORMAT_UNKNOWN: + default: + { + color[0] = 0; + color[1] = 0; + color[2] = 0; + color[3] = 0; + break; + } } } // Texture sampling functionality +static inline void sw_texture_fetch(float* color, const sw_texture_t* tex, int x, int y) +{ + sw_float_from_unorm8_simd(color, &tex->pixels[4*(y*tex->width + x)]); +} + static inline void sw_texture_sample_nearest(float *color, const sw_texture_t *tex, float u, float v) { u = (tex->sWrap == SW_REPEAT)? sw_fract(u) : sw_saturate(u); v = (tex->tWrap == SW_REPEAT)? sw_fract(v) : sw_saturate(v); - int x = u*tex->width, y = v*tex->height; + int x = u*tex->width; + int y = v*tex->height; - sw_get_pixel(color, tex->pixels.cptr, y*tex->width + x, tex->format); + sw_texture_fetch(color, tex, x, y); } static inline void sw_texture_sample_linear(float *color, const sw_texture_t *tex, float u, float v) { - // TODO: REVIEW: With a bit more cleverness we could clearly reduce the + // TODO: With a bit more cleverness we could clearly reduce the // number of operations here, but for now it works fine. - float xf = u*tex->width - 0.5f; - float yf = v*tex->height - 0.5f; + float xf = (u*tex->width) - 0.5f; + float yf = (v*tex->height) - 0.5f; - int x0 = (int)floorf(xf); - int y0 = (int)floorf(yf); + float fx = sw_fract(xf); + float fy = sw_fract(yf); - float fx = xf - x0; - float fy = yf - y0; + int x0 = (int)xf; + int y0 = (int)yf; int x1 = x0 + 1; int y1 = y0 + 1; + // NOTE: If the textures are POT we could avoid the division for SW_REPEAT + if (tex->sWrap == SW_CLAMP) { x0 = (x0 > tex->wMinus1)? tex->wMinus1 : x0; @@ -2212,10 +1981,10 @@ static inline void sw_texture_sample_linear(float *color, const sw_texture_t *te } float c00[4], c10[4], c01[4], c11[4]; - sw_get_pixel(c00, tex->pixels.cptr, y0*tex->width + x0, tex->format); - sw_get_pixel(c10, tex->pixels.cptr, y0*tex->width + x1, tex->format); - sw_get_pixel(c01, tex->pixels.cptr, y1*tex->width + x0, tex->format); - sw_get_pixel(c11, tex->pixels.cptr, y1*tex->width + x1, tex->format); + sw_texture_fetch(c00, tex, x0, y0); + sw_texture_fetch(c10, tex, x1, y0); + sw_texture_fetch(c01, tex, x0, y1); + sw_texture_fetch(c11, tex, x1, y1); for (int i = 0; i < 4; i++) { @@ -2512,23 +2281,23 @@ static inline void sw_triangle_clip_and_project(void) // Calculation of the reciprocal of W for normalization // as well as perspective-correct attributes - const float invW = 1.0f/v->homogeneous[3]; - v->homogeneous[3] = invW; + const float wRcp = 1.0f/v->homogeneous[3]; + v->homogeneous[3] = wRcp; // Division of XYZ coordinates by weight - v->homogeneous[0] *= invW; - v->homogeneous[1] *= invW; - v->homogeneous[2] *= invW; + v->homogeneous[0] *= wRcp; + v->homogeneous[1] *= wRcp; + v->homogeneous[2] *= wRcp; // Division of texture coordinates (perspective-correct) - v->texcoord[0] *= invW; - v->texcoord[1] *= invW; + v->texcoord[0] *= wRcp; + v->texcoord[1] *= wRcp; // Division of colors (perspective-correct) - v->color[0] *= invW; - v->color[1] *= invW; - v->color[2] *= invW; - v->color[3] *= invW; + v->color[0] *= wRcp; + v->color[1] *= wRcp; + v->color[2] *= wRcp; + v->color[3] *= wRcp; // Transformation to screen space sw_project_ndc_to_screen(v->screen, v->homogeneous); @@ -2583,8 +2352,8 @@ static inline void FUNC_NAME(const sw_texture_t *tex, const sw_vertex_t *start, } \ \ /* Pre-calculate the starting pointers for the framebuffer row */ \ - void *cptr = sw_framebuffer_get_color_addr(RLSW.framebuffer.color, y*RLSW.framebuffer.width + xStart); \ - void *dptr = sw_framebuffer_get_depth_addr(RLSW.framebuffer.depth, y*RLSW.framebuffer.width + xStart); \ + void *cptr = GET_COLOR_PTR(RLSW.framebuffer.color, y*RLSW.framebuffer.width + xStart); \ + void *dptr = GET_DEPTH_PTR(RLSW.framebuffer.depth, y*RLSW.framebuffer.width + xStart); \ \ /* Scanline rasterization */ \ for (int x = xStart; x < xEnd; x++) \ @@ -2624,12 +2393,7 @@ static inline void FUNC_NAME(const sw_texture_t *tex, const sw_vertex_t *start, { \ float dstColor[4]; \ sw_framebuffer_read_color(dstColor, cptr); \ - \ sw_blend_colors(dstColor, srcColor); \ - dstColor[0] = sw_saturate(dstColor[0]); \ - dstColor[1] = sw_saturate(dstColor[1]); \ - dstColor[2] = sw_saturate(dstColor[2]); \ - \ sw_framebuffer_write_color(cptr, dstColor); \ } \ else \ @@ -2651,8 +2415,8 @@ static inline void FUNC_NAME(const sw_texture_t *tex, const sw_vertex_t *start, v += dvDx; \ } \ \ - sw_framebuffer_inc_color_addr(&cptr); \ - sw_framebuffer_inc_depth_addr(&dptr); \ + INC_COLOR_PTR(cptr); \ + INC_DEPTH_PTR(dptr); \ } \ } @@ -2777,13 +2541,17 @@ static inline void sw_triangle_render(void) } \ } - if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH_BLEND) - else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_DEPTH_BLEND) - else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_TEX_BLEND) - else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST)) TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH) - else if (SW_STATE_CHECK(SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_BLEND) - else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST)) TRIANGLE_RASTER(sw_triangle_raster_DEPTH) - else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D)) TRIANGLE_RASTER(sw_triangle_raster_TEX) + uint32_t state = RLSW.stateFlags; + if (RLSW.currentTexture == 0) state &= ~SW_STATE_TEXTURE_2D; + if ((RLSW.srcFactor == SW_ONE) && (RLSW.dstFactor == SW_ZERO)) state &= ~SW_STATE_BLEND; + + if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH_BLEND) + else if (SW_STATE_CHECK_EX(state, SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_DEPTH_BLEND) + else if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_TEX_BLEND) + else if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST)) TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH) + else if (SW_STATE_CHECK_EX(state, SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_BLEND) + else if (SW_STATE_CHECK_EX(state, SW_STATE_DEPTH_TEST)) TRIANGLE_RASTER(sw_triangle_raster_DEPTH) + else if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D)) TRIANGLE_RASTER(sw_triangle_raster_TEX) else TRIANGLE_RASTER(sw_triangle_raster) #undef TRIANGLE_RASTER @@ -2859,23 +2627,23 @@ static inline void sw_quad_clip_and_project(void) // Calculation of the reciprocal of W for normalization // as well as perspective-correct attributes - const float invW = 1.0f/v->homogeneous[3]; - v->homogeneous[3] = invW; + const float wRcp = 1.0f/v->homogeneous[3]; + v->homogeneous[3] = wRcp; // Division of XYZ coordinates by weight - v->homogeneous[0] *= invW; - v->homogeneous[1] *= invW; - v->homogeneous[2] *= invW; + v->homogeneous[0] *= wRcp; + v->homogeneous[1] *= wRcp; + v->homogeneous[2] *= wRcp; // Division of texture coordinates (perspective-correct) - v->texcoord[0] *= invW; - v->texcoord[1] *= invW; + v->texcoord[0] *= wRcp; + v->texcoord[1] *= wRcp; // Division of colors (perspective-correct) - v->color[0] *= invW; - v->color[1] *= invW; - v->color[2] *= invW; - v->color[3] *= invW; + v->color[0] *= wRcp; + v->color[1] *= wRcp; + v->color[2] *= wRcp; + v->color[3] *= wRcp; // Transformation to screen space sw_project_ndc_to_screen(v->screen, v->homogeneous); @@ -2908,76 +2676,40 @@ static inline bool sw_quad_is_axis_aligned(void) static inline void sw_quad_sort_cw(const sw_vertex_t* *output) { - // Sort 4 quad vertices into clockwise order with fixed layout: - // - // v0 -- v1 - // | | - // v3 -- v2 - // - // The goal is: - // - v0: top-left (minimum Y, then minimum X) - // - v1: top-right (minimum Y row, maximum X) - // - v2: bottom-right (maximum Y, maximum X) - // - v3: bottom-left (maximum Y, minimum X) const sw_vertex_t *input = RLSW.vertexBuffer; - // Separate vertices into top and bottom based on Y-coordinate - const sw_vertex_t *top[2] = {NULL, NULL}; - const sw_vertex_t *bottom[2] = {NULL, NULL}; - int topCount = 0, bottomCount = 0; + // Calculate the centroid of the quad + float cx = (input[0].screen[0] + input[1].screen[0] + + input[2].screen[0] + input[3].screen[0])*0.25f; + float cy = (input[0].screen[1] + input[1].screen[1] + + input[2].screen[1] + input[3].screen[1])*0.25f; - // Find minimum and maximum Y - float minY = input[0].screen[1]; - float maxY = input[0].screen[1]; + // Calculate the angle of each vertex relative to the center + // and assign them directly to their correct position + const sw_vertex_t *corners[4] = { 0 }; - for (int i = 1; i < 4; i++) - { - if (input[i].screen[1] < minY) minY = input[i].screen[1]; - if (input[i].screen[1] > maxY) maxY = input[i].screen[1]; - } - - // 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]; + float dx = input[i].screen[0] - cx; + float dy = input[i].screen[1] - cy; + + // Determine the quadrant (clockwise from top-left) + // top-left: dx < 0, dy < 0 + // top-right: dx >= 0, dy < 0 + // bottom-right: dx >= 0, dy >= 0 + // bottom-left: dx < 0, dy >= 0 + + int idx; + if (dy < 0) idx = (dx < 0)? 0 : 1; // Top row + else idx = (dx < 0)? 3 : 2; // Bottom row + + corners[idx] = &input[i]; } - // If we don't have enough top/bottom vertices (e.g., Y values are all different), - // classify vertices as top or bottom based on whether they're closer to minY or maxY - for (int i = 0; i < 4; i++) - { - if ((topCount < 2) && (&input[i] != top[0]) && (&input[i] != bottom[0]) && (&input[i] != bottom[1])) - { - if (fabsf(input[i].screen[1] - minY) <= fabsf(input[i].screen[1] - maxY)) top[topCount++] = &input[i]; - } - if ((bottomCount < 2) && (&input[i] != top[0]) && (&input[i] != top[1]) && (&input[i] != bottom[0])) - { - if (fabsf(input[i].screen[1] - maxY) < fabsf(input[i].screen[1] - minY)) bottom[bottomCount++] = &input[i]; - } - } - - // Sort top vertices by X (left to right) - if ((topCount == 2) && (top[0]->screen[0] > top[1]->screen[0])) - { - const sw_vertex_t *temp = top[0]; - top[0] = top[1]; - top[1] = temp; - } - - // Sort bottom vertices by X (left to right) - if ((bottomCount == 2) && (bottom[0]->screen[0] > bottom[1]->screen[0])) - { - const sw_vertex_t *temp = bottom[0]; - bottom[0] = bottom[1]; - bottom[1] = temp; - } - - // Assign vertices in clockwise order as per the required layout - output[0] = top[0]; // v0: top-left - output[1] = top[topCount-1]; // v1: top-right - output[2] = bottom[bottomCount-1]; // v2: bottom-right - output[3] = bottom[0]; // v3: bottom-left + output[0] = corners[0]; // top-left + output[1] = corners[1]; // top-right + output[2] = corners[2]; // bottom-right + output[3] = corners[3]; // bottom-left } // TODO: REVIEW: Could a perfectly aligned quad, where one of the four points has a different depth, @@ -3052,8 +2784,8 @@ static inline void FUNC_NAME(void) \ for (int y = yMin; y < yMax; y++) \ { \ - void *cptr = sw_framebuffer_get_color_addr(cDstBase, y*wDst + xMin); \ - void *dptr = sw_framebuffer_get_depth_addr(dDstBase, y*wDst + xMin); \ + void *cptr = GET_COLOR_PTR(cDstBase, y*wDst + xMin); \ + void *dptr = GET_DEPTH_PTR(dDstBase, y*wDst + xMin); \ \ float z = zScanline; \ float u = uScanline; \ @@ -3101,13 +2833,7 @@ static inline void FUNC_NAME(void) { \ float dstColor[4]; \ sw_framebuffer_read_color(dstColor, cptr); \ - \ sw_blend_colors(dstColor, srcColor); \ - dstColor[0] = sw_saturate(dstColor[0]); \ - dstColor[1] = sw_saturate(dstColor[1]); \ - dstColor[2] = sw_saturate(dstColor[2]); \ - dstColor[3] = sw_saturate(dstColor[3]); \ - \ sw_framebuffer_write_color(cptr, dstColor); \ } \ else sw_framebuffer_write_color(cptr, srcColor); \ @@ -3125,8 +2851,8 @@ static inline void FUNC_NAME(void) v += tcDx[1]; \ } \ \ - sw_framebuffer_inc_color_addr(&cptr); \ - sw_framebuffer_inc_depth_addr(&dptr); \ + INC_COLOR_PTR(cptr); \ + INC_DEPTH_PTR(dptr); \ } \ \ zScanline += zDy; \ @@ -3163,15 +2889,19 @@ static inline void sw_quad_render(void) if (RLSW.vertexCounter < 3) return; + uint32_t state = RLSW.stateFlags; + if (RLSW.currentTexture == 0) state &= ~SW_STATE_TEXTURE_2D; + if ((RLSW.srcFactor == SW_ONE) && (RLSW.dstFactor == SW_ZERO)) state &= ~SW_STATE_BLEND; + 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(); - else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_BLEND)) sw_quad_raster_axis_aligned_TEX_BLEND(); - else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST)) sw_quad_raster_axis_aligned_TEX_DEPTH(); - else if (SW_STATE_CHECK(SW_STATE_BLEND)) sw_quad_raster_axis_aligned_BLEND(); - else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST)) sw_quad_raster_axis_aligned_DEPTH(); - else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D)) sw_quad_raster_axis_aligned_TEX(); + if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) sw_quad_raster_axis_aligned_TEX_DEPTH_BLEND(); + else if (SW_STATE_CHECK_EX(state, SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) sw_quad_raster_axis_aligned_DEPTH_BLEND(); + else if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D | SW_STATE_BLEND)) sw_quad_raster_axis_aligned_TEX_BLEND(); + else if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST)) sw_quad_raster_axis_aligned_TEX_DEPTH(); + else if (SW_STATE_CHECK_EX(state, SW_STATE_BLEND)) sw_quad_raster_axis_aligned_BLEND(); + else if (SW_STATE_CHECK_EX(state, SW_STATE_DEPTH_TEST)) sw_quad_raster_axis_aligned_DEPTH(); + else if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D)) sw_quad_raster_axis_aligned_TEX(); else sw_quad_raster_axis_aligned(); return; } @@ -3189,13 +2919,13 @@ static inline void sw_quad_render(void) } \ } - if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH_BLEND) - else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_DEPTH_BLEND) - else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_TEX_BLEND) - else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST)) TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH) - else if (SW_STATE_CHECK(SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_BLEND) - else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST)) TRIANGLE_RASTER(sw_triangle_raster_DEPTH) - else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D)) TRIANGLE_RASTER(sw_triangle_raster_TEX) + if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH_BLEND) + else if (SW_STATE_CHECK_EX(state, SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_DEPTH_BLEND) + else if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_TEX_BLEND) + else if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST)) TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH) + else if (SW_STATE_CHECK_EX(state, SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_BLEND) + else if (SW_STATE_CHECK_EX(state, SW_STATE_DEPTH_TEST)) TRIANGLE_RASTER(sw_triangle_raster_DEPTH) + else if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D)) TRIANGLE_RASTER(sw_triangle_raster_TEX) else TRIANGLE_RASTER(sw_triangle_raster) #undef TRIANGLE_RASTER @@ -3310,7 +3040,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; \ @@ -3366,8 +3096,8 @@ static inline void FUNC_NAME(const sw_vertex_t *v0, const sw_vertex_t *v1) \ for (int i = 0; i != longLen; i += sgnInc) \ { \ int offset = (y1 + i)*fbWidth + (x1 + (j >> 16)); \ - void *dptr = sw_framebuffer_get_depth_addr(dBuffer, offset); \ - void *cptr; \ + void *dptr = GET_DEPTH_PTR(dBuffer, offset); \ + void *cptr = NULL; \ \ if (ENABLE_DEPTH_TEST) \ { \ @@ -3377,13 +3107,12 @@ static inline void FUNC_NAME(const sw_vertex_t *v0, const sw_vertex_t *v1) \ \ sw_framebuffer_write_depth(dptr, z); \ \ - cptr = sw_framebuffer_get_color_addr(cBuffer, offset); \ + cptr = GET_COLOR_PTR(cBuffer, offset); \ \ if (ENABLE_COLOR_BLEND) \ { \ float dstColor[4]; \ sw_framebuffer_read_color(dstColor, cptr); \ - \ sw_blend_colors(dstColor, color); \ sw_framebuffer_write_color(cptr, dstColor); \ } \ @@ -3403,8 +3132,8 @@ static inline void FUNC_NAME(const sw_vertex_t *v0, const sw_vertex_t *v1) \ for (int i = 0; i != longLen; i += sgnInc) \ { \ int offset = (y1 + (j >> 16))*fbWidth + (x1 + i); \ - void *dptr = sw_framebuffer_get_depth_addr(dBuffer, offset); \ - void *cptr; \ + void *dptr = GET_DEPTH_PTR(dBuffer, offset); \ + void *cptr = NULL; \ \ if (ENABLE_DEPTH_TEST) \ { \ @@ -3414,17 +3143,16 @@ static inline void FUNC_NAME(const sw_vertex_t *v0, const sw_vertex_t *v1) \ \ sw_framebuffer_write_depth(dptr, z); \ \ - cptr = sw_framebuffer_get_color_addr(cBuffer, offset); \ + cptr = GET_COLOR_PTR(cBuffer, offset); \ \ if (ENABLE_COLOR_BLEND) \ { \ float dstColor[4]; \ sw_framebuffer_read_color(dstColor, cptr); \ - \ sw_blend_colors(dstColor, color); \ sw_framebuffer_write_color(cptr, dstColor); \ } \ - else sw_framebuffer_write_color(cptr, color); \ + else sw_framebuffer_write_color(cptr, color); \ \ discardB: \ j += decInc; \ @@ -3570,7 +3298,7 @@ static inline void FUNC_NAME(int x, int y, float z, const float color[4]) \ \ int offset = y*RLSW.framebuffer.width + x; \ \ - void *dptr = sw_framebuffer_get_depth_addr(RLSW.framebuffer.depth, offset); \ + void *dptr = GET_DEPTH_PTR(RLSW.framebuffer.depth, offset); \ \ if (ENABLE_DEPTH_TEST) \ { \ @@ -3580,13 +3308,12 @@ static inline void FUNC_NAME(int x, int y, float z, const float color[4]) \ \ sw_framebuffer_write_depth(dptr, z); \ \ - void *cptr = sw_framebuffer_get_color_addr(RLSW.framebuffer.color, offset); \ + void *cptr = GET_COLOR_PTR(RLSW.framebuffer.color, offset); \ \ if (ENABLE_COLOR_BLEND) \ { \ float dstColor[4]; \ sw_framebuffer_read_color(dstColor, cptr); \ - \ sw_blend_colors(dstColor, color); \ sw_framebuffer_write_color(cptr, dstColor); \ } \ @@ -3724,7 +3451,7 @@ static inline bool sw_is_texture_valid(uint32_t id) if (id == 0) valid = false; else if (id >= SW_MAX_TEXTURES) valid = false; - else if (RLSW.loadedTextures[id].pixels.cptr == 0) valid = false; + else if (RLSW.loadedTextures[id].pixels == NULL) valid = false; return true; } @@ -3872,26 +3599,24 @@ bool swInit(int w, int h) RLSW.polyMode = SW_FILL; RLSW.cullFace = SW_BACK; - static const float defTex[3*2*2] = { - 1.0f, 1.0f, 1.0f, - 1.0f, 1.0f, 1.0f, - 1.0f, 1.0f, 1.0f, - 1.0f, 1.0f, 1.0f, + static uint32_t defaultTex[3*2*2] = { + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF }; - RLSW.loadedTextures[0].pixels.cptr = defTex; + RLSW.loadedTextures[0].pixels = (uint8_t*)defaultTex; RLSW.loadedTextures[0].width = 2; RLSW.loadedTextures[0].height = 2; RLSW.loadedTextures[0].wMinus1 = 1; RLSW.loadedTextures[0].hMinus1 = 1; - RLSW.loadedTextures[0].format = SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32; RLSW.loadedTextures[0].minFilter = SW_NEAREST; RLSW.loadedTextures[0].magFilter = SW_NEAREST; RLSW.loadedTextures[0].sWrap = SW_REPEAT; RLSW.loadedTextures[0].tWrap = SW_REPEAT; RLSW.loadedTextures[0].tx = 0.5f; RLSW.loadedTextures[0].ty = 0.5f; - RLSW.loadedTextures[0].copy = false; RLSW.loadedTextureCount = 1; @@ -3900,10 +3625,13 @@ bool swInit(int w, int h) void swClose(void) { + // NOTE: Starts at texture 1, texture 0 does not have to be freed for (int i = 1; i < RLSW.loadedTextureCount; i++) { - sw_texture_t *texture = &RLSW.loadedTextures[i]; - if (sw_is_texture_valid(i) && texture->copy) SW_FREE(texture->pixels.ptr); + if (sw_is_texture_valid(i)) + { + SW_FREE(RLSW.loadedTextures[i].pixels); + } } SW_FREE(RLSW.framebuffer.color); @@ -3950,13 +3678,16 @@ void swCopyFramebuffer(int x, int y, int w, int h, SWformat format, SWtype type, case SW_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: sw_framebuffer_copy_to_R5G5B5A1(x, y, w, h, (uint16_t *)pixels); break; case SW_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: sw_framebuffer_copy_to_R4G4B4A4(x, y, w, h, (uint16_t *)pixels); break; case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: sw_framebuffer_copy_to_R8G8B8A8(x, y, w, h, (uint8_t *)pixels); break; - case SW_PIXELFORMAT_UNCOMPRESSED_R32: sw_framebuffer_copy_to_R32(x, y, w, h, (float *)pixels); break; - case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32: sw_framebuffer_copy_to_R32G32B32(x, y, w, h, (float *)pixels); break; - case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: sw_framebuffer_copy_to_R32G32B32A32(x, y, w, h, (float *)pixels); break; - case SW_PIXELFORMAT_UNCOMPRESSED_R16: sw_framebuffer_copy_to_R16(x, y, w, h, (sw_half_t *)pixels); break; - case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16: sw_framebuffer_copy_to_R16G16B16(x, y, w, h, (sw_half_t *)pixels); break; - case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: sw_framebuffer_copy_to_R16G16B16A16(x, y, w, h, (sw_half_t *)pixels); break; - default: RLSW.errCode = SW_INVALID_ENUM; break; + // Below: not implemented + case SW_PIXELFORMAT_UNCOMPRESSED_R32: + case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32: + case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: + case SW_PIXELFORMAT_UNCOMPRESSED_R16: + case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16: + case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: + default: + RLSW.errCode = SW_INVALID_ENUM; + break; } } @@ -3991,13 +3722,16 @@ void swBlitFramebuffer(int xDst, int yDst, int wDst, int hDst, int xSrc, int ySr case SW_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: sw_framebuffer_blit_to_R5G5B5A1(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (uint16_t *)pixels); break; case SW_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: sw_framebuffer_blit_to_R4G4B4A4(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (uint16_t *)pixels); break; case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: sw_framebuffer_blit_to_R8G8B8A8(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (uint8_t *)pixels); break; - case SW_PIXELFORMAT_UNCOMPRESSED_R32: sw_framebuffer_blit_to_R32(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (uint8_t *)pixels); break; - case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32: sw_framebuffer_blit_to_R32G32B32(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (float *)pixels); break; - case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: sw_framebuffer_blit_to_R32G32B32A32(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (float*)pixels); break; - case SW_PIXELFORMAT_UNCOMPRESSED_R16: sw_framebuffer_blit_to_R16(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (sw_half_t *)pixels); break; - case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16: sw_framebuffer_blit_to_R16G16B16(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (sw_half_t *)pixels); break; - case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: sw_framebuffer_blit_to_R16G16B16A16(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (sw_half_t *)pixels); break; - default: RLSW.errCode = SW_INVALID_ENUM; break; + // Below: not implemented + case SW_PIXELFORMAT_UNCOMPRESSED_R32: + case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32: + case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: + case SW_PIXELFORMAT_UNCOMPRESSED_R16: + case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16: + case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: + default: + RLSW.errCode = SW_INVALID_ENUM; + break; } } @@ -4814,17 +4548,14 @@ void swDeleteTextures(int count, uint32_t *textures) continue; } - if (RLSW.loadedTextures[textures[i]].copy) - { - SW_FREE(RLSW.loadedTextures[textures[i]].pixels.ptr); - } + SW_FREE(RLSW.loadedTextures[textures[i]].pixels); - RLSW.loadedTextures[textures[i]].pixels.cptr = NULL; + RLSW.loadedTextures[textures[i]].pixels = NULL; RLSW.freeTextureIds[RLSW.freeTextureIdCount++] = textures[i]; } } -void swTexImage2D(int width, int height, SWformat format, SWtype type, bool copy, const void *data) +void swTexImage2D(int width, int height, SWformat format, SWtype type, const void *data) { uint32_t id = RLSW.currentTexture; @@ -4844,33 +4575,27 @@ void swTexImage2D(int width, int height, SWformat format, SWtype type, bool copy sw_texture_t *texture = &RLSW.loadedTextures[id]; - if (copy) + int size = width*height; + texture->pixels = SW_MALLOC(4*size); + + if (texture->pixels == NULL) { - int bytes = sw_get_pixel_bytes((sw_pixelformat_t)pixelFormat); - int size = bytes*width*height; - texture->pixels.ptr = SW_MALLOC(size); - - if (texture->pixels.ptr == NULL) - { - RLSW.errCode = SW_STACK_OVERFLOW; // WARING: Out of memory... - return; - } - - for (int i = 0; i < size; i++) - { - ((uint8_t *)texture->pixels.ptr)[i] = ((uint8_t *)data)[i]; - } + RLSW.errCode = SW_STACK_OVERFLOW; // WARNING: Out of memory... + return; + } + + for (int i = 0; i < size; i++) + { + uint32_t *dst = &((uint32_t*)texture->pixels)[i]; + sw_get_pixel((uint8_t*)dst, data, i, pixelFormat); } - else texture->pixels.cptr = data; texture->width = width; texture->height = height; texture->wMinus1 = width - 1; texture->hMinus1 = height - 1; - texture->format = (sw_pixelformat_t)pixelFormat; texture->tx = 1.0f/width; texture->ty = 1.0f/height; - texture->copy = copy; } void swTexParameteri(int param, int value) @@ -4939,7 +4664,7 @@ void swBindTexture(uint32_t id) return; } - if (RLSW.loadedTextures[id].pixels.cptr == NULL) + if (RLSW.loadedTextures[id].pixels == NULL) { RLSW.errCode = SW_INVALID_OPERATION; return; From 4bb8c89084930862b70042845166739cf058e883 Mon Sep 17 00:00:00 2001 From: Jeffery Myers Date: Sat, 25 Oct 2025 00:49:31 -0700 Subject: [PATCH 162/167] Don't undefine the versions of LoadImage that don't conflict with raylib so that the Win32 platform can use them. (#5299) --- src/platforms/rcore_desktop_win32.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/platforms/rcore_desktop_win32.c b/src/platforms/rcore_desktop_win32.c index 9b66f8c4b..5b67c72b0 100644 --- a/src/platforms/rcore_desktop_win32.c +++ b/src/platforms/rcore_desktop_win32.c @@ -49,8 +49,6 @@ #define CloseWindow CloseWindowWin32 #define Rectangle RectangleWin32 #define ShowCursor ShowCursorWin32 -#define LoadImageA LoadImageAWin32 -#define LoadImageW LoadImageWin32 #define DrawTextA DrawTextAWin32 #define DrawTextW DrawTextWin32 #define DrawTextExA DrawTextExAWin32 @@ -63,8 +61,6 @@ #undef Rectangle // raylib symbol collision #undef ShowCursor // raylib symbol collision #undef LoadImage // raylib symbol collision -#undef LoadImageA -#undef LoadImageW #undef DrawText // raylib symbol collision #undef DrawTextA #undef DrawTextW @@ -1529,7 +1525,7 @@ int InitPlatform(void) // 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); + if (!windowClass.hIcon) windowClass.hIcon = LoadImageW(NULL, (LPCWSTR)IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED); // Register window class result = (int)RegisterClassExW(&windowClass); From dbcc5081964cb2413b32eecf2135d73e32420285 Mon Sep 17 00:00:00 2001 From: themushroompirates <59015901+themushroompirates@users.noreply.github.com> Date: Sat, 25 Oct 2025 10:41:39 +0200 Subject: [PATCH 163/167] [examples] Added `models_decals` (#5298) * Added decal models example * Code formatting to match Raylib conventions --- examples/models/models_decals.c | 573 +++ examples/models/models_decals.png | Bin 0 -> 62387 bytes .../models/resources/models/obj/character.mtl | 12 + .../models/resources/models/obj/character.obj | 3454 +++++++++++++++++ .../models/obj/character_diffuse.png | Bin 0 -> 41705 bytes examples/models/resources/raylib_logo.png | Bin 0 -> 3672 bytes 6 files changed, 4039 insertions(+) create mode 100644 examples/models/models_decals.c create mode 100644 examples/models/models_decals.png create mode 100644 examples/models/resources/models/obj/character.mtl create mode 100644 examples/models/resources/models/obj/character.obj create mode 100644 examples/models/resources/models/obj/character_diffuse.png create mode 100644 examples/models/resources/raylib_logo.png diff --git a/examples/models/models_decals.c b/examples/models/models_decals.c new file mode 100644 index 000000000..81bbd2796 --- /dev/null +++ b/examples/models/models_decals.c @@ -0,0 +1,573 @@ +/******************************************************************************************* +* +* raylib [models] example - decals +* +* Example complexity rating: [★★★☆] 3/4 +* +* Example originally created with raylib 5.6-dev +* +* Example contributed by JP Mortiboys (@themushroompirates) and reviewed by Ramon Santamaria (@raysan5) +* Based on previous work by @mrdoob +* +* 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 JP Mortiboys (@themushroompirates) and Ramon Santamaria (@raysan5) +* +********************************************************************************************/ + +#include "raylib.h" +#include "raymath.h" + +#include + +#undef FLT_MAX +#define FLT_MAX 340282346638528859811704183484516925440.0f // Maximum value of a float, from bit pattern 01111111011111111111111111111111 + +#define MAX_DECALS 256 + +typedef struct MeshBuilder { + int vertexCount; + int vertexCapacity; + Vector3 *vertices; + Vector2 *uvs; +} MeshBuilder; + +// Utility functions +void AddTriangleToMeshBuilder(MeshBuilder *mb, Vector3 vertices[3]); +void FreeMeshBuilder(MeshBuilder *mb); +Mesh BuildMesh(MeshBuilder *mb); + +Vector3 ClipSegment(Vector3 v0, Vector3 v1, Vector3 p, float s); + +Mesh GenMeshDecal(Mesh inputMesh, Ray ray); + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + SetConfigFlags(FLAG_MSAA_4X_HINT); + InitWindow(screenWidth, screenHeight, "raylib [models] example - decals"); + + // Define the camera to look into our 3d world + Camera camera = { 0 }; + camera.position = (Vector3){ 5.0f, 5.0f, 5.0f }; // Camera position + camera.target = (Vector3){ 0.0f, 1.0f, 0.0f }; // Camera looking at point + camera.up = (Vector3){ 0.0f, 1.6f, 0.0f }; // Camera up vector (rotation towards target) + camera.fovy = 45.0f; // Camera field-of-view Y + camera.projection = CAMERA_PERSPECTIVE; // Camera projection type + + // Load character model + Model model = LoadModel("resources/models/obj/character.obj"); + + // Apply character skin + Texture2D modelTexture = LoadTexture("resources/models/obj/character_diffuse.png"); // Load model texture + SetTextureFilter(modelTexture, TEXTURE_FILTER_BILINEAR); + model.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = modelTexture; // Set model diffuse texture + + + BoundingBox modelBBox = GetMeshBoundingBox(model.meshes[0]); // Get mesh bounding box + + camera.target = Vector3Lerp(modelBBox.min, modelBBox.max, 0.5f); + camera.position = Vector3Scale(modelBBox.max, 1.0f); + camera.position.x *= 0.1f; + + float modelSize = fminf( + fminf(fabsf(modelBBox.max.x - modelBBox.min.x), + fabsf(modelBBox.max.y - modelBBox.min.y)), + fabsf(modelBBox.max.z - modelBBox.min.z) + ); + + camera.position = (Vector3){ 0, modelBBox.max.y * 1.2f, modelSize * 3.0f }; + + float decalSize = modelSize * .25f; + float decalOffset = 0.01f; + + Model placementCube = LoadModelFromMesh(GenMeshCube(decalSize, decalSize, decalSize)); + placementCube.materials[0].maps[0].color = LIME; + + Material decalMaterial = LoadMaterialDefault(); + decalMaterial.maps[0].color = YELLOW; + + Image decalImage = LoadImage("resources/raylib_logo.png"); + ImageResizeNN(&decalImage, decalImage.width / 4, decalImage.height / 4); + Texture decalTexture = LoadTextureFromImage(decalImage); + UnloadImage(decalImage); + + SetTextureFilter(decalTexture, TEXTURE_FILTER_BILINEAR); + decalMaterial.maps[MATERIAL_MAP_DIFFUSE].texture = decalTexture; + decalMaterial.maps[MATERIAL_MAP_DIFFUSE].color = RAYWHITE; + + // We're going to use these to build up our decal meshes + // They'll resize automatically as we go, we'll free them at the end + MeshBuilder mesh_builders[2] = { {0}, {0} }; + + bool showModel = true; + Model decalModels[MAX_DECALS] = {0}; + int decalCount = 0; + + + 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 + //---------------------------------------------------------------------------------- + + if (IsMouseButtonDown(MOUSE_BUTTON_RIGHT)) { + UpdateCamera(&camera, CAMERA_THIRD_PERSON); + } + + if (IsKeyPressed(KEY_SPACE)) { + showModel = !showModel; + } + + // Display information about closest hit + RayCollision collision = { 0 }; + collision.distance = FLT_MAX; + collision.hit = false; + + // Get mouse ray + Ray ray = GetScreenToWorldRay(GetMousePosition(), camera); + + // Check ray collision against bounding box first, before trying the full ray-mesh test + RayCollision boxHitInfo = GetRayCollisionBox(ray, modelBBox); + + if ((boxHitInfo.hit) && decalCount < MAX_DECALS) + { + // Check ray collision against model meshes + RayCollision meshHitInfo = { 0 }; + for (int m = 0; m < model.meshCount; m++) + { + // NOTE: We consider the model.transform for the collision check but + // it can be checked against any transform Matrix, used when checking against same + // model drawn multiple times with multiple transforms + meshHitInfo = GetRayCollisionMesh(ray, model.meshes[m], model.transform); + if (meshHitInfo.hit) + { + // Save the closest hit mesh + if ((!collision.hit) || (collision.distance > meshHitInfo.distance)) collision = meshHitInfo; + } + } + + if (meshHitInfo.hit) + { + collision = meshHitInfo; + } + } + + // -------------- + + if (collision.hit && IsMouseButtonPressed(MOUSE_BUTTON_LEFT) && decalCount < MAX_DECALS) + { + + // Create the transformation to project the decal + Vector3 origin = Vector3Add(collision.point, Vector3Scale(collision.normal, 1.0f)); + Matrix splat = MatrixLookAt(collision.point, origin, (Vector3){0,1,0}); + + // Spin the placement around a bit + splat = MatrixMultiply(splat, MatrixRotateZ(DEG2RAD * ((float)GetRandomValue(-180, 180)))); + + Matrix splatInv = MatrixInvert(splat); + + // Reset the mesh builders + mesh_builders[0].vertexCount = 0; + mesh_builders[1].vertexCount = 0; + + // We'll be flip-flopping between the two mesh builders + // Reading from one and writing to the other, then swapping + int mb_index = 0; + + // First pass, just get any triangle inside the bounding box + // (for each mesh of the model) + for (int meshIndex = 0; meshIndex < model.meshCount; meshIndex++) { + Mesh mesh = model.meshes[meshIndex]; + for (int tri = 0; tri < mesh.triangleCount; tri++) + { + Vector3 vertices[3]; + + // The way we calculate the vertices of the mesh triangle + // depend on whether the mesh vertices are indexed or not + if (mesh.indices == 0) + { + for (int v = 0; v < 3; v++) { + vertices[v] = (Vector3) { + mesh.vertices[3*3*tri + 3*v + 0], + mesh.vertices[3*3*tri + 3*v + 1], + mesh.vertices[3*3*tri + 3*v + 2] + }; + } + } + else + { + for (int v = 0; v < 3; v++) + { + vertices[v] = (Vector3) { + mesh.vertices[ 3*mesh.indices[3*tri+0] + v], + mesh.vertices[ 3*mesh.indices[3*tri+1] + v], + mesh.vertices[ 3*mesh.indices[3*tri+2] + v] + }; + } + } + + // Transform all 3 vertices of the triangle + // and check if they are inside our decal box + int insideCount = 0; + for (int i = 0; i < 3; i++) + { + // To splat space + Vector3 v = Vector3Transform(vertices[i], splat); + + if (fabsf(v.x) 0) + { + AddTriangleToMeshBuilder(&mesh_builders[mb_index], vertices); + } + } + } + + // Clipping time! We need to clip against all 6 directions + Vector3 planes[6] = { + { 1, 0, 0 }, + { -1, 0, 0 }, + { 0, 1, 0 }, + { 0, -1, 0 }, + { 0, 0, 1 }, + { 0, 0, -1 } + }; + for (int face = 0; face < 6; face++) + { + // Swap current model builder (so we read from the one we just wrote to) + mb_index = 1 - mb_index; + + MeshBuilder *inMesh = &mesh_builders[1-mb_index]; + MeshBuilder *outMesh = &mesh_builders[mb_index]; + + // Reset write builder + outMesh->vertexCount = 0; + + float s = 0.5f * decalSize; + + for (int i = 0; i < inMesh->vertexCount; i+=3) + { + Vector3 nV1, nV2, nV3, nV4; + + float d1 = Vector3DotProduct(inMesh->vertices[ i + 0 ], planes[face] ) - s; + float d2 = Vector3DotProduct(inMesh->vertices[ i + 1 ], planes[face] ) - s; + float d3 = Vector3DotProduct(inMesh->vertices[ i + 2 ], planes[face] ) - s; + + int v1Out = d1 > 0; + int v2Out = d2 > 0; + int v3Out = d3 > 0; + + // calculate, how many vertices of the face lie outside of the clipping plane + int total = v1Out + v2Out + v3Out; + + switch ( total ) { + case 0: { + // the entire face lies inside of the plane, no clipping needed + AddTriangleToMeshBuilder(outMesh, (Vector3[3]){inMesh->vertices[i], inMesh->vertices[i+1], inMesh->vertices[i+2]}); + break; + } + + case 1: { + // one vertex lies outside of the plane, perform clipping + + if (v1Out) { + nV1 = inMesh->vertices[ i + 1 ]; + nV2 = inMesh->vertices[ i + 2 ]; + nV3 = ClipSegment( inMesh->vertices[ i ], nV1, planes[face], s ); + nV4 = ClipSegment( inMesh->vertices[ i ], nV2, planes[face], s ); + } + + if (v2Out) { + nV1 = inMesh->vertices[ i ]; + nV2 = inMesh->vertices[ i + 2 ]; + nV3 = ClipSegment( inMesh->vertices[ i + 1 ], nV1, planes[face], s ); + nV4 = ClipSegment( inMesh->vertices[ i + 1 ], nV2, planes[face], s ); + + AddTriangleToMeshBuilder(outMesh, (Vector3[3]){nV3, nV2, nV1}); + AddTriangleToMeshBuilder(outMesh, (Vector3[3]){nV2, nV3, nV4}); + break; + } + + if (v3Out) { + nV1 = inMesh->vertices[ i ]; + nV2 = inMesh->vertices[ i + 1 ]; + nV3 = ClipSegment( inMesh->vertices[ i + 2 ], nV1, planes[face], s ); + nV4 = ClipSegment( inMesh->vertices[ i + 2 ], nV2, planes[face], s ); + } + + AddTriangleToMeshBuilder(outMesh, (Vector3[3]){nV1, nV2, nV3}); + AddTriangleToMeshBuilder(outMesh, (Vector3[3]){nV4, nV3, nV2}); + + break; + } + + case 2: { + // two vertices lies outside of the plane, perform clipping + if (!v1Out) { + nV1 = inMesh->vertices[ i ]; + nV2 = ClipSegment( nV1, inMesh->vertices[ i + 1 ], planes[face], s ); + nV3 = ClipSegment( nV1, inMesh->vertices[ i + 2 ], planes[face], s ); + AddTriangleToMeshBuilder(outMesh, (Vector3[3]){nV1, nV2, nV3}); + } + if (!v2Out) { + nV1 = inMesh->vertices[ i + 1 ]; + nV2 = ClipSegment( nV1, inMesh->vertices[ i + 2 ], planes[face], s ); + nV3 = ClipSegment( nV1, inMesh->vertices[ i ], planes[face], s ); + AddTriangleToMeshBuilder(outMesh, (Vector3[3]){nV1, nV2, nV3}); + } + if (!v3Out) { + nV1 = inMesh->vertices[ i + 2 ]; + nV2 = ClipSegment( nV1, inMesh->vertices[ i ], planes[face], s ); + nV3 = ClipSegment( nV1, inMesh->vertices[ i + 1 ], planes[face], s ); + AddTriangleToMeshBuilder(outMesh, (Vector3[3]){nV1, nV2, nV3}); + } + break; + } + + case 3: { + // the entire face lies outside of the plane, so let's discard the corresponding vertices + break; + } + + } + } + } + + // Now we just need to re-transform the vertices + MeshBuilder *theMesh = &mesh_builders[mb_index]; + + // Allocate room for UVs + if (theMesh->vertexCount > 0) + { + theMesh->uvs = (Vector2*)MemAlloc(sizeof(Vector2)*theMesh->vertexCount); + for (int i = 0; i < theMesh->vertexCount; i++) + { + + // Calculate the UVs based on the projected coords + // They are clipped to (-decalSize .. decalSize) and we want them (0..1) + theMesh->uvs[i].x = (theMesh->vertices[i].x / decalSize + .5f); + theMesh->uvs[i].y = (theMesh->vertices[i].y / decalSize + .5f); + + // From splat space to world space + theMesh->vertices[i] = Vector3Transform(theMesh->vertices[i], splatInv); + + // Tiny nudge in the normal direction so it renders properly over the mesh + theMesh->vertices[i] = Vector3Add(theMesh->vertices[i], Vector3Scale(collision.normal, decalOffset)); + } + + // Decal model data ready, create it and add it + int decalIndex = decalCount++; + decalModels[decalIndex] = LoadModelFromMesh(BuildMesh(theMesh)); + decalModels[decalIndex].materials[0] = decalMaterial; + } + + } + + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + BeginMode3D(camera); + + // Draw the model at the origin and default scale + if (showModel) + { + DrawModel(model, (Vector3){0.0f, 0.0f, 0.0f}, 1.0f, WHITE); + } + + // Draw the decal models + for (int i = 0; i < decalCount; i++) + { + DrawModel(decalModels[i], (Vector3){0}, 1.0f, WHITE); + } + + // If we hit the mesh, draw the box for the decal + if (collision.hit) + { + + Vector3 origin = Vector3Add(collision.point, Vector3Scale(collision.normal, 1.0f)); + Matrix splat = MatrixLookAt(collision.point, origin, (Vector3){0,1,0}); + + placementCube.transform = MatrixInvert(splat); + DrawModel(placementCube, (Vector3){0}, 1.0f, Fade(WHITE, 0.5f)); + } + + DrawGrid(10, 10.0f); + + EndMode3D(); + + { + float yPos = 10; + float x0 = GetScreenWidth() - 300; + float x1 = x0 + 100; + float x2 = x1 + 100; + + DrawText("Vertices", x1, yPos, 10, LIME); + DrawText("Triangles", x2, yPos, 10, LIME); + yPos += 15; + + int vertexCount = 0; + int triangleCount = 0; + + for (int i = 0; i < model.meshCount; i++) + { + vertexCount += model.meshes[i].vertexCount; + triangleCount += model.meshes[i].triangleCount; + } + + DrawText("Main model", x0, yPos, 10, LIME); + DrawText(TextFormat("%d", vertexCount), x1, yPos, 10, LIME); + DrawText(TextFormat("%d", triangleCount), x2, yPos, 10, LIME); + yPos += 15; + + for (int i = 0; i < decalCount; i++) + { + DrawText(TextFormat("Decal #%d", i+1), x0, yPos, 10, LIME); + DrawText(TextFormat("%d", decalModels[i].meshes[0].vertexCount), x1, yPos, 10, LIME); + DrawText(TextFormat("%d", decalModels[i].meshes[0].triangleCount), x2, yPos, 10, LIME); + + vertexCount += decalModels[i].meshes[0].vertexCount; + triangleCount += decalModels[i].meshes[0].triangleCount; + yPos += 15; + } + + DrawText("TOTAL", x0, yPos, 10, LIME); + DrawText(TextFormat("%d", vertexCount), x1, yPos, 10, LIME); + DrawText(TextFormat("%d", triangleCount), x2, yPos, 10, LIME); + yPos += 15; + } + + DrawText("Hold RMB to move camera", 10, 430, 10, GRAY); + + DrawText("(c) Character model and texture from kenney.nl", screenWidth - 260, screenHeight - 20, 10, GRAY); + + DrawFPS(10, 10); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + UnloadModel(model); + UnloadTexture(modelTexture); + + for (int i = 0; i < decalCount; i++) + { + UnloadModel(decalModels[i]); + } + + UnloadTexture(decalTexture); + + FreeMeshBuilder(&mesh_builders[0]); + FreeMeshBuilder(&mesh_builders[1]); + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} + +// A really simple dynamic array manager +void AddTriangleToMeshBuilder(MeshBuilder *mb, Vector3 vertices[3]) { + // Reallocate and copy if we need to + if (mb->vertexCapacity <= mb->vertexCount + 3 ) + { + int newVertexCapacity = (1 + (mb->vertexCapacity / 256)) * 256; + Vector3 *newVertices = (Vector3*)MemAlloc(newVertexCapacity * sizeof(Vector3)); + if (mb->vertexCapacity > 0) + { + memcpy(newVertices, mb->vertices, mb->vertexCount * sizeof(Vector3)); + MemFree(mb->vertices); + } + mb->vertices = newVertices; + mb->vertexCapacity = newVertexCapacity; + } + + // Add 3 vertices + int index = mb->vertexCount; + mb->vertexCount += 3; + + for (int i = 0; i < 3; i++) + { + mb->vertices[index+i] = vertices[i]; + } +} + +void FreeMeshBuilder(MeshBuilder *mb) +{ + MemFree(mb->vertices); + + if (mb->uvs) + { + MemFree(mb->uvs); + } + + *mb = (MeshBuilder){ 0 }; +} + +// Construct a Raylib Mesh from our MeshBuilder data +Mesh BuildMesh(MeshBuilder *mb) +{ + Mesh outMesh = { 0 }; + + outMesh.vertexCount = mb->vertexCount; + outMesh.triangleCount = mb->vertexCount / 3; + + outMesh.vertices = MemAlloc(outMesh.vertexCount * 3 * sizeof(float)); + + if (mb->uvs) + { + outMesh.texcoords = MemAlloc(outMesh.vertexCount * 2 * sizeof(float)); + } + + for (int i = 0; i < mb->vertexCount; i++) + { + outMesh.vertices[3*i+0] = mb->vertices[i].x; + outMesh.vertices[3*i+1] = mb->vertices[i].y; + outMesh.vertices[3*i+2] = mb->vertices[i].z; + if (mb->uvs) + { + outMesh.texcoords[2*i+0] = mb->uvs[i].x; + outMesh.texcoords[2*i+1] = mb->uvs[i].y; + } + } + + UploadMesh(&outMesh, false); + + return outMesh; +} + +Vector3 ClipSegment(Vector3 v0, Vector3 v1, Vector3 p, float s) +{ + float d0 = Vector3DotProduct(v0, p) - s; + float d1 = Vector3DotProduct(v1, p) - s; + + float s0 = d0 / ( d0 - d1 ); + + Vector3 position = Vector3Lerp(v0, v1, s0); + + return position; +} \ No newline at end of file diff --git a/examples/models/models_decals.png b/examples/models/models_decals.png new file mode 100644 index 0000000000000000000000000000000000000000..48e027fe2d1711237f457995d46ddcc0647a102e GIT binary patch literal 62387 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 Ad;kCd literal 0 HcmV?d00001 diff --git a/examples/models/resources/models/obj/character.mtl b/examples/models/resources/models/obj/character.mtl new file mode 100644 index 000000000..96b272b29 --- /dev/null +++ b/examples/models/resources/models/obj/character.mtl @@ -0,0 +1,12 @@ +# Blender MTL File: 'None' +# Material Count: 1 + +newmtl skin +Ns 86.470579 +Ka 1.000000 1.000000 1.000000 +Kd 0.800000 0.800000 0.800000 +Ks 0.500000 0.500000 0.500000 +Ke 0.000000 0.000000 0.000000 +Ni 1.450000 +d 0.000000 +illum 9 diff --git a/examples/models/resources/models/obj/character.obj b/examples/models/resources/models/obj/character.obj new file mode 100644 index 000000000..be7e47863 --- /dev/null +++ b/examples/models/resources/models/obj/character.obj @@ -0,0 +1,3454 @@ +# Blender v2.83.2 OBJ File: '' +# www.blender.org +mtllib character.mtl +o characterMedium +v 0.410751 3.453012 0.200817 +v 0.176931 3.516046 -0.492870 +v 0.176931 3.069885 -0.492870 +v 0.193767 2.961166 0.489574 +v 0.193767 3.452389 0.455386 +v 0.400606 2.998632 0.217911 +v 0.400606 3.035397 -0.212411 +v 0.410751 3.483905 -0.212411 +v 0.188780 3.698580 0.247489 +v 0.188780 3.731344 -0.224509 +v 0.188780 2.741884 -0.224509 +v 0.188780 2.664058 0.281677 +v 0.338542 2.788810 0.205190 +v 0.323730 3.496119 -0.410188 +v 0.323730 3.441588 0.352035 +v 0.338542 3.642598 0.223085 +v 0.338542 2.852551 -0.208748 +v 0.176295 2.876968 -0.427238 +v 0.323730 3.072495 -0.410188 +v 0.193131 2.735571 0.459728 +v 0.323730 2.996823 0.381949 +v 0.338542 3.655763 -0.208748 +v 0.176295 3.660861 -0.399904 +v 0.193131 3.617279 0.405342 +v 0.180529 3.275434 -0.517282 +v 0.197366 3.218354 0.478425 +v 0.409350 3.230555 0.194491 +v 0.403118 3.253443 -0.219099 +v 0.429171 3.009897 0.014208 +v 0.439316 3.472003 0.009934 +v 0.198303 3.743473 0.020506 +v 0.198303 2.669343 0.029053 +v 0.286423 2.928726 -0.357824 +v 0.286423 2.767836 0.367046 +v 0.286423 3.636701 -0.357824 +v 0.301893 3.594941 0.358830 +v 0.357587 2.802252 0.025342 +v 0.322536 3.266541 -0.423686 +v 0.327481 3.227505 0.360122 +v 0.357587 3.654801 0.017864 +v 0.434369 3.238045 0.005717 +v 0.111250 2.648599 -0.113100 +v 0.129723 2.623841 0.000772 +v 0.110155 2.617475 0.111510 +v 0.098894 2.551101 -0.119944 +v 0.140309 2.525439 -0.009396 +v 0.098894 2.517193 0.100599 +v 0.208678 2.515187 -0.122760 +v 0.245812 2.502890 -0.002447 +v 0.208678 2.483677 0.109699 +v 0.271570 2.206755 -0.145013 +v 0.319908 2.187368 0.032075 +v 0.271570 2.177688 0.191096 +v 0.303127 1.441376 -0.106186 +v 0.355115 1.410218 0.080975 +v 0.289850 1.402806 0.240428 +v 0.260948 1.763152 0.232137 +v 0.307393 1.770383 0.075582 +v 0.260948 1.788246 -0.089088 +v 0.247213 2.324639 0.153241 +v 0.247213 2.354879 -0.163591 +v 0.115069 1.290704 0.269082 +v 0.017798 1.168477 -0.035384 +v 0.183067 1.284675 -0.183271 +v 0.084912 3.522239 -0.501146 +v 0.084912 3.064342 -0.512888 +v 0.084912 2.943401 0.510254 +v 0.084912 3.458095 0.476066 +v 0.090590 3.723567 0.254122 +v 0.090590 3.746935 -0.231142 +v 0.090590 2.722769 -0.231142 +v 0.090590 2.643034 0.288310 +v 0.084607 2.864935 -0.440534 +v 0.084607 2.702693 0.473189 +v 0.084607 3.673055 -0.413200 +v 0.084607 3.629352 0.421907 +v 0.086637 3.278739 -0.526585 +v 0.086636 3.215177 0.507309 +v 0.095154 3.754534 0.020506 +v 0.060191 2.658972 -0.154656 +v 0.053444 2.613782 0.136010 +v 0.047516 2.554504 -0.139039 +v 0.047516 2.514067 0.124693 +v 0.100126 2.519134 -0.142488 +v 0.100126 2.479805 0.136555 +v 0.130264 2.209162 -0.175208 +v 0.130264 2.175989 0.226360 +v 0.145386 1.454041 -0.168399 +v 0.145386 1.399946 0.290329 +v 0.125174 1.790136 -0.123980 +v 0.125174 1.762047 0.266843 +v 0.118592 2.321896 0.187758 +v 0.118592 2.358026 -0.194066 +v 0.064118 0.867640 -0.065778 +v 0.139275 0.844466 0.140266 +v 0.257486 0.890374 -0.145882 +v 0.359097 0.900878 0.061199 +v 0.074195 0.752219 -0.105874 +v 0.147259 0.698792 0.087905 +v 0.263534 0.755735 -0.191206 +v 0.364126 0.730329 0.010206 +v 0.092608 0.518587 -0.156357 +v 0.161208 0.488124 0.011298 +v 0.257654 0.503497 -0.235568 +v 0.342662 0.497755 -0.059963 +v 0.100936 1.052740 0.183646 +v 0.362186 1.124208 0.082677 +v 0.035605 1.007707 -0.051248 +v 0.244578 1.066754 -0.153714 +v 0.055029 1.214705 -0.163442 +v 0.255589 1.328226 0.210676 +v 0.140172 0.882954 -0.138230 +v 0.262287 0.869133 0.135226 +v 0.152224 0.756748 -0.186384 +v 0.268705 0.704238 0.080827 +v 0.163237 0.508650 -0.221611 +v 0.266438 0.484781 0.003128 +v 0.113057 1.038591 -0.152600 +v 0.246990 1.089520 0.173845 +v 0.054756 1.198160 0.101170 +v 0.310361 1.325851 -0.067512 +v 0.060255 0.853278 0.049460 +v 0.343613 0.899484 -0.056313 +v 0.071380 0.718974 0.002418 +v 0.350589 0.741909 -0.110914 +v 0.091684 0.503566 -0.057160 +v 0.339310 0.499423 -0.163148 +v 0.344611 1.099522 -0.066307 +v 0.028575 1.027615 0.082498 +v 0.455190 2.450647 -0.082374 +v 0.462809 2.465601 0.006612 +v 0.448972 2.441031 0.081440 +v 0.434408 2.252116 -0.088512 +v 0.448014 2.213438 0.029647 +v 0.428671 2.233589 0.135751 +v 0.442147 2.332059 0.110493 +v 1.328482 2.369486 -0.025838 +v 0.448115 2.351334 -0.094647 +v 0.717408 2.422497 -0.064617 +v 0.727228 2.428632 0.006928 +v 0.711866 2.404597 0.073618 +v 0.698886 2.236229 -0.077850 +v 0.706620 2.199933 0.027458 +v 0.693774 2.219717 0.102536 +v 0.705784 2.307478 0.109237 +v 0.945792 2.289033 0.134562 +v 0.711103 2.324656 -0.097021 +v 1.329792 2.357378 0.034079 +v 1.323088 2.354750 0.089928 +v 1.305094 2.214479 -0.036920 +v 1.300746 2.180356 0.051271 +v 1.300117 2.200886 0.110979 +v 1.313884 2.273778 0.121339 +v 1.509906 2.320435 -0.046242 +v 1.319060 2.287920 -0.055202 +v 0.930288 2.200850 0.122871 +v 0.936312 2.211617 -0.068478 +v 0.952059 2.307598 -0.088140 +v 0.936310 2.172915 0.046302 +v 0.968273 2.418404 0.023926 +v 0.961626 2.413997 -0.054054 +v 0.955096 2.394653 0.096614 +v 0.330881 2.488142 0.003375 +v 0.305188 2.468017 0.099597 +v 0.315496 2.226114 -0.122984 +v 0.320825 2.354873 -0.139518 +v 0.303439 2.230228 0.158131 +v 0.309166 2.327404 0.136383 +v 0.348316 2.192029 0.031171 +v 0.315498 2.485255 -0.117814 +v 1.401711 2.330388 -0.053750 +v 1.402313 2.325266 0.037149 +v 1.368471 2.326110 0.116069 +v 1.380995 2.227921 -0.070645 +v 1.378716 2.209659 0.062973 +v 1.340428 2.225900 0.146512 +v 1.351661 2.274332 0.162481 +v 1.795120 2.206148 -0.017422 +v 1.399326 2.275373 -0.096810 +v 1.525167 2.312472 0.043161 +v 1.504512 2.310743 0.126497 +v 1.486518 2.218486 -0.062778 +v 1.505804 2.196043 0.068815 +v 1.481542 2.209545 0.157907 +v 1.495307 2.257487 0.173365 +v 1.626749 2.173789 0.059473 +v 1.500484 2.266789 -0.090058 +v 1.809535 2.198612 0.054630 +v 1.788894 2.200041 0.121791 +v 1.762707 2.137646 -0.030749 +v 1.779807 2.119442 0.075304 +v 1.756964 2.132012 0.147105 +v 1.774950 2.163872 0.159563 +v 1.797727 2.160531 0.057501 +v 1.780926 2.169733 -0.052734 +v 1.607462 2.193023 -0.059653 +v 1.616252 2.226447 0.154119 +v 1.602486 2.185360 0.140125 +v 1.646111 2.273569 0.036250 +v 1.630851 2.280393 -0.044683 +v 1.621429 2.234418 -0.084348 +v 1.625457 2.272087 0.111690 +v 1.379530 2.252804 0.224500 +v 1.371148 2.204101 0.211689 +v 1.461364 2.245535 0.213279 +v 1.452982 2.196833 0.200468 +v 1.424118 2.225873 0.279904 +v 1.419068 2.175998 0.270241 +v 1.481443 2.235304 0.220739 +v 1.476394 2.185430 0.211076 +v 1.509712 2.198027 0.341520 +v 1.506171 2.163050 0.334743 +v 1.549915 2.204642 0.300027 +v 1.546374 2.169665 0.293251 +v 0.262061 0.256721 -0.179629 +v 0.125851 0.263241 -0.073885 +v 0.264548 0.252916 -0.065338 +v 0.141817 0.268149 -0.192735 +v 0.270091 0.253667 -0.122910 +v 0.125675 0.264206 -0.137064 +v 0.206420 0.264077 -0.203655 +v 0.230977 0.000692 0.289805 +v 0.342493 0.000690 0.270761 +v 0.163985 0.000688 -0.230879 +v 0.270393 0.000686 -0.245194 +v 0.144177 0.000691 0.033839 +v 0.288000 0.000691 0.291562 +v 0.372899 0.000687 -0.002369 +v 0.227192 0.000686 -0.254522 +v 0.257567 0.000689 0.016768 +v 0.137243 0.000692 0.170051 +v 0.391563 0.000688 0.127957 +v 0.273728 0.000690 0.160912 +v 0.338169 0.000686 -0.146682 +v 0.108448 0.000690 -0.113832 +v 0.239700 0.000687 -0.142594 +v 0.167568 0.000692 0.233611 +v 0.383765 0.000689 0.197667 +v 0.281809 0.000691 0.232984 +v 0.309290 0.000686 -0.218277 +v 0.229983 0.000687 -0.223266 +v 0.118360 0.000689 -0.190507 +v 0.130135 0.000690 -0.034828 +v 0.349068 0.000687 -0.064281 +v 0.249487 0.000688 -0.055304 +v 0.387775 0.000687 0.061323 +v 0.265648 0.000689 0.088840 +v 0.129773 0.000692 0.103416 +v 0.232718 0.085533 0.288274 +v 0.363576 0.085530 0.268239 +v 0.154897 0.085528 -0.243375 +v 0.260403 0.080414 -0.243911 +v 0.128135 0.085532 0.035193 +v 0.299506 0.085532 0.289325 +v 0.383870 0.085527 -0.003576 +v 0.214830 0.085527 -0.261124 +v 0.132008 0.085533 0.181044 +v 0.405763 0.085528 0.135972 +v 0.339530 0.085526 -0.157915 +v 0.096516 0.085530 -0.123177 +v 0.167580 0.085533 0.249102 +v 0.395495 0.085529 0.210885 +v 0.304116 0.077122 -0.204676 +v 0.110617 0.085530 -0.206279 +v 0.114426 0.085531 -0.038332 +v 0.357741 0.085527 -0.069335 +v 0.401320 0.085528 0.064622 +v 0.123244 0.085533 0.109694 +v 0.235360 0.121957 0.282892 +v 0.342479 0.121955 0.271351 +v 0.155498 0.140203 -0.234632 +v 0.258674 0.141703 -0.233045 +v 0.147943 0.140206 0.045064 +v 0.367478 0.140202 0.015099 +v 0.209678 0.140554 -0.248081 +v 0.151504 0.140207 0.167879 +v 0.387046 0.140203 0.131704 +v 0.326827 0.140201 -0.142554 +v 0.113117 0.142231 -0.125673 +v 0.174977 0.140207 0.230696 +v 0.378520 0.140204 0.201276 +v 0.291506 0.139635 -0.192779 +v 0.127237 0.141691 -0.187001 +v 0.134396 0.140206 -0.008056 +v 0.354118 0.140202 -0.035038 +v 0.382905 0.140203 0.065200 +v 0.143705 0.140207 0.101330 +v 0.244012 0.174412 0.250246 +v 0.312400 0.174411 0.237719 +v 0.154929 0.197920 -0.224667 +v 0.244653 0.200889 -0.226557 +v 0.200247 0.182648 0.039626 +v 0.320975 0.193251 0.026737 +v 0.200815 0.200081 -0.230324 +v 0.176892 0.181218 0.144060 +v 0.349336 0.193278 0.128903 +v 0.299466 0.209667 -0.141685 +v 0.117610 0.203001 -0.122411 +v 0.197637 0.187029 0.207154 +v 0.340156 0.188834 0.188204 +v 0.275703 0.199069 -0.189682 +v 0.130048 0.198871 -0.180965 +v 0.183002 0.199344 -0.013043 +v 0.295575 0.215862 -0.011766 +v 0.341167 0.191744 0.072780 +v 0.191423 0.184576 0.092515 +v 0.338887 0.000686 -0.105818 +v 0.244594 0.000688 -0.098949 +v 0.116803 0.000690 -0.073995 +v 0.348659 0.085527 -0.113812 +v 0.102306 0.085531 -0.080271 +v 0.339594 0.140202 -0.089574 +v 0.118165 0.140205 -0.060612 +v 0.304014 0.215861 -0.085942 +v 0.129758 0.215864 -0.062783 +v 0.261646 0.242079 -0.188306 +v 0.230162 0.234212 -0.224732 +v 0.193922 0.242264 -0.221201 +v 0.165941 0.245963 -0.208302 +v 0.280499 0.229314 -0.077601 +v 0.279868 0.243470 -0.137553 +v 0.127675 0.236447 -0.179834 +v 0.120948 0.240070 -0.122668 +v 0.128658 0.229317 -0.058955 +v 0.189612 0.231437 -0.029962 +v 0.259835 0.229315 -0.044259 +v 0.190037 0.256893 -0.038329 +v -0.410268 3.453012 0.200817 +v -0.176448 3.516046 -0.492870 +v -0.176448 3.069885 -0.492870 +v -0.193285 2.961166 0.489574 +v -0.193285 3.452389 0.455386 +v -0.400123 2.998632 0.217911 +v -0.400123 3.035397 -0.212411 +v -0.410268 3.483905 -0.212411 +v -0.188297 3.698580 0.247489 +v -0.188298 3.731344 -0.224509 +v -0.188298 2.741884 -0.224509 +v -0.188298 2.664058 0.281677 +v -0.338060 2.788810 0.205190 +v -0.323248 3.496119 -0.410188 +v -0.323248 3.441588 0.352035 +v -0.338059 3.642598 0.223085 +v -0.338060 2.852551 -0.208748 +v -0.175812 2.876968 -0.427238 +v -0.323248 3.072495 -0.410188 +v -0.192649 2.735571 0.459728 +v -0.323248 2.996823 0.381949 +v -0.338060 3.655763 -0.208748 +v -0.175812 3.660861 -0.399904 +v -0.192648 3.617279 0.405342 +v -0.180047 3.275434 -0.517282 +v 0.000241 3.527937 -0.505363 +v 0.000241 3.059241 -0.517105 +v -0.196883 3.218354 0.478425 +v 0.000241 2.927055 0.514236 +v 0.000241 3.457695 0.495095 +v -0.408868 3.230555 0.194491 +v -0.402636 3.253443 -0.219099 +v -0.428688 3.009897 0.014208 +v -0.438833 3.472003 0.009934 +v 0.000241 3.735282 0.260225 +v 0.000241 3.756304 -0.237245 +v -0.197821 3.743473 0.020506 +v -0.197821 2.669343 0.029053 +v 0.000241 2.716923 -0.237245 +v 0.000241 2.623689 0.294413 +v -0.285941 2.928726 -0.357824 +v -0.285941 2.767836 0.367046 +v -0.285941 3.636701 -0.357824 +v -0.301410 3.594941 0.358830 +v -0.357105 2.802252 0.025342 +v 0.000241 2.853864 -0.452768 +v -0.322054 3.266541 -0.423686 +v 0.000241 2.695371 0.485576 +v -0.326999 3.227505 0.360122 +v -0.357105 3.654801 0.017864 +v 0.000241 3.684277 -0.419779 +v 0.000241 3.640461 0.434294 +v 0.000241 3.279187 -0.533908 +v 0.000241 3.212254 0.507793 +v -0.433886 3.238045 0.005717 +v 0.000241 3.765371 0.020506 +v 0.000241 2.608866 0.157665 +v 0.000241 2.662452 -0.152277 +v -0.110768 2.648599 -0.113100 +v -0.129241 2.623841 0.000772 +v -0.109673 2.617475 0.111510 +v 0.000241 2.511192 0.146864 +v 0.000241 2.557636 -0.161210 +v -0.098412 2.551101 -0.119944 +v -0.139827 2.525439 -0.009396 +v -0.098412 2.517193 0.100599 +v 0.000241 2.476242 0.161267 +v 0.000241 2.522766 -0.165241 +v -0.208196 2.515187 -0.122760 +v -0.245330 2.502890 -0.002447 +v -0.208196 2.483677 0.109699 +v 0.000241 2.174426 0.258809 +v 0.000241 2.211377 -0.202993 +v -0.271088 2.206755 -0.145013 +v -0.319426 2.187368 0.032075 +v -0.271088 2.177688 0.191096 +v 0.000241 1.398135 0.309651 +v 0.000241 1.463624 -0.206620 +v -0.302644 1.441376 -0.106186 +v -0.354291 1.410232 0.081480 +v -0.288561 1.402802 0.240545 +v 0.000241 1.761031 0.298778 +v -0.260465 1.763152 0.232137 +v -0.306911 1.770383 0.075582 +v -0.260465 1.788246 -0.089088 +v 0.000241 1.791875 -0.156086 +v -0.246731 2.324639 0.153241 +v -0.246731 2.354880 -0.163592 +v 0.000241 2.360921 -0.206229 +v 0.000241 2.319373 0.219519 +v -0.113364 1.290662 0.268232 +v -0.018429 1.168483 -0.035181 +v -0.184480 1.284700 -0.183080 +v -0.000316 1.168480 -0.035282 +v -0.084430 3.522239 -0.501146 +v -0.084430 3.064342 -0.512888 +v -0.084430 2.943401 0.510254 +v -0.084429 3.458095 0.476066 +v -0.090108 3.723567 0.254122 +v -0.090108 3.746935 -0.231142 +v -0.090108 2.722769 -0.231142 +v -0.090108 2.643034 0.288310 +v -0.084125 2.864935 -0.440534 +v -0.084125 2.702693 0.473189 +v -0.084125 3.673055 -0.413200 +v -0.084125 3.629352 0.421907 +v -0.086154 3.278739 -0.526585 +v -0.086154 3.215177 0.507309 +v -0.094671 3.754534 0.020506 +v -0.059709 2.658972 -0.154656 +v -0.052962 2.613782 0.136010 +v -0.047034 2.554504 -0.139039 +v -0.047034 2.514068 0.124693 +v -0.099643 2.519134 -0.142488 +v -0.099643 2.479805 0.136555 +v -0.129782 2.209162 -0.175208 +v -0.129782 2.175989 0.226360 +v -0.144904 1.454041 -0.168399 +v -0.144904 1.399946 0.290329 +v -0.124691 1.790136 -0.123980 +v -0.124691 1.762047 0.266843 +v -0.118110 2.321897 0.187758 +v -0.118110 2.358026 -0.194066 +v 0.000241 1.284807 0.281643 +v 0.000241 1.284807 -0.179892 +v -0.065606 0.867575 -0.068223 +v -0.137184 0.844409 0.139088 +v -0.260316 0.890440 -0.144957 +v -0.358304 0.900967 0.063854 +v -0.076447 0.752149 -0.108154 +v -0.146162 0.698757 0.086858 +v -0.267231 0.755783 -0.190189 +v -0.364320 0.730428 0.012933 +v -0.095873 0.518518 -0.158302 +v -0.161565 0.488099 0.010515 +v -0.262272 0.503526 -0.234639 +v -0.344217 0.497838 -0.057588 +v -0.097973 1.052652 0.181831 +v -0.360885 1.124295 0.085420 +v -0.036763 1.007622 -0.054166 +v -0.247441 1.066813 -0.152981 +v -0.057083 1.214724 -0.162813 +v -0.253453 1.328216 0.210857 +v -0.001001 1.201565 -0.157958 +v -0.142896 0.882948 -0.139342 +v -0.260245 0.869150 0.136185 +v -0.155858 0.756730 -0.187298 +v -0.267706 0.704276 0.081887 +v -0.167628 0.508623 -0.222321 +v -0.266919 0.484820 0.004171 +v -0.115942 1.038571 -0.154153 +v -0.244148 1.089522 0.174570 +v -0.053830 1.198178 0.101779 +v -0.310544 1.325896 -0.066387 +v 0.000415 1.184651 0.093554 +v -0.059751 0.853190 0.046927 +v -0.344866 0.899585 -0.053907 +v -0.071771 0.718897 0.000070 +v -0.352883 0.742005 -0.108402 +v -0.093234 0.503499 -0.059137 +v -0.342657 0.499502 -0.160814 +v -0.345917 1.099626 -0.063848 +v -0.027398 1.027503 0.079441 +v -0.454708 2.450647 -0.082374 +v -0.462326 2.465601 0.006612 +v -0.448490 2.441031 0.081440 +v -0.433925 2.252116 -0.088512 +v -0.447532 2.213438 0.029647 +v -0.428189 2.233589 0.135751 +v -0.441665 2.332059 0.110493 +v -1.328000 2.369487 -0.025839 +v -0.447632 2.351334 -0.094647 +v -0.716926 2.422497 -0.064618 +v -0.726745 2.428632 0.006928 +v -0.711384 2.404597 0.073617 +v -0.698403 2.236229 -0.077851 +v -0.706138 2.199933 0.027457 +v -0.693291 2.219717 0.102535 +v -0.705302 2.307478 0.109236 +v -0.945310 2.289035 0.134561 +v -0.710620 2.324656 -0.097021 +v -1.329309 2.357379 0.034077 +v -1.322606 2.354751 0.089927 +v -1.304611 2.214480 -0.036921 +v -1.300263 2.180357 0.051270 +v -1.299635 2.200886 0.110977 +v -1.313401 2.273779 0.121337 +v -1.509424 2.320436 -0.046244 +v -1.318578 2.287921 -0.055203 +v -0.929806 2.200852 0.122871 +v -0.935830 2.211618 -0.068479 +v -0.951576 2.307599 -0.088141 +v -0.935828 2.172916 0.046301 +v -0.967791 2.418405 0.023925 +v -0.961144 2.413998 -0.054055 +v -0.954614 2.394654 0.096613 +v -0.330399 2.488142 0.003375 +v -0.304706 2.468017 0.099597 +v -0.315013 2.226115 -0.122984 +v -0.320343 2.354873 -0.139518 +v -0.302957 2.230229 0.158131 +v -0.308683 2.327404 0.136383 +v -0.347834 2.192029 0.031171 +v -0.315016 2.485255 -0.117814 +v -1.401229 2.330389 -0.053752 +v -1.401832 2.325267 0.037148 +v -1.367989 2.326111 0.116068 +v -1.380512 2.227921 -0.070646 +v -1.378233 2.209659 0.062972 +v -1.339946 2.225900 0.146510 +v -1.351179 2.274333 0.162479 +v -1.794637 2.206148 -0.017425 +v -1.398844 2.275373 -0.096812 +v -1.524685 2.312473 0.043160 +v -1.504030 2.310744 0.126495 +v -1.486035 2.218486 -0.062780 +v -1.505322 2.196043 0.068813 +v -1.481060 2.209546 0.157905 +v -1.494826 2.257488 0.173364 +v -1.626266 2.173790 0.059471 +v -1.500002 2.266789 -0.090059 +v -1.809052 2.198613 0.054628 +v -1.788411 2.200042 0.121789 +v -1.762224 2.137647 -0.030751 +v -1.779324 2.119443 0.075302 +v -1.756481 2.132013 0.147103 +v -1.774468 2.163872 0.159561 +v -1.797244 2.160531 0.057499 +v -1.780442 2.169733 -0.052736 +v -1.606979 2.193023 -0.059655 +v -1.615770 2.226447 0.154117 +v -1.602004 2.185361 0.140123 +v -1.645628 2.273569 0.036248 +v -1.630368 2.280394 -0.044685 +v -1.620946 2.234419 -0.084350 +v -1.624974 2.272088 0.111689 +v -1.379048 2.252805 0.224499 +v -1.370666 2.204103 0.211687 +v -1.460882 2.245536 0.213278 +v -1.452500 2.196834 0.200466 +v -1.423636 2.225874 0.279902 +v -1.418586 2.176000 0.270239 +v -1.480961 2.235306 0.220738 +v -1.475912 2.185432 0.211075 +v -1.509230 2.198029 0.341518 +v -1.505689 2.163052 0.334741 +v -1.549433 2.204644 0.300026 +v -1.545892 2.169667 0.293249 +v -0.265503 0.256741 -0.179040 +v -0.128605 0.263213 -0.074647 +v -0.266996 0.252931 -0.064922 +v -0.145572 0.268133 -0.193156 +v -0.273029 0.253686 -0.122348 +v -0.128976 0.264181 -0.137721 +v -0.210161 0.264081 -0.203502 +v -0.234285 0.000684 0.289802 +v -0.345794 0.000685 0.270758 +v -0.167301 0.000685 -0.230884 +v -0.273702 0.000685 -0.245200 +v -0.147492 0.000684 0.033835 +v -0.291304 0.000684 0.291559 +v -0.376200 0.000685 -0.002375 +v -0.230503 0.000685 -0.254528 +v -0.260875 0.000685 0.016763 +v -0.140559 0.000683 0.170049 +v -0.394861 0.000685 0.127952 +v -0.277034 0.000684 0.160908 +v -0.341473 0.000685 -0.146689 +v -0.111766 0.000684 -0.113835 +v -0.243010 0.000685 -0.142600 +v -0.170881 0.000684 0.233609 +v -0.387064 0.000685 0.197662 +v -0.285114 0.000684 0.232981 +v -0.312595 0.000685 -0.218283 +v -0.233294 0.000685 -0.223272 +v -0.121678 0.000684 -0.190511 +v -0.133452 0.000684 -0.034831 +v -0.352371 0.000685 -0.064287 +v -0.252796 0.000685 -0.055309 +v -0.391075 0.000685 0.061317 +v -0.268955 0.000685 0.088836 +v -0.133089 0.000684 0.103414 +v -0.236024 0.085525 0.288271 +v -0.366872 0.085526 0.268235 +v -0.158210 0.085526 -0.243380 +v -0.263710 0.080414 -0.243917 +v -0.131449 0.085526 0.035190 +v -0.302807 0.085526 0.289322 +v -0.387167 0.085527 -0.003582 +v -0.218139 0.085526 -0.261130 +v -0.135320 0.085525 0.181042 +v -0.409058 0.085527 0.135967 +v -0.342831 0.085527 -0.157921 +v -0.099833 0.085525 -0.123180 +v -0.170889 0.085525 0.249100 +v -0.398790 0.085527 0.210881 +v -0.307420 0.077122 -0.204682 +v -0.113933 0.085526 -0.206283 +v -0.117741 0.085526 -0.038335 +v -0.361040 0.085527 -0.069341 +v -0.404616 0.085527 0.064617 +v -0.126558 0.085525 0.109692 +v -0.238664 0.121950 0.282890 +v -0.345776 0.121951 0.271347 +v -0.158809 0.140201 -0.234637 +v -0.261978 0.141703 -0.233051 +v -0.151253 0.140201 0.045061 +v -0.370775 0.140202 0.015093 +v -0.212986 0.140554 -0.248087 +v -0.154814 0.140200 0.167876 +v -0.390340 0.140202 0.131699 +v -0.330126 0.140202 -0.142561 +v -0.116431 0.142227 -0.125676 +v -0.178285 0.140200 0.230694 +v -0.381814 0.140202 0.201272 +v -0.294809 0.139635 -0.192786 +v -0.130550 0.141688 -0.187006 +v -0.137707 0.140201 -0.008060 +v -0.357415 0.140202 -0.035044 +v -0.386200 0.140202 0.065195 +v -0.147016 0.140200 0.101327 +v -0.247314 0.174407 0.250243 +v -0.315698 0.174407 0.237716 +v -0.158239 0.197919 -0.224671 +v -0.247956 0.200890 -0.226562 +v -0.203553 0.182644 0.039623 +v -0.324272 0.193250 0.026732 +v -0.204122 0.200081 -0.230329 +v -0.180198 0.181212 0.144057 +v -0.352631 0.193276 0.128898 +v -0.302766 0.209668 -0.141691 +v -0.120922 0.202998 -0.122415 +v -0.200942 0.187023 0.207151 +v -0.343452 0.188832 0.188200 +v -0.279004 0.199070 -0.189688 +v -0.133359 0.198869 -0.180969 +v -0.186309 0.199341 -0.013046 +v -0.298874 0.215861 -0.011771 +v -0.344463 0.191743 0.072775 +v -0.194729 0.184572 0.092512 +v -0.342190 0.000685 -0.105824 +v -0.247903 0.000685 -0.098954 +v -0.120121 0.000684 -0.073998 +v -0.351959 0.085527 -0.113818 +v -0.105622 0.085526 -0.080274 +v -0.342893 0.140202 -0.089580 +v -0.121478 0.140201 -0.060615 +v -0.307313 0.215861 -0.085948 +v -0.133068 0.215860 -0.062786 +v -0.264947 0.242080 -0.188311 +v -0.233465 0.234212 -0.224737 +v -0.197228 0.242264 -0.221206 +v -0.169248 0.245962 -0.208306 +v -0.283799 0.229314 -0.077606 +v -0.283168 0.243471 -0.137559 +v -0.130985 0.236445 -0.179838 +v -0.124258 0.240067 -0.122671 +v -0.131967 0.229313 -0.058958 +v -0.192917 0.231434 -0.029966 +v -0.263136 0.229314 -0.044264 +v -0.192377 0.256884 -0.038600 +v -1.684602 2.165335 -0.045203 +v -1.679243 2.158687 0.143613 +v -1.727340 2.236091 0.045438 +v -1.702795 2.146616 0.067387 +v -1.695118 2.195160 0.156839 +v -1.712502 2.243271 -0.031055 +v -1.700694 2.202076 -0.068543 +v -1.706693 2.236064 0.116739 +v 1.685084 2.165334 -0.045201 +v 1.679725 2.158686 0.143615 +v 1.727823 2.236091 0.045440 +v 1.703278 2.146616 0.067389 +v 1.695601 2.195159 0.156841 +v 1.712985 2.243270 -0.031053 +v 1.701177 2.202075 -0.068541 +v 1.707175 2.236064 0.116741 +v 1.566276 2.184916 0.064144 +v 1.555779 2.241967 0.163742 +v 1.570378 2.300414 -0.045463 +v 1.560956 2.250603 -0.087203 +v 1.564984 2.291415 0.119094 +v 1.546990 2.205754 -0.061216 +v 1.542014 2.197453 0.149016 +v 1.585639 2.293020 0.039706 +v -1.565794 2.184916 0.064142 +v -1.555298 2.241968 0.163740 +v -1.569896 2.300415 -0.045465 +v -1.560474 2.250604 -0.087204 +v -1.564502 2.291416 0.119092 +v -1.546507 2.205755 -0.061217 +v -1.541532 2.197453 0.149014 +v -1.585157 2.293021 0.039704 +v 0.817599 2.223923 -0.073164 +v 0.817657 2.186424 0.036880 +v 0.839517 2.418247 -0.059336 +v 0.833481 2.399625 0.085116 +v 0.812031 2.210284 0.112704 +v 0.831581 2.316127 -0.092581 +v 0.836919 2.423518 0.015427 +v -0.817117 2.223924 -0.073165 +v -0.817175 2.186424 0.036879 +v -0.839035 2.418248 -0.059336 +v -0.832999 2.399626 0.085115 +v -0.811549 2.210284 0.112703 +v -0.831098 2.316128 -0.092581 +v -0.836436 2.423519 0.015427 +v 0.000241 1.579583 0.304214 +v 0.334021 1.590260 0.078120 +v 0.000241 1.627749 -0.181353 +v 0.277708 1.583014 0.235970 +v 0.282037 1.614811 -0.097637 +v 0.135280 1.622088 -0.146189 +v 0.135280 1.580997 0.278586 +v -0.333345 1.590268 0.078406 +v -0.276778 1.583012 0.236050 +v -0.281555 1.614811 -0.097637 +v -0.134797 1.622088 -0.146189 +v -0.134797 1.580997 0.278586 +v 0.266259 1.970420 0.211617 +v 0.266259 1.997501 -0.117050 +v 0.000241 1.967728 0.278793 +v 0.313651 1.978875 0.053829 +v 0.000241 2.001626 -0.179539 +v 0.127719 1.969018 0.246602 +v 0.127719 1.999649 -0.149594 +v -0.265777 1.970420 0.211617 +v -0.265777 1.997501 -0.117050 +v -0.313168 1.978875 0.053829 +v -0.127236 1.969018 0.246602 +v -0.127236 1.999649 -0.149594 +v 1.122344 2.200868 0.116925 +v 1.142700 2.297759 -0.071671 +v 1.154038 2.387891 0.029002 +v 1.136979 2.281405 0.127950 +v 1.127844 2.213048 -0.052699 +v 1.133873 2.176636 0.048787 +v 1.152195 2.391741 -0.039946 +v 1.146233 2.374701 0.093271 +v -1.121862 2.200869 0.116924 +v -1.142218 2.297760 -0.071672 +v -1.153556 2.387892 0.029001 +v -1.136497 2.281407 0.127949 +v -1.127362 2.213049 -0.052700 +v -1.133391 2.176636 0.048786 +v -1.151713 2.391742 -0.039947 +v -1.145751 2.374702 0.093270 +v 0.581107 2.319769 0.109865 +v 0.586750 2.337995 -0.095834 +v 0.593441 2.436572 -0.073496 +v 0.600412 2.447117 0.006770 +v 0.587561 2.422814 0.077529 +v 0.577991 2.206686 0.028552 +v 0.568364 2.226653 0.119143 +v 0.573788 2.244173 -0.083181 +v -0.580625 2.319769 0.109865 +v -0.586267 2.337995 -0.095834 +v -0.592958 2.436572 -0.073496 +v -0.599929 2.447117 0.006770 +v -0.587078 2.422814 0.077529 +v -0.577509 2.206685 0.028552 +v -0.567881 2.226653 0.119143 +v -0.573305 2.244173 -0.083181 +v 0.069151 0.811140 -0.084140 +v 0.143267 0.769931 0.115422 +v 0.361608 0.814996 0.037936 +v 0.265496 0.785043 0.109763 +v 0.146190 0.822050 -0.160339 +v 0.347095 0.821727 -0.081373 +v 0.065815 0.785709 0.027417 +v -0.070991 0.811069 -0.086508 +v -0.141651 0.769890 0.114305 +v -0.361270 0.815091 0.040619 +v -0.263946 0.785076 0.110766 +v -0.149333 0.822031 -0.161359 +v -0.348828 0.821822 -0.078922 +v -0.065734 0.785628 0.024971 +vt 0.424701 0.840048 +vt 0.423209 0.793785 +vt 0.461737 0.792426 +vt 0.464884 0.838834 +vt 0.468357 0.881332 +vt 0.416097 0.891155 +vt 0.382303 0.875623 +vt 0.388845 0.838885 +vt 0.386734 0.795098 +vt 0.579037 0.844668 +vt 0.567369 0.879717 +vt 0.544300 0.865660 +vt 0.547922 0.837220 +vt 0.549707 0.794263 +vt 0.582610 0.796170 +vt 0.598269 0.849956 +vt 0.602276 0.796592 +vt 0.621565 0.796099 +vt 0.617431 0.855287 +vt 0.601115 0.901709 +vt 0.583674 0.890608 +vt 0.580062 0.754791 +vt 0.546804 0.757119 +vt 0.544177 0.724490 +vt 0.573455 0.711359 +vt 0.598626 0.752337 +vt 0.595019 0.704367 +vt 0.617289 0.699781 +vt 0.620532 0.750242 +vt 0.349273 0.747190 +vt 0.347330 0.708825 +vt 0.370455 0.709217 +vt 0.379997 0.749138 +vt 0.352581 0.794437 +vt 0.329588 0.744940 +vt 0.331063 0.794428 +vt 0.315002 0.794084 +vt 0.314985 0.741795 +vt 0.314901 0.703498 +vt 0.329344 0.703695 +vt 0.354491 0.840733 +vt 0.357743 0.880856 +vt 0.332172 0.842510 +vt 0.333959 0.884940 +vt 0.315019 0.885796 +vt 0.315031 0.842108 +vt 0.414559 0.747483 +vt 0.399518 0.701783 +vt 0.448949 0.694770 +vt 0.456853 0.745548 +vt 0.505141 0.748829 +vt 0.508784 0.706093 +vt 0.507142 0.792801 +vt 0.508074 0.837122 +vt 0.514661 0.872259 +vt 0.419137 0.937326 +vt 0.478349 0.922822 +vt 0.424097 0.965195 +vt 0.486594 0.948330 +vt 0.495723 0.973192 +vt 0.428443 0.990876 +vt 0.345577 0.936058 +vt 0.314782 0.941388 +vt 0.375705 0.922558 +vt 0.532102 0.902649 +vt 0.545515 0.922196 +vt 0.559814 0.940878 +vt 0.436532 0.655316 +vt 0.362648 0.645806 +vt 0.382595 0.577465 +vt 0.445393 0.577416 +vt 0.535122 0.656711 +vt 0.561397 0.634699 +vt 0.607811 0.622342 +vt 0.339216 0.643866 +vt 0.314578 0.640560 +vt 0.510735 0.577421 +vt 0.559529 0.577420 +vt 0.444090 0.534948 +vt 0.509270 0.534980 +vt 0.347826 0.577463 +vt 0.314959 0.577465 +vt 0.314357 0.535019 +vt 0.343869 0.535021 +vt 0.327559 0.284656 +vt 0.332242 0.271386 +vt 0.359600 0.274896 +vt 0.357633 0.299914 +vt 0.321315 0.250312 +vt 0.314290 0.247970 +vt 0.314171 0.231740 +vt 0.334433 0.243039 +vt 0.382847 0.535032 +vt 0.558656 0.534925 +vt 0.325529 0.253434 +vt 0.351430 0.248123 +vt 0.319754 0.286217 +vt 0.333829 0.303559 +vt 0.418691 0.370972 +vt 0.389352 0.351632 +vt 0.418603 0.335552 +vt 0.431990 0.354981 +vt 0.338145 0.328760 +vt 0.366602 0.325961 +vt 0.377808 0.356778 +vt 0.343676 0.358303 +vt 0.335864 0.210609 +vt 0.314003 0.207365 +vt 0.314103 0.176477 +vt 0.345144 0.178504 +vt 0.387039 0.219621 +vt 0.390341 0.194177 +vt 0.422363 0.207716 +vt 0.418946 0.229929 +vt 0.345500 0.054288 +vt 0.315138 0.054235 +vt 0.315528 0.018181 +vt 0.347504 0.018238 +vt 0.376599 0.479159 +vt 0.415450 0.479198 +vt 0.416158 0.512649 +vt 0.378862 0.512649 +vt 0.417869 0.054390 +vt 0.379180 0.054356 +vt 0.383732 0.018359 +vt 0.421058 0.018359 +vt 0.344804 0.479148 +vt 0.345824 0.512586 +vt 0.343730 0.404567 +vt 0.376072 0.404566 +vt 0.374336 0.441555 +vt 0.343784 0.441555 +vt 0.416751 0.128948 +vt 0.377222 0.128952 +vt 0.374628 0.091879 +vt 0.414680 0.091883 +vt 0.414734 0.404572 +vt 0.414742 0.441555 +vt 0.344319 0.128948 +vt 0.314426 0.128944 +vt 0.314749 0.091873 +vt 0.343495 0.091877 +vt 0.377580 0.274898 +vt 0.379110 0.250741 +vt 0.414096 0.254865 +vt 0.413016 0.274926 +vt 0.383845 0.322909 +vt 0.415778 0.316747 +vt 0.785443 0.156150 +vt 0.764725 0.156147 +vt 0.765086 0.122612 +vt 0.785862 0.122612 +vt 0.799682 0.217712 +vt 0.787967 0.231864 +vt 0.787944 0.209717 +vt 0.806383 0.217712 +vt 0.817931 0.209717 +vt 0.817908 0.231864 +vt 0.313408 0.304910 +vt 0.313716 0.329378 +vt 0.371733 0.216071 +vt 0.314416 0.404567 +vt 0.314870 0.441555 +vt 0.315301 0.479147 +vt 0.315731 0.512570 +vt 0.379817 0.180762 +vt 0.313963 0.358401 +vt 0.313509 0.286997 +vt 0.603163 0.577407 +vt 0.606192 0.534877 +vt 0.745241 0.200706 +vt 0.748033 0.232049 +vt 0.860635 0.200706 +vt 0.857842 0.232049 +vt 0.709972 0.232115 +vt 0.709972 0.200711 +vt 0.709972 0.171386 +vt 0.709972 0.163211 +vt 0.711885 0.163092 +vt 0.722930 0.172839 +vt 0.895904 0.232115 +vt 0.895904 0.200711 +vt 0.882945 0.172839 +vt 0.893990 0.163092 +vt 0.895904 0.163211 +vt 0.895904 0.171386 +vt 0.746436 0.108499 +vt 0.728058 0.108499 +vt 0.727994 0.095821 +vt 0.746362 0.095822 +vt 0.742320 0.156136 +vt 0.722900 0.156121 +vt 0.728122 0.122612 +vt 0.746509 0.122612 +vt 0.820432 0.156150 +vt 0.806711 0.156148 +vt 0.806948 0.122612 +vt 0.820014 0.122612 +vt 0.863555 0.156136 +vt 0.841092 0.156147 +vt 0.840811 0.122612 +vt 0.859366 0.122612 +vt 0.820810 0.095822 +vt 0.806988 0.095820 +vt 0.807180 0.054984 +vt 0.822926 0.054984 +vt 0.820412 0.108499 +vt 0.806968 0.108499 +vt 0.859513 0.095822 +vt 0.859440 0.108499 +vt 0.840859 0.095821 +vt 0.785464 0.108499 +vt 0.765055 0.108499 +vt 0.765025 0.095821 +vt 0.785065 0.095822 +vt 0.765027 0.054984 +vt 0.748996 0.054984 +vt 0.749674 0.016269 +vt 0.765051 0.016269 +vt 0.840857 0.054984 +vt 0.856880 0.054984 +vt 0.782949 0.054984 +vt 0.729510 0.054983 +vt 0.799277 0.156148 +vt 0.882975 0.156121 +vt 0.798935 0.095820 +vt 0.798699 0.054984 +vt 0.877882 0.095821 +vt 0.876366 0.054983 +vt 0.730059 0.016269 +vt 0.798960 0.108499 +vt 0.877818 0.108499 +vt 0.877753 0.122612 +vt 0.798985 0.122612 +vt 0.840838 0.016269 +vt 0.856202 0.016269 +vt 0.782896 0.016268 +vt 0.798648 0.016268 +vt 0.449700 0.220684 +vt 0.449796 0.204123 +vt 0.480859 0.204123 +vt 0.480685 0.220695 +vt 0.449654 0.257610 +vt 0.449682 0.238404 +vt 0.480652 0.238492 +vt 0.480599 0.257655 +vt 0.449661 0.302478 +vt 0.449646 0.286082 +vt 0.480577 0.286036 +vt 0.480601 0.302370 +vt 0.449670 0.274956 +vt 0.480593 0.274987 +vt 0.377299 0.292342 +vt 0.412883 0.292280 +vt 0.427685 0.190243 +vt 0.435707 0.203873 +vt 0.566812 0.286023 +vt 0.566812 0.275036 +vt 0.595577 0.275057 +vt 0.595566 0.286095 +vt 0.566827 0.354952 +vt 0.566822 0.326817 +vt 0.595512 0.326825 +vt 0.595500 0.354952 +vt 0.566782 0.238670 +vt 0.566782 0.220717 +vt 0.595706 0.220705 +vt 0.595699 0.238600 +vt 0.566815 0.302227 +vt 0.595550 0.302456 +vt 0.449673 0.326828 +vt 0.480612 0.326823 +vt 0.449765 0.354952 +vt 0.480773 0.354952 +vt 0.936048 0.768188 +vt 0.936053 0.746623 +vt 0.924192 0.740812 +vt 0.923121 0.760166 +vt 0.936018 0.819789 +vt 0.936059 0.797784 +vt 0.916592 0.805110 +vt 0.913699 0.821253 +vt 0.935973 0.782601 +vt 0.915423 0.782034 +vt 0.911752 0.319669 +vt 0.933272 0.316595 +vt 0.941824 0.333084 +vt 0.910614 0.334381 +vt 0.566800 0.257742 +vt 0.595621 0.257734 +vt 0.566790 0.204124 +vt 0.595682 0.204124 +vt 0.506526 0.274998 +vt 0.506548 0.257674 +vt 0.532519 0.257694 +vt 0.532485 0.275009 +vt 0.506620 0.220701 +vt 0.506734 0.204123 +vt 0.532625 0.204124 +vt 0.532558 0.220707 +vt 0.532559 0.238577 +vt 0.506530 0.302339 +vt 0.506519 0.286032 +vt 0.532490 0.286028 +vt 0.532482 0.302308 +vt 0.506529 0.326822 +vt 0.532468 0.326821 +vt 0.506639 0.354952 +vt 0.532541 0.354952 +vt 0.420373 0.176908 +vt 0.414725 0.374942 +vt 0.885913 0.762972 +vt 0.885325 0.783977 +vt 0.889616 0.328988 +vt 0.912643 0.364253 +vt 0.892080 0.360976 +vt 0.879460 0.743643 +vt 0.891324 0.803735 +vt 0.891345 0.819504 +vt 0.896713 0.317960 +vt 0.936077 0.838896 +vt 0.917882 0.833832 +vt 0.948365 0.733420 +vt 0.934622 0.732855 +vt 0.849376 0.815349 +vt 0.850748 0.805248 +vt 0.836471 0.804603 +vt 0.835136 0.812201 +vt 0.845468 0.793376 +vt 0.831510 0.796107 +vt 0.917673 0.409579 +vt 0.942118 0.402143 +vt 0.940634 0.420541 +vt 0.917720 0.427678 +vt 0.838529 0.771488 +vt 0.832166 0.765778 +vt 0.818658 0.776896 +vt 0.825597 0.780492 +vt 0.891695 0.833437 +vt 0.868327 0.735148 +vt 0.887944 0.727402 +vt 0.871512 0.724326 +vt 0.941792 0.356512 +vt 0.824181 0.797634 +vt 0.812448 0.795354 +vt 0.828406 0.817321 +vt 0.830746 0.786410 +vt 0.844654 0.780574 +vt 0.900278 0.405603 +vt 0.901378 0.423637 +vt 0.844856 0.823697 +vt 0.876501 0.831755 +vt 0.877480 0.819001 +vt 0.863616 0.818497 +vt 0.861307 0.830073 +vt 0.872376 0.787311 +vt 0.872238 0.768855 +vt 0.858562 0.774738 +vt 0.859427 0.790645 +vt 0.895628 0.374273 +vt 0.915135 0.377867 +vt 0.917627 0.391481 +vt 0.899177 0.387570 +vt 0.865460 0.753064 +vt 0.851461 0.762485 +vt 0.857000 0.744904 +vt 0.845674 0.754660 +vt 0.942698 0.370129 +vt 0.943603 0.383745 +vt 0.878174 0.804814 +vt 0.865024 0.805893 +vt 0.914557 0.725788 +vt 0.924213 0.719241 +vt 0.914994 0.703678 +vt 0.906472 0.711107 +vt 0.881044 0.356556 +vt 0.875706 0.338668 +vt 0.863509 0.352136 +vt 0.879002 0.362548 +vt 0.863138 0.381292 +vt 0.852273 0.373989 +vt 0.885267 0.719886 +vt 0.871271 0.716399 +vt 0.894062 0.694357 +vt 0.896674 0.686606 +vt 0.881207 0.690837 +vt 0.886620 0.697803 +vt 0.822979 0.016268 +vt 0.807221 0.016268 +vt 0.875816 0.016269 +vt 0.767140 0.911152 +vt 0.774189 0.910992 +vt 0.771025 0.901580 +vt 0.764041 0.893569 +vt 0.762619 0.936895 +vt 0.770492 0.925697 +vt 0.696701 0.941705 +vt 0.711877 0.936747 +vt 0.712850 0.911002 +vt 0.696555 0.911002 +vt 0.714237 0.884771 +vt 0.699642 0.883044 +vt 0.663963 0.911002 +vt 0.680259 0.911002 +vt 0.684668 0.883866 +vt 0.669298 0.887352 +vt 0.666683 0.936525 +vt 0.681635 0.941705 +vt 0.736641 0.940160 +vt 0.745745 0.941028 +vt 0.748883 0.911001 +vt 0.739015 0.911001 +vt 0.747331 0.888913 +vt 0.738188 0.889775 +vt 0.652548 0.923774 +vt 0.650728 0.911086 +vt 0.654009 0.898398 +vt 0.729146 0.911001 +vt 0.728658 0.888542 +vt 0.727561 0.938163 +vt 0.685829 0.695635 +vt 0.692503 0.712229 +vt 0.708990 0.708576 +vt 0.708432 0.689949 +vt 0.636358 0.838542 +vt 0.651216 0.838339 +vt 0.651688 0.827846 +vt 0.635893 0.827677 +vt 0.781184 0.780586 +vt 0.761434 0.786870 +vt 0.765163 0.797322 +vt 0.785169 0.791226 +vt 0.644587 0.767637 +vt 0.662889 0.772774 +vt 0.667608 0.758644 +vt 0.648575 0.752749 +vt 0.673889 0.744932 +vt 0.655645 0.733289 +vt 0.636687 0.810221 +vt 0.652656 0.811979 +vt 0.655557 0.797710 +vt 0.638034 0.794237 +vt 0.751425 0.706855 +vt 0.736307 0.719414 +vt 0.743897 0.740484 +vt 0.762033 0.731608 +vt 0.770097 0.809706 +vt 0.787648 0.803114 +vt 0.775207 0.821912 +vt 0.791133 0.816315 +vt 0.756045 0.773861 +vt 0.741140 0.776355 +vt 0.746963 0.789506 +vt 0.749903 0.756858 +vt 0.738081 0.763188 +vt 0.728583 0.733966 +vt 0.733420 0.750248 +vt 0.683428 0.721761 +vt 0.690265 0.735383 +vt 0.699037 0.717821 +vt 0.675902 0.773849 +vt 0.678758 0.763215 +vt 0.663860 0.828975 +vt 0.666038 0.813500 +vt 0.651369 0.848259 +vt 0.662989 0.848260 +vt 0.662721 0.839648 +vt 0.726155 0.711178 +vt 0.718851 0.717725 +vt 0.763232 0.827184 +vt 0.767474 0.837667 +vt 0.779325 0.835265 +vt 0.753212 0.799839 +vt 0.758294 0.814508 +vt 0.683588 0.751217 +vt 0.658905 0.785523 +vt 0.671987 0.788046 +vt 0.669398 0.798853 +vt 0.770171 0.848260 +vt 0.779396 0.848260 +vt 0.737140 0.805935 +vt 0.745139 0.819551 +vt 0.691125 0.756638 +vt 0.696225 0.747399 +vt 0.671483 0.841478 +vt 0.672536 0.832167 +vt 0.695283 0.790443 +vt 0.692294 0.778048 +vt 0.684106 0.807013 +vt 0.755272 0.840706 +vt 0.757876 0.848260 +vt 0.689617 0.767062 +vt 0.751837 0.830942 +vt 0.726011 0.777908 +vt 0.724135 0.790230 +vt 0.727747 0.767067 +vt 0.723221 0.747063 +vt 0.728335 0.757320 +vt 0.702554 0.734897 +vt 0.676496 0.818660 +vt 0.669902 0.848260 +vt 0.715282 0.734795 +vt 0.744649 0.834372 +vt 0.747224 0.843692 +vt 0.678439 0.843499 +vt 0.679462 0.835501 +vt 0.740023 0.822211 +vt 0.676559 0.848260 +vt 0.718747 0.798862 +vt 0.731506 0.809276 +vt 0.681201 0.821956 +vt 0.749698 0.848260 +vt 0.689595 0.809913 +vt 0.701454 0.798968 +vt 0.731965 0.694501 +vt 0.685748 0.848259 +vt 0.686221 0.838135 +vt 0.741199 0.848260 +vt 0.688336 0.824075 +vt 0.697257 0.814380 +vt 0.734432 0.824734 +vt 0.739082 0.837215 +vt 0.710682 0.811176 +vt 0.725362 0.813361 +vt 0.794502 0.834892 +vt 0.769187 0.749663 +vt 0.775611 0.765710 +vt 0.794901 0.848257 +vt 0.640929 0.781632 +vt 0.666521 0.709568 +vt 0.636356 0.848259 +vt 0.205395 0.840356 +vt 0.165057 0.839231 +vt 0.168249 0.792680 +vt 0.206812 0.794023 +vt 0.214392 0.891615 +vt 0.161589 0.882055 +vt 0.241265 0.839077 +vt 0.247916 0.875817 +vt 0.243291 0.795273 +vt 0.050187 0.844482 +vt 0.081566 0.837294 +vt 0.084989 0.865972 +vt 0.061577 0.879960 +vt 0.047164 0.795723 +vt 0.080136 0.794155 +vt 0.030751 0.849572 +vt 0.011363 0.854676 +vt 0.008122 0.795077 +vt 0.027453 0.795879 +vt 0.044980 0.890795 +vt 0.027199 0.901816 +vt 0.050209 0.754404 +vt 0.083344 0.757041 +vt 0.057188 0.711303 +vt 0.086190 0.724548 +vt 0.031763 0.751718 +vt 0.009998 0.749349 +vt 0.013882 0.699460 +vt 0.035870 0.704195 +vt 0.280653 0.747292 +vt 0.249910 0.749310 +vt 0.259406 0.709407 +vt 0.282503 0.708944 +vt 0.277433 0.794536 +vt 0.300327 0.744987 +vt 0.298944 0.794473 +vt 0.300463 0.703752 +vt 0.275598 0.840835 +vt 0.272406 0.880931 +vt 0.297897 0.842557 +vt 0.296112 0.884965 +vt 0.215427 0.747718 +vt 0.173187 0.745804 +vt 0.181086 0.695152 +vt 0.230402 0.702057 +vt 0.124974 0.748995 +vt 0.121499 0.706399 +vt 0.122778 0.792952 +vt 0.121636 0.837433 +vt 0.114850 0.872809 +vt 0.211767 0.938667 +vt 0.151460 0.924131 +vt 0.206881 0.967319 +vt 0.202444 0.993810 +vt 0.133578 0.975415 +vt 0.143009 0.950086 +vt 0.284332 0.935822 +vt 0.254612 0.922405 +vt 0.097049 0.903456 +vt 0.083305 0.923173 +vt 0.068619 0.942013 +vt 0.194143 0.656045 +vt 0.184361 0.577417 +vt 0.247489 0.577466 +vt 0.266383 0.646033 +vt 0.095483 0.657314 +vt 0.069552 0.635446 +vt 0.023577 0.623156 +vt 0.289968 0.643994 +vt 0.071392 0.577421 +vt 0.119669 0.577423 +vt 0.120835 0.534998 +vt 0.185223 0.534962 +vt 0.282127 0.577464 +vt 0.284898 0.535025 +vt 0.299459 0.284656 +vt 0.269410 0.300468 +vt 0.267320 0.274905 +vt 0.294776 0.271386 +vt 0.306484 0.250312 +vt 0.293315 0.242924 +vt 0.245931 0.535039 +vt 0.071962 0.534946 +vt 0.275823 0.248153 +vt 0.301489 0.253434 +vt 0.307265 0.286217 +vt 0.293325 0.304171 +vt 0.208695 0.372787 +vt 0.194848 0.354981 +vt 0.207736 0.335642 +vt 0.238048 0.352770 +vt 0.289297 0.329143 +vt 0.284195 0.358809 +vt 0.249789 0.357798 +vt 0.260662 0.326638 +vt 0.291825 0.210419 +vt 0.282910 0.178142 +vt 0.240092 0.219225 +vt 0.207156 0.229503 +vt 0.203883 0.206876 +vt 0.237038 0.193441 +vt 0.284744 0.054246 +vt 0.283530 0.018181 +vt 0.253997 0.479174 +vt 0.252661 0.512749 +vt 0.215378 0.512749 +vt 0.215164 0.479218 +vt 0.212078 0.054277 +vt 0.209691 0.018239 +vt 0.247220 0.018239 +vt 0.250975 0.054268 +vt 0.285805 0.479156 +vt 0.285667 0.512634 +vt 0.285068 0.404567 +vt 0.285942 0.441555 +vt 0.255333 0.441555 +vt 0.252561 0.404567 +vt 0.211458 0.128944 +vt 0.214464 0.091875 +vt 0.254730 0.091874 +vt 0.251290 0.128949 +vt 0.214951 0.441555 +vt 0.213861 0.404572 +vt 0.284433 0.128947 +vt 0.285957 0.091875 +vt 0.249199 0.274905 +vt 0.212908 0.274933 +vt 0.211924 0.254886 +vt 0.247827 0.250786 +vt 0.210380 0.317703 +vt 0.243254 0.323720 +vt 0.634500 0.156150 +vt 0.634082 0.122612 +vt 0.654909 0.122612 +vt 0.655078 0.156147 +vt 0.620451 0.217712 +vt 0.631999 0.209717 +vt 0.631977 0.231864 +vt 0.985614 0.217712 +vt 0.973899 0.231864 +vt 0.973876 0.209717 +vt 0.255597 0.215743 +vt 0.247850 0.179997 +vt 0.028247 0.577410 +vt 0.025045 0.534903 +vt 0.674703 0.200706 +vt 0.671910 0.232049 +vt 0.931173 0.200706 +vt 0.933965 0.232049 +vt 0.697013 0.172839 +vt 0.708058 0.163092 +vt 0.908862 0.172839 +vt 0.897817 0.163092 +vt 0.673508 0.108499 +vt 0.673582 0.095822 +vt 0.691950 0.095821 +vt 0.691886 0.108499 +vt 0.677624 0.156136 +vt 0.673434 0.122612 +vt 0.691822 0.122612 +vt 0.697044 0.156121 +vt 0.971375 0.156150 +vt 0.971794 0.122612 +vt 0.984917 0.122612 +vt 0.985209 0.156148 +vt 0.928252 0.156136 +vt 0.932441 0.122612 +vt 0.951042 0.122612 +vt 0.950589 0.156147 +vt 0.970997 0.095822 +vt 0.968881 0.054984 +vt 0.984631 0.054984 +vt 0.984867 0.095820 +vt 0.971395 0.108499 +vt 0.984892 0.108499 +vt 0.932368 0.108499 +vt 0.932294 0.095822 +vt 0.950965 0.095821 +vt 0.634480 0.108499 +vt 0.634879 0.095822 +vt 0.654938 0.095821 +vt 0.654923 0.108499 +vt 0.654936 0.054984 +vt 0.654925 0.016269 +vt 0.670270 0.016269 +vt 0.670948 0.054984 +vt 0.934928 0.054984 +vt 0.950969 0.054984 +vt 0.636994 0.054984 +vt 0.690377 0.054983 +vt 0.620779 0.156148 +vt 0.908832 0.156121 +vt 0.621056 0.095820 +vt 0.621248 0.054984 +vt 0.913926 0.095821 +vt 0.915498 0.054983 +vt 0.689838 0.016269 +vt 0.621036 0.108499 +vt 0.913990 0.108499 +vt 0.914054 0.122612 +vt 0.621016 0.122612 +vt 0.935606 0.016269 +vt 0.950999 0.016269 +vt 0.621289 0.016268 +vt 0.637047 0.016268 +vt 0.176090 0.220682 +vt 0.145191 0.220694 +vt 0.145087 0.204123 +vt 0.175901 0.204123 +vt 0.176179 0.257611 +vt 0.145241 0.257656 +vt 0.145210 0.238484 +vt 0.176125 0.238395 +vt 0.176168 0.302520 +vt 0.145242 0.302415 +vt 0.145255 0.286054 +vt 0.176196 0.286099 +vt 0.145244 0.274996 +vt 0.176147 0.274965 +vt 0.213159 0.292296 +vt 0.249624 0.292358 +vt 0.190858 0.203868 +vt 0.204472 0.190753 +vt 0.059422 0.286044 +vt 0.031066 0.286124 +vt 0.031049 0.275075 +vt 0.059417 0.275048 +vt 0.059492 0.354952 +vt 0.031128 0.354952 +vt 0.031124 0.326827 +vt 0.059475 0.326819 +vt 0.059279 0.238666 +vt 0.030929 0.238598 +vt 0.030921 0.220705 +vt 0.059276 0.220716 +vt 0.031084 0.302521 +vt 0.059440 0.302276 +vt 0.176146 0.326829 +vt 0.145236 0.326824 +vt 0.175964 0.354952 +vt 0.145141 0.354952 +vt 0.936052 0.597770 +vt 0.923354 0.589708 +vt 0.924484 0.570357 +vt 0.936057 0.576206 +vt 0.936019 0.649366 +vt 0.913751 0.650767 +vt 0.916692 0.634633 +vt 0.936061 0.627368 +vt 0.915592 0.611553 +vt 0.935975 0.612170 +vt 0.797433 0.319246 +vt 0.796272 0.333957 +vt 0.827484 0.332708 +vt 0.818957 0.316206 +vt 0.059362 0.257746 +vt 0.031009 0.257741 +vt 0.030934 0.204124 +vt 0.059305 0.204124 +vt 0.118260 0.275008 +vt 0.093911 0.275019 +vt 0.093876 0.257696 +vt 0.118252 0.257676 +vt 0.118222 0.220700 +vt 0.093831 0.220705 +vt 0.093754 0.204124 +vt 0.118173 0.204123 +vt 0.093831 0.238570 +vt 0.118261 0.302386 +vt 0.093919 0.302358 +vt 0.093909 0.286048 +vt 0.118265 0.286051 +vt 0.118262 0.326824 +vt 0.093936 0.326823 +vt 0.118215 0.354952 +vt 0.093852 0.354952 +vt 0.208452 0.175985 +vt 0.212772 0.376778 +vt 0.885489 0.613407 +vt 0.886139 0.592404 +vt 0.775283 0.328531 +vt 0.777696 0.360523 +vt 0.798255 0.363832 +vt 0.879743 0.573056 +vt 0.891403 0.648951 +vt 0.891428 0.633182 +vt 0.782396 0.317514 +vt 0.936077 0.668483 +vt 0.917897 0.663357 +vt 0.934937 0.562431 +vt 0.948678 0.563037 +vt 0.849446 0.644672 +vt 0.835215 0.641481 +vt 0.836574 0.633887 +vt 0.850848 0.634574 +vt 0.831637 0.625377 +vt 0.845604 0.622687 +vt 0.803215 0.409166 +vt 0.803234 0.427265 +vt 0.826158 0.420164 +vt 0.827672 0.401768 +vt 0.838730 0.600779 +vt 0.825771 0.609744 +vt 0.818842 0.606128 +vt 0.832383 0.595050 +vt 0.891712 0.662885 +vt 0.868635 0.564528 +vt 0.871852 0.553715 +vt 0.888276 0.556840 +vt 0.827416 0.356136 +vt 0.824304 0.626881 +vt 0.812578 0.624567 +vt 0.828470 0.646582 +vt 0.830902 0.615677 +vt 0.844827 0.609883 +vt 0.785826 0.405163 +vt 0.786898 0.423198 +vt 0.844902 0.653006 +vt 0.876523 0.661158 +vt 0.861333 0.659431 +vt 0.863677 0.647862 +vt 0.877540 0.648407 +vt 0.872530 0.616702 +vt 0.859570 0.619998 +vt 0.858753 0.604088 +vt 0.872446 0.598246 +vt 0.781225 0.373826 +vt 0.784753 0.387128 +vt 0.803196 0.391068 +vt 0.800726 0.377450 +vt 0.851688 0.591814 +vt 0.865716 0.582435 +vt 0.845924 0.583972 +vt 0.857280 0.574250 +vt 0.829185 0.383372 +vt 0.828300 0.369754 +vt 0.878275 0.634222 +vt 0.865123 0.635262 +vt 0.914893 0.555304 +vt 0.906852 0.540600 +vt 0.915395 0.533196 +vt 0.924568 0.548786 +vt 0.761358 0.338190 +vt 0.766667 0.356086 +vt 0.749140 0.351639 +vt 0.737870 0.373475 +vt 0.748724 0.380794 +vt 0.764617 0.362075 +vt 0.885620 0.549316 +vt 0.871635 0.545787 +vt 0.894491 0.523813 +vt 0.887040 0.527237 +vt 0.881647 0.520255 +vt 0.897126 0.516070 +vt 0.968828 0.016268 +vt 0.984580 0.016268 +vt 0.916038 0.016269 +vt 0.934523 0.917621 +vt 0.931424 0.935204 +vt 0.938408 0.927193 +vt 0.941572 0.917780 +vt 0.930002 0.891877 +vt 0.937875 0.903075 +vt 0.864084 0.887068 +vt 0.863938 0.917771 +vt 0.880234 0.917771 +vt 0.879260 0.892026 +vt 0.867026 0.945729 +vt 0.881621 0.944002 +vt 0.831347 0.917772 +vt 0.836681 0.941421 +vt 0.852052 0.944907 +vt 0.847642 0.917771 +vt 0.834066 0.892248 +vt 0.849018 0.887068 +vt 0.904024 0.888613 +vt 0.906398 0.917771 +vt 0.916266 0.917771 +vt 0.913129 0.887745 +vt 0.905572 0.938997 +vt 0.914714 0.939860 +vt 0.819931 0.904999 +vt 0.818111 0.917687 +vt 0.821392 0.930376 +vt 0.896042 0.940231 +vt 0.896530 0.917771 +vt 0.894944 0.890609 +vt 0.686042 0.524352 +vt 0.708647 0.518689 +vt 0.709177 0.537312 +vt 0.692687 0.540948 +vt 0.636372 0.667162 +vt 0.635921 0.656300 +vt 0.651714 0.656493 +vt 0.651227 0.666984 +vt 0.781285 0.609428 +vt 0.785249 0.620097 +vt 0.765233 0.626167 +vt 0.761520 0.615688 +vt 0.644711 0.596297 +vt 0.648718 0.581418 +vt 0.667739 0.587337 +vt 0.663002 0.601458 +vt 0.655822 0.561957 +vt 0.674036 0.573634 +vt 0.636733 0.638857 +vt 0.638119 0.622878 +vt 0.655630 0.626375 +vt 0.652694 0.640638 +vt 0.751631 0.535644 +vt 0.762210 0.560416 +vt 0.744045 0.569271 +vt 0.736483 0.548184 +vt 0.787716 0.631988 +vt 0.770153 0.638555 +vt 0.791176 0.645197 +vt 0.775239 0.650769 +vt 0.756154 0.602668 +vt 0.747050 0.618300 +vt 0.741245 0.605142 +vt 0.750033 0.585655 +vt 0.738203 0.591970 +vt 0.733559 0.579024 +vt 0.728733 0.562733 +vt 0.683603 0.550467 +vt 0.699215 0.546547 +vt 0.690416 0.564106 +vt 0.678881 0.591921 +vt 0.676012 0.602550 +vt 0.666074 0.642176 +vt 0.663882 0.657641 +vt 0.651365 0.677015 +vt 0.662728 0.668313 +vt 0.662980 0.677015 +vt 0.726341 0.539931 +vt 0.719028 0.546474 +vt 0.779342 0.664126 +vt 0.767486 0.666511 +vt 0.763261 0.656022 +vt 0.758344 0.643339 +vt 0.753283 0.628664 +vt 0.683726 0.579931 +vt 0.658998 0.614197 +vt 0.672082 0.616741 +vt 0.669471 0.627536 +vt 0.779389 0.677016 +vt 0.770165 0.677015 +vt 0.745182 0.648362 +vt 0.737201 0.634733 +vt 0.696399 0.576131 +vt 0.691285 0.585364 +vt 0.672552 0.660852 +vt 0.671485 0.670160 +vt 0.692397 0.606771 +vt 0.695369 0.619169 +vt 0.684166 0.635721 +vt 0.757870 0.677015 +vt 0.755280 0.669527 +vt 0.689760 0.595785 +vt 0.751861 0.659762 +vt 0.724212 0.618997 +vt 0.726110 0.606671 +vt 0.727889 0.595831 +vt 0.728493 0.586086 +vt 0.723396 0.575823 +vt 0.702738 0.563637 +vt 0.676524 0.647357 +vt 0.669891 0.677015 +vt 0.715467 0.563548 +vt 0.747228 0.672502 +vt 0.744669 0.663180 +vt 0.679473 0.664199 +vt 0.678437 0.672191 +vt 0.740064 0.651011 +vt 0.676547 0.677015 +vt 0.731566 0.638069 +vt 0.718813 0.627622 +vt 0.681227 0.650664 +vt 0.749692 0.677015 +vt 0.689654 0.638630 +vt 0.701529 0.627703 +vt 0.732176 0.523263 +vt 0.685735 0.677015 +vt 0.686228 0.666838 +vt 0.741198 0.677015 +vt 0.688358 0.652787 +vt 0.697308 0.643104 +vt 0.734468 0.653528 +vt 0.739084 0.666015 +vt 0.710741 0.639927 +vt 0.725417 0.642145 +vt 0.794526 0.663780 +vt 0.769330 0.578484 +vt 0.775733 0.594543 +vt 0.794904 0.677014 +vt 0.641034 0.610282 +vt 0.666728 0.538248 +vt 0.636356 0.677015 +vn 0.9457 0.1443 0.2913 +vn 0.9564 -0.0041 0.2922 +vn 0.9998 -0.0209 -0.0009 +vn 0.9824 0.1864 0.0134 +vn 0.7379 0.6737 0.0405 +vn 0.7078 0.6423 0.2941 +vn 0.6460 0.4611 0.6084 +vn 0.7695 0.1073 0.6296 +vn 0.7886 0.0331 0.6140 +vn 0.3103 0.2935 -0.9042 +vn 0.3025 0.7212 -0.6232 +vn 0.6054 0.6169 -0.5030 +vn 0.7379 0.2250 -0.6362 +vn 0.7562 -0.0103 -0.6543 +vn 0.3308 0.0001 -0.9437 +vn 0.1084 0.3109 -0.9442 +vn 0.0989 0.0136 -0.9950 +vn -0.0000 0.0197 -0.9998 +vn -0.0000 0.3126 -0.9499 +vn -0.0000 0.7558 -0.6548 +vn 0.1472 0.7442 -0.6515 +vn 0.3550 -0.2096 -0.9110 +vn 0.7477 -0.1850 -0.6378 +vn 0.6791 -0.4538 -0.5770 +vn 0.3752 -0.5647 -0.7350 +vn 0.1368 -0.2014 -0.9699 +vn 0.1695 -0.6011 -0.7810 +vn 0.0000 -0.6130 -0.7901 +vn -0.0000 -0.2004 -0.9797 +vn 0.4474 -0.0538 0.8927 +vn 0.4742 -0.5231 0.7082 +vn 0.7731 -0.4655 0.4308 +vn 0.8083 -0.0705 0.5845 +vn 0.4476 0.0625 0.8920 +vn 0.1322 -0.0587 0.9895 +vn 0.1444 0.0607 0.9877 +vn -0.0000 0.0525 0.9986 +vn 0.0000 -0.0698 0.9976 +vn 0.0000 -0.6245 0.7810 +vn 0.2144 -0.6358 0.7415 +vn 0.4047 0.1590 0.9005 +vn 0.3492 0.5807 0.7354 +vn 0.1784 0.2024 0.9629 +vn 0.2000 0.6209 0.7580 +vn 0.0000 0.6376 0.7704 +vn -0.0000 0.1969 0.9804 +vn 0.9553 -0.1362 0.2625 +vn 0.8333 -0.5293 0.1596 +vn 0.8217 -0.5659 -0.0678 +vn 0.9850 -0.1721 -0.0131 +vn 0.9458 -0.1792 -0.2708 +vn 0.7735 -0.5442 -0.3250 +vn 0.9657 -0.0170 -0.2589 +vn 0.9520 0.1879 -0.2416 +vn 0.7174 0.6660 -0.2046 +vn 0.2950 0.9058 0.3042 +vn 0.3086 0.9496 0.0553 +vn 0.1702 0.9347 0.3120 +vn 0.1370 0.9891 0.0545 +vn 0.0000 0.9989 0.0475 +vn 0.0000 0.9489 0.3155 +vn 0.2964 0.9341 -0.1988 +vn 0.1395 0.9681 -0.2083 +vn 0.0000 0.9774 -0.2113 +vn 0.5914 -0.8002 -0.0998 +vn 0.4555 -0.8719 0.1795 +vn 0.6394 -0.6842 0.3507 +vn 0.8795 -0.4694 -0.0788 +vn 0.4438 -0.7827 -0.4363 +vn 0.1549 -0.8154 -0.5578 +vn 0.0000 -0.8224 -0.5689 +vn 0.2065 -0.9492 0.2376 +vn -0.0000 -0.9727 0.2319 +vn 0.6646 -0.5276 -0.5291 +vn 0.2417 -0.5411 -0.8054 +vn 0.7131 0.6934 0.1032 +vn 0.5830 0.4427 -0.6813 +vn 0.3650 -0.6772 0.6388 +vn -0.0000 -0.7727 0.6348 +vn 0.0000 0.2392 0.9710 +vn 0.3422 0.2291 0.9113 +vn 0.2187 0.9685 0.1193 +vn 0.2776 0.7794 -0.5617 +vn 0.0000 0.4232 0.9060 +vn 0.2215 0.4915 0.8423 +vn 0.5299 0.4783 0.7003 +vn 0.3187 0.1528 -0.9355 +vn 0.2344 0.7167 0.6568 +vn 0.2099 0.4105 -0.8874 +vn 0.3673 -0.9301 0.0098 +vn 0.3974 -0.5924 -0.7008 +vn 0.1794 -0.6195 -0.7642 +vn 0.0690 -0.9969 -0.0385 +vn 0.1877 0.1073 -0.9763 +vn 0.2476 0.0854 -0.9651 +vn 0.4933 -0.2459 -0.8344 +vn 0.2022 -0.1020 -0.9740 +vn 0.2329 0.2954 0.9266 +vn 0.0000 0.3022 0.9532 +vn -0.0000 0.1792 0.9838 +vn 0.2403 0.1796 0.9539 +vn 0.2128 0.2478 0.9452 +vn 0.4914 -0.2255 0.8412 +vn 0.1337 -0.5254 0.8403 +vn 0.1148 0.2277 0.9669 +vn 0.2362 0.0566 0.9700 +vn 0.0000 0.0526 0.9986 +vn -0.0009 -0.0926 0.9957 +vn 0.2385 -0.0982 0.9662 +vn 0.7220 0.1360 -0.6784 +vn 0.9918 0.1212 0.0408 +vn 0.9923 0.0130 0.1231 +vn 0.7610 0.0535 -0.6465 +vn 0.6859 0.0936 0.7216 +vn 0.6979 -0.1956 0.6890 +vn 0.2849 0.1291 -0.9498 +vn 0.2636 0.0932 -0.9601 +vn 0.2253 -0.1212 -0.9667 +vn 0.6874 -0.1083 -0.7181 +vn 0.7076 0.0146 -0.7065 +vn 0.2536 0.0037 -0.9673 +vn 0.9995 -0.0294 0.0078 +vn 0.6908 0.0535 0.7211 +vn 0.6725 0.0801 0.7358 +vn 0.9981 0.0555 0.0252 +vn 0.2430 0.0914 0.9657 +vn -0.0000 0.0953 0.9955 +vn 0.0000 0.0740 0.9973 +vn 0.2426 0.0741 0.9673 +vn 0.2022 0.9739 0.1031 +vn 0.2013 0.6974 0.6878 +vn 0.1541 0.6819 0.7150 +vn 0.1655 0.9817 0.0947 +vn 0.3004 0.0419 -0.9529 +vn 0.1688 0.0258 -0.9853 +vn 0.4500 -0.1523 0.8799 +vn -0.4454 -0.1944 0.8740 +vn -0.3460 -0.2779 0.8962 +vn 0.3766 -0.1964 0.9053 +vn 0.5997 -0.3336 0.7274 +vn 0.8694 -0.0087 -0.4940 +vn 0.0000 0.3057 -0.9521 +vn 0.0000 0.1113 -0.9938 +vn 0.2453 0.2787 0.9285 +vn 0.0000 -0.1176 -0.9931 +vn 0.0000 0.0149 -0.9999 +vn -0.0000 0.1493 -0.9888 +vn 0.0000 0.0659 -0.9978 +vn 0.6091 0.0343 0.7924 +vn 0.0000 -0.0920 -0.9958 +vn 0.0000 0.1404 -0.9901 +vn 0.0000 -0.4846 -0.8747 +vn 0.1067 -0.4160 0.9031 +vn 0.3116 -0.0248 -0.9499 +vn -0.0013 -0.6103 0.7922 +vn 0.0003 -0.9575 0.2883 +vn -0.0006 -0.9977 -0.0685 +vn -0.5755 -0.7952 -0.1911 +vn -0.5898 -0.6462 0.4843 +vn -0.0011 -0.1368 -0.9906 +vn -0.1764 -0.3704 -0.9120 +vn -0.0020 -0.7436 -0.6687 +vn -0.9340 -0.1822 0.3072 +vn -0.9184 0.0606 -0.3909 +vn -0.9107 0.0462 -0.4104 +vn -0.9365 -0.1814 0.3002 +vn -0.9426 -0.1215 0.3112 +vn -0.9450 -0.1377 -0.2966 +vn -0.9243 -0.0652 -0.3762 +vn -0.9228 -0.2105 0.3226 +vn 0.8756 0.0396 -0.4815 +vn 0.9476 -0.0151 0.3190 +vn 0.9181 -0.0664 0.3906 +vn 0.9077 0.0723 -0.4133 +vn -0.4433 -0.1404 -0.8853 +vn 0.3698 -0.0259 -0.9287 +vn 0.3708 0.1432 -0.9176 +vn -0.4292 0.0769 -0.8999 +vn 0.8919 0.1157 -0.4372 +vn 0.9256 -0.1284 0.3562 +vn 0.9305 -0.2256 0.2887 +vn 0.8784 -0.1012 -0.4671 +vn 0.8901 0.1775 -0.4199 +vn 0.9257 -0.0826 0.3690 +vn -0.3939 0.2181 -0.8929 +vn -0.4115 0.2799 -0.8674 +vn 0.3324 0.2377 -0.9127 +vn 0.3702 -0.2797 0.8858 +vn -0.3684 -0.3290 0.8695 +vn -0.3734 -0.3396 0.8633 +vn 0.3699 -0.3096 0.8760 +vn -0.3218 -0.2828 0.9036 +vn -0.9240 -0.1780 0.3384 +vn -0.9034 -0.0051 0.4289 +vn -0.1555 0.0783 0.9847 +vn 0.2807 -0.0015 -0.9598 +vn -0.4512 0.0172 -0.8923 +vn 0.4510 -0.2961 0.8420 +vn -0.9203 -0.0430 -0.3889 +vn -0.9785 0.0388 -0.2025 +vn 0.1337 0.2725 -0.9528 +vn -0.6002 0.0760 -0.7962 +vn 0.6684 0.1792 0.7219 +vn 0.9807 0.1591 0.1132 +vn 0.0231 -0.5921 0.8055 +vn -0.0441 -0.9976 -0.0530 +vn -0.0785 -0.9958 -0.0464 +vn -0.0514 -0.6426 0.7645 +vn 0.1031 0.6834 0.7227 +vn 0.0614 0.1922 0.9794 +vn -0.0142 0.1514 0.9884 +vn 0.0418 0.7022 0.7108 +vn 0.0286 0.0423 -0.9987 +vn 0.1078 0.7277 -0.6773 +vn 0.0901 0.7629 -0.6402 +vn 0.0343 0.0455 -0.9984 +vn 0.1349 0.9851 0.1063 +vn 0.0795 0.9895 0.1207 +vn 0.2886 0.7054 -0.6474 +vn 0.2213 0.7031 -0.6758 +vn 0.1543 0.8126 -0.5621 +vn 0.1374 0.9816 0.1329 +vn 0.3013 0.9452 0.1258 +vn 0.1981 0.8835 -0.4245 +vn 0.0229 -0.9997 -0.0021 +vn 0.0623 -0.6655 -0.7438 +vn 0.0341 -0.7440 -0.6674 +vn 0.1430 -0.9897 0.0080 +vn 0.0423 0.1045 0.9936 +vn 0.0253 -0.6320 0.7746 +vn 0.0240 -0.7308 0.6822 +vn -0.3127 0.2099 0.9264 +vn 0.0965 0.0398 -0.9945 +vn -0.1350 0.1050 -0.9853 +vn -0.0256 -0.6368 -0.7706 +vn -0.0322 -0.6542 -0.7556 +vn 0.1349 0.8453 0.5169 +vn -0.4932 0.4930 0.7168 +vn -0.0139 0.8416 0.5400 +vn 0.0750 0.8493 -0.5225 +vn -0.1172 0.0807 -0.9898 +vn 0.2518 0.9644 0.0807 +vn -0.1514 -0.7066 -0.6913 +vn 0.0599 -0.9980 0.0190 +vn 0.1047 0.7466 0.6570 +vn 0.0280 0.9910 0.1306 +vn -0.0336 0.7148 0.6986 +vn 0.0289 0.7181 0.6953 +vn 0.0847 0.9874 0.1334 +vn -0.1332 -0.6247 0.7694 +vn -0.1064 -0.9942 -0.0166 +vn -0.0407 -0.9991 0.0079 +vn -0.0547 -0.6278 0.7764 +vn -0.0227 0.1091 0.9938 +vn 0.0379 0.0500 -0.9980 +vn 0.0584 0.7850 -0.6168 +vn 0.0999 0.7937 -0.6001 +vn 0.0656 0.0439 -0.9969 +vn -0.0380 -0.6635 -0.7472 +vn 0.0085 -0.6713 -0.7411 +vn 0.8732 -0.4872 0.0139 +vn 0.1845 0.8730 0.4514 +vn 0.2209 0.9735 0.0600 +vn -0.5726 -0.6425 0.5092 +vn -0.1516 -0.9884 -0.0104 +vn 0.1681 -0.8946 0.4139 +vn 0.3284 0.3520 0.8765 +vn 0.1938 0.8999 -0.3906 +vn 0.0779 0.1056 -0.9914 +vn 0.2088 0.0236 -0.9777 +vn 0.4326 0.8074 -0.4012 +vn 0.8096 0.4726 -0.3482 +vn 0.6046 -0.1712 -0.7779 +vn 0.4070 0.9114 0.0607 +vn 0.9199 0.3892 0.0477 +vn -0.3275 -0.9444 -0.0292 +vn -0.1998 -0.8212 -0.5345 +vn 0.2486 -0.8576 -0.4502 +vn 0.4146 -0.9085 0.0525 +vn 0.0541 0.2120 0.9758 +vn -0.2886 -0.7432 0.6036 +vn 0.1971 -0.7858 0.5863 +vn 0.5629 -0.0268 0.8261 +vn -0.0910 -0.8166 -0.5699 +vn 0.5147 0.8181 0.2567 +vn 0.2374 -0.8666 -0.4388 +vn 0.9324 -0.3612 0.0109 +vn 0.7483 0.4975 0.4388 +vn 0.3372 0.8276 0.4488 +vn -0.1555 -0.8122 -0.5622 +vn 0.0736 0.0760 -0.9944 +vn 0.1485 0.0722 -0.9863 +vn -0.1638 -0.8029 -0.5731 +vn 0.3115 0.9481 0.0636 +vn 0.3176 0.8353 0.4488 +vn 0.3268 0.8416 0.4299 +vn 0.3667 0.9284 0.0598 +vn -0.0652 -0.7833 0.6183 +vn -0.1876 -0.9821 -0.0192 +vn -0.2699 -0.9624 -0.0318 +vn -0.1672 -0.7777 0.6060 +vn 0.2008 0.1620 0.9661 +vn 0.1350 0.2102 0.9683 +vn 0.2863 0.8648 -0.4125 +vn 0.3527 0.8371 -0.4183 +vn -0.5104 0.6254 0.5902 +vn -0.7359 -0.6521 0.1822 +vn -0.5788 -0.7442 0.3334 +vn -0.4153 0.5623 0.7151 +vn 0.3722 -0.5937 -0.7135 +vn 0.7782 -0.6218 -0.0880 +vn 0.0267 -0.7229 0.6905 +vn 0.5714 0.7000 -0.4283 +vn 0.1233 0.3691 0.9212 +vn 0.8710 0.4712 0.1392 +vn 0.8376 0.2166 -0.5015 +vn -0.0000 -1.0000 0.0000 +vn 0.0084 -0.6750 -0.7378 +vn 0.3680 -0.6369 -0.6774 +vn 0.6015 -0.6121 -0.5133 +vn -0.6355 -0.6986 -0.3287 +vn -0.3370 -0.7295 -0.5952 +vn -0.7034 -0.7107 -0.0097 +vn -0.5972 -0.8019 0.0184 +vn 0.6442 -0.7370 -0.2048 +vn 0.6648 -0.7399 -0.1029 +vn 0.6664 -0.7454 0.0181 +vn 0.6517 -0.7303 0.2050 +vn -0.5592 -0.6963 0.4499 +vn -0.6826 -0.7042 0.1955 +vn -0.6484 -0.7443 0.1597 +vn -0.6932 -0.7206 0.0148 +vn 0.7022 -0.6799 -0.2114 +vn 0.6342 -0.7655 -0.1091 +vn -0.2498 -0.6440 0.7231 +vn 0.1061 -0.6663 0.7381 +vn 0.4440 -0.6813 0.5820 +vn 0.6185 -0.7625 -0.1899 +vn -0.6115 -0.7763 0.1532 +vn 0.6837 0.0752 0.7259 +vn 0.1525 0.1246 0.9804 +vn 0.4903 0.1374 -0.8606 +vn 0.7599 0.1599 -0.6301 +vn -0.9665 0.0230 0.2556 +vn -0.9782 0.0452 0.2028 +vn 0.9493 0.0983 -0.2986 +vn 0.9839 0.0914 -0.1536 +vn 0.9960 0.0812 0.0373 +vn 0.9159 0.1392 -0.3765 +vn 0.9780 0.0775 -0.1938 +vn -0.7453 0.1106 0.6575 +vn -0.9495 0.1270 0.2870 +vn -0.9970 0.0745 -0.0194 +vn -0.8740 0.0598 -0.4823 +vn -0.9951 0.0798 0.0585 +vn -0.8303 0.5511 0.0824 +vn -0.8523 0.3910 0.3476 +vn -0.9916 0.1283 0.0146 +vn -0.8484 0.5290 -0.0195 +vn -0.7014 0.4470 0.5552 +vn -0.8576 0.4754 0.1962 +vn 0.9409 0.0844 0.3281 +vn 0.8080 0.4997 0.3121 +vn 0.4611 0.4221 0.7805 +vn 0.8317 0.4977 -0.2460 +vn 0.8603 0.4813 -0.1678 +vn 0.7603 0.2592 -0.5956 +vn 0.8765 0.3184 -0.3611 +vn 0.0027 0.0640 -0.9979 +vn 0.0179 0.2134 -0.9768 +vn 0.5328 0.2307 -0.8142 +vn -0.3109 0.0989 0.9453 +vn -0.2355 0.3923 0.8892 +vn -0.9029 0.1928 -0.3842 +vn -0.5381 0.2055 -0.8174 +vn -0.5082 0.0300 -0.8607 +vn -0.9301 0.2315 0.2851 +vn -0.9798 0.1938 -0.0499 +vn 0.8834 0.4680 0.0259 +vn 0.9585 0.0708 -0.2762 +vn 0.8740 0.4463 -0.1921 +vn 0.9188 0.3598 -0.1622 +vn -0.8756 0.2043 0.4377 +vn -0.9977 0.0637 -0.0225 +vn 0.4477 0.8941 0.0123 +vn 0.4095 0.8844 0.2238 +vn 0.4740 0.2525 -0.8436 +vn 0.7825 0.3019 -0.5445 +vn 0.3908 0.8872 0.2453 +vn 0.4131 0.9101 -0.0329 +vn 0.7671 0.6409 -0.0280 +vn -0.5579 0.2025 -0.8048 +vn -0.0554 0.2166 -0.9747 +vn 0.4242 0.8999 -0.1010 +vn -0.9151 0.1009 -0.3904 +vn -0.3681 0.9119 0.1818 +vn -0.4525 0.6615 0.5981 +vn -0.3940 0.9187 -0.0283 +vn -0.4085 0.8532 0.3243 +vn -0.5208 0.8521 0.0525 +vn 0.2601 0.7859 0.5609 +vn 0.8501 0.4447 -0.2822 +vn -0.1194 0.7620 0.6365 +vn -0.8841 0.1773 -0.4324 +vn -0.4165 0.3095 -0.8548 +vn 0.3278 0.3994 -0.8562 +vn 0.6951 0.4915 -0.5247 +vn -0.9970 0.0755 -0.0137 +vn -0.1212 0.4521 -0.8837 +vn -0.1949 0.4563 0.8682 +vn -0.7707 0.2211 0.5976 +vn 0.8312 0.5333 -0.1575 +vn 0.6322 0.7536 0.1800 +vn 0.2893 0.7521 0.5922 +vn -0.9457 0.1443 0.2913 +vn -0.9824 0.1864 0.0134 +vn -0.9998 -0.0209 -0.0009 +vn -0.9564 -0.0041 0.2922 +vn -0.7078 0.6423 0.2941 +vn -0.7379 0.6737 0.0405 +vn -0.7695 0.1073 0.6296 +vn -0.6460 0.4611 0.6084 +vn -0.7886 0.0331 0.6140 +vn -0.3103 0.2935 -0.9042 +vn -0.7379 0.2250 -0.6362 +vn -0.6054 0.6169 -0.5030 +vn -0.3025 0.7212 -0.6232 +vn -0.3308 0.0001 -0.9437 +vn -0.7562 -0.0103 -0.6543 +vn -0.1084 0.3109 -0.9442 +vn -0.0989 0.0136 -0.9950 +vn -0.1472 0.7442 -0.6515 +vn -0.3550 -0.2096 -0.9110 +vn -0.7477 -0.1850 -0.6378 +vn -0.3752 -0.5647 -0.7350 +vn -0.6791 -0.4538 -0.5770 +vn -0.1368 -0.2014 -0.9699 +vn -0.1695 -0.6011 -0.7810 +vn -0.4474 -0.0538 0.8927 +vn -0.8083 -0.0705 0.5845 +vn -0.7731 -0.4655 0.4308 +vn -0.4742 -0.5231 0.7082 +vn -0.4476 0.0625 0.8920 +vn -0.1322 -0.0587 0.9895 +vn -0.1444 0.0607 0.9877 +vn -0.2144 -0.6358 0.7415 +vn -0.4047 0.1590 0.9005 +vn -0.3492 0.5807 0.7354 +vn -0.1784 0.2024 0.9629 +vn -0.2000 0.6209 0.7580 +vn -0.9553 -0.1362 0.2625 +vn -0.9850 -0.1721 -0.0131 +vn -0.8217 -0.5659 -0.0678 +vn -0.8333 -0.5293 0.1596 +vn -0.9458 -0.1792 -0.2708 +vn -0.7735 -0.5442 -0.3250 +vn -0.9657 -0.0170 -0.2589 +vn -0.9520 0.1879 -0.2416 +vn -0.7174 0.6660 -0.2046 +vn -0.2950 0.9058 0.3042 +vn -0.3086 0.9496 0.0553 +vn -0.1702 0.9347 0.3120 +vn -0.1370 0.9891 0.0545 +vn -0.2964 0.9341 -0.1988 +vn -0.1395 0.9681 -0.2083 +vn -0.5914 -0.8002 -0.0998 +vn -0.8795 -0.4694 -0.0788 +vn -0.6394 -0.6842 0.3507 +vn -0.4555 -0.8719 0.1795 +vn -0.4438 -0.7827 -0.4363 +vn -0.1549 -0.8154 -0.5578 +vn -0.2065 -0.9492 0.2376 +vn -0.2417 -0.5411 -0.8054 +vn -0.6646 -0.5276 -0.5291 +vn -0.5830 0.4427 -0.6813 +vn -0.7131 0.6934 0.1032 +vn -0.3650 -0.6772 0.6388 +vn -0.3422 0.2291 0.9113 +vn -0.2776 0.7794 -0.5617 +vn -0.2187 0.9685 0.1193 +vn -0.2215 0.4915 0.8423 +vn -0.5299 0.4783 0.7003 +vn -0.3187 0.1528 -0.9355 +vn -0.2344 0.7167 0.6568 +vn -0.2099 0.4105 -0.8874 +vn -0.3673 -0.9301 0.0098 +vn -0.0690 -0.9969 -0.0385 +vn -0.1794 -0.6195 -0.7642 +vn -0.3974 -0.5924 -0.7008 +vn -0.1877 0.1073 -0.9763 +vn -0.2022 -0.1020 -0.9740 +vn -0.4933 -0.2459 -0.8344 +vn -0.2476 0.0854 -0.9651 +vn -0.2329 0.2954 0.9266 +vn -0.2403 0.1796 0.9539 +vn -0.2128 0.2478 0.9452 +vn -0.1148 0.2277 0.9669 +vn -0.1337 -0.5254 0.8403 +vn -0.4914 -0.2255 0.8412 +vn -0.2364 0.0565 0.9700 +vn -0.2399 -0.1022 0.9654 +vn -0.7225 0.1357 -0.6780 +vn -0.7618 0.0546 -0.6455 +vn -0.9917 0.0127 0.1276 +vn -0.9918 0.1202 0.0423 +vn -0.6966 -0.1992 0.6893 +vn -0.6855 0.0928 0.7222 +vn -0.2849 0.1291 -0.9498 +vn -0.2631 0.0936 -0.9602 +vn -0.2253 -0.1212 -0.9667 +vn -0.2536 0.0037 -0.9673 +vn -0.7077 0.0144 -0.7064 +vn -0.6874 -0.1083 -0.7181 +vn -0.9995 -0.0294 0.0078 +vn -0.9982 0.0549 0.0255 +vn -0.6726 0.0797 0.7357 +vn -0.6908 0.0535 0.7211 +vn -0.2430 0.0914 0.9657 +vn -0.2426 0.0740 0.9673 +vn -0.2022 0.9739 0.1031 +vn -0.1655 0.9817 0.0947 +vn -0.1541 0.6819 0.7150 +vn -0.2013 0.6974 0.6878 +vn -0.1688 0.0258 -0.9853 +vn -0.3004 0.0419 -0.9529 +vn -0.4369 -0.1528 0.8864 +vn -0.3610 -0.1963 0.9117 +vn 0.3613 -0.2783 0.8900 +vn 0.4588 -0.1943 0.8670 +vn -0.5930 -0.3361 0.7317 +vn -0.8740 -0.0068 -0.4859 +vn -0.2453 0.2787 0.9285 +vn -0.6091 0.0343 0.7924 +vn -0.1059 -0.4199 0.9014 +vn -0.3165 -0.0232 -0.9483 +vn 0.5913 -0.6474 0.4808 +vn 0.5748 -0.7942 -0.1971 +vn 0.1734 -0.3703 -0.9126 +vn 0.9391 -0.1828 0.2909 +vn 0.9414 -0.1820 0.2838 +vn 0.9035 0.0456 -0.4262 +vn 0.9115 0.0601 -0.4068 +vn 0.9472 -0.1220 0.2966 +vn 0.9282 -0.2111 0.3065 +vn 0.9176 -0.0657 -0.3922 +vn 0.9397 -0.1373 -0.3132 +vn -0.8826 0.0408 -0.4683 +vn -0.9147 0.0729 -0.3974 +vn -0.9113 -0.0659 0.4065 +vn -0.9426 -0.0146 0.3336 +vn 0.4306 -0.1368 -0.8921 +vn 0.4136 0.0768 -0.9072 +vn -0.3866 0.1436 -0.9110 +vn -0.3825 -0.0232 -0.9236 +vn -0.8993 0.1163 -0.4216 +vn -0.8859 -0.1006 -0.4528 +vn -0.9258 -0.2249 0.3039 +vn -0.9193 -0.1278 0.3722 +vn -0.8971 0.1781 -0.4043 +vn -0.9193 -0.0821 0.3850 +vn 0.3966 0.2797 -0.8743 +vn 0.3785 0.2178 -0.8996 +vn -0.3480 0.2379 -0.9068 +vn -0.3550 -0.2796 0.8921 +vn -0.3548 -0.3094 0.8823 +vn 0.3881 -0.3399 0.8567 +vn 0.3832 -0.3294 0.8629 +vn 0.3361 -0.2834 0.8982 +vn 0.1673 0.0823 0.9825 +vn 0.9087 -0.0107 0.4173 +vn 0.9291 -0.1794 0.3233 +vn 0.4369 0.0163 -0.8994 +vn -0.2959 -0.0015 -0.9552 +vn -0.4374 -0.2958 0.8492 +vn 0.9138 -0.0443 -0.4037 +vn 0.9765 0.0369 -0.2121 +vn 0.5910 0.0741 -0.8033 +vn -0.1439 0.2747 -0.9507 +vn -0.9780 0.1679 0.1240 +vn -0.6588 0.1851 0.7292 +vn -0.0231 -0.5921 0.8055 +vn 0.0514 -0.6426 0.7645 +vn 0.0785 -0.9958 -0.0464 +vn 0.0441 -0.9976 -0.0530 +vn -0.1031 0.6834 0.7227 +vn -0.0417 0.7022 0.7107 +vn 0.0142 0.1514 0.9884 +vn -0.0614 0.1922 0.9794 +vn -0.0286 0.0423 -0.9987 +vn -0.0343 0.0455 -0.9984 +vn -0.0901 0.7629 -0.6402 +vn -0.1078 0.7277 -0.6773 +vn -0.0795 0.9895 0.1207 +vn -0.1349 0.9851 0.1063 +vn -0.2213 0.7031 -0.6758 +vn -0.2886 0.7054 -0.6474 +vn -0.1543 0.8126 -0.5621 +vn -0.1981 0.8835 -0.4245 +vn -0.3013 0.9452 0.1258 +vn -0.1374 0.9816 0.1329 +vn -0.0229 -0.9997 -0.0021 +vn -0.1430 -0.9897 0.0080 +vn -0.0341 -0.7440 -0.6674 +vn -0.0623 -0.6655 -0.7438 +vn -0.0423 0.1045 0.9936 +vn 0.3127 0.2099 0.9264 +vn -0.0240 -0.7308 0.6822 +vn -0.0253 -0.6320 0.7746 +vn 0.1350 0.1050 -0.9853 +vn -0.0965 0.0398 -0.9945 +vn 0.0256 -0.6368 -0.7706 +vn 0.0322 -0.6542 -0.7556 +vn -0.1349 0.8453 0.5169 +vn 0.0139 0.8416 0.5400 +vn 0.4932 0.4930 0.7168 +vn 0.1172 0.0807 -0.9898 +vn -0.0750 0.8493 -0.5225 +vn -0.2518 0.9644 0.0807 +vn -0.0599 -0.9980 0.0190 +vn 0.1514 -0.7066 -0.6913 +vn -0.1047 0.7466 0.6570 +vn -0.0280 0.9910 0.1306 +vn -0.0847 0.9874 0.1334 +vn -0.0289 0.7181 0.6953 +vn 0.0336 0.7148 0.6986 +vn 0.1332 -0.6247 0.7694 +vn 0.0547 -0.6278 0.7764 +vn 0.0407 -0.9991 0.0079 +vn 0.1064 -0.9942 -0.0166 +vn 0.0227 0.1091 0.9938 +vn -0.0379 0.0500 -0.9980 +vn -0.0656 0.0439 -0.9969 +vn -0.0999 0.7937 -0.6001 +vn -0.0584 0.7850 -0.6168 +vn 0.0380 -0.6635 -0.7472 +vn -0.0085 -0.6713 -0.7411 +vn -0.8732 -0.4872 0.0139 +vn -0.2209 0.9735 0.0600 +vn -0.1845 0.8730 0.4514 +vn 0.5726 -0.6425 0.5092 +vn -0.1681 -0.8946 0.4139 +vn 0.1516 -0.9884 -0.0104 +vn -0.3284 0.3520 0.8765 +vn -0.0779 0.1056 -0.9914 +vn -0.1938 0.8999 -0.3906 +vn -0.2088 0.0236 -0.9777 +vn -0.6045 -0.1712 -0.7779 +vn -0.8096 0.4726 -0.3482 +vn -0.4326 0.8074 -0.4012 +vn -0.9199 0.3892 0.0477 +vn -0.4070 0.9114 0.0607 +vn 0.3275 -0.9444 -0.0292 +vn -0.4146 -0.9085 0.0526 +vn -0.2486 -0.8576 -0.4502 +vn 0.1998 -0.8212 -0.5345 +vn -0.0541 0.2120 0.9758 +vn -0.5629 -0.0268 0.8261 +vn -0.1971 -0.7858 0.5863 +vn 0.2886 -0.7432 0.6036 +vn 0.0910 -0.8166 -0.5699 +vn -0.2374 -0.8666 -0.4388 +vn -0.5147 0.8181 0.2567 +vn -0.9324 -0.3612 0.0109 +vn -0.7483 0.4975 0.4388 +vn -0.3372 0.8276 0.4487 +vn 0.1555 -0.8122 -0.5622 +vn 0.1638 -0.8029 -0.5731 +vn -0.1485 0.0722 -0.9863 +vn -0.0736 0.0760 -0.9944 +vn -0.3115 0.9481 0.0636 +vn -0.3667 0.9284 0.0598 +vn -0.3268 0.8416 0.4299 +vn -0.3176 0.8353 0.4488 +vn 0.0652 -0.7833 0.6183 +vn 0.1672 -0.7777 0.6060 +vn 0.2699 -0.9624 -0.0318 +vn 0.1876 -0.9821 -0.0192 +vn -0.1350 0.2102 0.9683 +vn -0.2008 0.1620 0.9661 +vn -0.2863 0.8648 -0.4125 +vn -0.3527 0.8371 -0.4183 +vn 0.5104 0.6254 0.5902 +vn 0.4153 0.5623 0.7151 +vn 0.5788 -0.7442 0.3334 +vn 0.7359 -0.6521 0.1822 +vn -0.0267 -0.7229 0.6905 +vn -0.7782 -0.6218 -0.0880 +vn -0.3722 -0.5937 -0.7135 +vn -0.5714 0.7000 -0.4283 +vn -0.1233 0.3691 0.9212 +vn -0.8710 0.4712 0.1392 +vn -0.8425 0.2212 -0.4912 +vn -0.6016 -0.6121 -0.5133 +vn -0.3680 -0.6369 -0.6774 +vn -0.0084 -0.6750 -0.7378 +vn 0.6355 -0.6986 -0.3287 +vn 0.3370 -0.7295 -0.5952 +vn 0.7034 -0.7107 -0.0097 +vn 0.5971 -0.8019 0.0184 +vn -0.6648 -0.7399 -0.1029 +vn -0.6442 -0.7370 -0.2047 +vn -0.6517 -0.7302 0.2050 +vn -0.6664 -0.7454 0.0181 +vn 0.5592 -0.6963 0.4499 +vn 0.6826 -0.7042 0.1954 +vn 0.6484 -0.7443 0.1597 +vn 0.6931 -0.7206 0.0148 +vn -0.6342 -0.7655 -0.1091 +vn -0.7022 -0.6799 -0.2114 +vn 0.2498 -0.6440 0.7231 +vn -0.1061 -0.6663 0.7381 +vn -0.4440 -0.6813 0.5820 +vn -0.6185 -0.7625 -0.1899 +vn 0.6115 -0.7763 0.1532 +vn -0.1525 0.1246 0.9804 +vn -0.6837 0.0753 0.7259 +vn -0.7599 0.1599 -0.6301 +vn -0.4904 0.1374 -0.8606 +vn 0.9782 0.0451 0.2028 +vn 0.9665 0.0229 0.2556 +vn -0.9839 0.0914 -0.1535 +vn -0.9493 0.0983 -0.2986 +vn -0.9960 0.0812 0.0373 +vn -0.9780 0.0775 -0.1937 +vn -0.9159 0.1393 -0.3765 +vn 0.9495 0.1269 0.2870 +vn 0.7453 0.1105 0.6575 +vn 0.9970 0.0744 -0.0194 +vn 0.8740 0.0597 -0.4823 +vn 0.9951 0.0798 0.0585 +vn 0.8523 0.3909 0.3475 +vn 0.8304 0.5511 0.0824 +vn 0.9916 0.1283 0.0146 +vn 0.8484 0.5290 -0.0195 +vn 0.8577 0.4753 0.1961 +vn 0.7014 0.4469 0.5552 +vn -0.9409 0.0844 0.3281 +vn -0.4611 0.4221 0.7805 +vn -0.8080 0.4997 0.3121 +vn -0.8603 0.4813 -0.1678 +vn -0.8317 0.4977 -0.2460 +vn -0.8765 0.3184 -0.3610 +vn -0.7604 0.2592 -0.5955 +vn -0.0027 0.0640 -0.9979 +vn -0.5328 0.2307 -0.8142 +vn -0.0179 0.2134 -0.9768 +vn 0.3109 0.0989 0.9453 +vn 0.2355 0.3923 0.8892 +vn 0.5083 0.0300 -0.8607 +vn 0.5382 0.2055 -0.8174 +vn 0.9029 0.1928 -0.3841 +vn 0.9798 0.1938 -0.0499 +vn 0.9302 0.2314 0.2851 +vn -0.8834 0.4680 0.0259 +vn -0.9585 0.0708 -0.2762 +vn -0.8740 0.4463 -0.1920 +vn -0.9188 0.3598 -0.1622 +vn 0.9977 0.0636 -0.0225 +vn 0.8756 0.2043 0.4376 +vn -0.4095 0.8845 0.2238 +vn -0.4477 0.8941 0.0123 +vn -0.7826 0.3019 -0.5445 +vn -0.4740 0.2525 -0.8436 +vn -0.4131 0.9101 -0.0329 +vn -0.3908 0.8872 0.2454 +vn -0.7671 0.6409 -0.0280 +vn 0.0554 0.2166 -0.9747 +vn 0.5579 0.2025 -0.8048 +vn -0.4242 0.8999 -0.1010 +vn 0.9151 0.1009 -0.3904 +vn 0.4525 0.6614 0.5981 +vn 0.3681 0.9118 0.1818 +vn 0.3940 0.9187 -0.0283 +vn 0.5208 0.8521 0.0525 +vn 0.4086 0.8532 0.3243 +vn -0.2601 0.7859 0.5609 +vn -0.8501 0.4447 -0.2822 +vn 0.1194 0.7620 0.6365 +vn 0.4148 0.3089 -0.8559 +vn 0.8842 0.1771 -0.4323 +vn -0.6931 0.4946 -0.5244 +vn -0.3279 0.4006 -0.8556 +vn 0.9973 0.0714 -0.0155 +vn 0.1210 0.4544 -0.8825 +vn 0.7698 0.2210 0.5987 +vn 0.1922 0.4608 0.8664 +vn -0.8281 0.5387 -0.1555 +vn -0.6279 0.7573 0.1795 +vn -0.2868 0.7541 0.5909 +usemtl skin +s 1 +f 1/1/1 27/2/2 41/3/3 30/4/4 +f 1/1/1 30/4/4 40/5/5 16/6/6 +f 1/1/1 16/6/6 36/7/7 15/8/8 +f 1/1/1 15/8/8 39/9/9 27/2/2 +f 2/10/10 23/11/11 35/12/12 14/13/13 +f 2/10/10 14/13/13 38/14/14 25/15/15 +f 65/16/16 77/17/17 380/18/18 353/19/19 +f 65/16/16 353/19/19 378/20/20 75/21/21 +f 3/22/22 25/15/15 38/14/14 19/23/23 +f 3/22/22 19/23/23 33/24/24 18/25/25 +f 66/26/26 73/27/27 373/28/28 354/29/29 +f 66/26/26 354/29/29 380/18/18 77/17/17 +f 4/30/30 20/31/31 34/32/32 21/33/33 +f 4/30/30 21/33/33 39/9/9 26/34/34 +f 67/35/35 78/36/36 381/37/37 356/38/38 +f 67/35/35 356/38/38 375/39/39 74/40/40 +f 5/41/41 26/34/34 39/9/9 15/8/8 +f 5/41/41 15/8/8 36/7/7 24/42/42 +f 68/43/43 76/44/44 379/45/45 357/46/46 +f 68/43/43 357/46/46 381/37/37 78/36/36 +f 6/47/47 13/48/48 37/49/49 29/50/50 +f 6/47/47 29/50/50 41/3/3 27/2/2 +f 6/47/47 27/2/2 39/9/9 21/33/33 +f 6/47/47 21/33/33 34/32/32 13/48/48 +f 7/51/51 17/52/52 33/24/24 19/23/23 +f 7/51/51 19/23/23 38/14/14 28/53/53 +f 7/51/51 28/53/53 41/3/3 29/50/50 +f 7/51/51 29/50/50 37/49/49 17/52/52 +f 8/54/54 28/53/53 38/14/14 14/13/13 +f 8/54/54 14/13/13 35/12/12 22/55/55 +f 8/54/54 22/55/55 40/5/5 30/4/4 +f 8/54/54 30/4/4 41/3/3 28/53/53 +f 9/56/56 16/6/6 40/5/5 31/57/57 +f 69/58/58 79/59/59 383/60/60 362/61/61 +f 69/62/58 362/63/61 379/45/45 76/44/44 +f 9/64/56 24/42/42 36/7/7 16/6/6 +f 10/65/62 22/55/55 35/12/12 23/11/11 +f 70/66/63 75/21/21 378/20/20 363/67/64 +f 70/66/63 363/67/64 383/60/60 79/59/59 +f 10/65/62 31/57/57 40/5/5 22/55/55 +f 32/68/65 12/69/66 44/70/67 43/71/68 +f 11/72/69 18/25/25 33/24/24 17/52/52 +f 11/72/69 17/52/52 37/49/49 32/68/65 +f 71/73/70 366/74/71 373/28/28 73/27/27 +f 12/69/66 32/68/65 37/49/49 13/48/48 +f 12/69/66 13/48/48 34/32/32 20/31/31 +f 72/75/72 74/40/40 375/39/39 367/76/73 +f 71/73/70 11/72/69 42/77/74 80/78/75 +f 42/77/74 43/71/68 46/79/76 45/80/77 +f 81/81/78 384/82/79 389/83/80 83/84/81 +f 11/72/69 32/68/65 43/71/68 42/77/74 +f 72/75/72 367/76/73 384/82/79 81/81/78 +f 45/85/77 46/86/76 49/87/82 48/88/83 +f 83/89/81 389/90/80 394/91/84 85/92/85 +f 43/71/68 44/70/67 47/93/86 46/79/76 +f 80/78/75 42/77/74 45/80/77 82/94/87 +f 46/86/76 47/95/86 50/96/88 49/87/82 +f 82/97/87 45/85/77 48/88/83 84/98/89 +f 169/99/90 165/100/91 133/101/92 134/102/93 +f 93/103/94 61/104/95 51/105/96 86/106/97 +f 92/107/98 417/108/99 399/109/100 87/110/101 +f 168/111/102 167/112/103 135/113/104 136/114/105 +f 741/115/106 735/116/107 404/117/108 89/118/109 +f 739/119/110 736/120/111 55/121/112 54/122/113 +f 736/123/111 738/124/114 56/125/115 55/126/112 +f 740/127/116 739/119/110 54/122/113 88/128/117 +f 753/129/118 748/130/119 59/131/120 90/132/121 +f 750/133/122 747/134/123 57/135/124 58/136/125 +f 748/130/119 750/137/122 58/138/125 59/131/120 +f 752/139/126 749/140/127 409/141/128 91/142/129 +f 163/143/130 164/144/131 132/145/132 131/146/133 +f 85/92/85 394/91/84 417/108/99 92/107/98 +f 84/98/89 48/88/83 61/104/95 93/103/94 +f 165/100/91 166/147/134 138/148/135 133/101/92 +f 119/149/136 106/150/137 95/151/138 113/152/139 +f 55/153/112 56/154/115 111/155/140 +f 55/156/112 121/157/141 54/158/113 +f 395/159/142 84/98/89 93/103/94 416/160/143 +f 50/96/88 85/92/85 92/107/98 60/161/144 +f 747/134/123 752/139/126 91/142/129 57/135/124 +f 751/162/145 753/129/118 90/132/121 413/163/146 +f 737/164/147 740/127/116 88/128/117 405/165/148 +f 738/124/114 741/115/106 89/118/109 56/125/115 +f 60/161/144 92/107/98 87/110/101 53/166/149 +f 416/160/143 93/103/94 86/106/97 400/167/150 +f 390/168/151 82/97/87 84/98/89 395/159/142 +f 385/169/152 80/78/75 82/94/87 390/170/151 +f 47/95/86 83/89/81 85/92/85 50/96/88 +f 12/69/66 72/75/72 81/81/78 44/70/67 +f 44/70/67 81/81/78 83/84/81 47/93/86 +f 366/74/71 71/73/70 80/78/75 385/169/152 +f 12/69/66 20/31/31 74/40/40 72/75/72 +f 11/72/69 71/73/70 73/27/27 18/25/25 +f 10/65/62 70/66/63 79/59/59 31/57/57 +f 10/65/62 23/11/11 75/21/21 70/66/63 +f 9/64/56 69/62/58 76/44/44 24/42/42 +f 9/56/56 31/57/57 79/59/59 69/58/58 +f 5/41/41 68/43/43 78/36/36 26/34/34 +f 5/41/41 24/42/42 76/44/44 68/43/43 +f 4/30/30 67/35/35 74/40/40 20/31/31 +f 4/30/30 26/34/34 78/36/36 67/35/35 +f 3/22/22 66/26/26 77/17/17 25/15/15 +f 3/22/22 18/25/25 73/27/27 66/26/26 +f 2/10/10 65/16/16 75/21/21 23/11/11 +f 2/10/10 25/15/15 77/17/17 65/16/16 +f 62/171/153 56/154/115 89/172/109 +f 64/173/154 88/174/117 54/158/113 +f 404/175/108 451/176/155 62/171/153 89/172/109 +f 482/177/156 421/178/157 63/179/158 120/180/159 +f 405/181/148 88/174/117 64/173/154 452/182/160 +f 110/183/161 63/184/158 421/185/157 471/186/162 +f 797/187/163 791/188/164 98/189/165 124/190/166 +f 129/191/167 108/192/168 94/193/169 122/194/170 +f 128/195/171 107/196/172 97/197/173 123/198/174 +f 118/199/175 109/200/176 96/201/177 112/202/178 +f 125/203/179 101/204/180 105/205/181 127/206/182 +f 796/207/183 793/208/184 101/204/180 125/203/179 +f 114/209/185 795/210/186 100/211/187 +f 794/212/188 792/213/189 99/214/190 115/215/191 +f 103/216/192 126/217/193 216/218/194 327/219/195 +f 114/209/185 100/211/187 104/220/196 116/221/197 +f 115/215/191 99/214/190 103/216/192 117/222/198 +f 124/190/166 98/189/165 102/223/199 126/217/193 +f 110/183/161 64/173/154 109/200/176 118/199/175 +f 121/157/141 55/156/112 107/196/172 128/195/171 +f 120/180/159 63/179/158 108/192/168 129/191/167 +f 111/155/140 62/171/153 106/150/137 119/149/136 +f 55/153/112 111/155/140 119/149/136 107/224/172 +f 63/184/158 110/183/161 118/199/175 108/225/168 +f 101/226/180 115/215/191 117/222/198 105/227/181 +f 98/228/165 114/209/185 116/221/197 102/229/199 +f 126/217/193 102/223/199 220/230/200 216/218/194 +f 793/231/184 794/212/188 115/215/191 101/226/180 +f 791/232/164 795/210/186 114/209/185 98/228/165 +f 108/225/168 118/199/175 112/202/178 94/233/169 +f 64/173/154 110/183/161 471/186/162 452/182/160 +f 107/224/172 119/149/136 113/152/139 97/234/173 +f 116/221/197 104/220/196 221/235/201 218/236/202 +f 62/171/153 120/180/159 129/191/167 106/150/137 +f 64/173/154 121/157/141 128/195/171 109/200/176 +f 99/214/190 124/190/166 126/217/193 103/216/192 +f 105/227/181 117/222/198 217/237/203 219/238/204 +f 796/207/183 125/203/179 100/211/187 +f 100/211/187 125/203/179 127/206/182 104/220/196 +f 109/200/176 128/195/171 123/198/174 96/201/177 +f 106/150/137 129/191/167 122/194/170 95/151/138 +f 792/213/189 797/187/163 124/190/166 99/214/190 +f 451/176/155 482/177/156 120/180/159 62/171/153 +f 62/171/153 111/155/140 56/154/115 +f 64/173/154 54/158/113 121/157/141 +f 781/239/205 780/240/206 143/241/207 144/242/208 +f 779/243/209 775/244/210 145/245/211 141/246/212 +f 776/247/213 777/248/214 139/249/215 147/250/216 +f 777/248/214 778/251/217 140/252/218 139/249/215 +f 166/147/134 170/253/219 130/254/220 138/148/135 +f 164/144/131 168/111/102 136/114/105 132/145/132 +f 170/253/219 163/143/130 131/146/133 130/254/220 +f 167/112/103 169/255/90 134/256/93 135/113/104 +f 765/257/221 761/258/222 148/259/223 137/260/224 +f 764/261/225 763/262/226 150/263/227 151/264/228 +f 762/265/229 759/266/230 152/267/231 153/268/232 +f 763/262/226 760/269/233 155/270/234 150/263/227 +f 778/251/217 779/243/209 141/246/212 140/252/218 +f 782/271/235 776/247/213 147/250/216 142/272/236 +f 775/244/210 781/239/205 144/242/208 145/245/211 +f 780/273/206 782/271/235 142/272/236 143/274/207 +f 149/275/237 153/276/232 177/277/238 173/278/239 +f 155/279/234 137/280/224 171/281/240 179/282/241 +f 137/280/224 148/283/223 172/284/242 171/281/240 +f 151/285/228 150/286/227 174/287/243 175/288/244 +f 760/269/233 765/257/221 137/260/224 155/270/234 +f 766/289/245 762/265/229 153/268/232 149/290/237 +f 759/266/230 764/291/225 151/292/228 152/267/231 +f 761/258/222 766/289/245 149/290/237 148/259/223 +f 727/293/246 724/294/247 162/295/248 160/296/249 +f 725/297/250 722/298/251 159/299/252 156/300/253 +f 162/295/248 724/294/247 146/301/254 +f 726/302/255 723/303/256 161/304/257 158/305/258 +f 721/306/259 726/302/255 158/305/258 157/307/260 +f 725/297/250 156/300/253 146/301/254 +f 722/308/251 721/306/259 157/307/260 159/309/252 +f 723/303/256 727/293/246 160/296/249 161/304/257 +f 53/166/149 52/310/261 169/255/90 167/112/103 +f 48/88/83 49/87/82 163/143/130 170/253/219 +f 50/96/88 60/161/144 168/111/102 164/144/131 +f 61/104/95 48/88/83 170/253/219 166/147/134 +f 51/105/96 61/104/95 166/147/134 165/100/91 +f 49/87/82 50/96/88 164/144/131 163/143/130 +f 60/161/144 53/166/149 167/112/103 168/111/102 +f 52/311/261 51/105/96 165/100/91 169/99/90 +f 172/284/242 173/278/239 181/312/262 180/313/263 +f 176/314/264 175/288/244 183/315/265 184/316/266 +f 173/278/239 177/277/238 185/317/267 181/312/262 +f 179/282/241 171/281/240 154/318/268 187/319/269 +f 152/320/231 151/285/228 175/288/244 176/314/264 +f 148/283/223 149/275/237 173/278/239 172/284/242 +f 150/321/227 155/279/234 179/282/241 174/322/243 +f 153/276/232 152/323/231 176/324/264 177/277/238 +f 703/325/270 702/326/271 178/327/272 195/328/273 +f 702/326/271 699/329/274 188/330/275 178/327/272 +f 700/331/276 697/332/277 190/333/278 191/334/279 +f 701/335/280 698/336/281 192/337/282 193/338/283 +f 174/322/243 179/282/241 187/319/269 182/339/284 +f 184/340/266 185/317/267 205/341/285 206/342/286 +f 175/288/244 174/287/243 182/343/284 183/315/265 +f 171/281/240 172/284/242 180/313/263 154/318/268 +f 194/344/287 193/338/283 192/337/282 191/345/279 +f 195/328/273 194/344/287 191/345/279 190/346/278 +f 178/327/272 188/330/275 194/344/287 195/328/273 +f 188/330/275 189/347/288 193/338/283 194/344/287 +f 704/348/289 701/335/280 193/338/283 189/347/288 +f 698/349/281 700/331/276 191/334/279 192/350/282 +f 699/329/274 704/348/289 189/347/288 188/330/275 +f 697/351/277 703/325/270 195/328/273 190/346/278 +f 710/352/290 708/353/291 201/354/292 196/355/293 +f 712/356/294 709/357/295 202/358/296 199/359/297 +f 711/360/298 705/361/299 186/362/300 198/363/301 +f 709/357/295 706/364/302 197/365/303 202/358/296 +f 706/364/302 711/366/298 198/367/301 197/365/303 +f 705/361/299 710/368/290 196/369/293 186/362/300 +f 707/370/304 712/356/294 199/359/297 200/371/305 +f 708/353/291 707/370/304 200/371/305 201/354/292 +f 203/372/306 204/373/307 208/374/308 207/375/309 +f 176/314/264 184/316/266 206/376/286 204/377/307 +f 185/317/267 177/277/238 203/372/306 205/341/285 +f 177/277/238 176/324/264 204/373/307 203/372/306 +f 208/378/308 210/379/310 214/380/311 212/381/312 +f 204/377/307 206/376/286 210/379/310 208/378/308 +f 205/341/285 203/372/306 207/375/309 209/382/313 +f 206/342/286 205/341/285 209/382/313 210/383/310 +f 211/384/314 212/385/312 214/386/311 213/387/315 +f 209/382/313 207/375/309 211/384/314 213/387/315 +f 210/383/310 209/382/313 213/387/315 214/386/311 +f 207/375/309 208/374/308 212/385/312 211/384/314 +f 104/220/196 127/206/182 215/388/316 221/235/201 +f 127/206/182 105/205/181 219/389/204 215/388/316 +f 102/229/199 116/221/197 218/236/202 220/390/200 +f 117/222/198 103/216/192 327/219/195 217/237/203 +f 241/391/317 229/392/318 225/393/319 240/394/320 +f 242/395/321 224/396/322 229/392/318 241/391/317 +f 248/397/323 226/398/324 230/399/317 247/400/317 +f 247/400/317 230/399/317 228/401/325 246/402/326 +f 239/403/317 233/404/317 232/405/327 238/406/328 +f 237/407/329 231/408/330 233/404/317 239/403/317 +f 309/409/331 235/410/332 236/411/317 308/412/317 +f 308/412/317 236/411/317 234/413/333 307/414/334 +f 222/415/335 237/407/329 239/403/317 227/416/336 +f 227/416/336 239/403/317 238/406/328 223/417/337 +f 235/410/332 242/395/321 241/391/317 236/411/317 +f 236/411/317 241/391/317 240/394/320 234/413/333 +f 230/399/317 245/418/317 244/419/338 228/401/325 +f 226/398/324 243/420/339 245/418/317 230/399/317 +f 233/404/317 247/400/317 246/402/326 232/405/327 +f 231/408/330 248/397/323 247/400/317 233/404/317 +f 223/421/337 250/422/340 254/423/341 227/424/336 +f 225/425/319 252/426/342 263/427/343 240/428/320 +f 243/429/339 265/430/344 311/431/345 309/432/331 +f 228/433/325 255/434/346 267/435/347 246/436/326 +f 246/436/326 267/435/347 258/437/348 232/438/327 +f 234/439/333 259/440/349 310/441/350 307/442/334 +f 237/443/329 261/444/351 257/445/352 231/446/330 +f 240/428/320 263/427/343 259/440/349 234/439/333 +f 309/432/331 311/431/345 260/447/353 235/448/332 +f 235/448/332 260/447/353 264/449/354 242/450/321 +f 253/451/355 273/452/356 284/453/357 265/430/344 +f 268/454/358 287/455/359 273/452/356 253/451/355 +f 261/444/351 280/456/360 276/457/361 257/445/352 +f 262/458/362 281/459/363 270/460/364 250/422/340 +f 255/434/346 274/461/365 286/462/366 267/435/347 +f 263/427/343 282/463/367 278/464/368 259/440/349 +f 256/465/369 275/466/370 272/467/371 252/426/342 +f 249/468/372 269/469/373 280/456/360 261/444/351 +f 264/449/354 283/470/374 271/471/375 251/472/376 +f 257/445/352 276/457/361 287/455/359 268/454/358 +f 311/431/345 313/473/377 279/474/378 260/447/353 +f 258/437/348 277/475/379 281/459/363 262/458/362 +f 252/426/342 272/467/371 282/463/367 263/427/343 +f 266/476/380 285/477/381 274/461/365 255/434/346 +f 310/441/350 312/478/382 285/477/381 266/476/380 +f 251/472/376 271/471/375 275/479/370 256/480/369 +f 267/435/347 286/462/366 277/475/379 258/437/348 +f 260/447/353 279/474/378 283/470/374 264/449/354 +f 313/473/377 315/481/383 298/482/384 279/474/378 +f 277/475/379 296/483/385 300/484/386 281/459/363 +f 272/467/371 291/485/387 301/486/388 282/463/367 +f 285/477/381 304/487/389 293/488/390 274/461/365 +f 312/478/382 314/489/391 304/487/389 285/477/381 +f 271/471/375 290/490/392 294/491/393 275/479/370 +f 286/462/366 305/492/394 296/483/385 277/475/379 +f 279/474/378 298/482/384 302/493/395 283/470/374 +f 273/452/356 292/494/396 303/495/397 284/453/357 +f 287/455/359 306/496/398 292/494/396 273/452/356 +f 280/456/360 299/497/399 295/498/400 276/457/361 +f 281/459/363 300/484/386 289/499/401 270/460/364 +f 274/461/365 293/488/390 305/492/394 286/462/366 +f 282/463/367 301/486/388 297/500/402 278/464/368 +f 275/466/370 294/501/393 291/485/387 272/467/371 +f 269/469/373 288/502/403 299/497/399 280/456/360 +f 283/470/374 302/493/395 290/490/392 271/471/375 +f 276/457/361 295/498/400 306/496/398 287/455/359 +f 290/490/392 302/493/395 322/503/404 319/504/405 +f 301/486/388 291/485/387 317/505/406 316/506/407 +f 302/493/395 298/482/384 323/507/408 322/503/404 +f 291/485/387 294/501/393 318/508/409 317/505/406 +f 315/481/383 303/495/397 325/509/410 324/510/411 +f 297/500/402 301/486/388 316/506/407 321/511/412 +f 294/491/393 290/490/392 319/504/405 318/512/409 +f 314/489/391 297/500/402 321/511/412 320/513/413 +f 303/495/397 304/487/389 326/514/414 325/509/410 +f 269/469/373 270/460/364 289/499/401 288/502/403 +f 300/484/386 296/483/385 295/498/400 299/497/399 +f 306/496/398 295/498/400 296/483/385 305/492/394 +f 305/492/394 293/488/390 292/494/396 306/496/398 +f 303/495/397 292/494/396 293/488/390 304/487/389 +f 304/487/389 314/489/391 320/513/413 326/514/414 +f 298/482/384 315/481/383 324/510/411 323/507/408 +f 278/464/368 297/500/402 314/489/391 312/478/382 +f 284/453/357 303/495/397 315/481/383 313/473/377 +f 259/440/349 278/464/368 312/478/382 310/441/350 +f 265/430/344 284/453/357 313/473/377 311/431/345 +f 227/424/336 254/423/341 249/468/372 222/515/335 +f 245/418/317 308/412/317 307/414/334 244/419/338 +f 243/420/339 309/409/331 308/412/317 245/418/317 +f 221/516/201 215/517/316 316/506/407 317/505/406 +f 318/512/409 319/504/405 221/518/201 +f 221/516/201 317/505/406 318/508/409 +f 219/519/204 217/520/203 320/513/413 321/511/412 +f 220/521/200 218/522/202 322/503/404 323/507/408 +f 215/517/316 219/519/204 321/511/412 316/506/407 +f 218/522/202 221/518/201 319/504/405 322/503/404 +f 327/523/195 216/524/194 324/510/411 325/509/410 +f 325/509/410 326/514/414 327/523/195 +f 217/520/203 327/523/195 326/514/414 320/513/413 +f 216/524/194 220/521/200 323/507/408 324/510/411 +f 222/515/335 249/468/372 261/444/351 237/443/329 +f 242/450/321 264/449/354 251/472/376 224/525/322 +f 248/526/323 268/454/358 253/451/355 226/527/324 +f 224/525/322 251/472/376 256/480/369 229/528/318 +f 231/446/330 257/445/352 268/454/358 248/526/323 +f 307/442/334 310/441/350 266/476/380 244/529/338 +f 232/438/327 258/437/348 262/458/362 238/530/328 +f 244/529/338 266/476/380 255/434/346 228/433/325 +f 226/527/324 253/451/355 265/430/344 243/429/339 +f 229/531/318 256/465/369 252/426/342 225/425/319 +f 238/530/328 262/458/362 250/422/340 223/421/337 +f 299/497/399 288/502/403 289/499/401 300/484/386 +f 250/422/340 270/460/364 254/423/341 +f 254/423/341 269/469/373 249/468/372 +f 269/469/373 254/423/341 270/460/364 +f 328/532/415 361/533/416 382/534/417 358/535/418 +f 328/532/415 343/536/419 377/537/420 361/533/416 +f 328/532/415 342/538/421 371/539/422 343/536/419 +f 328/532/415 358/535/418 376/540/423 342/538/421 +f 329/541/424 341/542/425 370/543/426 350/544/427 +f 329/541/424 352/545/428 374/546/429 341/542/425 +f 422/547/430 353/548/19 380/549/18 434/550/431 +f 422/547/430 432/551/432 378/552/20 353/548/19 +f 330/553/433 346/554/434 374/546/429 352/545/428 +f 330/553/433 345/555/435 368/556/436 346/554/434 +f 423/557/437 354/558/29 373/559/28 430/560/438 +f 423/557/437 434/550/431 380/549/18 354/558/29 +f 331/561/439 348/562/440 369/563/441 347/564/442 +f 331/561/439 355/565/443 376/540/423 348/562/440 +f 424/566/444 356/38/38 381/37/37 435/567/445 +f 424/566/444 431/568/446 375/39/39 356/38/38 +f 332/569/447 342/538/421 376/540/423 355/565/443 +f 332/569/447 351/570/448 371/539/422 342/538/421 +f 425/571/449 357/46/46 379/45/45 433/572/450 +f 425/571/449 435/567/445 381/37/37 357/46/46 +f 333/573/451 360/574/452 372/575/453 340/576/454 +f 333/573/451 358/535/418 382/534/417 360/574/452 +f 333/573/451 348/562/440 376/540/423 358/535/418 +f 333/573/451 340/576/454 369/563/441 348/562/440 +f 334/577/455 346/554/434 368/556/436 344/578/456 +f 334/577/455 359/579/457 374/546/429 346/554/434 +f 334/577/455 360/574/452 382/534/417 359/579/457 +f 334/577/455 344/578/456 372/575/453 360/574/452 +f 335/580/458 341/542/425 374/546/429 359/579/457 +f 335/580/458 349/581/459 370/543/426 341/542/425 +f 335/580/458 361/533/416 377/537/420 349/581/459 +f 335/580/458 359/579/457 382/534/417 361/533/416 +f 336/582/460 364/583/461 377/537/420 343/536/419 +f 426/584/462 362/585/61 383/586/60 436/587/463 +f 426/588/462 433/572/450 379/45/45 362/63/61 +f 336/589/460 343/536/419 371/539/422 351/570/448 +f 337/590/464 350/544/427 370/543/426 349/581/459 +f 427/591/465 363/592/64 378/552/20 432/551/432 +f 427/591/465 436/587/463 383/586/60 363/592/64 +f 337/590/464 349/581/459 377/537/420 364/583/461 +f 365/593/466 387/594/467 388/595/468 339/596/469 +f 338/597/470 344/578/456 368/556/436 345/555/435 +f 338/597/470 365/593/466 372/575/453 344/578/456 +f 428/598/471 430/560/438 373/559/28 366/599/71 +f 339/596/469 340/576/454 372/575/453 365/593/466 +f 339/596/469 347/564/442 369/563/441 340/576/454 +f 429/600/472 367/76/73 375/39/39 431/568/446 +f 428/598/471 437/601/473 386/602/474 338/597/470 +f 386/602/474 391/603/475 392/604/476 387/594/467 +f 438/605/477 440/606/478 389/83/80 384/82/79 +f 338/597/470 386/602/474 387/594/467 365/593/466 +f 429/600/472 438/605/477 384/82/79 367/76/73 +f 391/607/475 396/608/479 397/609/480 392/610/476 +f 440/611/478 442/612/481 394/91/84 389/90/80 +f 387/594/467 392/604/476 393/613/482 388/595/468 +f 437/601/473 439/614/483 391/603/475 386/602/474 +f 392/610/476 397/609/480 398/615/484 393/616/482 +f 439/617/483 441/618/485 396/608/479 391/607/475 +f 530/619/486 495/620/487 494/621/488 526/622/489 +f 450/623/490 443/624/491 401/625/492 415/626/493 +f 449/627/494 444/628/495 399/109/100 417/108/99 +f 529/629/496 497/630/497 496/631/498 528/632/499 +f 746/633/500 446/634/501 404/117/108 735/116/107 +f 744/635/502 406/636/503 407/637/504 742/638/505 +f 742/639/505 407/640/504 408/641/506 743/642/507 +f 745/643/508 445/644/509 406/636/503 744/635/502 +f 758/645/510 447/646/511 412/647/512 755/648/513 +f 756/649/514 411/650/515 410/651/516 754/652/517 +f 755/648/513 412/647/512 411/653/515 756/654/514 +f 757/655/518 448/656/519 409/141/128 749/140/127 +f 524/657/520 492/658/521 493/659/522 525/660/523 +f 442/612/481 449/627/494 417/108/99 394/91/84 +f 441/618/485 450/623/490 415/626/493 396/608/479 +f 526/622/489 494/621/488 499/661/524 527/662/525 +f 479/663/526 473/664/527 454/665/528 465/666/529 +f 407/667/504 470/668/530 408/669/506 +f 407/670/504 406/671/503 481/672/531 +f 395/159/142 416/160/143 450/623/490 441/618/485 +f 398/615/484 414/673/532 449/627/494 442/612/481 +f 754/652/517 410/651/516 448/656/519 757/655/518 +f 751/162/145 413/163/146 447/646/511 758/645/510 +f 737/164/147 405/165/148 445/644/509 745/643/508 +f 743/642/507 408/641/506 446/634/501 746/633/500 +f 414/673/532 403/674/533 444/628/495 449/627/494 +f 416/160/143 400/167/150 443/624/491 450/623/490 +f 390/168/151 395/159/142 441/618/485 439/617/483 +f 385/675/152 390/676/151 439/614/483 437/601/473 +f 393/616/482 398/615/484 442/612/481 440/611/478 +f 339/596/469 388/595/468 438/605/477 429/600/472 +f 388/595/468 393/613/482 440/606/478 438/605/477 +f 366/599/71 385/675/152 437/601/473 428/598/471 +f 339/596/469 429/600/472 431/568/446 347/564/442 +f 338/597/470 345/555/435 430/560/438 428/598/471 +f 337/590/464 364/583/461 436/587/463 427/591/465 +f 337/590/464 427/591/465 432/551/432 350/544/427 +f 336/589/460 351/570/448 433/572/450 426/588/462 +f 336/582/460 426/584/462 436/587/463 364/583/461 +f 332/569/447 355/565/443 435/567/445 425/571/449 +f 332/569/447 425/571/449 433/572/450 351/570/448 +f 331/561/439 347/564/442 431/568/446 424/566/444 +f 331/561/439 424/566/444 435/567/445 355/565/443 +f 330/553/433 352/545/428 434/550/431 423/557/437 +f 330/553/433 423/557/437 430/560/438 345/555/435 +f 329/541/424 350/544/427 432/551/432 422/547/430 +f 329/541/424 422/547/430 434/550/431 352/545/428 +f 418/677/534 446/678/501 408/669/506 +f 420/679/535 406/671/503 445/680/509 +f 404/175/108 446/678/501 418/677/534 451/176/155 +f 482/177/156 480/681/536 419/682/537 421/178/157 +f 405/181/148 452/182/160 420/679/535 445/680/509 +f 469/683/538 471/186/162 421/185/157 419/684/537 +f 804/685/539 485/686/540 457/687/541 798/688/542 +f 490/689/543 483/690/544 453/691/545 467/692/546 +f 489/693/547 484/694/548 456/695/549 466/696/550 +f 478/697/551 472/698/552 455/699/553 468/700/554 +f 486/701/555 488/702/556 464/703/557 460/704/558 +f 803/705/559 486/701/555 460/704/558 800/706/560 +f 802/707/561 474/708/562 459/709/563 +f 801/710/564 475/711/565 458/712/566 799/713/567 +f 462/714/568 688/715/569 577/716/570 487/717/571 +f 474/708/562 476/718/572 463/719/573 459/709/563 +f 475/711/565 477/720/574 462/714/568 458/712/566 +f 485/686/540 487/717/571 461/721/575 457/687/541 +f 469/683/538 478/697/551 468/700/554 420/679/535 +f 481/672/531 489/693/547 466/696/550 407/670/504 +f 480/681/536 490/689/543 467/692/546 419/682/537 +f 470/668/530 479/663/526 465/666/529 418/677/534 +f 407/667/504 466/722/550 479/663/526 470/668/530 +f 419/684/537 467/723/546 478/697/551 469/683/538 +f 460/724/558 464/725/557 477/720/574 475/711/565 +f 457/726/541 461/727/575 476/718/572 474/708/562 +f 487/717/571 577/716/570 581/728/576 461/721/575 +f 800/729/560 460/724/558 475/711/565 801/710/564 +f 798/730/542 457/726/541 474/708/562 802/707/561 +f 467/723/546 453/731/545 472/698/552 478/697/551 +f 420/679/535 452/182/160 471/186/162 469/683/538 +f 466/722/550 456/732/549 473/664/527 479/663/526 +f 476/718/572 579/733/577 582/734/578 463/719/573 +f 418/677/534 465/666/529 490/689/543 480/681/536 +f 420/679/535 468/700/554 489/693/547 481/672/531 +f 458/712/566 462/714/568 487/717/571 485/686/540 +f 464/725/557 580/735/579 578/736/580 477/720/574 +f 459/709/563 486/701/555 803/705/559 +f 459/709/563 463/719/573 488/702/556 486/701/555 +f 468/700/554 455/699/553 484/694/548 489/693/547 +f 465/666/529 454/665/528 483/690/544 490/689/543 +f 799/713/567 458/712/566 485/686/540 804/685/539 +f 451/176/155 418/677/534 480/681/536 482/177/156 +f 418/677/534 408/669/506 470/668/530 +f 420/679/535 481/672/531 406/671/503 +f 789/737/581 505/738/582 504/739/583 788/740/584 +f 787/741/585 502/742/586 506/743/587 783/744/588 +f 784/745/589 508/746/590 500/747/591 785/748/592 +f 785/748/592 500/747/591 501/749/593 786/750/594 +f 527/662/525 499/661/524 491/751/595 531/752/596 +f 525/660/523 493/659/522 497/630/497 529/629/496 +f 531/752/596 491/751/595 492/658/521 524/657/520 +f 528/632/499 496/631/498 495/753/487 530/754/486 +f 773/755/597 498/756/598 509/757/599 769/758/600 +f 772/759/601 512/760/602 511/761/603 771/762/604 +f 770/763/605 514/764/606 513/765/607 767/766/608 +f 771/762/604 511/761/603 516/767/609 768/768/610 +f 786/750/594 501/749/593 502/742/586 787/741/585 +f 790/769/611 503/770/612 508/746/590 784/745/589 +f 783/744/588 506/743/587 505/738/582 789/737/581 +f 788/771/584 504/772/583 503/770/612 790/769/611 +f 510/773/613 534/774/614 538/775/615 514/776/606 +f 516/777/609 540/778/616 532/779/617 498/780/598 +f 498/780/598 532/779/617 533/781/618 509/782/599 +f 512/783/602 536/784/619 535/785/620 511/786/603 +f 768/768/610 516/767/609 498/756/598 773/755/597 +f 774/787/621 510/788/613 514/764/606 770/763/605 +f 767/766/608 513/765/607 512/789/602 772/790/601 +f 769/758/600 509/757/599 510/788/613 774/787/621 +f 734/791/622 521/792/623 523/793/624 731/794/625 +f 732/795/626 517/796/627 520/797/628 729/798/629 +f 731/794/625 523/793/624 507/799/630 +f 733/800/631 519/801/632 522/802/633 730/803/634 +f 728/804/635 518/805/636 519/801/632 733/800/631 +f 507/799/630 517/796/627 732/795/626 +f 729/806/629 520/807/628 518/805/636 728/804/635 +f 730/803/634 522/802/633 521/792/623 734/791/622 +f 403/674/533 528/632/499 530/754/486 402/808/637 +f 396/608/479 531/752/596 524/657/520 397/609/480 +f 398/615/484 525/660/523 529/629/496 414/673/532 +f 415/626/493 527/662/525 531/752/596 396/608/479 +f 401/625/492 526/622/489 527/662/525 415/626/493 +f 397/609/480 524/657/520 525/660/523 398/615/484 +f 414/673/532 529/629/496 528/632/499 403/674/533 +f 402/809/637 530/619/486 526/622/489 401/625/492 +f 533/781/618 541/810/638 542/811/639 534/774/614 +f 537/812/640 545/813/641 544/814/642 536/784/619 +f 534/774/614 542/811/639 546/815/643 538/775/615 +f 540/778/616 548/816/644 515/817/645 532/779/617 +f 513/818/607 537/812/640 536/784/619 512/783/602 +f 509/782/599 533/781/618 534/774/614 510/773/613 +f 511/819/603 535/820/620 540/778/616 516/777/609 +f 514/776/606 538/775/615 537/821/640 513/822/607 +f 695/823/646 556/824/647 539/825/648 694/826/649 +f 694/826/649 539/825/648 549/827/650 691/828/651 +f 692/829/652 552/830/653 551/831/654 689/832/655 +f 693/833/656 554/834/657 553/835/658 690/836/659 +f 535/820/620 543/837/660 548/816/644 540/778/616 +f 545/838/641 567/839/661 566/840/662 546/815/643 +f 536/784/619 544/814/642 543/841/660 535/785/620 +f 532/779/617 515/817/645 541/810/638 533/781/618 +f 555/842/663 552/843/653 553/835/658 554/834/657 +f 556/824/647 551/844/654 552/843/653 555/842/663 +f 539/825/648 556/824/647 555/842/663 549/827/650 +f 549/827/650 555/842/663 554/834/657 550/845/664 +f 696/846/665 550/845/664 554/834/657 693/833/656 +f 690/847/659 553/848/658 552/830/653 692/829/652 +f 691/828/651 549/827/650 550/845/664 696/846/665 +f 689/849/655 551/844/654 556/824/647 695/823/646 +f 718/850/666 557/851/667 562/852/668 716/853/669 +f 720/854/670 560/855/671 563/856/672 717/857/673 +f 719/858/674 559/859/675 547/860/676 713/861/677 +f 717/857/673 563/856/672 558/862/678 714/863/679 +f 714/863/679 558/862/678 559/864/675 719/865/674 +f 713/861/677 547/860/676 557/866/667 718/867/666 +f 715/868/680 561/869/681 560/855/671 720/854/670 +f 716/853/669 562/852/668 561/869/681 715/868/680 +f 564/870/682 568/871/683 569/872/684 565/873/685 +f 537/812/640 565/874/685 567/875/661 545/813/641 +f 546/815/643 566/840/662 564/870/682 538/775/615 +f 538/775/615 564/870/682 565/873/685 537/821/640 +f 569/876/684 573/877/686 575/878/687 571/879/688 +f 565/874/685 569/876/684 571/879/688 567/875/661 +f 566/840/662 570/880/689 568/871/683 564/870/682 +f 567/839/661 571/881/688 570/880/689 566/840/662 +f 572/882/690 574/883/691 575/884/687 573/885/686 +f 570/880/689 574/883/691 572/882/690 568/871/683 +f 571/881/688 575/884/687 574/883/691 570/880/689 +f 568/871/683 572/882/690 573/885/686 569/872/684 +f 463/719/573 582/734/578 576/886/692 488/702/556 +f 488/702/556 576/886/692 580/887/579 464/703/557 +f 461/727/575 581/888/576 579/733/577 476/718/572 +f 477/720/574 578/736/580 688/715/569 462/714/568 +f 602/889/317 601/890/693 586/891/694 590/892/695 +f 603/893/696 602/889/317 590/892/695 585/894/697 +f 609/895/698 608/896/317 591/897/317 587/898/699 +f 608/896/317 607/899/700 589/900/701 591/897/317 +f 600/901/317 599/902/702 593/903/703 594/904/317 +f 598/905/704 600/901/317 594/904/317 592/906/705 +f 670/907/706 669/908/317 597/909/317 596/910/707 +f 669/908/317 668/911/708 595/912/709 597/909/317 +f 583/913/710 588/914/711 600/901/317 598/905/704 +f 588/914/711 584/915/712 599/902/702 600/901/317 +f 596/910/707 597/909/317 602/889/317 603/893/696 +f 597/909/317 595/912/709 601/890/693 602/889/317 +f 591/897/317 589/900/701 605/916/713 606/917/317 +f 587/898/699 591/897/317 606/917/317 604/918/714 +f 594/904/317 593/903/703 607/899/700 608/896/317 +f 592/906/705 594/904/317 608/896/317 609/895/698 +f 584/919/712 588/920/711 615/921/715 611/922/716 +f 586/923/694 601/924/693 624/925/717 613/926/718 +f 604/927/714 670/928/706 672/929/719 626/930/720 +f 589/931/701 607/932/700 628/933/721 616/934/722 +f 607/932/700 593/935/703 619/936/723 628/933/721 +f 595/937/709 668/938/708 671/939/724 620/940/725 +f 598/941/704 592/942/705 618/943/726 622/944/727 +f 601/924/693 595/937/709 620/940/725 624/925/717 +f 670/928/706 596/945/707 621/946/728 672/929/719 +f 596/945/707 603/947/696 625/948/729 621/946/728 +f 614/949/730 626/930/720 645/950/731 634/951/732 +f 629/952/733 614/949/730 634/951/732 648/953/734 +f 622/944/727 618/943/726 637/954/735 641/955/736 +f 623/956/737 611/922/716 631/957/738 642/958/739 +f 616/934/722 628/933/721 647/959/740 635/960/741 +f 624/925/717 620/940/725 639/961/742 643/962/743 +f 617/963/744 613/926/718 633/964/745 636/965/746 +f 610/966/747 622/944/727 641/955/736 630/967/748 +f 625/948/729 612/968/749 632/969/750 644/970/751 +f 618/943/726 629/952/733 648/953/734 637/954/735 +f 672/929/719 621/946/728 640/971/752 674/972/753 +f 619/936/723 623/956/737 642/958/739 638/973/754 +f 613/926/718 624/925/717 643/962/743 633/964/745 +f 627/974/755 616/934/722 635/960/741 646/975/756 +f 671/939/724 627/974/755 646/975/756 673/976/757 +f 612/968/749 617/977/744 636/978/746 632/969/750 +f 628/933/721 619/936/723 638/973/754 647/959/740 +f 621/946/728 625/948/729 644/970/751 640/971/752 +f 674/972/753 640/971/752 659/979/758 676/980/759 +f 638/973/754 642/958/739 661/981/760 657/982/761 +f 633/964/745 643/962/743 662/983/762 652/984/763 +f 646/975/756 635/960/741 654/985/764 665/986/765 +f 673/976/757 646/975/756 665/986/765 675/987/766 +f 632/969/750 636/978/746 655/988/767 651/989/768 +f 647/959/740 638/973/754 657/982/761 666/990/769 +f 640/971/752 644/970/751 663/991/770 659/979/758 +f 634/951/732 645/950/731 664/992/771 653/993/772 +f 648/953/734 634/951/732 653/993/772 667/994/773 +f 641/955/736 637/954/735 656/995/774 660/996/775 +f 642/958/739 631/957/738 650/997/776 661/981/760 +f 635/960/741 647/959/740 666/990/769 654/985/764 +f 643/962/743 639/961/742 658/998/777 662/983/762 +f 636/965/746 633/964/745 652/984/763 655/999/767 +f 630/967/748 641/955/736 660/996/775 649/1000/778 +f 644/970/751 632/969/750 651/989/768 663/991/770 +f 637/954/735 648/953/734 667/994/773 656/995/774 +f 651/989/768 680/1001/779 683/1002/780 663/991/770 +f 662/983/762 677/1003/781 678/1004/782 652/984/763 +f 663/991/770 683/1002/780 684/1005/783 659/979/758 +f 652/984/763 678/1004/782 679/1006/784 655/999/767 +f 676/980/759 685/1007/785 686/1008/786 664/992/771 +f 658/998/777 682/1009/787 677/1003/781 662/983/762 +f 655/988/767 679/1010/784 680/1001/779 651/989/768 +f 675/987/766 681/1011/788 682/1009/787 658/998/777 +f 664/992/771 686/1008/786 687/1012/789 665/986/765 +f 630/967/748 649/1000/778 650/997/776 631/957/738 +f 661/981/760 660/996/775 656/995/774 657/982/761 +f 667/994/773 666/990/769 657/982/761 656/995/774 +f 666/990/769 667/994/773 653/993/772 654/985/764 +f 664/992/771 665/986/765 654/985/764 653/993/772 +f 665/986/765 687/1012/789 681/1011/788 675/987/766 +f 659/979/758 684/1005/783 685/1007/785 676/980/759 +f 639/961/742 673/976/757 675/987/766 658/998/777 +f 645/950/731 674/972/753 676/980/759 664/992/771 +f 620/940/725 671/939/724 673/976/757 639/961/742 +f 626/930/720 672/929/719 674/972/753 645/950/731 +f 588/920/711 583/1013/710 610/966/747 615/921/715 +f 606/917/317 605/916/713 668/911/708 669/908/317 +f 604/918/714 606/917/317 669/908/317 670/907/706 +f 582/1014/578 678/1004/782 677/1003/781 576/1015/692 +f 679/1010/784 582/1016/578 680/1001/779 +f 582/1014/578 679/1006/784 678/1004/782 +f 580/1017/579 682/1009/787 681/1011/788 578/1018/580 +f 581/1019/576 684/1005/783 683/1002/780 579/1020/577 +f 576/1015/692 677/1003/781 682/1009/787 580/1017/579 +f 579/1020/577 683/1002/780 680/1001/779 582/1016/578 +f 688/1021/569 686/1008/786 685/1007/785 577/1022/570 +f 686/1008/786 688/1021/569 687/1012/789 +f 578/1018/580 681/1011/788 687/1012/789 688/1021/569 +f 577/1022/570 685/1007/785 684/1005/783 581/1019/576 +f 583/1013/710 598/941/704 622/944/727 610/966/747 +f 603/947/696 585/1023/697 612/968/749 625/948/729 +f 609/1024/698 587/1025/699 614/949/730 629/952/733 +f 585/1023/697 590/1026/695 617/977/744 612/968/749 +f 592/942/705 609/1024/698 629/952/733 618/943/726 +f 668/938/708 605/1027/713 627/974/755 671/939/724 +f 593/935/703 599/1028/702 623/956/737 619/936/723 +f 605/1027/713 589/931/701 616/934/722 627/974/755 +f 587/1025/699 604/927/714 626/930/720 614/949/730 +f 590/1029/695 586/923/694 613/926/718 617/963/744 +f 599/1028/702 584/919/712 611/922/716 623/956/737 +f 660/996/775 661/981/760 650/997/776 649/1000/778 +f 611/922/716 615/921/715 631/957/738 +f 615/921/715 610/966/747 630/967/748 +f 630/967/748 631/957/738 615/921/715 +f 557/851/667 689/849/655 695/823/646 562/852/668 +f 560/855/671 691/828/651 696/846/665 563/856/672 +f 559/859/675 690/847/659 692/829/652 547/860/676 +f 563/856/672 696/846/665 693/833/656 558/862/678 +f 558/862/678 693/833/656 690/836/659 559/864/675 +f 547/860/676 692/829/652 689/832/655 557/866/667 +f 561/869/681 694/826/649 691/828/651 560/855/671 +f 562/852/668 695/823/646 694/826/649 561/869/681 +f 196/355/293 201/354/292 703/325/270 697/351/277 +f 199/359/297 202/358/296 704/348/289 699/329/274 +f 198/363/301 186/362/300 700/331/276 698/349/281 +f 202/358/296 197/365/303 701/335/280 704/348/289 +f 197/365/303 198/367/301 698/336/281 701/335/280 +f 186/362/300 196/369/293 697/332/277 700/331/276 +f 200/371/305 199/359/297 699/329/274 702/326/271 +f 201/354/292 200/371/305 702/326/271 703/325/270 +f 187/319/269 154/318/268 707/370/304 708/353/291 +f 154/318/268 180/313/263 712/356/294 707/370/304 +f 183/315/265 182/343/284 710/368/290 705/361/299 +f 185/317/267 184/340/266 711/366/298 706/364/302 +f 181/312/262 185/317/267 706/364/302 709/357/295 +f 184/316/266 183/315/265 705/361/299 711/360/298 +f 180/313/263 181/312/262 709/357/295 712/356/294 +f 182/339/284 187/319/269 708/353/291 710/352/290 +f 548/816/644 716/853/669 715/868/680 515/817/645 +f 515/817/645 715/868/680 720/854/670 541/810/638 +f 544/814/642 713/861/677 718/867/666 543/841/660 +f 546/815/643 714/863/679 719/865/674 545/838/641 +f 542/811/639 717/857/673 714/863/679 546/815/643 +f 545/813/641 719/858/674 713/861/677 544/814/642 +f 541/810/638 720/854/670 717/857/673 542/811/639 +f 543/837/660 718/850/666 716/853/669 548/816/644 +f 139/249/215 140/252/218 727/293/246 723/303/256 +f 143/274/207 142/272/236 721/306/259 722/308/251 +f 145/245/211 144/242/208 725/297/250 +f 142/272/236 147/250/216 726/302/255 721/306/259 +f 147/250/216 139/249/215 723/303/256 726/302/255 +f 141/246/212 145/245/211 724/294/247 +f 144/242/208 143/241/207 722/298/251 725/297/250 +f 140/252/218 141/246/212 724/294/247 727/293/246 +f 500/747/591 730/803/634 734/791/622 501/749/593 +f 504/772/583 729/806/629 728/804/635 503/770/612 +f 505/738/582 506/743/587 732/795/626 +f 503/770/612 728/804/635 733/800/631 508/746/590 +f 508/746/590 733/800/631 730/803/634 500/747/591 +f 502/742/586 731/794/625 506/743/587 +f 505/738/582 732/795/626 729/798/629 504/739/583 +f 501/749/593 734/791/622 731/794/625 502/742/586 +f 410/651/516 743/642/507 746/633/500 448/656/519 +f 413/163/146 737/164/147 745/643/508 447/646/511 +f 447/646/511 745/643/508 744/635/502 412/647/512 +f 411/650/515 742/639/505 743/642/507 410/651/516 +f 412/647/512 744/635/502 742/638/505 411/653/515 +f 448/656/519 746/633/500 735/116/107 409/141/128 +f 57/135/124 91/142/129 741/115/106 738/124/114 +f 413/163/146 90/132/121 740/127/116 737/164/147 +f 90/132/121 59/131/120 739/119/110 740/127/116 +f 58/136/125 57/135/124 738/124/114 736/123/111 +f 59/131/120 58/138/125 736/120/111 739/119/110 +f 91/142/129 409/141/128 735/116/107 741/115/106 +f 400/167/150 751/162/145 758/645/510 443/624/491 +f 403/674/533 754/652/517 757/655/518 444/628/495 +f 444/628/495 757/655/518 749/140/127 399/109/100 +f 401/625/492 755/648/513 756/654/514 402/809/637 +f 402/808/637 756/649/514 754/652/517 403/674/533 +f 443/624/491 758/645/510 755/648/513 401/625/492 +f 400/167/150 86/106/97 753/129/118 751/162/145 +f 53/166/149 87/110/101 752/139/126 747/134/123 +f 87/110/101 399/109/100 749/140/127 752/139/126 +f 51/105/96 52/311/261 750/137/122 748/130/119 +f 52/310/261 53/166/149 747/134/123 750/133/122 +f 86/106/97 51/105/96 748/130/119 753/129/118 +f 160/296/249 162/295/248 766/289/245 761/258/222 +f 156/300/253 159/299/252 764/291/225 759/266/230 +f 162/295/248 146/301/254 762/265/229 766/289/245 +f 158/305/258 161/304/257 765/257/221 760/269/233 +f 157/307/260 158/305/258 760/269/233 763/262/226 +f 146/301/254 156/300/253 759/266/230 762/265/229 +f 159/309/252 157/307/260 763/262/226 764/261/225 +f 161/304/257 160/296/249 761/258/222 765/257/221 +f 521/792/623 769/758/600 774/787/621 523/793/624 +f 517/796/627 767/766/608 772/790/601 520/797/628 +f 523/793/624 774/787/621 770/763/605 507/799/630 +f 519/801/632 768/768/610 773/755/597 522/802/633 +f 518/805/636 771/762/604 768/768/610 519/801/632 +f 507/799/630 770/763/605 767/766/608 517/796/627 +f 520/807/628 772/759/601 771/762/604 518/805/636 +f 522/802/633 773/755/597 769/758/600 521/792/623 +f 134/102/93 133/101/92 782/271/235 780/273/206 +f 136/114/105 135/113/104 781/239/205 775/244/210 +f 133/101/92 138/148/135 776/247/213 782/271/235 +f 131/146/133 132/145/132 779/243/209 778/251/217 +f 130/254/220 131/146/133 778/251/217 777/248/214 +f 138/148/135 130/254/220 777/248/214 776/247/213 +f 132/145/132 136/114/105 775/244/210 779/243/209 +f 135/113/104 134/256/93 780/240/206 781/239/205 +f 495/620/487 788/771/584 790/769/611 494/621/488 +f 497/630/497 783/744/588 789/737/581 496/631/498 +f 494/621/488 790/769/611 784/745/589 499/661/524 +f 492/658/521 786/750/594 787/741/585 493/659/522 +f 491/751/595 785/748/592 786/750/594 492/658/521 +f 499/661/524 784/745/589 785/748/592 491/751/595 +f 493/659/522 787/741/585 783/744/588 497/630/497 +f 496/631/498 789/737/581 788/740/584 495/753/487 +f 506/743/587 507/799/630 732/795/626 +f 145/245/211 146/301/254 724/294/247 +f 506/743/587 731/794/625 507/799/630 +f 145/245/211 725/297/250 146/301/254 +f 95/151/138 122/194/170 797/187/163 792/213/189 +f 96/201/177 123/198/174 796/207/183 +f 94/233/169 112/202/178 795/210/186 791/232/164 +f 97/234/173 113/152/139 794/212/188 793/231/184 +f 113/152/139 95/151/138 792/213/189 794/212/188 +f 112/202/178 96/201/177 795/210/186 +f 123/198/174 97/197/173 793/208/184 796/207/183 +f 122/194/170 94/193/169 791/188/164 797/187/163 +f 454/665/528 799/713/567 804/685/539 483/690/544 +f 484/694/548 455/699/553 803/705/559 +f 453/731/545 798/730/542 802/707/561 472/698/552 +f 456/732/549 800/729/560 801/710/564 473/664/527 +f 473/664/527 801/710/564 799/713/567 454/665/528 +f 472/698/552 802/707/561 455/699/553 +f 484/694/548 803/705/559 800/706/560 456/695/549 +f 483/690/544 804/685/539 798/688/542 453/691/545 +f 455/699/553 459/709/563 803/705/559 +f 96/201/177 100/211/187 795/210/186 +f 455/699/553 802/707/561 459/709/563 +f 96/201/177 796/207/183 100/211/187 diff --git a/examples/models/resources/models/obj/character_diffuse.png b/examples/models/resources/models/obj/character_diffuse.png new file mode 100644 index 0000000000000000000000000000000000000000..0fae9d8944dce8f7f307d73b454f86200d569afc GIT binary patch literal 41705 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 F{U1buITru` literal 0 HcmV?d00001 From 79fd6be0084a80dcbf7c7af2c1ccb12b78b77c47 Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 25 Oct 2025 11:14:53 +0200 Subject: [PATCH 164/167] Minor format tweaks --- src/external/rlsw.h | 73 ++++++++++++++++++++------------------------- 1 file changed, 33 insertions(+), 40 deletions(-) diff --git a/src/external/rlsw.h b/src/external/rlsw.h index 626cb2cc5..bc7a813d3 100644 --- a/src/external/rlsw.h +++ b/src/external/rlsw.h @@ -791,8 +791,7 @@ typedef struct { } sw_vertex_t; typedef struct { - - uint8_t* pixels; // Texture pixels (RGBA32) + uint8_t *pixels; // Texture pixels (RGBA32) int width, height; // Dimensions of the texture int wMinus1, hMinus1; // Dimensions minus one @@ -805,7 +804,6 @@ typedef struct { float tx; // Texel width float ty; // Texel height - } sw_texture_t; typedef struct { @@ -881,7 +879,6 @@ typedef struct { int freeTextureIdCount; uint32_t stateFlags; - } sw_context_t; //---------------------------------------------------------------------------------- @@ -966,11 +963,7 @@ static inline int sw_clampi(int v, int min, int max) return v; } -static inline void sw_lerp_vertex_PTCH( - sw_vertex_t *SW_RESTRICT out, - const sw_vertex_t *SW_RESTRICT a, - const sw_vertex_t *SW_RESTRICT b, - float t) +static inline void sw_lerp_vertex_PTCH(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT a, const sw_vertex_t *SW_RESTRICT b, float t) { const float tInv = 1.0f - t; @@ -997,11 +990,7 @@ static inline void sw_lerp_vertex_PTCH( out->homogeneous[3] = a->homogeneous[3]*tInv + b->homogeneous[3]*t; } -static inline void sw_get_vertex_grad_PTCH( - sw_vertex_t *SW_RESTRICT out, - const sw_vertex_t *SW_RESTRICT a, - const sw_vertex_t *SW_RESTRICT b, - float scale) +static inline void sw_get_vertex_grad_PTCH(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT a, const sw_vertex_t *SW_RESTRICT b, float scale) { // Calculate gradients for Position out->position[0] = (b->position[0] - a->position[0])*scale; @@ -1026,9 +1015,7 @@ static inline void sw_get_vertex_grad_PTCH( out->homogeneous[3] = (b->homogeneous[3] - a->homogeneous[3])*scale; } -static inline void sw_add_vertex_grad_PTCH( - sw_vertex_t *SW_RESTRICT out, - const sw_vertex_t *SW_RESTRICT gradients) +static inline void sw_add_vertex_grad_PTCH(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT gradients) { // Add gradients to Position out->position[0] += gradients->position[0]; @@ -1065,7 +1052,6 @@ static inline void sw_float_to_unorm8_simd(uint8_t dst[4], const float src[4]) uint8x8_t narrow8 = vmovn_u16(vcombine_u16(narrow16, narrow16)); vst1_lane_u32((uint32_t*)dst, vreinterpret_u32_u8(narrow8), 0); - #elif defined(SW_HAS_SSE41) __m128 values = _mm_loadu_ps(src); __m128 scaled = _mm_mul_ps(values, _mm_set1_ps(255.0f)); @@ -1075,7 +1061,6 @@ static inline void sw_float_to_unorm8_simd(uint8_t dst[4], const float src[4]) clamped = _mm_packus_epi32(clamped, clamped); clamped = _mm_packus_epi16(clamped, clamped); *(uint32_t*)dst = _mm_cvtsi128_si32(clamped); - #elif defined(SW_HAS_SSE2) __m128 values = _mm_loadu_ps(src); __m128 scaled = _mm_mul_ps(values, _mm_set1_ps(255.0f)); @@ -1085,7 +1070,6 @@ static inline void sw_float_to_unorm8_simd(uint8_t dst[4], const float src[4]) clamped = _mm_packs_epi32(clamped, clamped); clamped = _mm_packus_epi16(clamped, clamped); *(uint32_t*)dst = _mm_cvtsi128_si32(clamped); - #else for (int i = 0; i < 4; i++) { @@ -1110,14 +1094,12 @@ static inline void sw_float_from_unorm8_simd(float dst[4], const uint8_t src[4]) float32x4_t floats = vcvtq_f32_u32(ints); floats = vmulq_n_f32(floats, 1.0f/255.0f); vst1q_f32(dst, floats); - #elif defined(SW_HAS_SSE41) __m128i bytes = _mm_cvtsi32_si128(*(const uint32_t*)src); __m128i ints = _mm_cvtepu8_epi32(bytes); __m128 floats = _mm_cvtepi32_ps(ints); floats = _mm_mul_ps(floats, _mm_set1_ps(1.0f/255.0f)); _mm_storeu_ps(dst, floats); - #elif defined(SW_HAS_SSE2) __m128i bytes = _mm_cvtsi32_si128(*(const uint32_t*)src); bytes = _mm_unpacklo_epi8(bytes, _mm_setzero_si128()); @@ -1125,7 +1107,6 @@ static inline void sw_float_from_unorm8_simd(float dst[4], const uint8_t src[4]) __m128 floats = _mm_cvtepi32_ps(ints); floats = _mm_mul_ps(floats, _mm_set1_ps(1.0f/255.0f)); _mm_storeu_ps(dst, floats); - #else dst[0] = (float)src[0]/255.0f; dst[1] = (float)src[1]/255.0f; @@ -1188,7 +1169,7 @@ static inline sw_half_t sw_half_from_float(float i) } // Framebuffer management functions - +//------------------------------------------------------------------------------------------- static inline bool sw_framebuffer_load(int w, int h) { int size = w*h; @@ -1731,9 +1712,10 @@ DEFINE_FRAMEBUFFER_BLIT_BEGIN(R8G8B8A8, uint8_t) dst += 4; } DEFINE_FRAMEBUFFER_BLIT_END() +//------------------------------------------------------------------------------------------- // Pixel format management functions - +//------------------------------------------------------------------------------------------- static inline int sw_get_pixel_format(SWformat format, SWtype type) { int channels = 0; @@ -1920,9 +1902,10 @@ static inline void sw_get_pixel(uint8_t *color, const void *pixels, uint32_t off } } } +//------------------------------------------------------------------------------------------- // Texture sampling functionality - +//------------------------------------------------------------------------------------------- static inline void sw_texture_fetch(float* color, const sw_texture_t* tex, int x, int y) { sw_float_from_unorm8_simd(color, &tex->pixels[4*(y*tex->width + x)]); @@ -2016,9 +1999,10 @@ static inline void sw_texture_sample(float *color, const sw_texture_t *tex, floa default: break; } } +//------------------------------------------------------------------------------------------- -// Color Blending functionality - +// Color blending functionality +//------------------------------------------------------------------------------------------- static inline void sw_factor_zero(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst) { factor[0] = factor[1] = factor[2] = factor[3] = 0.0f; @@ -2091,17 +2075,19 @@ static inline void sw_blend_colors(float *SW_RESTRICT dst/*[4]*/, const float *S dst[2] = srcFactor[2]*src[2] + dstFactor[2]*dst[2]; dst[3] = srcFactor[3]*src[3] + dstFactor[3]*dst[3]; } +//------------------------------------------------------------------------------------------- // Projection helper functions - +//------------------------------------------------------------------------------------------- static inline void sw_project_ndc_to_screen(float screen[2], const float ndc[4]) { screen[0] = RLSW.vpCenter[0] + ndc[0]*RLSW.vpHalfSize[0]; screen[1] = RLSW.vpCenter[1] - ndc[1]*RLSW.vpHalfSize[1]; } +//------------------------------------------------------------------------------------------- -// Polygon Clipping management - +// Polygon clipping management +//------------------------------------------------------------------------------------------- #define DEFINE_CLIP_FUNC(name, FUNC_IS_INSIDE, FUNC_COMPUTE_T) \ static inline int sw_clip_##name( \ sw_vertex_t output[SW_MAX_CLIPPED_POLYGON_VERTICES], \ @@ -2133,9 +2119,10 @@ static inline int sw_clip_##name( \ return outputCount; \ } +//------------------------------------------------------------------------------------------- // Frustum cliping functions - +//------------------------------------------------------------------------------------------- #define IS_INSIDE_PLANE_W(h) ((h)[3] >= SW_CLIP_EPSILON) #define IS_INSIDE_PLANE_X_POS(h) ((h)[0] <= (h)[3]) #define IS_INSIDE_PLANE_X_NEG(h) (-(h)[0] <= (h)[3]) @@ -2159,9 +2146,10 @@ DEFINE_CLIP_FUNC(y_pos, IS_INSIDE_PLANE_Y_POS, COMPUTE_T_PLANE_Y_POS) DEFINE_CLIP_FUNC(y_neg, IS_INSIDE_PLANE_Y_NEG, COMPUTE_T_PLANE_Y_NEG) DEFINE_CLIP_FUNC(z_pos, IS_INSIDE_PLANE_Z_POS, COMPUTE_T_PLANE_Z_POS) DEFINE_CLIP_FUNC(z_neg, IS_INSIDE_PLANE_Z_NEG, COMPUTE_T_PLANE_Z_NEG) +//------------------------------------------------------------------------------------------- // Scissor clip functions - +//------------------------------------------------------------------------------------------- #define COMPUTE_T_SCISSOR_X_MIN(hPrev, hCurr) (((RLSW.scClipMin[0])*(hPrev)[3] - (hPrev)[0])/(((hCurr)[0] - (RLSW.scClipMin[0])*(hCurr)[3]) - ((hPrev)[0] - (RLSW.scClipMin[0])*(hPrev)[3]))) #define COMPUTE_T_SCISSOR_X_MAX(hPrev, hCurr) (((RLSW.scClipMax[0])*(hPrev)[3] - (hPrev)[0])/(((hCurr)[0] - (RLSW.scClipMax[0])*(hCurr)[3]) - ((hPrev)[0] - (RLSW.scClipMax[0])*(hPrev)[3]))) #define COMPUTE_T_SCISSOR_Y_MIN(hPrev, hCurr) (((RLSW.scClipMin[1])*(hPrev)[3] - (hPrev)[1])/(((hCurr)[1] - (RLSW.scClipMin[1])*(hCurr)[3]) - ((hPrev)[1] - (RLSW.scClipMin[1])*(hPrev)[3]))) @@ -2176,9 +2164,9 @@ DEFINE_CLIP_FUNC(scissor_x_min, IS_INSIDE_SCISSOR_X_MIN, COMPUTE_T_SCISSOR_X_MIN DEFINE_CLIP_FUNC(scissor_x_max, IS_INSIDE_SCISSOR_X_MAX, COMPUTE_T_SCISSOR_X_MAX) DEFINE_CLIP_FUNC(scissor_y_min, IS_INSIDE_SCISSOR_Y_MIN, COMPUTE_T_SCISSOR_Y_MIN) DEFINE_CLIP_FUNC(scissor_y_max, IS_INSIDE_SCISSOR_Y_MAX, COMPUTE_T_SCISSOR_Y_MAX) +//------------------------------------------------------------------------------------------- -// Main clip function - +// Main polygon clip function static inline bool sw_polygon_clip(sw_vertex_t polygon[SW_MAX_CLIPPED_POLYGON_VERTICES], int *vertexCounter) { static sw_vertex_t tmp[SW_MAX_CLIPPED_POLYGON_VERTICES]; @@ -2218,7 +2206,7 @@ static inline bool sw_polygon_clip(sw_vertex_t polygon[SW_MAX_CLIPPED_POLYGON_VE } // Triangle rendering logic - +//------------------------------------------------------------------------------------------- static inline bool sw_triangle_face_culling(void) { // NOTE: Face culling is done before clipping to avoid unnecessary computations. @@ -2556,9 +2544,10 @@ static inline void sw_triangle_render(void) #undef TRIANGLE_RASTER } +//------------------------------------------------------------------------------------------- // Quad rendering logic - +//------------------------------------------------------------------------------------------- static inline bool sw_quad_face_culling(void) { // NOTE: Face culling is done before clipping to avoid unnecessary computations. @@ -2930,9 +2919,10 @@ static inline void sw_quad_render(void) #undef TRIANGLE_RASTER } +//------------------------------------------------------------------------------------------- // Line rendering logic - +//------------------------------------------------------------------------------------------- static inline bool sw_line_clip_coord(float q, float p, float *t0, float *t1) { if (fabsf(p) < SW_CLIP_EPSILON) @@ -3243,9 +3233,10 @@ static inline void sw_line_render(sw_vertex_t *vertices) else sw_line_raster(&vertices[0], &vertices[1]); } } +//------------------------------------------------------------------------------------------- // Point rendering logic - +//------------------------------------------------------------------------------------------- static inline bool sw_point_clip_and_project(sw_vertex_t *v) { if (v->homogeneous[3] != 1.0f) @@ -3409,9 +3400,10 @@ static inline void sw_point_render(sw_vertex_t *v) else sw_point_raster(v->screen[0], v->screen[1], v->homogeneous[2], v->color); } } +//------------------------------------------------------------------------------------------- // Polygon modes mendering logic - +//------------------------------------------------------------------------------------------- static inline void sw_poly_point_render(void) { for (int i = 0; i < RLSW.vertexCounter; i++) sw_point_render(&RLSW.vertexBuffer[i]); @@ -3546,6 +3538,7 @@ static inline bool sw_is_blend_dst_factor_valid(int blend) return result; } +//------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------- // Module Functions Definition From efe62f0e0df426ff64b14edc75dafd934552f1c0 Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 25 Oct 2025 11:15:30 +0200 Subject: [PATCH 165/167] Formating review to follow raylib code conventions #5298 --- examples/models/models_decals.c | 397 +++++++++++++++----------------- 1 file changed, 181 insertions(+), 216 deletions(-) diff --git a/examples/models/models_decals.c b/examples/models/models_decals.c index 81bbd2796..af1ecfc6d 100644 --- a/examples/models/models_decals.c +++ b/examples/models/models_decals.c @@ -2,7 +2,7 @@ * * raylib [models] example - decals * -* Example complexity rating: [★★★☆] 3/4 +* Example complexity rating: [★★★★] 4/4 * * Example originally created with raylib 5.6-dev * @@ -17,15 +17,19 @@ ********************************************************************************************/ #include "raylib.h" + #include "raymath.h" -#include +#include // Required for: memcpy() #undef FLT_MAX #define FLT_MAX 340282346638528859811704183484516925440.0f // Maximum value of a float, from bit pattern 01111111011111111111111111111111 #define MAX_DECALS 256 +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- typedef struct MeshBuilder { int vertexCount; int vertexCapacity; @@ -33,14 +37,14 @@ typedef struct MeshBuilder { Vector2 *uvs; } MeshBuilder; -// Utility functions -void AddTriangleToMeshBuilder(MeshBuilder *mb, Vector3 vertices[3]); -void FreeMeshBuilder(MeshBuilder *mb); -Mesh BuildMesh(MeshBuilder *mb); - -Vector3 ClipSegment(Vector3 v0, Vector3 v1, Vector3 p, float s); - -Mesh GenMeshDecal(Mesh inputMesh, Ray ray); +//------------------------------------------------------------------------------------ +// Module Functions Declaration +//------------------------------------------------------------------------------------ +static void AddTriangleToMeshBuilder(MeshBuilder *mb, Vector3 vertices[3]); +static void FreeMeshBuilder(MeshBuilder *mb); +static Mesh BuildMesh(MeshBuilder *mb); +static Mesh GenMeshDecal(Mesh inputMesh, Ray ray); +static Vector3 ClipSegment(Vector3 v0, Vector3 v1, Vector3 p, float s); //------------------------------------------------------------------------------------ // Program main entry point @@ -67,11 +71,10 @@ int main(void) Model model = LoadModel("resources/models/obj/character.obj"); // Apply character skin - Texture2D modelTexture = LoadTexture("resources/models/obj/character_diffuse.png"); // Load model texture + Texture2D modelTexture = LoadTexture("resources/models/obj/character_diffuse.png"); SetTextureFilter(modelTexture, TEXTURE_FILTER_BILINEAR); - model.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = modelTexture; // Set model diffuse texture + model.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = modelTexture; - BoundingBox modelBBox = GetMeshBoundingBox(model.meshes[0]); // Get mesh bounding box camera.target = Vector3Lerp(modelBBox.min, modelBBox.max, 0.5f); @@ -79,14 +82,12 @@ int main(void) camera.position.x *= 0.1f; float modelSize = fminf( - fminf(fabsf(modelBBox.max.x - modelBBox.min.x), - fabsf(modelBBox.max.y - modelBBox.min.y)), - fabsf(modelBBox.max.z - modelBBox.min.z) - ); + fminf(fabsf(modelBBox.max.x - modelBBox.min.x), fabsf(modelBBox.max.y - modelBBox.min.y)), + fabsf(modelBBox.max.z - modelBBox.min.z)); - camera.position = (Vector3){ 0, modelBBox.max.y * 1.2f, modelSize * 3.0f }; + camera.position = (Vector3){ 0.0f, modelBBox.max.y*1.2f, modelSize*3.0f }; - float decalSize = modelSize * .25f; + float decalSize = modelSize*0.25f; float decalOffset = 0.01f; Model placementCube = LoadModelFromMesh(GenMeshCube(decalSize, decalSize, decalSize)); @@ -96,7 +97,7 @@ int main(void) decalMaterial.maps[0].color = YELLOW; Image decalImage = LoadImage("resources/raylib_logo.png"); - ImageResizeNN(&decalImage, decalImage.width / 4, decalImage.height / 4); + ImageResizeNN(&decalImage, decalImage.width/4, decalImage.height/4); Texture decalTexture = LoadTextureFromImage(decalImage); UnloadImage(decalImage); @@ -106,28 +107,23 @@ int main(void) // We're going to use these to build up our decal meshes // They'll resize automatically as we go, we'll free them at the end - MeshBuilder mesh_builders[2] = { {0}, {0} }; + MeshBuilder meshBuilders[2] = { 0 }; bool showModel = true; - Model decalModels[MAX_DECALS] = {0}; + Model decalModels[MAX_DECALS] = { 0 }; int decalCount = 0; - 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 //---------------------------------------------------------------------------------- - - if (IsMouseButtonDown(MOUSE_BUTTON_RIGHT)) { - UpdateCamera(&camera, CAMERA_THIRD_PERSON); - } - - if (IsKeyPressed(KEY_SPACE)) { - showModel = !showModel; - } + if (IsMouseButtonDown(MOUSE_BUTTON_RIGHT)) UpdateCamera(&camera, CAMERA_THIRD_PERSON); + + if (IsKeyPressed(KEY_SPACE)) showModel = !showModel; // Display information about closest hit RayCollision collision = { 0 }; @@ -140,7 +136,7 @@ int main(void) // Check ray collision against bounding box first, before trying the full ray-mesh test RayCollision boxHitInfo = GetRayCollisionBox(ray, modelBBox); - if ((boxHitInfo.hit) && decalCount < MAX_DECALS) + if ((boxHitInfo.hit) && (decalCount < MAX_DECALS)) { // Check ray collision against model meshes RayCollision meshHitInfo = { 0 }; @@ -153,52 +149,47 @@ int main(void) if (meshHitInfo.hit) { // Save the closest hit mesh - if ((!collision.hit) || (collision.distance > meshHitInfo.distance)) collision = meshHitInfo; + if (!collision.hit || (collision.distance > meshHitInfo.distance)) collision = meshHitInfo; } } - if (meshHitInfo.hit) - { - collision = meshHitInfo; - } + if (meshHitInfo.hit) collision = meshHitInfo; } - // -------------- - - if (collision.hit && IsMouseButtonPressed(MOUSE_BUTTON_LEFT) && decalCount < MAX_DECALS) + // Add decal to mesh on hit point + if (collision.hit && IsMouseButtonPressed(MOUSE_BUTTON_LEFT) && (decalCount < MAX_DECALS)) { - // Create the transformation to project the decal Vector3 origin = Vector3Add(collision.point, Vector3Scale(collision.normal, 1.0f)); - Matrix splat = MatrixLookAt(collision.point, origin, (Vector3){0,1,0}); + Matrix splat = MatrixLookAt(collision.point, origin, (Vector3){ 0.0f, 1.0f, 0.0f }); // Spin the placement around a bit - splat = MatrixMultiply(splat, MatrixRotateZ(DEG2RAD * ((float)GetRandomValue(-180, 180)))); - + splat = MatrixMultiply(splat, MatrixRotateZ(DEG2RAD*((float)GetRandomValue(-180, 180)))); Matrix splatInv = MatrixInvert(splat); // Reset the mesh builders - mesh_builders[0].vertexCount = 0; - mesh_builders[1].vertexCount = 0; + meshBuilders[0].vertexCount = 0; + meshBuilders[1].vertexCount = 0; // We'll be flip-flopping between the two mesh builders // Reading from one and writing to the other, then swapping - int mb_index = 0; + int mbIndex = 0; - // First pass, just get any triangle inside the bounding box - // (for each mesh of the model) - for (int meshIndex = 0; meshIndex < model.meshCount; meshIndex++) { + // First pass, just get any triangle inside the bounding box (for each mesh of the model) + for (int meshIndex = 0; meshIndex < model.meshCount; meshIndex++) + { Mesh mesh = model.meshes[meshIndex]; for (int tri = 0; tri < mesh.triangleCount; tri++) { - Vector3 vertices[3]; + Vector3 vertices[3] = { 0 }; // The way we calculate the vertices of the mesh triangle // depend on whether the mesh vertices are indexed or not if (mesh.indices == 0) { - for (int v = 0; v < 3; v++) { - vertices[v] = (Vector3) { + for (int v = 0; v < 3; v++) + { + vertices[v] = (Vector3){ mesh.vertices[3*3*tri + 3*v + 0], mesh.vertices[3*3*tri + 3*v + 1], mesh.vertices[3*3*tri + 3*v + 2] @@ -209,7 +200,7 @@ int main(void) { for (int v = 0; v < 3; v++) { - vertices[v] = (Vector3) { + vertices[v] = (Vector3){ mesh.vertices[ 3*mesh.indices[3*tri+0] + v], mesh.vertices[ 3*mesh.indices[3*tri+1] + v], mesh.vertices[ 3*mesh.indices[3*tri+2] + v] @@ -225,19 +216,14 @@ int main(void) // To splat space Vector3 v = Vector3Transform(vertices[i], splat); - if (fabsf(v.x) 0) - { - AddTriangleToMeshBuilder(&mesh_builders[mb_index], vertices); - } + if (insideCount > 0) AddTriangleToMeshBuilder(&meshBuilders[mbIndex], vertices); } } @@ -250,20 +236,21 @@ int main(void) { 0, 0, 1 }, { 0, 0, -1 } }; + for (int face = 0; face < 6; face++) { // Swap current model builder (so we read from the one we just wrote to) - mb_index = 1 - mb_index; + mbIndex = 1 - mbIndex; - MeshBuilder *inMesh = &mesh_builders[1-mb_index]; - MeshBuilder *outMesh = &mesh_builders[mb_index]; + MeshBuilder *inMesh = &meshBuilders[1 - mbIndex]; + MeshBuilder *outMesh = &meshBuilders[mbIndex]; // Reset write builder outMesh->vertexCount = 0; - float s = 0.5f * decalSize; + float s = 0.5f*decalSize; - for (int i = 0; i < inMesh->vertexCount; i+=3) + for (int i = 0; i < inMesh->vertexCount; i += 3) { Vector3 nV1, nV2, nV3, nV4; @@ -271,100 +258,101 @@ int main(void) float d2 = Vector3DotProduct(inMesh->vertices[ i + 1 ], planes[face] ) - s; float d3 = Vector3DotProduct(inMesh->vertices[ i + 2 ], planes[face] ) - s; - int v1Out = d1 > 0; - int v2Out = d2 > 0; - int v3Out = d3 > 0; + int v1Out = (d1 > 0); + int v2Out = (d2 > 0); + int v3Out = (d3 > 0); - // calculate, how many vertices of the face lie outside of the clipping plane + // Calculate, how many vertices of the face lie outside of the clipping plane int total = v1Out + v2Out + v3Out; - switch ( total ) { - case 0: { - // the entire face lies inside of the plane, no clipping needed + switch (total) + { + case 0: + { + // The entire face lies inside of the plane, no clipping needed AddTriangleToMeshBuilder(outMesh, (Vector3[3]){inMesh->vertices[i], inMesh->vertices[i+1], inMesh->vertices[i+2]}); - break; - } - - case 1: { - // one vertex lies outside of the plane, perform clipping - - if (v1Out) { - nV1 = inMesh->vertices[ i + 1 ]; - nV2 = inMesh->vertices[ i + 2 ]; - nV3 = ClipSegment( inMesh->vertices[ i ], nV1, planes[face], s ); - nV4 = ClipSegment( inMesh->vertices[ i ], nV2, planes[face], s ); + } break; + case 1: + { + // One vertex lies outside of the plane, perform clipping + if (v1Out) + { + nV1 = inMesh->vertices[i + 1]; + nV2 = inMesh->vertices[i + 2]; + nV3 = ClipSegment(inMesh->vertices[i], nV1, planes[face], s); + nV4 = ClipSegment(inMesh->vertices[i], nV2, planes[face], s); } - if (v2Out) { - nV1 = inMesh->vertices[ i ]; - nV2 = inMesh->vertices[ i + 2 ]; - nV3 = ClipSegment( inMesh->vertices[ i + 1 ], nV1, planes[face], s ); - nV4 = ClipSegment( inMesh->vertices[ i + 1 ], nV2, planes[face], s ); + if (v2Out) + { + nV1 = inMesh->vertices[i]; + nV2 = inMesh->vertices[i + 2]; + nV3 = ClipSegment(inMesh->vertices[i + 1], nV1, planes[face], s); + nV4 = ClipSegment(inMesh->vertices[i + 1], nV2, planes[face], s); AddTriangleToMeshBuilder(outMesh, (Vector3[3]){nV3, nV2, nV1}); AddTriangleToMeshBuilder(outMesh, (Vector3[3]){nV2, nV3, nV4}); break; } - if (v3Out) { - nV1 = inMesh->vertices[ i ]; - nV2 = inMesh->vertices[ i + 1 ]; - nV3 = ClipSegment( inMesh->vertices[ i + 2 ], nV1, planes[face], s ); - nV4 = ClipSegment( inMesh->vertices[ i + 2 ], nV2, planes[face], s ); + if (v3Out) + { + nV1 = inMesh->vertices[i]; + nV2 = inMesh->vertices[i + 1]; + nV3 = ClipSegment(inMesh->vertices[i + 2], nV1, planes[face], s); + nV4 = ClipSegment(inMesh->vertices[i + 2], nV2, planes[face], s); } AddTriangleToMeshBuilder(outMesh, (Vector3[3]){nV1, nV2, nV3}); AddTriangleToMeshBuilder(outMesh, (Vector3[3]){nV4, nV3, nV2}); - - break; - } - - case 2: { - // two vertices lies outside of the plane, perform clipping - if (!v1Out) { - nV1 = inMesh->vertices[ i ]; - nV2 = ClipSegment( nV1, inMesh->vertices[ i + 1 ], planes[face], s ); - nV3 = ClipSegment( nV1, inMesh->vertices[ i + 2 ], planes[face], s ); + } break; + case 2: + { + // Two vertices lies outside of the plane, perform clipping + if (!v1Out) + { + nV1 = inMesh->vertices[i]; + nV2 = ClipSegment(nV1, inMesh->vertices[i + 1], planes[face], s); + nV3 = ClipSegment(nV1, inMesh->vertices[i + 2], planes[face], s); AddTriangleToMeshBuilder(outMesh, (Vector3[3]){nV1, nV2, nV3}); } - if (!v2Out) { - nV1 = inMesh->vertices[ i + 1 ]; - nV2 = ClipSegment( nV1, inMesh->vertices[ i + 2 ], planes[face], s ); - nV3 = ClipSegment( nV1, inMesh->vertices[ i ], planes[face], s ); + + if (!v2Out) + { + nV1 = inMesh->vertices[i + 1]; + nV2 = ClipSegment(nV1, inMesh->vertices[i + 2], planes[face], s); + nV3 = ClipSegment(nV1, inMesh->vertices[i], planes[face], s); AddTriangleToMeshBuilder(outMesh, (Vector3[3]){nV1, nV2, nV3}); } - if (!v3Out) { - nV1 = inMesh->vertices[ i + 2 ]; - nV2 = ClipSegment( nV1, inMesh->vertices[ i ], planes[face], s ); - nV3 = ClipSegment( nV1, inMesh->vertices[ i + 1 ], planes[face], s ); + + if (!v3Out) + { + nV1 = inMesh->vertices[i + 2]; + nV2 = ClipSegment(nV1, inMesh->vertices[i], planes[face], s); + nV3 = ClipSegment(nV1, inMesh->vertices[i + 1], planes[face], s); AddTriangleToMeshBuilder(outMesh, (Vector3[3]){nV1, nV2, nV3}); } - break; - } - - case 3: { - // the entire face lies outside of the plane, so let's discard the corresponding vertices - break; - } - + } break; + case 3: // The entire face lies outside of the plane, so let's discard the corresponding vertices + default: break; } } } // Now we just need to re-transform the vertices - MeshBuilder *theMesh = &mesh_builders[mb_index]; + MeshBuilder *theMesh = &meshBuilders[mbIndex]; // Allocate room for UVs if (theMesh->vertexCount > 0) { - theMesh->uvs = (Vector2*)MemAlloc(sizeof(Vector2)*theMesh->vertexCount); + theMesh->uvs = (Vector2 *)MemAlloc(sizeof(Vector2)*theMesh->vertexCount); + for (int i = 0; i < theMesh->vertexCount; i++) { - // Calculate the UVs based on the projected coords // They are clipped to (-decalSize .. decalSize) and we want them (0..1) - theMesh->uvs[i].x = (theMesh->vertices[i].x / decalSize + .5f); - theMesh->uvs[i].y = (theMesh->vertices[i].y / decalSize + .5f); + theMesh->uvs[i].x = (theMesh->vertices[i].x/decalSize + 0.5f); + theMesh->uvs[i].y = (theMesh->vertices[i].y/decalSize + 0.5f); // From splat space to world space theMesh->vertices[i] = Vector3Transform(theMesh->vertices[i], splatInv); @@ -378,89 +366,73 @@ int main(void) decalModels[decalIndex] = LoadModelFromMesh(BuildMesh(theMesh)); decalModels[decalIndex].materials[0] = decalMaterial; } - } - //---------------------------------------------------------------------------------- // Draw //---------------------------------------------------------------------------------- BeginDrawing(); - ClearBackground(RAYWHITE); BeginMode3D(camera); - // Draw the model at the origin and default scale - if (showModel) - { - DrawModel(model, (Vector3){0.0f, 0.0f, 0.0f}, 1.0f, WHITE); - } + if (showModel) DrawModel(model, (Vector3){0.0f, 0.0f, 0.0f}, 1.0f, WHITE); // Draw the decal models - for (int i = 0; i < decalCount; i++) - { - DrawModel(decalModels[i], (Vector3){0}, 1.0f, WHITE); - } + for (int i = 0; i < decalCount; i++) DrawModel(decalModels[i], (Vector3){0}, 1.0f, WHITE); // If we hit the mesh, draw the box for the decal if (collision.hit) { - Vector3 origin = Vector3Add(collision.point, Vector3Scale(collision.normal, 1.0f)); Matrix splat = MatrixLookAt(collision.point, origin, (Vector3){0,1,0}); - placementCube.transform = MatrixInvert(splat); DrawModel(placementCube, (Vector3){0}, 1.0f, Fade(WHITE, 0.5f)); } DrawGrid(10, 10.0f); - EndMode3D(); + + float yPos = 10; + float x0 = GetScreenWidth() - 300; + float x1 = x0 + 100; + float x2 = x1 + 100; + DrawText("Vertices", x1, yPos, 10, LIME); + DrawText("Triangles", x2, yPos, 10, LIME); + yPos += 15; + + int vertexCount = 0; + int triangleCount = 0; + + for (int i = 0; i < model.meshCount; i++) { - float yPos = 10; - float x0 = GetScreenWidth() - 300; - float x1 = x0 + 100; - float x2 = x1 + 100; + vertexCount += model.meshes[i].vertexCount; + triangleCount += model.meshes[i].triangleCount; + } + + DrawText("Main model", x0, yPos, 10, LIME); + DrawText(TextFormat("%d", vertexCount), x1, yPos, 10, LIME); + DrawText(TextFormat("%d", triangleCount), x2, yPos, 10, LIME); + yPos += 15; + + for (int i = 0; i < decalCount; i++) + { + DrawText(TextFormat("Decal #%d", i+1), x0, yPos, 10, LIME); + DrawText(TextFormat("%d", decalModels[i].meshes[0].vertexCount), x1, yPos, 10, LIME); + DrawText(TextFormat("%d", decalModels[i].meshes[0].triangleCount), x2, yPos, 10, LIME); - DrawText("Vertices", x1, yPos, 10, LIME); - DrawText("Triangles", x2, yPos, 10, LIME); - yPos += 15; - - int vertexCount = 0; - int triangleCount = 0; - - for (int i = 0; i < model.meshCount; i++) - { - vertexCount += model.meshes[i].vertexCount; - triangleCount += model.meshes[i].triangleCount; - } - - DrawText("Main model", x0, yPos, 10, LIME); - DrawText(TextFormat("%d", vertexCount), x1, yPos, 10, LIME); - DrawText(TextFormat("%d", triangleCount), x2, yPos, 10, LIME); - yPos += 15; - - for (int i = 0; i < decalCount; i++) - { - DrawText(TextFormat("Decal #%d", i+1), x0, yPos, 10, LIME); - DrawText(TextFormat("%d", decalModels[i].meshes[0].vertexCount), x1, yPos, 10, LIME); - DrawText(TextFormat("%d", decalModels[i].meshes[0].triangleCount), x2, yPos, 10, LIME); - - vertexCount += decalModels[i].meshes[0].vertexCount; - triangleCount += decalModels[i].meshes[0].triangleCount; - yPos += 15; - } - - DrawText("TOTAL", x0, yPos, 10, LIME); - DrawText(TextFormat("%d", vertexCount), x1, yPos, 10, LIME); - DrawText(TextFormat("%d", triangleCount), x2, yPos, 10, LIME); + vertexCount += decalModels[i].meshes[0].vertexCount; + triangleCount += decalModels[i].meshes[0].triangleCount; yPos += 15; } + + DrawText("TOTAL", x0, yPos, 10, LIME); + DrawText(TextFormat("%d", vertexCount), x1, yPos, 10, LIME); + DrawText(TextFormat("%d", triangleCount), x2, yPos, 10, LIME); + yPos += 15; DrawText("Hold RMB to move camera", 10, 430, 10, GRAY); - DrawText("(c) Character model and texture from kenney.nl", screenWidth - 260, screenHeight - 20, 10, GRAY); DrawFPS(10, 10); @@ -474,15 +446,13 @@ int main(void) UnloadModel(model); UnloadTexture(modelTexture); - for (int i = 0; i < decalCount; i++) - { - UnloadModel(decalModels[i]); - } - + // TODO: WARNING: This line crashes program on closing + //for (int i = 0; i < decalCount; i++) UnloadModel(decalModels[i]); + UnloadTexture(decalTexture); - FreeMeshBuilder(&mesh_builders[0]); - FreeMeshBuilder(&mesh_builders[1]); + FreeMeshBuilder(&meshBuilders[0]); + FreeMeshBuilder(&meshBuilders[1]); CloseWindow(); // Close window and OpenGL context //-------------------------------------------------------------------------------------- @@ -490,18 +460,24 @@ int main(void) return 0; } -// A really simple dynamic array manager -void AddTriangleToMeshBuilder(MeshBuilder *mb, Vector3 vertices[3]) { +//---------------------------------------------------------------------------------- +// Module Functions Definition +//---------------------------------------------------------------------------------- +// Add triangles to mesh builder (dynamic array manager) +static void AddTriangleToMeshBuilder(MeshBuilder *mb, Vector3 vertices[3]) +{ // Reallocate and copy if we need to - if (mb->vertexCapacity <= mb->vertexCount + 3 ) + if (mb->vertexCapacity <= (mb->vertexCount + 3)) { - int newVertexCapacity = (1 + (mb->vertexCapacity / 256)) * 256; - Vector3 *newVertices = (Vector3*)MemAlloc(newVertexCapacity * sizeof(Vector3)); + int newVertexCapacity = (1 + (mb->vertexCapacity/256))*256; + Vector3 *newVertices = (Vector3 *)MemAlloc(newVertexCapacity*sizeof(Vector3)); + if (mb->vertexCapacity > 0) { - memcpy(newVertices, mb->vertices, mb->vertexCount * sizeof(Vector3)); + memcpy(newVertices, mb->vertices, mb->vertexCount*sizeof(Vector3)); MemFree(mb->vertices); } + mb->vertices = newVertices; mb->vertexCapacity = newVertexCapacity; } @@ -510,44 +486,33 @@ void AddTriangleToMeshBuilder(MeshBuilder *mb, Vector3 vertices[3]) { int index = mb->vertexCount; mb->vertexCount += 3; - for (int i = 0; i < 3; i++) - { - mb->vertices[index+i] = vertices[i]; - } + for (int i = 0; i < 3; i++) mb->vertices[index+i] = vertices[i]; } -void FreeMeshBuilder(MeshBuilder *mb) +// Free mesh builder +static void FreeMeshBuilder(MeshBuilder *mb) { MemFree(mb->vertices); - - if (mb->uvs) - { - MemFree(mb->uvs); - } - + if (mb->uvs) MemFree(mb->uvs); *mb = (MeshBuilder){ 0 }; } -// Construct a Raylib Mesh from our MeshBuilder data -Mesh BuildMesh(MeshBuilder *mb) +// Build a Mesh from MeshBuilder data +static Mesh BuildMesh(MeshBuilder *mb) { Mesh outMesh = { 0 }; outMesh.vertexCount = mb->vertexCount; - outMesh.triangleCount = mb->vertexCount / 3; - - outMesh.vertices = MemAlloc(outMesh.vertexCount * 3 * sizeof(float)); - - if (mb->uvs) - { - outMesh.texcoords = MemAlloc(outMesh.vertexCount * 2 * sizeof(float)); - } - + outMesh.triangleCount = mb->vertexCount/3; + outMesh.vertices = MemAlloc(outMesh.vertexCount*3*sizeof(float)); + if (mb->uvs) outMesh.texcoords = MemAlloc(outMesh.vertexCount*2*sizeof(float)); + for (int i = 0; i < mb->vertexCount; i++) { outMesh.vertices[3*i+0] = mb->vertices[i].x; outMesh.vertices[3*i+1] = mb->vertices[i].y; outMesh.vertices[3*i+2] = mb->vertices[i].z; + if (mb->uvs) { outMesh.texcoords[2*i+0] = mb->uvs[i].x; @@ -560,14 +525,14 @@ Mesh BuildMesh(MeshBuilder *mb) return outMesh; } -Vector3 ClipSegment(Vector3 v0, Vector3 v1, Vector3 p, float s) +// Clip segment +static Vector3 ClipSegment(Vector3 v0, Vector3 v1, Vector3 p, float s) { float d0 = Vector3DotProduct(v0, p) - s; float d1 = Vector3DotProduct(v1, p) - s; - - float s0 = d0 / ( d0 - d1 ); + float s0 = d0/(d0 - d1); Vector3 position = Vector3Lerp(v0, v1, s0); return position; -} \ No newline at end of file +} From 6f101f40110cf1e5f49792ec2bf1ae4dfa0d3ab6 Mon Sep 17 00:00:00 2001 From: Jopestpe <47086979+Jopestpe@users.noreply.github.com> Date: Sat, 25 Oct 2025 08:38:06 -0300 Subject: [PATCH 166/167] [examples] Added: `shapes_math_sine_cosine` (#5257) * draft: [examples] Added shapes_math_sine_cosine * draft: [examples] Added screenshot shapes_math_sine_cosine * Explementary * Varying radius * adjustments * added comments and reorganized UI labels * Updated Makefile, README.md, and examples_list.txt * tabs to spaces * Fix MSVC compilation --------- Co-authored-by: Ray --- examples/Makefile | 1 + examples/Makefile.Web | 4 + examples/README.md | 2 +- examples/examples_list.txt | 1 + examples/shapes/shapes_math_sine_cosine.c | 176 ++++++++++++++++++++ examples/shapes/shapes_math_sine_cosine.png | Bin 0 -> 22098 bytes 6 files changed, 183 insertions(+), 1 deletion(-) create mode 100644 examples/shapes/shapes_math_sine_cosine.c create mode 100644 examples/shapes/shapes_math_sine_cosine.png diff --git a/examples/Makefile b/examples/Makefile index ef7cb5948..9ae8bb480 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -564,6 +564,7 @@ SHAPES = \ shapes/shapes_lines_bezier \ shapes/shapes_logo_raylib \ shapes/shapes_logo_raylib_anim \ + shapes/shapes_math_sine_cosine \ shapes/shapes_mouse_trail \ shapes/shapes_pie_chart \ shapes/shapes_rectangle_advanced \ diff --git a/examples/Makefile.Web b/examples/Makefile.Web index 5d4f3ffab..0e9b9f92f 100644 --- a/examples/Makefile.Web +++ b/examples/Makefile.Web @@ -564,6 +564,7 @@ SHAPES = \ shapes/shapes_lines_bezier \ shapes/shapes_logo_raylib \ shapes/shapes_logo_raylib_anim \ + shapes/shapes_math_sine_cosine \ shapes/shapes_mouse_trail \ shapes/shapes_pie_chart \ shapes/shapes_rectangle_advanced \ @@ -899,6 +900,9 @@ shapes/shapes_logo_raylib: shapes/shapes_logo_raylib.c shapes/shapes_logo_raylib_anim: shapes/shapes_logo_raylib_anim.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) +shapes/shapes_math_sine_cosine: shapes/shapes_math_sine_cosine.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) + shapes/shapes_mouse_trail: shapes/shapes_mouse_trail.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) diff --git a/examples/README.md b/examples/README.md index 19d110344..bbb0a0388 100644 --- a/examples/README.md +++ b/examples/README.md @@ -71,7 +71,7 @@ Examples using raylib[core](../src/rcore.c) platform functionality like window c | [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] +### category: shapes [32] Examples using raylib shapes drawing functionality, provided by raylib [shapes](../src/rshapes.c) module. diff --git a/examples/examples_list.txt b/examples/examples_list.txt index 71cda6c1a..4805a37ec 100644 --- a/examples/examples_list.txt +++ b/examples/examples_list.txt @@ -80,6 +80,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_math_sine_cosine;★★☆☆;5.6-dev;5.6-dev;2025;2025;"Jopestpe";@jopestpe 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 diff --git a/examples/shapes/shapes_math_sine_cosine.c b/examples/shapes/shapes_math_sine_cosine.c new file mode 100644 index 000000000..f61d4f548 --- /dev/null +++ b/examples/shapes/shapes_math_sine_cosine.c @@ -0,0 +1,176 @@ +/******************************************************************************************* +* +* raylib [shapes] example - math sine cosine +* +* Example complexity rating: [★★☆☆] 2/4 +* +* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev +* +* Example contributed by Jopestpe (@jopestpe) +* +* 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 Jopestpe (@jopestpe) +* +********************************************************************************************/ + +#include "raylib.h" +#include +#include "raymath.h" + +#define RAYGUI_IMPLEMENTATION +#include "raygui.h" // Required for GUI controls + +// Wave points for sine/cosine visualization +#define WAVE_POINTS 36 + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + SetConfigFlags(FLAG_MSAA_4X_HINT); + InitWindow(screenWidth, screenHeight, "raylib [shapes] example - math sine cosine"); + + Vector2 sinePoints[WAVE_POINTS]; + Vector2 cosPoints[WAVE_POINTS]; + Vector2 center = { (screenWidth/2.0f) - 30.f, screenHeight/2.0f }; + Rectangle start = { 20.f, screenHeight - 120.f , 200.0f, 100.0f}; + float radius = 130.0f; + float angle = 0.0f; + bool pause = false; + + for (int i = 0; i < WAVE_POINTS; i++) + { + float t = i/(float)(WAVE_POINTS - 1); + float currentAngle = t*360.0f*DEG2RAD; + sinePoints[i] = (Vector2){ start.x + t*start.width, start.y + start.height/2.0f - sinf(currentAngle)*(start.height/2.0f) }; + cosPoints[i] = (Vector2){ start.x + t*start.width, start.y + start.height/2.0f - cosf(currentAngle)*(start.height/2.0f) }; + } + + 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 + //---------------------------------------------------------------------------------- + float angleRad = angle*DEG2RAD; + float cosRad = cosf(angleRad); + float sinRad = sinf(angleRad); + + Vector2 point = { center.x + cosRad*radius, center.y - sinRad*radius }; + Vector2 limitMin = { center.x - radius, center.y - radius }; + Vector2 limitMax = { center.x + radius, center.y + radius }; + + float complementary = 90.0f - angle; + float supplementary = 180.0f - angle; + float explementary = 360.0f - angle; + + float tangent = Clamp(tanf(angleRad), -10.0f, 10.0f); + float cotangent = (fabsf(tangent) > 0.001f) ? Clamp(1.0f/tangent, -radius, radius) : 0.0f; + Vector2 tangentPoint = { center.x + radius, center.y - tangent*radius }; + Vector2 cotangentPoint = { center.x + cotangent*radius, center.y - radius }; + + angle = Wrap(angle + (!pause ? 1.0f : 0.0f), 0.0f, 360.0f); + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + ClearBackground(RAYWHITE); + + // Cotangent (orange) + DrawLineEx((Vector2){ center.x , limitMin.y }, (Vector2){ cotangentPoint.x, limitMin.y }, 2.0f, ORANGE); + DrawLineDashed(center, cotangentPoint, 10.0f, 4.0f, ORANGE); + + // Side background + DrawLine(580, 0, 580, GetScreenHeight(), (Color){ 218, 218, 218, 255 }); + DrawRectangle(580, 0, GetScreenWidth(), GetScreenHeight(), (Color){ 232, 232, 232, 255 }); + + // Base circle and axes + DrawCircleLinesV(center, radius, GRAY); + DrawLineEx((Vector2){ center.x, limitMin.y }, (Vector2){ center.x, limitMax.y }, 1.0f, GRAY); + DrawLineEx((Vector2){ limitMin.x, center.y }, (Vector2){ limitMax.x, center.y }, 1.f, GRAY); + + // Wave graph axes + DrawLineEx((Vector2){ start.x , start.y }, (Vector2){ start.x , start.y + start.height }, 2.0f, GRAY); + DrawLineEx((Vector2){ start.x + start.width, start.y }, (Vector2){ start.x + start.width, start.y + start.height }, 2.0f, GRAY); + DrawLineEx((Vector2){ start.x, start.y + start.height/2 }, (Vector2){ start.x + start.width, start.y + start.height/2 }, 2.0f, GRAY); + + // Wave graph axis labels + DrawText("1", start.x - 8, start.y, 6, GRAY); + DrawText("0", start.x - 8, start.y + start.height/2 - 6, 6, GRAY); + DrawText("-1", start.x - 12, start.y + start.height - 8, 6, GRAY); + DrawText("0", start.x - 2, start.y + start.height + 4, 6, GRAY); + DrawText("360", start.x + start.width - 8, start.y + start.height + 4, 6, GRAY); + + // Sine (red - vertical) + DrawLineEx((Vector2){ center.x, center.y }, (Vector2){ center.x, point.y }, 2.0f, RED); + DrawLineDashed((Vector2){ point.x, center.y }, (Vector2){ point.x, point.y }, 10.0f, 4.0f, RED); + DrawText(TextFormat("Sine %.2f", sinRad), 640, 190, 6, RED); + DrawCircleV((Vector2){ start.x + (angle/360.0f)*start.width, start.y + ((-sinRad + 1)*start.height/2.0f) }, 4.0f, RED); + DrawSplineLinear(sinePoints, WAVE_POINTS, 1.0f, RED); + + // Cosine (blue - horizontal) + DrawLineEx((Vector2){ center.x, center.y }, (Vector2){ point.x, center.y }, 2.0f, BLUE); + DrawLineDashed((Vector2){ center.x , point.y }, (Vector2){ point.x, point.y }, 10.0f, 4.0f, BLUE); + DrawText(TextFormat("Cosine %.2f", cosRad), 640, 210, 6, BLUE); + DrawCircleV((Vector2){ start.x + (angle/360.0f)*start.width, start.y + ((-cosRad + 1)*start.height/2.0f) }, 4.0f, BLUE); + DrawSplineLinear(cosPoints, WAVE_POINTS, 1.0f, BLUE); + + // Tangent (purple) + DrawLineEx((Vector2){ limitMax.x , center.y }, (Vector2){ limitMax.x, tangentPoint.y }, 2.0f, PURPLE); + DrawLineDashed(center, tangentPoint, 10.0f, 4.0f, PURPLE); + DrawText(TextFormat("Tangent %.2f", tangent), 640, 230, 6, PURPLE); + + // Cotangent (orange) + DrawText(TextFormat("Cotangent %.2f", cotangent), 640, 250, 6, ORANGE); + + // Complementary angle (beige) + DrawCircleSectorLines(center, radius*0.6f , -angle, -90.f , 36.0f, BEIGE); + DrawText(TextFormat("Complementary %0.f°",complementary), 640, 150, 6, BEIGE); + + // Supplementary angle (darkblue) + DrawCircleSectorLines(center, radius*0.5f , -angle, -180.f , 36.0f, DARKBLUE); + DrawText(TextFormat("Supplementary %0.f°",supplementary), 640, 130, 6, DARKBLUE); + + // Explementary angle (pink) + DrawCircleSectorLines(center, radius*0.4f , -angle, -360.f , 36.0f, PINK); + DrawText(TextFormat("Explementary %0.f°",explementary), 640, 170, 6, PINK); + + // Current angle - arc (lime), radius (black), endpoint (black) + DrawCircleSectorLines(center, radius*0.7f , -angle, 0.f, 36.0f, LIME); + DrawLineEx((Vector2){ center.x , center.y }, point, 2.0f, BLACK); + DrawCircleV(point, 4.0f, BLACK); + + // Draw GUI controls + //------------------------------------------------------------------------------ + GuiSetStyle(LABEL, TEXT_COLOR_NORMAL, ColorToInt(GRAY)); + GuiToggle((Rectangle){ 640, 70, 120, 20}, TextFormat("Pause"), &pause); + GuiSetStyle(LABEL, TEXT_COLOR_NORMAL, ColorToInt(LIME)); + GuiSliderBar((Rectangle){ 640, 40, 120, 20}, "Angle", TextFormat("%.0f°", angle), &angle, 0.0f, 360.f); + + // Angle values panel + GuiGroupBox((Rectangle){ 620, 110, 140, 170}, "Angle Values"); + //------------------------------------------------------------------------------ + DrawFPS(10, 10); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} \ No newline at end of file diff --git a/examples/shapes/shapes_math_sine_cosine.png b/examples/shapes/shapes_math_sine_cosine.png new file mode 100644 index 0000000000000000000000000000000000000000..b561f74fbbd06ab006df7e5789e79a6cba255b07 GIT binary patch literal 22098 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 PL%{ExzL{Pr&L#SP=KmFB literal 0 HcmV?d00001 From a25d11ad1a3d7c5660127229a3a9ffd62a2225e4 Mon Sep 17 00:00:00 2001 From: Kris Date: Sat, 25 Oct 2025 17:12:35 +0530 Subject: [PATCH 167/167] Add example: shapes_math_angle_rotation (angle rotation lines) (#5236) Co-authored-by: Ray --- examples/shaders/shaders_palette_switch.c | 4 +- examples/shapes/shapes_math_angle_rotation.c | 102 ++++ .../shapes/shapes_math_angle_rotation.png | Bin 0 -> 4869 bytes .../shapes_math_angle_rotation.vcxproj | 569 ++++++++++++++++++ projects/VS2022/raylib.sln | 2 + 5 files changed, 675 insertions(+), 2 deletions(-) create mode 100644 examples/shapes/shapes_math_angle_rotation.c create mode 100644 examples/shapes/shapes_math_angle_rotation.png create mode 100644 projects/VS2022/examples/shapes_math_angle_rotation.vcxproj diff --git a/examples/shaders/shaders_palette_switch.c b/examples/shaders/shaders_palette_switch.c index 048fe7fbc..e23cad1d3 100644 --- a/examples/shaders/shaders_palette_switch.c +++ b/examples/shaders/shaders_palette_switch.c @@ -1,6 +1,6 @@ /******************************************************************************************* * -* raylib [shaders] example - palette switch +* raylib [shaders] example - palette switch * * Example complexity rating: [★★★☆] 3/4 * @@ -11,7 +11,7 @@ * on OpenGL ES 2.0 platforms (Android, Raspberry Pi, HTML5), use #version 100 shaders * raylib comes with shaders ready for both versions, check raylib/shaders install folder * -* Example originally created with raylib 2.5, last time updated with raylib 3.7 +* Example originally created with raylib 2.5, last time updated with raylib 3.7 * * Example contributed by Marco Lizza (@MarcoLizza) and reviewed by Ramon Santamaria (@raysan5) * diff --git a/examples/shapes/shapes_math_angle_rotation.c b/examples/shapes/shapes_math_angle_rotation.c new file mode 100644 index 000000000..0e4802064 --- /dev/null +++ b/examples/shapes/shapes_math_angle_rotation.c @@ -0,0 +1,102 @@ +/******************************************************************************************* +* +* raylib [shapes] example - Math angle rotation lines +* +* Example complexity rating: [★☆☆☆] 1/4 +* +* Example originally created with raylib 5.5, last time updated with raylib 5.6 +* +* Example contributed by Kris (@krispy-snacc) and reviewed by Ramon Santamaria (@raysan5) +* +* Example licensed under an unmodified zlib/libpng license +* +********************************************************************************************/ + +#include "raylib.h" +#include "raymath.h" // for DEG2RAD + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 720; + const int screenHeight = 400; + + InitWindow(screenWidth, screenHeight, "raylib [shapes] example - angle rotation lines"); + SetTargetFPS(60); + + Vector2 center = { screenWidth / 2.0f, screenHeight / 2.0f }; + const float lineLength = 150.0f; + + // Predefined angles for fixed lines + int angles[] = { 0, 30, 60, 90 }; + int numAngles = sizeof(angles)/sizeof(angles[0]); + + float totalAngle = 0.0f; // Animated rotation angle + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) + { + // Update + //---------------------------------------------------------------------------------- + totalAngle += 1.0f; // degrees per frame + if (totalAngle >= 360.0f) totalAngle -= 360.0f; + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + ClearBackground(WHITE); + + DrawText("Fixed angles + rotating line", 10, 10, 20, LIGHTGRAY); + + // Draw fixed-angle lines with colorful gradient + for (int i = 0; i < numAngles; i++) + { + float rad = angles[i] * DEG2RAD; + Vector2 end = { center.x + cosf(rad) * lineLength, + center.y + sinf(rad) * lineLength }; + + // Gradient color from green → cyan → blue → magenta + Color col; + switch(i) + { + case 0: col = GREEN; break; + case 1: col = ORANGE; break; + case 2: col = BLUE; break; + case 3: col = MAGENTA; break; + default: col = WHITE; break; + } + + DrawLineEx(center, end, 5.0f, col); + + // Draw angle label slightly offset along the line + Vector2 textPos = { center.x + cosf(rad) * (lineLength + 20), + center.y + sinf(rad) * (lineLength + 20) }; + DrawText(TextFormat("%d°", angles[i]), (int)textPos.x, (int)textPos.y, 20, col); + } + + // Draw animated rotating line with changing color + float animRad = totalAngle * DEG2RAD; + Vector2 animEnd = { center.x + cosf(animRad) * lineLength, + center.y + sinf(animRad) * lineLength }; + + // Cycle through HSV colors for animated line + Color animCol = ColorFromHSV(fmodf(totalAngle, 360.0f), 0.8f, 0.9f); + DrawLineEx(center, animEnd, 5.0f, animCol); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + CloseWindow(); + //-------------------------------------------------------------------------------------- + + return 0; +} diff --git a/examples/shapes/shapes_math_angle_rotation.png b/examples/shapes/shapes_math_angle_rotation.png new file mode 100644 index 0000000000000000000000000000000000000000..fd9a92360b6c2f187c91324a3b2005bb83471e5d GIT binary patch literal 4869 zcmeHLd010d7C$c}CF}tUf}jcFQc4u1Dkw?dnK#43#JZvYVm4V_X^ zi(&^+rVth-6&bEdT(}< z&{{{}9dro5uu1d7r2OJN04C=)ySsjJBxIoL(LozIcC=Mnn>HjO)_oqw)|bRN8QB5p zuN&Wo9fd#K*J)0$`}0`%dk!zQGe&t8Q)Auhw+FAO(Qyl0d4_7w{3&C%Ir5DuDR^ax zjL8-=0dRAS0C1a30ib!}=;>+#5g^l;hUBsV0|+OQ0Vp>A7VSh@URm;nhK5vI{p#!M zzxri3ZoEe{Ffj5kW>nfZpQm;n`-wjkV=IzAsaXgL8@fis|FoTSX}WH*nqAOH^@~$Y+8!FRk4aKbgw_|>s^op`@%i;H zTpEhX%Bg&1&5tGH&Z;=^j`D&4#s%5Hp~k^ZC5H1Va6lnkGt046`8g;HE`E2QT)0!- z{_0oN!Tqn^1gq5TQt@PBQgBI&Tq;t2rg}X&Q8+m6STwGDl$01Km-i}rcC?QNQm?nk z-%5VHA(Xc(v^#_J<62nWBU^R+T{`>UyvMqeeuzI^C4g48^N?vye6 z8QZUAtdjq*g~e+v?rI!VPs&yc3<$)qh=>vYZ^8B?*%mqE=hqX>!l8WFgpMzqe4{Q` zZQal4YDkoLW(+Ze$yJ@nQ*8_FC9la8+(0Z7t`-iFES9>16JUgjk6L8Hdt}>C7BRLs z#QXAT6Gc9eEb)9%O6`6b*K%wv5kHT5q-E3{=`~f);8@d8=wkOw5HOJs(hO>234fC9 zm;S!}140;sNM?3;$%M5}jb>(4butQ^az}_rdK;^H3dO03^Q=A4hx!B}tyr8)_sN8c z2u&c!e(j*?Gk>II$Oxk;*Xgr*XIR*9>PNc55HS21^_ z+9y5k1=jCwwfqpi-;9IR$Gm|fwr=rmw;x;uP7Yuk|8VuhDr*8WXB>ypC_3}p$m+3r z^_P2J%6@L;de_XUW8NVUD*jSA!TI4BtFXwC9?v4dB82V57n7A2WeyHmd68I!3Bop2 zEEm?cvvZuS36fg~9q({;_0Bz{xVCxLcaX(1FSfn}J)VgACFU?zpV0f!VLK;wkaxUI zp(7Wn-$yh^4LK#W8M#Ua7sRc6Ca*7Qg-sS^G1Q?YeUDOAXlh-eJf7pwQ?wKE&jIFi zWBZOAXC4{O*Xb+_!?H@L5#4!>!}^=dtVUukIXcAum4pXYqR{rR6HBA%KI}+i?4m0U ziQ9PU4jAP^Pd+y~yd2#Vm-d0|*x*jK8E{;7Tv`uJvL z$Bog6wmL0@kw{bUcA2eT%Uwr8y=VRzth+xF)?@FzMSm668feD{- zV$|kSA@Mig<|MXoF04mr({+jZVuIX}6jjA>2VV~y4u2-1ddaz-u~(M6-Os*5#J3*N zF=HNMC(>(@vy-~(ZfOuV6z7b3dh)A)5`kfgBZxM+nFGmA{AC5YCwq)Wk(h(4AUn_3AHIyy@|wp_4cj?ae?k{dgs)gL@vNqc_6u6Y-K z�#!_#s$6c)mHR>ejP0bqpfS2PIqFH+gd`oy&VZajU4>@Z1v?@*mn^WmMC%e zCU1HmxY<33o+sgWIUp=RytX-1)YtzvU3bK83$+(f6Tv0 zSh+7xDeV});vAQ;NK?GQ+}RK$Iw*vOAJ@1TM$vs%wxGIMrbAJD&Q)sfmz_F`!uS%f zisZV7x(?rHvYdAS%g0gm=Ka8B#2V8gy3+>xEow}y%>H6HhpskC<4XSgk(;mMg3Oq< zW)y`_Y<+TW1f6zA_iFxZs&Orp+PsRX2`9=om6Y9Ba4ukB#-hmd<(ETFtNN`ZuE>MY zQtE?isr2X%5!XOya;~d;GvT(jARNJCrPPLKFC4B! zsyPLwMEnMkEU=XcpNkh0;Vzk?$StKly_O2A&@gf3$q6H+G@fghNyaWN(;O$!u#ta4 z72(XLKs=Hiy{%pP^2*Z*ZDtx^zJ=oCoCp#Yc7MP5dnpG@osL$*`nJi{W2~Mu7nYFZ zW#`KY8d`90MyV_h>E7^OF^7oWm!m`zPMwnn-9$x&;%vdT8LPVtSb)-5vd@DI@})@h zYO+H<{=s2@q8b^}l?l}dk8N+39#%x5_G3%f(?8$j{IEql-HChf79l?6Nqbx9y7IUg z^6+95g!z?I!Ys=y6L@@&K(M;or?sbFyJdM2Vw0gAS+W)d&2magT(w{+&Uu zgEv62hTi2&ybHBqkc=Q#b4sbwy(Fx98Aj+or|RkC8WSXOD4&8-YA<^3WRISoR`o2H z&5hG?v`58BvWYLno?y(@kr>D9}a>e$aW8f#zgv-W{YSM*RcveByYTczJFrG zc?1)zy1v^yW6~2BcgZRKzbM$<+k8g!4J7waBdE81qXs}l{AugC&q>F5N#*FdAyrgTL(K1m+&X<&)7hP zgP!K%0Da$4D0B0#Wu!I6Cn?Q=9sW*Z!Wyx68ydK|Ne$vNRW4L8n|p;$Zl(q&jev9Z z?frw~Le~OB&28^)CK5hrbS#_(JWVtA{^u=4kNr1V{r*Gzni@u0OZ_5P_b*#W?2qB} o9e)3Xna$h2{QE9}W(ofy + + + + 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 + shapes_math_angle_rotation + 10.0 + shapes_math_angle_rotation + + + + 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\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + 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 ec35ed5e5..8d2704abf 100644 --- a/projects/VS2022/raylib.sln +++ b/projects/VS2022/raylib.sln @@ -395,6 +395,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_text_file_loading", "e EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shaders_mandelbrot_set", "examples\shaders_mandelbrot_set.vcxproj", "{1C829D1A-892C-451C-AF0B-AC65C85F5CC6}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_math_angle_rotation", "examples\shapes_math_angle_rotation.vcxproj", "{6B1A933E-71B8-4C1F-9E79-02D98830E671}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug.DLL|ARM64 = Debug.DLL|ARM64

5=3z&^$j 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 s$8SCT%`DKW|Nr6t& Date: Sun, 28 Sep 2025 23:47:39 +0200 Subject: [PATCH 043/167] Update examples_report.md --- tools/rexm/examples_report.md | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/rexm/examples_report.md b/tools/rexm/examples_report.md index bb37b2db7..7c9de0b57 100644 --- a/tools/rexm/examples_report.md +++ b/tools/rexm/examples_report.md @@ -57,6 +57,7 @@ Example elements validated: | core_high_dpi | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | core_render_texture | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | core_undo_redo | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| core_input_actions | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shapes_basic_shapes | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shapes_bouncing_ball | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shapes_colors_palette | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | From f76666af3f08765037f2b5b5b350eb70a61202ec Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 28 Sep 2025 23:48:10 +0200 Subject: [PATCH 044/167] REXM: Avoid updating metadata from `others` examples --- 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 7f303538c..f6c297769 100644 --- a/tools/rexm/rexm.c +++ b/tools/rexm/rexm.c @@ -2331,7 +2331,7 @@ static const char *GenerateUUIDv4(void) // Update source code header and comments metadata static void UpdateSourceMetadata(const char *exSrcPath, const rlExampleInfo *info) { - if (FileExists(exSrcPath) && IsFileExtension(exSrcPath, ".c")) + if (FileExists(exSrcPath) && IsFileExtension(exSrcPath, ".c") && (!TextIsEqual(info->category, "others"))) { // WARNING: Cache a copy of exSrcPath to avoid modifications by TextFormat() char exSourcePath[512] = { 0 }; From 584bc14929d3083c6a5a6c8979d6989cd17fc9a5 Mon Sep 17 00:00:00 2001 From: Le Juez Victor <90587919+Bigfoot71@users.noreply.github.com> Date: Mon, 29 Sep 2025 10:28:20 +0200 Subject: [PATCH 045/167] [rlgl] Add Software Rendering Support (#4832) * add base of rlsw.h * implement state support Also replace the triangle rasterization functions with macros that generate specific functions for each state of the rendering system. Also, add the OpenGL definitions in order to add a binding for rlgl. * branchless float saturation * apply perspective correction to colors * impl line clipping and rasterization + tweak function names * impl face culling * impl color blending * fixes and tweaks * add clear buffer bitmasks * small optimizations / tweaks * review ndc to screen projection * avoid to recalculate MVP when its not needed + tweaks * review the loading and management of textures to be closer to the OpenGL API * texture sampling optimization * review get pixel functions + review unorm/float conversion * add several buffer format support Several depth and color formats have been added for the framebuffer. 8-bit, 16-bit, and 24-bit formats are now available for depth. RGB 8-bit (332), RGB 16-bit (565), and RGB 24-bit (888) formats are now available for color. Alpha support is no longer present for the framebuffer at the moment, but it can easily be restored by adding the formats and reinterpolating the alpha in the areas that do not perform color blending. Additionally, this commit brings performance improvements. * tweaks * impl line width * impl points + point size * fix and improve polygon clipping functions * impl polygone modes * add some not planned functions - `glDepthMask` - `glColorMask` * framebuffer resizing + handle init failure * add quick notes about line clipping algorithms used * start to impl scissor test + review line clipping The support for the scissor test has been implemented for clearing as well as for triangle clipping. The implementation for lines and points is still missing. I also removed the 2D clipping of lines that used the Cohen-Sutherland algorithm, opting instead to always use the Liang-Barsky algorithm in all cases. This simplifies the implementation, and the 2D version would have caused issues when interpolating vertices in the future if we want to implement additional features. * review scissor clear * review `swScissor` * impl line scissor clipping * round screen coordinate (line rasterization) * impl point scissor clipping * remove unused defs * add getter functions * gl binding * add `glHint` and `glShadeModel` macros (not implmented) * binding tweaks * impl copy framebuffer function + glReadPixels * review `swCopyFramebuffer` * update rlgl.h * update rlgl.h * texture copy support * fix typo.. * add get error function * def sw alloc macros * reimpl get color buffer func just in case * remove normal interpolation * review texture wrap * fix ndc projection (viewport/scissor) * impl framebuffer blit function * reduce matrix compuations and memory usage * swBegin tweaks * preventing a possible division by zero * remove useless scissor related data * review color blending system * greatly improve float saturation * tweak lerp vertex function * use opitmized fract function in sw_texture_map * tweak framebuffer functions for better readability * optimized copy/blit functions for each dst format * review framebuffer filling functions * impl specific quad rendering func * use of a single global vertex buffer * fix 'sw_poly_point_render' * added `SW_RESTRICT` and redesigned `sw_lerp_vertex_PNCTH` * tweak the pipeline flow regarding the face culling avoids misprediction, improves vectorization if possible * new rendering path for axis aligned quads * oops, translating some comments * use of `restrict` for blending function parameters * update rlgl.h * adding `GRAPHICS_API_OPENGL_11_SOFTWARE` in `DrawMesh` * add `RL_OPENGL_11_SOFTWARE` enum * temp tweak * build fixes * fix DrawMesh for GL 1.1 * update swClose * review texture format + fix copy * set minimum req vertices to 3 (quads) * check swInit * review pixelformat * tweaks * fix animNormals (DrawMesh) * fallback color/texcoord (swDrawArrays) * review swMultMatrixf * fix texture pool alloc.. * review triangle scanlines increment all data * fix `sw_quad_sort_cw` * impl sdl platform * rm def * increase max clipped polygon vertices * improve triangle rasterization along Y axis improved robustness against numerical errors incremental interpolation along Y simplified function, fewer jumps * review current vertex data + increase max clipped polygon vertices (for extreme cases) * fix and improve polygon clipping Sets the vertex count to zero when the polygon is invalid Stops clipping when the vertex count drops below 3 * fix gradient calculation * cache texture size minus one + comments * tweaks * BGRA copy support * adding software backend option (cmake) * update Makefile * fix face culling * excluse some exemple with the software backend * review SW_CLAMP case in sw_texture_map * review sw_saturate * review line raster * fix sw_quad_is_aligned * review sw_raster_quad_axis_aligned * tweaks * codepoint fix (?) * fix var name... * rcore_drm software renderering * cleanup and tweaks * adding support for `GL_POINT_SIZE` and `GL_LINE_WIDTH` get * fix sampling issue * fix swBlendFunc --------- Co-authored-by: Ray --- CMakeOptions.txt | 2 +- cmake/LibraryConfigurations.cmake | 2 + examples/CMakeLists.txt | 4 + src/Makefile | 18 +- src/external/rlsw.h | 5230 +++++++++++++++++++++++++++++ src/platforms/rcore_desktop_sdl.c | 143 +- src/platforms/rcore_drm.c | 364 +- src/rlgl.h | 87 +- src/rmodels.c | 2 +- 9 files changed, 5739 insertions(+), 113 deletions(-) create mode 100644 src/external/rlsw.h diff --git a/CMakeOptions.txt b/CMakeOptions.txt index 3c1c12742..32cfb814e 100644 --- a/CMakeOptions.txt +++ b/CMakeOptions.txt @@ -8,7 +8,7 @@ if(EMSCRIPTEN) endif() enum_option(PLATFORM "Desktop;Web;Android;Raspberry Pi;DRM;SDL" "Platform to build for.") -enum_option(OPENGL_VERSION "OFF;4.3;3.3;2.1;1.1;ES 2.0;ES 3.0" "Force a specific OpenGL Version?") +enum_option(OPENGL_VERSION "OFF;4.3;3.3;2.1;1.1;ES 2.0;ES 3.0;Software" "Force a specific OpenGL Version?") # Configuration options option(BUILD_EXAMPLES "Build the examples." ${PROJECT_IS_TOP_LEVEL}) diff --git a/cmake/LibraryConfigurations.cmake b/cmake/LibraryConfigurations.cmake index 98c7f2362..8f127fc23 100644 --- a/cmake/LibraryConfigurations.cmake +++ b/cmake/LibraryConfigurations.cmake @@ -158,6 +158,8 @@ if (NOT ${OPENGL_VERSION} MATCHES "OFF") set(GRAPHICS "GRAPHICS_API_OPENGL_ES2") elseif (${OPENGL_VERSION} MATCHES "ES 3.0") set(GRAPHICS "GRAPHICS_API_OPENGL_ES3") + elseif (${OPENGL_VERSION} MATCHES "Software") + set(GRAPHICS "GRAPHICS_API_OPENGL_11_SOFTWARE") endif () if (NOT "${SUGGESTED_GRAPHICS}" STREQUAL "" AND NOT "${SUGGESTED_GRAPHICS}" STREQUAL "${GRAPHICS}") message(WARNING "You are overriding the suggested GRAPHICS=${SUGGESTED_GRAPHICS} with ${GRAPHICS}! This may fail.") diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index e63c1a7c8..b482df0fc 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -105,6 +105,10 @@ elseif ("${PLATFORM}" STREQUAL "DRM") list(REMOVE_ITEM example_sources ${CMAKE_CURRENT_SOURCE_DIR}/others/rlgl_standalone.c) list(REMOVE_ITEM example_sources ${CMAKE_CURRENT_SOURCE_DIR}/others/raylib_opengl_interop.c) +elseif ("${OPENGL_VERSION}" STREQUAL "Software") + list(REMOVE_ITEM example_sources ${CMAKE_CURRENT_SOURCE_DIR}/others/rlgl_standalone.c) + list(REMOVE_ITEM example_sources ${CMAKE_CURRENT_SOURCE_DIR}/others/raylib_opengl_interop.c) + elseif (NOT SUPPORT_GESTURES_SYSTEM) # Items requiring gestures system list(REMOVE_ITEM example_sources ${CMAKE_CURRENT_SOURCE_DIR}/textures/textures_mouse_painting.c) diff --git a/src/Makefile b/src/Makefile index f2bdd811e..e767d21d0 100644 --- a/src/Makefile +++ b/src/Makefile @@ -235,20 +235,22 @@ endif # NOTE: By default use OpenGL 3.3 on desktop platforms ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW) GRAPHICS ?= GRAPHICS_API_OPENGL_33 - #GRAPHICS = GRAPHICS_API_OPENGL_11 # Uncomment to use OpenGL 1.1 - #GRAPHICS = GRAPHICS_API_OPENGL_21 # Uncomment to use OpenGL 2.1 - #GRAPHICS = GRAPHICS_API_OPENGL_43 # Uncomment to use OpenGL 4.3 - #GRAPHICS = GRAPHICS_API_OPENGL_ES2 # Uncomment to use OpenGL ES 2.0 (ANGLE) + #GRAPHICS = GRAPHICS_API_OPENGL_11_SOFTWARE # Uncomment to use software rendering + #GRAPHICS = GRAPHICS_API_OPENGL_11 # Uncomment to use OpenGL 1.1 + #GRAPHICS = GRAPHICS_API_OPENGL_21 # Uncomment to use OpenGL 2.1 + #GRAPHICS = GRAPHICS_API_OPENGL_43 # Uncomment to use OpenGL 4.3 + #GRAPHICS = GRAPHICS_API_OPENGL_ES2 # Uncomment to use OpenGL ES 2.0 (ANGLE) endif ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_SDL) GRAPHICS ?= GRAPHICS_API_OPENGL_33 endif ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_RGFW) GRAPHICS ?= GRAPHICS_API_OPENGL_33 - #GRAPHICS = GRAPHICS_API_OPENGL_11 # Uncomment to use OpenGL 1.1 - #GRAPHICS = GRAPHICS_API_OPENGL_21 # Uncomment to use OpenGL 2.1 - #GRAPHICS = GRAPHICS_API_OPENGL_43 # Uncomment to use OpenGL 4.3 - #GRAPHICS = GRAPHICS_API_OPENGL_ES2 # Uncomment to use OpenGL ES 2.0 (ANGLE) + #GRAPHICS = GRAPHICS_API_OPENGL_11_SOFTWARE # Uncomment to use software rendering + #GRAPHICS = GRAPHICS_API_OPENGL_11 # Uncomment to use OpenGL 1.1 + #GRAPHICS = GRAPHICS_API_OPENGL_21 # Uncomment to use OpenGL 2.1 + #GRAPHICS = GRAPHICS_API_OPENGL_43 # Uncomment to use OpenGL 4.3 + #GRAPHICS = GRAPHICS_API_OPENGL_ES2 # Uncomment to use OpenGL ES 2.0 (ANGLE) endif ifeq ($(TARGET_PLATFORM),PLATFORM_DRM) # On DRM OpenGL ES 2.0 must be used diff --git a/src/external/rlsw.h b/src/external/rlsw.h new file mode 100644 index 000000000..2177467ec --- /dev/null +++ b/src/external/rlsw.h @@ -0,0 +1,5230 @@ +/** + * MIT License + * + * Copyright (c) 2025 Le Juez Victor + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef RLSW_H +#define RLSW_H + +#include +#include + +/* === RLSW Definition And Macros === */ + +#ifndef SW_MALLOC +# define SW_MALLOC(sz) malloc(sz) +#endif + +#ifndef SW_REALLOC +# define SW_REALLOC(ptr, newSz) realloc(ptr, newSz) +#endif + +#ifndef SW_FREE +# define SW_FREE(ptr) free(ptr) +#endif + +#ifndef SW_RESTRICT +# ifdef _MSC_VER +# define SW_RESTRICT __restrict +# else +# define SW_RESTRICT restrict +# endif +#endif + +#ifndef SW_GL_FRAMEBUFFER_COPY_BGRA +# define SW_GL_FRAMEBUFFER_COPY_BGRA true +#endif + +#ifndef SW_GL_BINDING_COPY_TEXTURE +# define SW_GL_BINDING_COPY_TEXTURE true +#endif + +#ifndef SW_COLOR_BUFFER_BITS +# define SW_COLOR_BUFFER_BITS 24 +#endif + +#ifndef SW_DEPTH_BUFFER_BITS +# define SW_DEPTH_BUFFER_BITS 16 +#endif + +#ifndef SW_MAX_PROJECTION_STACK_SIZE +# define SW_MAX_PROJECTION_STACK_SIZE 2 +#endif + +#ifndef SW_MAX_MODELVIEW_STACK_SIZE +# define SW_MAX_MODELVIEW_STACK_SIZE 8 +#endif + +#ifndef SW_MAX_TEXTURE_STACK_SIZE +# define SW_MAX_TEXTURE_STACK_SIZE 2 +#endif + +#ifndef SW_MAX_TEXTURES +# define SW_MAX_TEXTURES 128 +#endif + +#ifndef SW_MAX_CLIPPED_POLYGON_VERTICES +// Under normal circumstances, clipping a polygon can add at most one vertex per clipping plane. +// Considering the largest polygon involved is a quadrilateral (4 vertices), +// and that clipping occurs against both the frustum (6 planes) +// and the scissors (4 planes), +// the maximum number of vertices after clipping is: +// 4 (original vertices) + 6 (frustum planes) + 4 (scissors planes) = 14 +# define SW_MAX_CLIPPED_POLYGON_VERTICES 14 +#endif + +#ifndef SW_CLIP_EPSILON +# define SW_CLIP_EPSILON 1e-4f +#endif + +/* === OpenGL Compatibility Types === */ + +typedef unsigned int GLenum; +typedef unsigned char GLboolean; +typedef unsigned int GLbitfield; +typedef void GLvoid; +typedef signed char GLbyte; +typedef short GLshort; +typedef int GLint; +typedef unsigned char GLubyte; +typedef unsigned short GLushort; +typedef unsigned int GLuint; +typedef int GLsizei; +typedef float GLfloat; +typedef float GLclampf; +typedef double GLdouble; +typedef double GLclampd; + +/* === OpenGL Definitions === */ + +#define GL_FALSE 0 +#define GL_TRUE 1 + +#define GL_SCISSOR_TEST 0x0C11 +#define GL_TEXTURE_2D 0x0DE1 +#define GL_DEPTH_TEST 0x0B71 +#define GL_CULL_FACE 0x0B44 +#define GL_BLEND 0x0BE2 + +#define GL_VENDOR 0x1F00 +#define GL_RENDERER 0x1F01 +#define GL_VERSION 0x1F02 +#define GL_EXTENSIONS 0x1F03 + +//#define GL_ATTRIB_STACK_DEPTH 0x0BB0 +//#define GL_CLIENT_ATTRIB_STACK_DEPTH 0x0BB1 +#define GL_COLOR_CLEAR_VALUE 0x0C22 +//#define GL_COLOR_WRITEMASK 0x0C23 +//#define GL_CURRENT_INDEX 0x0B01 +#define GL_CURRENT_COLOR 0x0B00 +//#define GL_CURRENT_NORMAL 0x0B02 +//#define GL_CURRENT_RASTER_COLOR 0x0B04 +//#define GL_CURRENT_RASTER_DISTANCE 0x0B09 +//#define GL_CURRENT_RASTER_INDEX 0x0B05 +//#define GL_CURRENT_RASTER_POSITION 0x0B07 +//#define GL_CURRENT_RASTER_TEXTURE_COORDS 0x0B06 +//#define GL_CURRENT_RASTER_POSITION_VALID 0x0B08 +#define GL_CURRENT_TEXTURE_COORDS 0x0B03 +#define GL_POINT_SIZE 0x0B11 +#define GL_LINE_WIDTH 0x0B21 +//#define GL_INDEX_CLEAR_VALUE 0x0C20 +//#define GL_INDEX_MODE 0x0C30 +//#define GL_INDEX_WRITEMASK 0x0C21 +#define GL_MODELVIEW_MATRIX 0x0BA6 +#define GL_MODELVIEW_STACK_DEPTH 0x0BA3 +//#define GL_NAME_STACK_DEPTH 0x0D70 +#define GL_PROJECTION_MATRIX 0x0BA7 +#define GL_PROJECTION_STACK_DEPTH 0x0BA4 +//#define GL_RENDER_MODE 0x0C40 +//#define GL_RGBA_MODE 0x0C31 +#define GL_TEXTURE_MATRIX 0x0BA8 +#define GL_TEXTURE_STACK_DEPTH 0x0BA5 +#define GL_VIEWPORT 0x0BA2 + +#define GL_COLOR_BUFFER_BIT 0x00004000 +#define GL_DEPTH_BUFFER_BIT 0x00000100 + +#define GL_MODELVIEW 0x1700 +#define GL_PROJECTION 0x1701 +#define GL_TEXTURE 0x1702 + +#define GL_VERTEX_ARRAY 0x8074 +#define GL_NORMAL_ARRAY 0x8075 //< WARNING: Not implemented (defined for RLGL) +#define GL_COLOR_ARRAY 0x8076 +//#define GL_INDEX_ARRAY 0x8077 +#define GL_TEXTURE_COORD_ARRAY 0x8078 + +#define GL_POINTS 0x0000 +#define GL_LINES 0x0001 +//#define GL_LINE_LOOP 0x0002 +//#define GL_LINE_STRIP 0x0003 +#define GL_TRIANGLES 0x0004 +//#define GL_TRIANGLE_STRIP 0x0005 +//#define GL_TRIANGLE_FAN 0x0006 +#define GL_QUADS 0x0007 +//#define GL_QUAD_STRIP 0x0008 +//#define GL_POLYGON 0x0009 + +#define GL_POINT 0x1B00 +#define GL_LINE 0x1B01 +#define GL_FILL 0x1B02 + +#define GL_FRONT 0x0404 +#define GL_BACK 0x0405 + +#define GL_ZERO 0 +#define GL_ONE 1 +#define GL_SRC_COLOR 0x0300 +#define GL_ONE_MINUS_SRC_COLOR 0x0301 +#define GL_SRC_ALPHA 0x0302 +#define GL_ONE_MINUS_SRC_ALPHA 0x0303 +#define GL_DST_ALPHA 0x0304 +#define GL_ONE_MINUS_DST_ALPHA 0x0305 +#define GL_DST_COLOR 0x0306 +#define GL_ONE_MINUS_DST_COLOR 0x0307 +#define GL_SRC_ALPHA_SATURATE 0x0308 + +#define GL_NEAREST 0x2600 +#define GL_LINEAR 0x2601 + +#define GL_REPEAT 0x2901 +#define GL_CLAMP 0x2900 + +#define GL_TEXTURE_MAG_FILTER 0x2800 +#define GL_TEXTURE_MIN_FILTER 0x2801 + +#define GL_TEXTURE_WRAP_S 0x2802 +#define GL_TEXTURE_WRAP_T 0x2803 + +#define GL_NO_ERROR 0 +#define GL_INVALID_ENUM 0x0500 +#define GL_INVALID_VALUE 0x0501 +#define GL_INVALID_OPERATION 0x0502 +#define GL_STACK_OVERFLOW 0x0503 +#define GL_STACK_UNDERFLOW 0x0504 +#define GL_OUT_OF_MEMORY 0x0505 + +#define GL_ALPHA 0x1906 +#define GL_LUMINANCE 0x1909 +#define GL_LUMINANCE_ALPHA 0x190A +#define GL_RGB 0x1907 +#define GL_RGBA 0x1908 + +#define GL_BYTE 0x1400 +#define GL_UNSIGNED_BYTE 0x1401 +#define GL_SHORT 0x1402 +#define GL_UNSIGNED_SHORT 0x1403 +#define GL_INT 0x1404 +#define GL_UNSIGNED_INT 0x1405 +#define GL_FLOAT 0x1406 + +/* === Not Used Definitions === */ + +#define GL_PERSPECTIVE_CORRECTION_HINT 0x0C50 +#define GL_PACK_ALIGNMENT 0x0D05 +#define GL_UNPACK_ALIGNMENT 0x0CF5 +#define GL_LINE_SMOOTH 0x0B20 +#define GL_SMOOTH 0x1D01 +#define GL_NICEST 0x1102 +#define GL_CCW 0x0901 +#define GL_CW 0x0900 +#define GL_NEVER 0x0200 +#define GL_LESS 0x0201 +#define GL_EQUAL 0x0202 +#define GL_LEQUAL 0x0203 +#define GL_GREATER 0x0204 +#define GL_NOTEQUAL 0x0205 +#define GL_GEQUAL 0x0206 +#define GL_ALWAYS 0x0207 + +/* === OpenGL Binding === */ + +#define glReadPixels(x, y, w, h, f, t, p) swCopyFramebuffer((x), (y), (w), (h), (f), (t), (p)) +#define glEnable(state) swEnable((state)) +#define glDisable(state) swDisable((state)) +#define glGetFloatv(pname, params) swGetFloatv((pname), (params)) +#define glGetString(pname) swGetString((pname)) +#define glGetError() swGetError() +#define glViewport(x, y, w, h) swViewport((x), (y), (w), (h)) +#define glScissor(x, y, w, h) swScissor((x), (y), (w), (h)) +#define glClearColor(r, g, b, a) swClearColor((r), (g), (b), (a)) +#define glClear(bitmask) swClear((bitmask)) +#define glBlendFunc(sfactor, dfactor) swBlendFunc((sfactor), (dfactor)) +#define glPolygonMode(face, mode) swPolygonMode((mode)) +#define glCullFace(face) swCullFace((face)) +#define glPointSize(size) swPointSize((size)) +#define glLineWidth(width) swLineWidth((width)) +#define glMatrixMode(mode) swMatrixMode((mode)) +#define glPushMatrix() swPushMatrix() +#define glPopMatrix() swPopMatrix() +#define glLoadIdentity() swLoadIdentity() +#define glTranslatef(x, y, z) swTranslatef((x), (y), (z)) +#define glRotatef(a, x, y, z) swRotatef((a), (x), (y), (z)) +#define glScalef(x, y, z) swScalef((x), (y), (z)) +#define glMultMatrixf(v) swMultMatrixf((v)) +#define glFrustum(l, r, b, t, n, f) swFrustum((l), (r), (b), (t), (n), (f)) +#define glOrtho(l, r, b, t, n, f) swOrtho((l), (r), (b), (t), (n), (f)) +#define glBegin(mode) swBegin((mode)) +#define glEnd() swEnd() +#define glVertex2i(x, y) swVertex2i((x), (y)) +#define glVertex2f(x, y) swVertex2f((x), (y)) +#define glVertex2fv(v) swVertex2fv((v)) +#define glVertex3i(x, y, z) swVertex3i((x), (y), (z)) +#define glVertex3f(x, y, z) swVertex3f((x), (y), (z)) +#define glvertex3fv(v) swVertex3fv((v)) +#define glVertex4i(x, y, z, w) swVertex4i((x), (y), (z), (w)) +#define glVertex4f(x, y, z, w) swVertex4f((x), (y), (z), (w)) +#define glVertex4fv(v) swVertex4fv((v)) +#define glColor3ub(r, g, b) swColor3ub((r), (g), (b)) +#define glColor3ubv(v) swColor3ubv((v)) +#define glColor3f(r, g, b) swColor3f((r), (g), (b)) +#define glColor3fv(v) swColor3fv((v)) +#define glColor4ub(r, g, b, a) swColor4ub((r), (g), (b), (a)) +#define glColor4ubv(v) swColor4ubv((v)) +#define glColor4f(r, g, b, a) swColor4f((r), (g), (b), (a)) +#define glColor4fv(v) swColor4fv((v)) +#define glTexCoord2f(u, v) swTexCoord2f((u), (v)) +#define glTexCoord2fv(v) swTexCoord2fv((v)) + +#define glEnableClientState(t) ((void)(t)) +#define glDisableClientState(t) swBindArray((t), 0) +#define glVertexPointer(sz, t, s, p) swBindArray(SW_VERTEX_ARRAY, (p)) +#define glTexCoordPointer(sz, t, s, p) swBindArray(SW_TEXTURE_COORD_ARRAY, (p)) +#define glColorPointer(sz, t, s, p) swBindArray(SW_COLOR_ARRAY, (p)) +#define glDrawArrays(m, o, c) swDrawArrays((m), (o), (c)) +#define glGenTextures(c, v) swGenTextures((c), (v)) +#define glDeleteTextures(c, v) swDeleteTextures((c), (v)) +#define glTexImage2D(tr, l, if, w, h, b, f, t, p) swTexImage2D((w), (h), (f), (t), SW_GL_BINDING_COPY_TEXTURE, (p)) +#define glTexParameteri(tr, pname, param) swTexParameteri((pname), (param)) +#define glBindTexture(tr, id) swBindTexture((id)) + +/* === Not Implemented === */ + +#define glClearDepth(X) ((void)(X)) +#define glDepthMask(X) ((void)(X)) +#define glColorMask(X,Y,Z,W) ((void)(X),(void)(Y),(void)(Z),(void)(W)) +#define glPixelStorei(X,Y) ((void)(X),(void)(Y)) +#define glHint(X,Y) ((void)(X),(void)(Y)) +#define glShadeModel(X) ((void)(X)) +#define glFrontFace(X) ((void)(X)) +#define glDepthFunc(X) ((void)(X)) +#define glTexSubImage2D(X,Y,Z,W,A,B,C,D,E) ((void)(X),(void)(Y),(void)(Z),(void)(W),(void)(A),(void)(B),(void)(C),(void)(D),(void)(E)) +#define glGetTexImage(X,Y,Z,W,A) ((void)(X),(void)(Y),(void)(Z),(void)(W),(void)(A)) +#define glDrawElements(X,Y,Z,W) ((void)(X),(void)(Y),(void)(Z),(void)(W)) +#define glNormal3f(X,Y,Z) ((void)(X),(void)(Y),(void)(Z)) +#define glNormal3fv(X) ((void)(X)) +#define glNormalPointer(X,Y,Z) ((void)(X),(void)(Y),(void)(Z)) + +/* === RLSW Enums === */ + +typedef enum { + SW_SCISSOR_TEST = GL_SCISSOR_TEST, + SW_TEXTURE_2D = GL_TEXTURE_2D, + SW_DEPTH_TEST = GL_DEPTH_TEST, + SW_CULL_FACE = GL_CULL_FACE, + SW_BLEND = GL_BLEND +} SWstate; + +typedef enum { + SW_VENDOR = GL_VENDOR, + SW_RENDERER = GL_RENDERER, + SW_VERSION = GL_VERSION, + SW_EXTENSIONS = GL_EXTENSIONS, + SW_COLOR_CLEAR_VALUE = GL_COLOR_CLEAR_VALUE, + SW_CURRENT_COLOR = GL_CURRENT_COLOR, + SW_CURRENT_TEXTURE_COORDS = GL_CURRENT_TEXTURE_COORDS, + SW_POINT_SIZE = GL_POINT_SIZE, + SW_LINE_WIDTH = GL_LINE_WIDTH, + SW_MODELVIEW_MATRIX = GL_MODELVIEW_MATRIX, + SW_MODELVIEW_STACK_DEPTH = GL_MODELVIEW_STACK_DEPTH, + SW_PROJECTION_MATRIX = GL_PROJECTION_MATRIX, + SW_PROJECTION_STACK_DEPTH = GL_PROJECTION_STACK_DEPTH, + SW_TEXTURE_MATRIX = GL_TEXTURE_MATRIX, + SW_TEXTURE_STACK_DEPTH = GL_TEXTURE_STACK_DEPTH, + SW_VIEWPORT = GL_VIEWPORT +} SWget; + +typedef enum { + SW_COLOR_BUFFER_BIT = GL_COLOR_BUFFER_BIT, + SW_DEPTH_BUFFER_BIT = GL_DEPTH_BUFFER_BIT +} SWbuffer; + +typedef enum { + SW_PROJECTION = GL_PROJECTION, + SW_MODELVIEW = GL_MODELVIEW, + SW_TEXTURE = GL_TEXTURE +} SWmatrix; + +typedef enum { + SW_VERTEX_ARRAY = GL_VERTEX_ARRAY, + SW_TEXTURE_COORD_ARRAY = GL_TEXTURE_COORD_ARRAY, + SW_COLOR_ARRAY = GL_COLOR_ARRAY +} SWarray; + +typedef enum { + SW_POINTS = GL_POINTS, + SW_LINES = GL_LINES, + SW_TRIANGLES = GL_TRIANGLES, + SW_QUADS = GL_QUADS +} SWdraw; + +typedef enum { + SW_POINT = GL_POINT, + SW_LINE = GL_LINE, + SW_FILL = GL_FILL +} SWpoly; + +typedef enum { + SW_FRONT = GL_FRONT, + SW_BACK = GL_BACK, +} SWface; + +typedef enum { + SW_ZERO = GL_ZERO, + SW_ONE = GL_ONE, + SW_SRC_COLOR = GL_SRC_COLOR, + SW_ONE_MINUS_SRC_COLOR = GL_ONE_MINUS_SRC_COLOR, + SW_SRC_ALPHA = GL_SRC_ALPHA, + SW_ONE_MINUS_SRC_ALPHA = GL_ONE_MINUS_SRC_ALPHA, + SW_DST_ALPHA = GL_DST_ALPHA, + SW_ONE_MINUS_DST_ALPHA = GL_ONE_MINUS_DST_ALPHA, + SW_DST_COLOR = GL_DST_COLOR, + SW_ONE_MINUS_DST_COLOR = GL_ONE_MINUS_DST_COLOR, + SW_SRC_ALPHA_SATURATE = GL_SRC_ALPHA_SATURATE +} SWfactor; + +typedef enum { + SW_LUMINANCE = GL_LUMINANCE, + SW_LUMINANCE_ALPHA = GL_LUMINANCE_ALPHA, + SW_RGB = GL_RGB, + SW_RGBA = GL_RGBA, +} SWformat; + +typedef enum { + SW_UNSIGNED_BYTE = GL_UNSIGNED_BYTE, + SW_BYTE = GL_BYTE, + SW_UNSIGNED_SHORT = GL_UNSIGNED_SHORT, + SW_SHORT = GL_SHORT, + SW_UNSIGNED_INT = GL_UNSIGNED_INT, + SW_INT = GL_INT, + SW_FLOAT = GL_FLOAT +} SWtype; + +typedef enum { + SW_NEAREST = GL_NEAREST, + SW_LINEAR = GL_LINEAR +} SWfilter; + +typedef enum { + SW_REPEAT = GL_REPEAT, + SW_CLAMP = GL_CLAMP, +} SWwrap; + +typedef enum { + SW_TEXTURE_MIN_FILTER = GL_TEXTURE_MIN_FILTER, + SW_TEXTURE_MAG_FILTER = GL_TEXTURE_MAG_FILTER, + SW_TEXTURE_WRAP_S = GL_TEXTURE_WRAP_S, + SW_TEXTURE_WRAP_T = GL_TEXTURE_WRAP_T +} SWtexparam; + +typedef enum { + SW_NO_ERROR = GL_NO_ERROR, + SW_INVALID_ENUM = GL_INVALID_ENUM, + SW_INVALID_VALUE = GL_INVALID_VALUE, + SW_STACK_OVERFLOW = GL_STACK_OVERFLOW, + SW_STACK_UNDERFLOW = GL_STACK_UNDERFLOW, + SW_INVALID_OPERATION = GL_INVALID_OPERATION, +} SWerrcode; + +/* === Public API === */ + +bool swInit(int w, int h); +void swClose(void); + +bool swResizeFramebuffer(int w, int h); +void swCopyFramebuffer(int x, int y, int w, int h, SWformat format, SWtype type, void* pixels); +void swBlitFramebuffer(int xDst, int yDst, int wDst, int hDst, int xSrc, int ySrc, int wSrc, int hSrc, SWformat format, SWtype type, void* pixels); +void* swGetColorBuffer(int* w, int* h); + +void swEnable(SWstate state); +void swDisable(SWstate state); + +void swGetFloatv(SWget name, float* v); +const char* swGetString(SWget name); +SWerrcode swGetError(void); + +void swViewport(int x, int y, int width, int height); +void swScissor(int x, int y, int width, int height); + +void swClearColor(float r, float g, float b, float a); +void swClear(uint32_t bitmask); + +void swBlendFunc(SWfactor sfactor, SWfactor dfactor); +void swPolygonMode(SWpoly mode); +void swCullFace(SWface face); + +void swPointSize(float size); +void swLineWidth(float width); + +void swMatrixMode(SWmatrix mode); +void swPushMatrix(void); +void swPopMatrix(void); +void swLoadIdentity(void); +void swTranslatef(float x, float y, float z); +void swRotatef(float angle, float x, float y, float z); +void swScalef(float x, float y, float z); +void swMultMatrixf(const float* mat); +void swFrustum(double left, double right, double bottom, double top, double znear, double zfar); +void swOrtho(double left, double right, double bottom, double top, double znear, double zfar); + +void swBegin(SWdraw mode); +void swEnd(void); + +void swVertex2i(int x, int y); +void swVertex2f(float x, float y); +void swVertex2fv(const float* v); +void swVertex3i(int x, int y, int z); +void swVertex3f(float x, float y, float z); +void swVertex3fv(const float* v); +void swVertex4i(int x, int y, int z, int w); +void swVertex4f(float x, float y, float z, float w); +void swVertex4fv(const float* v); + +void swColor3ub(uint8_t r, uint8_t g, uint8_t b); +void swColor3ubv(const uint8_t* v); +void swColor3f(float r, float g, float b); +void swColor3fv(const float* v); +void swColor4ub(uint8_t r, uint8_t g, uint8_t b, uint8_t a); +void swColor4ubv(const uint8_t* v); +void swColor4f(float r, float g, float b, float a); +void swColor4fv(const float* v); + +void swTexCoord2f(float u, float v); +void swTexCoord2fv(const float* v); + +void swBindArray(SWarray type, void *buffer); +void swDrawArrays(SWdraw mode, int offset, int count); + +void swGenTextures(int count, uint32_t* textures); +void swDeleteTextures(int count, uint32_t* textures); + +void swTexImage2D(int width, int height, SWformat format, SWtype type, bool copy, const void* data); +void swTexParameteri(int param, int value); +void swBindTexture(uint32_t id); + +#endif // RLSW_H + +/* === RLSW Implementation === */ + +#ifdef RLSW_IMPL + +#include +#include +#include + +/* === Defines and Macros === */ + +#define SW_PI 3.14159265358979323846f +#define SW_DEG2RAD (SW_PI/180.0f) +#define SW_RAD2DEG (180.0f/SW_PI) + +#define SW_COLOR_PIXEL_SIZE (SW_COLOR_BUFFER_BITS / 8) +#define SW_DEPTH_PIXEL_SIZE (SW_DEPTH_BUFFER_BITS / 8) + +#define SW_STATE_CHECK(flags) ((RLSW.stateFlags & (flags)) == (flags)) + +#define SW_STATE_SCISSOR_TEST (1 << 0) +#define SW_STATE_TEXTURE_2D (1 << 1) +#define SW_STATE_DEPTH_TEST (1 << 2) +#define SW_STATE_CULL_FACE (1 << 3) +#define SW_STATE_BLEND (1 << 4) + +/* === Internal Structs === */ + +typedef enum { + SW_PIXELFORMAT_UNKNOWN = 0, + SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE, // 8 bit per pixel (no alpha) + SW_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA, // 8*2 bpp (2 channels) + SW_PIXELFORMAT_UNCOMPRESSED_R5G6B5, // 16 bpp + SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8, // 24 bpp + SW_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1, // 16 bpp (1 bit alpha) + SW_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4, // 16 bpp (4 bit alpha) + SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, // 32 bpp + SW_PIXELFORMAT_UNCOMPRESSED_R32, // 32 bpp (1 channel - float) + SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32, // 32*3 bpp (3 channels - float) + SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32, // 32*4 bpp (4 channels - float) + SW_PIXELFORMAT_UNCOMPRESSED_R16, // 16 bpp (1 channel - half float) + SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16, // 16*3 bpp (3 channels - half float) + SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16, // 16*4 bpp (4 channels - half float) +} sw_pixelformat_t; + +typedef void (*sw_factor_f)( + float* SW_RESTRICT factor, + const float* SW_RESTRICT src, + const float* SW_RESTRICT dst +); + +typedef float sw_matrix_t[4*4]; +typedef uint16_t sw_half_t; + +typedef struct { + + float position[4]; // Position coordinates + float texcoord[2]; // Texture coordinates + float color[4]; // Color + + float homogeneous[4]; // Homogeneous coordinates + float screen[2]; // Screen coordinates + +} sw_vertex_t; + +typedef struct { + + // Dirty hack for copied data + // TODO: Rework copied image handling + + union { + const void* cptr; //< NOTE: Is used for all data reads + void* ptr; //< WARNING: Should only be used to allocate and free data + } pixels; + + int width, height; //< Dimensions of the texture + int wMinus1, hMinus1; //< Dimensions minus one + sw_pixelformat_t format; //< Pixel format (internal representation) + + SWfilter minFilter; //< Minification filter + SWfilter magFilter; //< Magnification filter + + SWwrap sWrap; //< texcoord.x wrap mode + SWwrap tWrap; //< texcoord.y wrap mode + + float tx; //< Texel width + float ty; //< Texel height + + bool copy; //< Flag indicating whether memory has been allocated + +} sw_texture_t; + +typedef struct { + void *color; + void *depth; + int width; + int height; + int allocSz; +} sw_framebuffer_t; + +typedef struct { + + sw_framebuffer_t framebuffer; + float clearColor[4]; // Color used to clear the screen + float clearDepth; // Depth value used to clear the screen + + int vpCenter[2]; // Represents the center of the viewport + int vpHalfSize[2]; // Represents the half dimensions of the viewport + int vpSize[2]; // Represents the dimensions of the viewport (minus one) + int vpMin[2]; // Represents the minimum renderable point of the viewport (top-left) + int vpMax[2]; // Represents the maximum renderable point of the viewport (bottom-right) + + int scMin[2]; // Represents the minimum renderable point of the scissor rect (top-left) + int scMax[2]; // Represents the maximum renderable point of the scissor rect (bottom-right) + float scClipMin[2]; // Represents the minimum renderable point of the scissor rect in clip space + float scClipMax[2]; // Represents the maximum renderable point of the scissor rect in clip space + + uint32_t currentTexture; + + struct { + float* positions; + float* texcoords; + uint8_t* colors; + } array; + + struct { + float texcoord[2]; + float color[4]; + } current; + + sw_vertex_t vertexBuffer[SW_MAX_CLIPPED_POLYGON_VERTICES]; // Buffer used for storing primitive vertices, used for processing and rendering + int vertexCounter; // Number of vertices in 'ctx.vertexBuffer' + + SWdraw drawMode; // Current primitive mode (e.g., lines, triangles) + SWpoly polyMode; // Current polygon filling mode (e.g., lines, triangles) + int reqVertices; // Number of vertices required for the primitive being drawn + float pointRadius; // Rasterized point radius + float lineWidth; // Rasterized line width + + sw_matrix_t stackProjection[SW_MAX_PROJECTION_STACK_SIZE]; // Projection matrix stack for push/pop operations + sw_matrix_t stackModelview[SW_MAX_MODELVIEW_STACK_SIZE]; // Modelview matrix stack for push/pop operations + sw_matrix_t stackTexture[SW_MAX_TEXTURE_STACK_SIZE]; // Texture matrix stack for push/pop operations + uint32_t stackProjectionCounter; // Counter for matrix stack operations + uint32_t stackModelviewCounter; // Counter for matrix stack operations + uint32_t stackTextureCounter; // Counter for matrix stack operations + SWmatrix currentMatrixMode; // Current matrix mode (e.g., sw_MODELVIEW, sw_PROJECTION) + sw_matrix_t* currentMatrix; // Pointer to the currently used matrix according to the mode + sw_matrix_t matMVP; // Model view projection matrix, calculated and used internally + bool isDirtyMVP; // Indicates if the MVP matrix should be rebuilt + + SWfactor srcFactor; + SWfactor dstFactor; + + sw_factor_f srcFactorFunc; + sw_factor_f dstFactorFunc; + + SWface cullFace; // Faces to cull + SWerrcode errCode; // Last error code + + sw_texture_t* loadedTextures; + int loadedTextureCount; + + uint32_t* freeTextureIds; + int freeTextureIdCount; + + uint32_t stateFlags; + +} sw_context_t; + +/* === Global Data === */ + +static sw_context_t RLSW = { 0 }; + +/* === Helper Functions === */ + +static inline void sw_matrix_id(sw_matrix_t dst) +{ + dst[0] = 1, dst[1] = 0, dst[2] = 0, dst[3] = 0; + dst[4] = 0, dst[5] = 1, dst[6] = 0, dst[7] = 0; + dst[8] = 0, dst[9] = 0, dst[10] = 1, dst[11] = 0; + dst[12] = 0, dst[13] = 0, dst[14] = 0, dst[15] = 1; +} + +static inline void sw_matrix_mul_rst(float* SW_RESTRICT dst, const float* SW_RESTRICT left, const float* SW_RESTRICT right) +{ + float l00 = left[0], l01 = left[1], l02 = left[2], l03 = left[3]; + float l10 = left[4], l11 = left[5], l12 = left[6], l13 = left[7]; + float l20 = left[8], l21 = left[9], l22 = left[10], l23 = left[11]; + float l30 = left[12], l31 = left[13], l32 = left[14], l33 = left[15]; + + dst[0] = l00 * right[0] + l01 * right[4] + l02 * right[8] + l03 * right[12]; + dst[4] = l10 * right[0] + l11 * right[4] + l12 * right[8] + l13 * right[12]; + dst[8] = l20 * right[0] + l21 * right[4] + l22 * right[8] + l23 * right[12]; + dst[12] = l30 * right[0] + l31 * right[4] + l32 * right[8] + l33 * right[12]; + + dst[1] = l00 * right[1] + l01 * right[5] + l02 * right[9] + l03 * right[13]; + dst[5] = l10 * right[1] + l11 * right[5] + l12 * right[9] + l13 * right[13]; + dst[9] = l20 * right[1] + l21 * right[5] + l22 * right[9] + l23 * right[13]; + dst[13] = l30 * right[1] + l31 * right[5] + l32 * right[9] + l33 * right[13]; + + dst[2] = l00 * right[2] + l01 * right[6] + l02 * right[10] + l03 * right[14]; + dst[6] = l10 * right[2] + l11 * right[6] + l12 * right[10] + l13 * right[14]; + dst[10] = l20 * right[2] + l21 * right[6] + l22 * right[10] + l23 * right[14]; + dst[14] = l30 * right[2] + l31 * right[6] + l32 * right[10] + l33 * right[14]; + + dst[3] = l00 * right[3] + l01 * right[7] + l02 * right[11] + l03 * right[15]; + dst[7] = l10 * right[3] + l11 * right[7] + l12 * right[11] + l13 * right[15]; + dst[11] = l20 * right[3] + l21 * right[7] + l22 * right[11] + l23 * right[15]; + dst[15] = l30 * right[3] + l31 * right[7] + l32 * right[11] + l33 * right[15]; +} + +static inline void sw_matrix_mul(sw_matrix_t dst, const sw_matrix_t left, const sw_matrix_t right) +{ + float result[16]; + + sw_matrix_mul_rst(result, left, right); + + for (int i = 0; i < 16; i++) { + dst[i] = result[i]; + } +} + +static inline float sw_saturate(float x) +{ + union { float f; uint32_t u; } fb; + fb.f = x; + + // Check if x < 0.0f + // If sign bit is set (MSB), x is negative + if ((fb.u & 0x80000000) != 0) { + return 0.0f; + } + + // Check if x > 1.0f + // Works for positive floats: IEEE 754 ordering matches integer ordering + if (fb.u > 0x3F800000) { + return 1.0f; + } + + // x is in [0.0f, 1.0f] + return x; +} + +static inline float sw_fract(float x) +{ + return x - floorf(x); +} + +static inline int sw_clampi(int v, int min, int max) +{ + if (v < min) return min; + if (v > max) return max; + return v; +} + +static inline void sw_lerp_vertex_PTCH( + sw_vertex_t* SW_RESTRICT out, + const sw_vertex_t* SW_RESTRICT a, + const sw_vertex_t* SW_RESTRICT b, + float t) +{ + const float tInv = 1.0f - t; + + // Position interpolation (4 components) + out->position[0] = a->position[0] * tInv + b->position[0] * t; + out->position[1] = a->position[1] * tInv + b->position[1] * t; + out->position[2] = a->position[2] * tInv + b->position[2] * t; + out->position[3] = a->position[3] * tInv + b->position[3] * t; + + // Texture coordinate interpolation (2 components) + out->texcoord[0] = a->texcoord[0] * tInv + b->texcoord[0] * t; + out->texcoord[1] = a->texcoord[1] * tInv + b->texcoord[1] * t; + + // Color interpolation (4 components) + out->color[0] = a->color[0] * tInv + b->color[0] * t; + out->color[1] = a->color[1] * tInv + b->color[1] * t; + out->color[2] = a->color[2] * tInv + b->color[2] * t; + out->color[3] = a->color[3] * tInv + b->color[3] * t; + + // Homogeneous coordinate interpolation (4 components) + out->homogeneous[0] = a->homogeneous[0] * tInv + b->homogeneous[0] * t; + out->homogeneous[1] = a->homogeneous[1] * tInv + b->homogeneous[1] * t; + out->homogeneous[2] = a->homogeneous[2] * tInv + b->homogeneous[2] * t; + out->homogeneous[3] = a->homogeneous[3] * tInv + b->homogeneous[3] * t; +} + +static inline void sw_get_vertex_grad_PTCH( + sw_vertex_t* SW_RESTRICT out, + const sw_vertex_t* SW_RESTRICT a, + const sw_vertex_t* SW_RESTRICT b, + float scale) +{ + // Calculate gradients for Position + out->position[0] = (b->position[0] - a->position[0]) * scale; + out->position[1] = (b->position[1] - a->position[1]) * scale; + out->position[2] = (b->position[2] - a->position[2]) * scale; + out->position[3] = (b->position[3] - a->position[3]) * scale; + + // Calculate gradients for Texture coordinates + out->texcoord[0] = (b->texcoord[0] - a->texcoord[0]) * scale; + out->texcoord[1] = (b->texcoord[1] - a->texcoord[1]) * scale; + + // Calculate gradients for Color + out->color[0] = (b->color[0] - a->color[0]) * scale; + out->color[1] = (b->color[1] - a->color[1]) * scale; + out->color[2] = (b->color[2] - a->color[2]) * scale; + out->color[3] = (b->color[3] - a->color[3]) * scale; + + // Calculate gradients for Homogeneous coordinates + out->homogeneous[0] = (b->homogeneous[0] - a->homogeneous[0]) * scale; + out->homogeneous[1] = (b->homogeneous[1] - a->homogeneous[1]) * scale; + out->homogeneous[2] = (b->homogeneous[2] - a->homogeneous[2]) * scale; + out->homogeneous[3] = (b->homogeneous[3] - a->homogeneous[3]) * scale; +} + +static inline void sw_add_vertex_grad_PTCH( + sw_vertex_t* SW_RESTRICT out, + const sw_vertex_t* SW_RESTRICT gradients) +{ + // Add gradients to Position + out->position[0] += gradients->position[0]; + out->position[1] += gradients->position[1]; + out->position[2] += gradients->position[2]; + out->position[3] += gradients->position[3]; + + // Add gradients to Texture coordinates + out->texcoord[0] += gradients->texcoord[0]; + out->texcoord[1] += gradients->texcoord[1]; + + // Add gradients to Color + out->color[0] += gradients->color[0]; + out->color[1] += gradients->color[1]; + out->color[2] += gradients->color[2]; + out->color[3] += gradients->color[3]; + + // Add gradients to Homogeneous coordinates + out->homogeneous[0] += gradients->homogeneous[0]; + out->homogeneous[1] += gradients->homogeneous[1]; + out->homogeneous[2] += gradients->homogeneous[2]; + out->homogeneous[3] += gradients->homogeneous[3]; +} + +/* === Half Floating Point === */ + +static inline uint32_t sw_f16_to_f32_ui(uint16_t h) +{ + uint32_t s = (uint32_t)(h & 0x8000) << 16; + int32_t em = h & 0x7fff; + + // bias exponent and pad mantissa with 0; 112 is relative exponent bias (127-15) + int32_t r = (em + (112 << 10)) << 13; + + // denormal: flush to zero + r = (em < (1 << 10)) ? 0 : r; + + // infinity/NaN; note that we preserve NaN payload as a byproduct of unifying inf/nan cases + // 112 is an exponent bias fixup; since we already applied it once, applying it twice converts 31 to 255 + r += (em >= (31 << 10)) ? (112 << 23) : 0; + + return s | r; +} + +static inline float sw_f16_to_f32(sw_half_t y) +{ + union { float f; uint32_t i; } v = { + .i = sw_f16_to_f32_ui(y) + }; + return v.f; +} + +static inline uint16_t sw_f16_from_f32_ui(uint32_t ui) +{ + int32_t s = (ui >> 16) & 0x8000; + int32_t em = ui & 0x7fffffff; + + // bias exponent and round to nearest; 112 is relative exponent bias (127-15) + int32_t h = (em - (112 << 23) + (1 << 12)) >> 13; + + // underflow: flush to zero; 113 encodes exponent -14 + h = (em < (113 << 23)) ? 0 : h; + + // overflow: infinity; 143 encodes exponent 16 + h = (em >= (143 << 23)) ? 0x7c00 : h; + + // NaN; note that we convert all types of NaN to qNaN + h = (em > (255 << 23)) ? 0x7e00 : h; + + return (uint16_t)(s | h); +} + +static inline sw_half_t sw_f16_from_f32(float i) +{ + union { float f; uint32_t i; } v; + v.f = i; + return sw_f16_from_f32_ui(v.i); +} + +/* === Framebuffer Part === */ + +static inline bool sw_framebuffer_load(int w, int h) +{ + int size = w * h; + + RLSW.framebuffer.color = SW_MALLOC(SW_COLOR_PIXEL_SIZE * size); + if (RLSW.framebuffer.color == NULL) return false; + + RLSW.framebuffer.depth = SW_MALLOC(SW_DEPTH_PIXEL_SIZE * size); + if (RLSW.framebuffer.depth == NULL) return false; + + RLSW.framebuffer.width = w; + RLSW.framebuffer.height = h; + RLSW.framebuffer.allocSz = w * h; + + return true; +} + +static inline bool sw_framebuffer_resize(int w, int h) +{ + int newSize = w * h; + + if (newSize <= RLSW.framebuffer.allocSz) { + RLSW.framebuffer.width = w; + RLSW.framebuffer.height = h; + return true; + } + + void* newColor = SW_REALLOC(RLSW.framebuffer.color, newSize); + if (newColor == NULL) return false; + + void* newDepth = SW_REALLOC(RLSW.framebuffer.depth, newSize); + if (newDepth == NULL) return false; + + RLSW.framebuffer.color = newColor; + RLSW.framebuffer.depth = newDepth; + + RLSW.framebuffer.width = w; + RLSW.framebuffer.height = h; + RLSW.framebuffer.allocSz = newSize; + + return true; +} + +static inline void* sw_framebuffer_get_color_addr(const void* ptr, uint32_t offset) +{ + return (uint8_t*)ptr + offset * SW_COLOR_PIXEL_SIZE; +} + +static inline void sw_framebuffer_inc_color_addr(void** ptr) +{ + *ptr = (void*)(((uint8_t*)*ptr) + SW_COLOR_PIXEL_SIZE); +} + +static inline void sw_framebuffer_inc_const_color_addr(const void** ptr) +{ + *ptr = (const void*)(((const uint8_t*)*ptr) + SW_COLOR_PIXEL_SIZE); +} + +static inline void* sw_framebuffer_get_depth_addr(const void* ptr, uint32_t offset) +{ + return (uint8_t*)ptr + offset * SW_DEPTH_PIXEL_SIZE; +} + +static inline void sw_framebuffer_inc_depth_addr(void** ptr) +{ + *ptr = (void*)(((uint8_t*)*ptr) + SW_DEPTH_PIXEL_SIZE); +} + +#if (SW_COLOR_BUFFER_BITS == 8) // RGB - 332 + +static inline void sw_framebuffer_read_color(float dst[4], const void* src) +{ + uint8_t pixel = ((uint8_t*)src)[0]; + + dst[0] = ((pixel >> 5) & 0x07) * (1.0f / 7.0f); + dst[1] = ((pixel >> 2) & 0x07) * (1.0f / 7.0f); + dst[2] = (pixel & 0x03) * (1.0f / 3.0f); + dst[3] = 1.0f; +} + +static inline void sw_framebuffer_read_color8(uint8_t dst[4], const void* src) +{ + uint8_t pixel = ((const uint8_t*)src)[0]; + + uint8_t r = (pixel >> 5) & 0x07; + uint8_t g = (pixel >> 2) & 0x07; + uint8_t b = pixel & 0x03; + + dst[0] = (r * 255 + 3) / 7; + dst[1] = (g * 255 + 3) / 7; + dst[2] = (b * 255 + 1) / 3; + dst[3] = 255; +} + +static inline void sw_framebuffer_write_color(void* dst, const float color[3]) +{ + uint8_t r = ((uint8_t)(color[0] * UINT8_MAX) >> 5) & 0x07; + uint8_t g = ((uint8_t)(color[1] * UINT8_MAX) >> 5) & 0x07; + uint8_t b = ((uint8_t)(color[2] * UINT8_MAX) >> 6) & 0x03; + + ((uint8_t*)dst)[0] = (r << 5) | (g << 2) | b; +} + +static inline void sw_framebuffer_fill_color(void* ptr, int size, const float color[3]) +{ + uint8_t r8 = (uint8_t)(color[0] * 7.0f + 0.5f); + uint8_t g8 = (uint8_t)(color[1] * 7.0f + 0.5f); + uint8_t b8 = (uint8_t)(color[2] * 3.0f + 0.5f); + + uint8_t packedColor = ((r8 & 0x07) << 5) | ((g8 & 0x07) << 2) | (b8 & 0x03); + + uint8_t* p = (uint8_t*)ptr; + + if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST) { + int wScissor = RLSW.scMax[0] - RLSW.scMin[0] + 1; + for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++) { + uint8_t* curPtr = p + y * RLSW.framebuffer.width + RLSW.scMin[0]; + for (int xCount = 0; xCount < wScissor; xCount++) { + *curPtr++ = packedColor; + } + } + } + else { + for (int i = 0; i < size; i++) { + *p++ = packedColor; + } + } +} + +#elif (SW_COLOR_BUFFER_BITS == 16) // RGB - 565 + +static inline void sw_framebuffer_read_color(float dst[4], const void* src) +{ + uint16_t pixel = ((uint16_t*)src)[0]; + + dst[0] = ((pixel >> 11) & 0x1F) * (1.0f / 31.0f); + dst[1] = ((pixel >> 5) & 0x3F) * (1.0f / 63.0f); + dst[2] = (pixel & 0x1F) * (1.0f / 31.0f); + dst[3] = 1.0f; +} + +static inline void sw_framebuffer_read_color8(uint8_t dst[4], const void* src) +{ + uint16_t pixel = ((const uint16_t*)src)[0]; + + uint8_t r = (pixel >> 11) & 0x1F; + uint8_t g = (pixel >> 5) & 0x3F; + uint8_t b = pixel & 0x1F; + + dst[0] = (r * 255 + 15) / 31; + dst[1] = (g * 255 + 31) / 63; + dst[2] = (b * 255 + 15) / 31; + dst[3] = 255; +} + +static inline void sw_framebuffer_write_color(void* dst, const float color[3]) +{ + uint8_t r = (uint8_t)(color[0] * 31.0f + 0.5f) & 0x1F; + uint8_t g = (uint8_t)(color[1] * 63.0f + 0.5f) & 0x3F; + uint8_t b = (uint8_t)(color[2] * 31.0f + 0.5f) & 0x1F; + + ((uint16_t*)dst)[0] = (r << 11) | (g << 5) | b; +} + +static inline void sw_framebuffer_fill_color(void* ptr, int size, const float color[3]) +{ + uint16_t r16 = (uint16_t)(color[0] * 31.0f + 0.5f); + uint16_t g_16 = (uint16_t)(color[1] * 63.0f + 0.5f); + uint16_t b_16 = (uint16_t)(color[2] * 31.0f + 0.5f); + + uint16_t packedColor = ((r16 & 0x1F) << 11) | ((g_16 & 0x3F) << 5) | (b_16 & 0x1F); + + uint16_t* p = (uint16_t*)ptr; + + if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST) { + int wScissor = RLSW.scMax[0] - RLSW.scMin[0] + 1; + for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++) { + uint16_t* curPtr = p + y * RLSW.framebuffer.width + RLSW.scMin[0]; + for (int xCount = 0; xCount < wScissor; xCount++) { + *curPtr++ = packedColor; + } + } + } + else { + for (int i = 0; i < size; i++) { + *p++ = packedColor; + } + } +} + +#elif (SW_COLOR_BUFFER_BITS == 24) // RGB - 888 + +static inline void sw_framebuffer_read_color(float dst[4], const void* src) +{ + dst[0] = ((uint8_t*)src)[0] * (1.0f / 255.0f); + dst[1] = ((uint8_t*)src)[1] * (1.0f / 255.0f); + dst[2] = ((uint8_t*)src)[2] * (1.0f / 255.0f); + dst[3] = 1.0f; +} + +static inline void sw_framebuffer_read_color8(uint8_t dst[4], const void* src) +{ + dst[0] = ((uint8_t*)src)[0]; + dst[1] = ((uint8_t*)src)[1]; + dst[2] = ((uint8_t*)src)[2]; + dst[3] = 255; +} + +static inline void sw_framebuffer_write_color(void* dst, const float color[3]) +{ + ((uint8_t*)dst)[0] = (uint8_t)(color[0] * UINT8_MAX); + ((uint8_t*)dst)[1] = (uint8_t)(color[1] * UINT8_MAX); + ((uint8_t*)dst)[2] = (uint8_t)(color[2] * UINT8_MAX); +} + +static inline void sw_framebuffer_fill_color(void* ptr, int size, const float color[3]) +{ + uint8_t r = (uint8_t)(color[0] * 255.0f); + uint8_t g = (uint8_t)(color[1] * 255.0f); + uint8_t b = (uint8_t)(color[2] * 255.0f); + + uint8_t* p = (uint8_t*)ptr; + + if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST) { + int wScissor = RLSW.scMax[0] - RLSW.scMin[0] + 1; + for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++) { + uint8_t* curPtr = p + 3 * (y * RLSW.framebuffer.width + RLSW.scMin[0]); + for (int xCount = 0; xCount < wScissor; xCount++) { + *curPtr++ = r; + *curPtr++ = g; + *curPtr++ = b; + } + } + } + else { + for (int i = 0; i < size; i++) { + *p++ = r; + *p++ = g; + *p++ = b; + } + } +} + +#endif // SW_COLOR_BUFFER_BITS + +#if (SW_DEPTH_BUFFER_BITS == 8) + +static inline float sw_framebuffer_read_depth(const void* src) +{ + return (float)((uint8_t*)src)[0] * (1.0f / UINT8_MAX); +} + +static inline void sw_framebuffer_write_depth(void* dst, float depth) +{ + ((uint8_t*)dst)[0] = (uint8_t)(depth * UINT8_MAX); +} + +static inline void sw_framebuffer_fill_depth(void* ptr, int size, float value) +{ + uint8_t d8 = (uint8_t)(value * UINT8_MAX); + uint8_t* p = (uint8_t*)ptr; + + if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST) { + int wScissor = RLSW.scMax[0] - RLSW.scMin[0] + 1; + for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++) { + uint8_t* curPtr = p + y * RLSW.framebuffer.width + RLSW.scMin[0]; + for (int xCount = 0; xCount < wScissor; xCount++) { + *curPtr++ = d8; + } + } + } + else { + for (int i = 0; i < size; i++) { + *p++ = d8; + } + } +} + +#elif (SW_DEPTH_BUFFER_BITS == 16) + +static inline float sw_framebuffer_read_depth(const void* src) +{ + return (float)((uint16_t*)src)[0] * (1.0f / UINT16_MAX); +} + +static inline void sw_framebuffer_write_depth(void* dst, float depth) +{ + ((uint16_t*)dst)[0] = (uint16_t)(depth * UINT16_MAX); +} + +static inline void sw_framebuffer_fill_depth(void* ptr, int size, float value) +{ + uint16_t d16 = (uint16_t)(value * UINT16_MAX); + uint16_t* p = (uint16_t*)ptr; + + if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST) { + int wScissor = RLSW.scMax[0] - RLSW.scMin[0] + 1; + for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++) { + uint16_t* curPtr = p + y * RLSW.framebuffer.width + RLSW.scMin[0]; + for (int xCount = 0; xCount < wScissor; xCount++) { + *curPtr++ = d16; + } + } + } + else { + for (int i = 0; i < size; i++) { + *p++ = d16; + } + } +} + +#elif (SW_DEPTH_BUFFER_BITS == 24) + +static inline float sw_framebuffer_read_depth(const void* src) +{ + uint32_t depth24 = (((uint8_t*)src)[0] << 16) | + (((uint8_t*)src)[1] << 8) | + ((uint8_t*)src)[2]; + + return depth24 / (float)0xFFFFFF; +} + +static inline void sw_framebuffer_write_depth(void* dst, float depth) +{ + uint32_t depth24 = (uint32_t)(depth * 0xFFFFFF); + + ((uint8_t*)dst)[0] = (depth24 >> 16) & 0xFF; + ((uint8_t*)dst)[1] = (depth24 >> 8) & 0xFF; + ((uint8_t*)dst)[2] = depth24 & 0xFF; +} + +static inline void sw_framebuffer_fill_depth(void* ptr, int size, float value) +{ + uint32_t d32 = (uint32_t)(value * UINT32_MAX); + uint8_t d_byte0 = (uint8_t)((d32 >> 16) & 0xFF); + uint8_t d_byte1 = (uint8_t)((d32 >> 8) & 0xFF); + uint8_t d_byte2 = (uint8_t)(d32 & 0xFF); + + uint8_t* p = (uint8_t*)ptr; + + if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST) { + int wScissor = RLSW.scMax[0] - RLSW.scMin[0] + 1; + for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++) { + uint8_t* curPtr = p + 3 * (y * RLSW.framebuffer.width + RLSW.scMin[0]); + for (int xCount = 0; xCount < wScissor; xCount++) { + *curPtr++ = d_byte0; + *curPtr++ = d_byte1; + *curPtr++ = d_byte2; + } + } + } + else { + for (int i = 0; i < size; i++) { + *p++ = d_byte0; + *p++ = d_byte1; + *p++ = d_byte2; + } + } +} + +#endif // SW_DEPTH_BUFFER_BITS + +static inline void sw_framebuffer_fill(void* colorPtr, void* depthPtr, int size, float color[4], float depth_value) +{ +#if (SW_COLOR_BUFFER_BITS == 8) + // Calculate and pack 3:3:2 color + // Scale color components to the max value for each bit depth and round + uint8_t r8 = (uint8_t)(color[0] * 7.0f + 0.5f); + uint8_t g8 = (uint8_t)(color[1] * 7.0f + 0.5f); + uint8_t b8 = (uint8_t)(color[2] * 3.0f + 0.5f); + // Pack the components into a single byte + uint8_t packedColor = ((r8 & 0x07) << 5) | ((g8 & 0x07) << 2) | (b8 & 0x03); + uint8_t* cptr = (uint8_t*)colorPtr; +#elif (SW_COLOR_BUFFER_BITS == 16) + // Calculate and pack 5:6:5 color + // Scale color components to the max value for each bit depth and round + uint16_t r16 = (uint16_t)(color[0] * 31.0f + 0.5f); + uint16_t g16 = (uint16_t)(color[1] * 63.0f + 0.5f); + uint16_t b16 = (uint16_t)(color[2] * 31.0f + 0.5f); + // Pack the components into a 16-bit value + uint16_t packedColor = ((r16 & 0x1F) << 11) | ((g16 & 0x3F) << 5) | (b16 & 0x1F); + uint16_t* cptr = (uint16_t*)colorPtr; +#elif (SW_COLOR_BUFFER_BITS == 24) + // Calculate 8:8:8 color components + uint8_t r24 = (uint8_t)(color[0] * 255.0f); + uint8_t g24 = (uint8_t)(color[1] * 255.0f); + uint8_t b24 = (uint8_t)(color[2] * 255.0f); + uint8_t* cptr = (uint8_t*)colorPtr; +#endif + +#if (SW_DEPTH_BUFFER_BITS == 8) + // Calculate 8-bit depth + uint8_t d8 = (uint8_t)(depth_value * UINT8_MAX); + uint8_t* dptr = (uint8_t*)depthPtr; +#elif (SW_DEPTH_BUFFER_BITS == 16) + // Calculate 16-bit depth + uint16_t d16 = (uint16_t)(depth_value * UINT16_MAX); + uint16_t* dptr = (uint16_t*)depthPtr; +#elif (SW_DEPTH_BUFFER_BITS == 24) + // Calculate 24-bit depth and pre-calculate bytes + uint32_t d32 = (uint32_t)(depth_value * UINT32_MAX); + uint8_t dByte0 = (uint8_t)((d32 >> 16) & 0xFF); + uint8_t dByte1 = (uint8_t)((d32 >> 8) & 0xFF); + uint8_t dByte2 = (uint8_t)(d32 & 0xFF); + uint8_t* dptr = (uint8_t*)depthPtr; +#endif + + if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST) { + int wScissor = RLSW.scMax[0] - RLSW.scMin[0] + 1; + for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++) { + int rowStartIdx = y * RLSW.framebuffer.width + RLSW.scMin[0]; + + // Calculate starting pointers for the current row within the scissor rectangle +# if (SW_COLOR_BUFFER_BITS == 8) + uint8_t* curCPtr = cptr + rowStartIdx; +# elif (SW_COLOR_BUFFER_BITS == 16) + uint16_t* curCPtr = cptr + rowStartIdx; +# elif (SW_COLOR_BUFFER_BITS == 24) + uint8_t* curCPtr = cptr + 3 * rowStartIdx; +# endif + +# if (SW_DEPTH_BUFFER_BITS == 8) + uint8_t* curDPtr = dptr + rowStartIdx; +# elif (SW_DEPTH_BUFFER_BITS == 16) + uint16_t* curDPtr = dptr + rowStartIdx; +# elif (SW_DEPTH_BUFFER_BITS == 24) + uint8_t* curDPtr = dptr + 3 * rowStartIdx; +# endif + + // Fill the current row within the scissor rectangle + for (int xCount = 0; xCount < wScissor; xCount++) + { + // Write color +# if (SW_COLOR_BUFFER_BITS == 8) + *curCPtr++ = packedColor; +# elif (SW_COLOR_BUFFER_BITS == 16) + *curCPtr++ = packedColor; +# elif (SW_COLOR_BUFFER_BITS == 24) + *curCPtr++ = r24; + *curCPtr++ = g24; + *curCPtr++ = b24; +# endif + + // Write depth +# if (SW_DEPTH_BUFFER_BITS == 8) + *curDPtr++ = d8; +# elif (SW_DEPTH_BUFFER_BITS == 16) + *curDPtr++ = d16; +# elif (SW_DEPTH_BUFFER_BITS == 24) + *curDPtr++ = dByte0; + *curDPtr++ = dByte1; + *curDPtr++ = dByte2; +# endif + } + } + return; + } + + for (int i = 0; i < size; i++) + { + // Write color +# if (SW_COLOR_BUFFER_BITS == 8) + *cptr++ = packedColor; +# elif (SW_COLOR_BUFFER_BITS == 16) + *cptr++ = packedColor; +# elif (SW_COLOR_BUFFER_BITS == 24) + *cptr++ = r24; + *cptr++ = g24; + *cptr++ = b24; +# endif + + // Write depth +# if (SW_DEPTH_BUFFER_BITS == 8) + *dptr++ = d8; +# elif (SW_DEPTH_BUFFER_BITS == 16) + *dptr++ = d16; +# elif (SW_DEPTH_BUFFER_BITS == 24) + *dptr++ = dByte0; + *dptr++ = dByte1; + *dptr++ = dByte2; +# endif + } +} + +#define DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(name, DST_PTR_T) \ +static inline void sw_framebuffer_copy_to_##name(int x, int y, int w, int h, DST_PTR_T* dst) \ +{ \ + const void* src = RLSW.framebuffer.color; \ + \ + for (int iy = y; iy < h; iy++) { \ + for (int ix = x; ix < w; ix++) { \ + uint8_t color[4]; \ + sw_framebuffer_read_color8(color, src); \ + +#define DEFINE_FRAMEBUFFER_COPY_F32_BEGIN(name, DST_PTR_T) \ +static inline void sw_framebuffer_copy_to_##name(int x, int y, int w, int h, DST_PTR_T* dst) \ +{ \ + const void* src = RLSW.framebuffer.color; \ + \ + for (int iy = y; iy < h; iy++) { \ + for (int ix = x; ix < w; ix++) { \ + float color[4]; \ + sw_framebuffer_read_color(color, src); \ + +#define DEFINE_FRAMEBUFFER_COPY_END() \ + sw_framebuffer_inc_const_color_addr(&src); \ + } \ + } \ +} + +DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(GRAYSCALE, uint8_t) +{ + // NTSC grayscale conversion: Y = 0.299R + 0.587G + 0.114B + uint8_t gray = (uint8_t)((color[0] * 299 + color[1] * 587 + color[2] * 114 + 500) / 1000); + *dst++ = gray; +} +DEFINE_FRAMEBUFFER_COPY_END() + +DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(GRAYALPHA, uint8_t) +{ + // Convert RGB to grayscale using NTSC formula + uint8_t gray = (uint8_t)((color[0] * 299 + color[1] * 587 + color[2] * 114 + 500) / 1000); + + dst[0] = gray; + dst[1] = color[3]; // alpha + + dst += 2; +} +DEFINE_FRAMEBUFFER_COPY_END() + +DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(R5G6B5, uint16_t) +{ + // Convert 8-bit RGB to 5:6:5 format + uint8_t r5 = (color[0] * 31 + 127) / 255; + uint8_t g6 = (color[1] * 63 + 127) / 255; + uint8_t b5 = (color[2] * 31 + 127) / 255; + +#if SW_GL_FRAMEBUFFER_COPY_BGRA + uint16_t rgb565 = (b5 << 11) | (g6 << 5) | r5; +#else // RGBA + uint16_t rgb565 = (r5 << 11) | (g6 << 5) | b5; +#endif + + *dst++ = rgb565; +} +DEFINE_FRAMEBUFFER_COPY_END() + +DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(R8G8B8, uint8_t) +{ +#if SW_GL_FRAMEBUFFER_COPY_BGRA + dst[0] = color[2]; + dst[1] = color[1]; + dst[2] = color[0]; +#else // RGBA + dst[0] = color[0]; + dst[1] = color[1]; + dst[2] = color[2]; +#endif + + dst += 3; +} +DEFINE_FRAMEBUFFER_COPY_END() + +DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(R5G5B5A1, uint16_t) +{ + uint8_t r5 = (color[0] * 31 + 127) / 255; + uint8_t g5 = (color[1] * 31 + 127) / 255; + uint8_t b5 = (color[2] * 31 + 127) / 255; + uint8_t a1 = color[3] >= 128 ? 1 : 0; + +#if SW_GL_FRAMEBUFFER_COPY_BGRA + uint16_t pixel = (b5 << 11) | (g5 << 6) | (r5 << 1) | a1; +#else // RGBA + uint16_t pixel = (r5 << 11) | (g5 << 6) | (b5 << 1) | a1; +#endif + + *dst++ = pixel; +} +DEFINE_FRAMEBUFFER_COPY_END() + +DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(R4G4B4A4, uint16_t) +{ + uint8_t r4 = (color[0] * 15 + 127) / 255; + uint8_t g4 = (color[1] * 15 + 127) / 255; + uint8_t b4 = (color[2] * 15 + 127) / 255; + uint8_t a4 = (color[3] * 15 + 127) / 255; + +#if SW_GL_FRAMEBUFFER_COPY_BGRA + uint16_t pixel = (b4 << 12) | (g4 << 8) | (r4 << 4) | a4; +#else // RGBA + uint16_t pixel = (r4 << 12) | (g4 << 8) | (b4 << 4) | a4; +#endif + + *dst++ = pixel; +} +DEFINE_FRAMEBUFFER_COPY_END() + +DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(R8G8B8A8, uint8_t) +{ +#if SW_GL_FRAMEBUFFER_COPY_BGRA + dst[0] = color[2]; + dst[1] = color[1]; + dst[2] = color[0]; +#else // RGBA + dst[0] = color[0]; + dst[1] = color[1]; + dst[2] = color[2]; +#endif + dst[3] = color[3]; + + dst += 4; +} +DEFINE_FRAMEBUFFER_COPY_END() + +DEFINE_FRAMEBUFFER_COPY_F32_BEGIN(R32, float) +{ + dst[0] = color[0]; + dst++; +} +DEFINE_FRAMEBUFFER_COPY_END() + +DEFINE_FRAMEBUFFER_COPY_F32_BEGIN(R32G32B32, float) +{ +#if SW_GL_FRAMEBUFFER_COPY_BGRA + dst[0] = color[2]; + dst[1] = color[1]; + dst[2] = color[0]; +#else // RGBA + dst[0] = color[0]; + dst[1] = color[1]; + dst[2] = color[2]; +#endif + + dst += 3; +} +DEFINE_FRAMEBUFFER_COPY_END() + +DEFINE_FRAMEBUFFER_COPY_F32_BEGIN(R32G32B32A32, float) +{ +#if SW_GL_FRAMEBUFFER_COPY_BGRA + dst[0] = color[2]; + dst[1] = color[1]; + dst[2] = color[0]; +#else // RGBA + dst[0] = color[0]; + dst[1] = color[1]; + dst[2] = color[2]; +#endif + dst[3] = color[3]; + + dst += 4; +} +DEFINE_FRAMEBUFFER_COPY_END() + +DEFINE_FRAMEBUFFER_COPY_F32_BEGIN(R16, sw_half_t) +{ + dst[0] = sw_f16_from_f32(color[0]); + dst++; +} +DEFINE_FRAMEBUFFER_COPY_END() + +DEFINE_FRAMEBUFFER_COPY_F32_BEGIN(R16G16B16, sw_half_t) +{ +#if SW_GL_FRAMEBUFFER_COPY_BGRA + dst[0] = sw_f16_from_f32(color[2]); + dst[1] = sw_f16_from_f32(color[1]); + dst[2] = sw_f16_from_f32(color[0]); +#else // RGBA + dst[0] = sw_f16_from_f32(color[0]); + dst[1] = sw_f16_from_f32(color[1]); + dst[2] = sw_f16_from_f32(color[2]); +#endif + + dst += 3; +} +DEFINE_FRAMEBUFFER_COPY_END() + +DEFINE_FRAMEBUFFER_COPY_F32_BEGIN(R16G16B16A16, sw_half_t) +{ +#if SW_GL_FRAMEBUFFER_COPY_BGRA + dst[0] = sw_f16_from_f32(color[2]); + dst[1] = sw_f16_from_f32(color[1]); + dst[2] = sw_f16_from_f32(color[0]); +#else // RGBA + dst[0] = sw_f16_from_f32(color[0]); + dst[1] = sw_f16_from_f32(color[1]); + dst[2] = sw_f16_from_f32(color[2]); +#endif + dst[3] = sw_f16_from_f32(color[3]); + + dst += 4; +} +DEFINE_FRAMEBUFFER_COPY_END() + +#define DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(name, DST_PTR_T) \ +static inline void sw_framebuffer_blit_to_##name( \ + int xDst, int yDst, int wDst, int hDst, \ + int xSrc, int ySrc, int wSrc, int hSrc, \ + DST_PTR_T* dst) \ +{ \ + const uint8_t* srcBase = RLSW.framebuffer.color; \ + int fbWidth = RLSW.framebuffer.width; \ + \ + uint32_t xScale = ((uint32_t)wSrc << 16) / (uint32_t)wDst; \ + uint32_t yScale = ((uint32_t)hSrc << 16) / (uint32_t)hDst; \ + \ + for (int dy = 0; dy < hDst; dy++) { \ + uint32_t yFix = ((uint32_t)ySrc << 16) + dy * yScale; \ + int sy = yFix >> 16; \ + \ + for (int dx = 0; dx < wDst; dx++) { \ + uint32_t xFix = dx * xScale; \ + int sx = xFix >> 16; \ + const void* srcPtr = sw_framebuffer_get_color_addr(srcBase, sy * fbWidth + sx); \ + uint8_t color[4]; \ + sw_framebuffer_read_color8(color, srcPtr); \ + +#define DEFINE_FRAMEBUFFER_BLIT_F32_BEGIN(name, DST_PTR_T) \ +static inline void sw_framebuffer_blit_to_##name( \ + int xDst, int yDst, int wDst, int hDst, \ + int xSrc, int ySrc, int wSrc, int hSrc, \ + DST_PTR_T* dst) \ +{ \ + const uint8_t* srcBase = RLSW.framebuffer.color; \ + int fbWidth = RLSW.framebuffer.width; \ + \ + uint32_t xScale = ((uint32_t)wSrc << 16) / (uint32_t)wDst; \ + uint32_t yScale = ((uint32_t)hSrc << 16) / (uint32_t)hDst; \ + \ + for (int dy = 0; dy < hDst; dy++) { \ + uint32_t yFix = ((uint32_t)ySrc << 16) + dy * yScale; \ + int sy = yFix >> 16; \ + \ + for (int dx = 0; dx < wDst; dx++) { \ + uint32_t xFix = dx * xScale; \ + int sx = xFix >> 16; \ + const void* srcPtr = sw_framebuffer_get_color_addr(srcBase, sy * fbWidth + sx); \ + float color[4]; \ + sw_framebuffer_read_color(color, srcPtr); \ + +#define DEFINE_FRAMEBUFFER_BLIT_END() \ + } \ + } \ +} + +DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(GRAYSCALE, uint8_t) +{ + uint8_t gray = (uint8_t)((color[0] * 299 + color[1] * 587 + color[2] * 114 + 500) / 1000); + *dst++ = gray; +} +DEFINE_FRAMEBUFFER_BLIT_END() + +DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(GRAYALPHA, uint8_t) +{ + uint8_t gray = (uint8_t)((color[0] * 299 + color[1] * 587 + color[2] * 114 + 500) / 1000); + + dst[0] = gray; + dst[1] = color[3]; // alpha + + dst += 2; +} +DEFINE_FRAMEBUFFER_BLIT_END() + +DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(R5G6B5, uint16_t) +{ + uint8_t r5 = (color[0] * 31 + 127) / 255; + uint8_t g6 = (color[1] * 63 + 127) / 255; + uint8_t b5 = (color[2] * 31 + 127) / 255; + +#if SW_GL_FRAMEBUFFER_COPY_BGRA + uint16_t rgb565 = (b5 << 11) | (g6 << 5) | r5; +#else // RGBA + uint16_t rgb565 = (r5 << 11) | (g6 << 5) | b5; +#endif + + *dst++ = rgb565; +} +DEFINE_FRAMEBUFFER_BLIT_END() + +DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(R8G8B8, uint8_t) +{ +#if SW_GL_FRAMEBUFFER_COPY_BGRA + dst[0] = color[2]; + dst[1] = color[1]; + dst[2] = color[0]; +#else // RGBA + dst[0] = color[0]; + dst[1] = color[1]; + dst[2] = color[2]; +#endif + + dst += 3; +} +DEFINE_FRAMEBUFFER_BLIT_END() + +DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(R5G5B5A1, uint16_t) +{ + uint8_t r5 = (color[0] * 31 + 127) / 255; + uint8_t g5 = (color[1] * 31 + 127) / 255; + uint8_t b5 = (color[2] * 31 + 127) / 255; + uint8_t a1 = color[3] >= 128 ? 1 : 0; + +#if SW_GL_FRAMEBUFFER_COPY_BGRA + uint16_t pixel = (b5 << 11) | (g5 << 6) | (r5 << 1) | a1; +#else // RGBA + uint16_t pixel = (r5 << 11) | (g5 << 6) | (b5 << 1) | a1; +#endif + + *dst++ = pixel; +} +DEFINE_FRAMEBUFFER_BLIT_END() + +DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(R4G4B4A4, uint16_t) +{ + uint8_t r4 = (color[0] * 15 + 127) / 255; + uint8_t g4 = (color[1] * 15 + 127) / 255; + uint8_t b4 = (color[2] * 15 + 127) / 255; + uint8_t a4 = (color[3] * 15 + 127) / 255; + +#if SW_GL_FRAMEBUFFER_COPY_BGRA + uint16_t pixel = (b4 << 12) | (g4 << 8) | (r4 << 4) | a4; +#else // RGBA + uint16_t pixel = (r4 << 12) | (g4 << 8) | (b4 << 4) | a4; +#endif + + *dst++ = pixel; +} +DEFINE_FRAMEBUFFER_BLIT_END() + +DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(R8G8B8A8, uint8_t) +{ +#if SW_GL_FRAMEBUFFER_COPY_BGRA + dst[0] = color[2]; + dst[1] = color[1]; + dst[2] = color[0]; +#else // RGBA + dst[0] = color[0]; + dst[1] = color[1]; + dst[2] = color[2]; +#endif + dst[3] = color[3]; + + dst += 4; +} +DEFINE_FRAMEBUFFER_BLIT_END() + +DEFINE_FRAMEBUFFER_BLIT_F32_BEGIN(R32, uint8_t) +{ + dst[0] = color[0]; + dst++; +} +DEFINE_FRAMEBUFFER_BLIT_END() + +DEFINE_FRAMEBUFFER_BLIT_F32_BEGIN(R32G32B32, float) +{ +#if SW_GL_FRAMEBUFFER_COPY_BGRA + dst[0] = color[2]; + dst[1] = color[1]; + dst[2] = color[0]; +#else // RGBA + dst[0] = color[0]; + dst[1] = color[1]; + dst[2] = color[2]; +#endif + + dst += 3; +} +DEFINE_FRAMEBUFFER_BLIT_END() + +DEFINE_FRAMEBUFFER_BLIT_F32_BEGIN(R32G32B32A32, float) +{ +#if SW_GL_FRAMEBUFFER_COPY_BGRA + dst[0] = color[2]; + dst[1] = color[1]; + dst[2] = color[0]; +#else // RGBA + dst[0] = color[0]; + dst[1] = color[1]; + dst[2] = color[2]; +#endif + dst[3] = color[3]; + + dst += 4; +} +DEFINE_FRAMEBUFFER_BLIT_END() + +DEFINE_FRAMEBUFFER_BLIT_F32_BEGIN(R16, sw_half_t) +{ + dst[0] = sw_f16_from_f32(color[0]); + dst++; +} +DEFINE_FRAMEBUFFER_BLIT_END() + +DEFINE_FRAMEBUFFER_BLIT_F32_BEGIN(R16G16B16, sw_half_t) +{ +#if SW_GL_FRAMEBUFFER_COPY_BGRA + dst[0] = sw_f16_from_f32(color[2]); + dst[1] = sw_f16_from_f32(color[1]); + dst[2] = sw_f16_from_f32(color[0]); +#else // RGBA + dst[0] = sw_f16_from_f32(color[0]); + dst[1] = sw_f16_from_f32(color[1]); + dst[2] = sw_f16_from_f32(color[2]); +#endif + + dst += 3; +} +DEFINE_FRAMEBUFFER_BLIT_END() + +DEFINE_FRAMEBUFFER_BLIT_F32_BEGIN(R16G16B16A16, sw_half_t) +{ +#if SW_GL_FRAMEBUFFER_COPY_BGRA + dst[0] = sw_f16_from_f32(color[2]); + dst[1] = sw_f16_from_f32(color[1]); + dst[2] = sw_f16_from_f32(color[0]); +#else // RGBA + dst[0] = sw_f16_from_f32(color[0]); + dst[1] = sw_f16_from_f32(color[1]); + dst[2] = sw_f16_from_f32(color[2]); +#endif + dst[3] = sw_f16_from_f32(color[3]); + + dst += 4; +} +DEFINE_FRAMEBUFFER_BLIT_END() + +/* === Pixel Format Part === */ + +static inline int sw_get_pixel_format(SWformat format, SWtype type) +{ + int channels = 0; + int bitsPerChannel = 8; // Default: 8 bits per channel + + // Determine the number of channels (format) + switch (format) { + case SW_LUMINANCE: channels = 1; break; + case SW_LUMINANCE_ALPHA: channels = 2; break; + case SW_RGB: channels = 3; break; + case SW_RGBA: channels = 4; break; + default: + return SW_PIXELFORMAT_UNKNOWN; + } + + // Determine the depth of each channel (type) + switch (type) { + case SW_UNSIGNED_BYTE: bitsPerChannel = 8; break; + case SW_BYTE: bitsPerChannel = 8; break; + case SW_UNSIGNED_SHORT: bitsPerChannel = 16; break; + case SW_SHORT: bitsPerChannel = 16; break; + case SW_UNSIGNED_INT: bitsPerChannel = 32; break; + case SW_INT: bitsPerChannel = 32; break; + case SW_FLOAT: bitsPerChannel = 32; break; + default: + return SW_PIXELFORMAT_UNKNOWN; + } + + // Map the format and type to the correct internal format + if (bitsPerChannel == 8) { + if (channels == 1) return SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE; + if (channels == 2) return SW_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA; + if (channels == 3) return SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8; + if (channels == 4) return SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; + } + else if (bitsPerChannel == 16) { + if (channels == 1) return SW_PIXELFORMAT_UNCOMPRESSED_R16; + if (channels == 3) return SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16; + if (channels == 4) return SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16; + } + else if (bitsPerChannel == 32) { + if (channels == 1) return SW_PIXELFORMAT_UNCOMPRESSED_R32; + if (channels == 3) return SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32; + if (channels == 4) return SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32; + } + + return SW_PIXELFORMAT_UNKNOWN; +} + +int sw_get_pixel_bytes(sw_pixelformat_t format) +{ + int bpp = 0; + + switch (format) { + case SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: bpp = 1; break; + case SW_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: + case SW_PIXELFORMAT_UNCOMPRESSED_R5G6B5: + case SW_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: + case SW_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: bpp = 2; break; + case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: bpp = 4; break; + case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8: bpp = 3; break; + case SW_PIXELFORMAT_UNCOMPRESSED_R32: bpp = 4; break; + case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32: bpp = 4*3; break; + case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: bpp = 4*4; break; + case SW_PIXELFORMAT_UNCOMPRESSED_R16: bpp = 2; break; + case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16: bpp = 2*3; break; + case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: bpp = 2*4; break; + default: break; + } + + return bpp; +} + +static inline void sw_get_pixel_grayscale(float* color, const void* pixels, uint32_t offset) +{ + float gray = (float)((uint8_t*)pixels)[offset] * (1.0f / 255); + + color[0] = gray; + color[1] = gray; + color[2] = gray; + color[3] = 1.0f; +} + +static inline void sw_get_pixel_red_16(float* color, const void* pixels, uint32_t offset) +{ + float value = sw_f16_to_f32(((sw_half_t*)pixels)[offset]); + + color[0] = value; + color[1] = value; + color[2] = value; + color[3] = 1.0f; +} + +static inline void sw_get_pixel_red_32(float* color, const void* pixels, uint32_t offset) +{ + float value = ((float*)pixels)[offset]; + + color[0] = value; + color[1] = value; + color[2] = value; + color[3] = 1.0f; +} + +static inline void sw_get_pixel_grayscale_alpha(float* color, const void* pixels, uint32_t offset) +{ + const uint8_t* pixelData = (const uint8_t*)pixels + 2 * offset; + + color[0] = color[1] = color[2] = (float)pixelData[0] * (1.0f / 255); + color[3] = (float)pixelData[1] * (1.0f / 255); +} + +static inline void sw_get_pixel_rgb_565(float* color, const void* pixels, uint32_t offset) +{ + uint16_t pixel = ((uint16_t*)pixels)[offset]; + + color[0] = (float)((pixel & 0xF800) >> 11) / 31; + color[1] = (float)((pixel & 0x7E0) >> 5) / 63; + color[2] = (float)(pixel & 0x1F) / 31; + color[3] = 1.0f; +} + +static inline void sw_get_pixel_rgb_888(float* color, const void* pixels, uint32_t offset) +{ + const uint8_t* pixel = (const uint8_t*)pixels + 3 * offset; + + color[0] = (float)pixel[0] * (1.0f / 255); + color[1] = (float)pixel[1] * (1.0f / 255); + color[2] = (float)pixel[2] * (1.0f / 255); + color[3] = 1.0f; +} + +static inline void sw_get_pixel_rgb_161616(float* color, const void* pixels, uint32_t offset) +{ + const sw_half_t *pixel = (sw_half_t*)pixels + 3 * offset; + + color[0] = sw_f16_to_f32(pixel[0]); + color[1] = sw_f16_to_f32(pixel[1]); + color[2] = sw_f16_to_f32(pixel[2]); + color[3] = 1.0f; +} + +static inline void sw_get_pixel_rgb_323232(float* color, const void* pixels, uint32_t offset) +{ + const float *pixel = (float*)pixels + 3 * offset; + + color[0] = pixel[0]; + color[1] = pixel[1]; + color[2] = pixel[2]; + color[3] = 1.0f; +} + +static inline void sw_get_pixel_rgba_5551(float* color, const void* pixels, uint32_t offset) +{ + uint16_t pixel = ((uint16_t*)pixels)[offset]; + + color[0] = (float)((pixel & 0xF800) >> 11) / 31; + color[1] = (float)((pixel & 0x7C0) >> 6) / 31; + color[2] = (float)((pixel & 0x3E) >> 1) / 31; + color[3] = (float)(pixel & 0x1); +} + +static inline void sw_get_pixel_rgba_4444(float* color, const void* pixels, uint32_t offset) +{ + uint16_t pixel = ((uint16_t*)pixels)[offset]; + + color[0] = (float)((pixel & 0xF000) >> 12) / 15; + color[1] = (float)((pixel & 0xF00) >> 8) / 15; + color[2] = (float)((pixel & 0xF0) >> 4) / 15; + color[3] = (float)(pixel & 0xF) / 15; +} + +static inline void sw_get_pixel_rgba_8888(float* color, const void* pixels, uint32_t offset) +{ + const uint8_t *pixel = (uint8_t*)pixels + 4 * offset; + + color[0] = (float)pixel[0] * (1.0f / 255); + color[1] = (float)pixel[1] * (1.0f / 255); + color[2] = (float)pixel[2] * (1.0f / 255); + color[3] = (float)pixel[3] * (1.0f / 255); +} + +static inline void sw_get_pixel_rgba_16161616(float* color, const void* pixels, uint32_t offset) +{ + const sw_half_t *pixel = (sw_half_t*)pixels + 4 * offset; + + color[0] = sw_f16_to_f32(pixel[0]); + color[1] = sw_f16_to_f32(pixel[1]); + color[2] = sw_f16_to_f32(pixel[2]); + color[3] = sw_f16_to_f32(pixel[3]); +} + +static inline void sw_get_pixel_rgba_32323232(float* color, const void* pixels, uint32_t offset) +{ + const float *pixel = (float*)pixels + 4 * offset; + + color[0] = pixel[0]; + color[1] = pixel[1]; + color[2] = pixel[2]; + color[3] = pixel[3]; +} + +static inline void sw_get_pixel(float* color, const void* pixels, uint32_t offset, sw_pixelformat_t format) +{ + switch (format) { + case SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: + sw_get_pixel_grayscale(color, pixels, offset); + break; + case SW_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: + sw_get_pixel_grayscale_alpha(color, pixels, offset); + break; + case SW_PIXELFORMAT_UNCOMPRESSED_R5G6B5: + sw_get_pixel_rgb_565(color, pixels, offset); + break; + case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8: + sw_get_pixel_rgb_888(color, pixels, offset); + break; + case SW_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: + sw_get_pixel_rgba_5551(color, pixels, offset); + break; + case SW_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: + sw_get_pixel_rgba_4444(color, pixels, offset); + break; + case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: + sw_get_pixel_rgba_8888(color, pixels, offset); + break; + case SW_PIXELFORMAT_UNCOMPRESSED_R32: + sw_get_pixel_red_32(color, pixels, offset); + break; + case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32: + sw_get_pixel_rgb_323232(color, pixels, offset); + break; + case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: + sw_get_pixel_rgba_32323232(color, pixels, offset); + break; + case SW_PIXELFORMAT_UNCOMPRESSED_R16: + sw_get_pixel_red_16(color, pixels, offset); + break; + case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16: + sw_get_pixel_rgb_161616(color, pixels, offset); + break; + case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: + sw_get_pixel_rgba_16161616(color, pixels, offset); + break; + case SW_PIXELFORMAT_UNKNOWN: + break; + } +} + +/* === Texture Sampling Part === */ + +static inline void sw_texture_sample_nearest(float* color, const sw_texture_t* tex, float u, float v) +{ + u = (tex->sWrap == SW_REPEAT) ? sw_fract(u) : sw_saturate(u); + v = (tex->tWrap == SW_REPEAT) ? sw_fract(v) : sw_saturate(v); + + int x = u * tex->width, y = v * tex->height; + + sw_get_pixel(color, tex->pixels.cptr, y * tex->width + x, tex->format); +} + +static inline void sw_texture_sample_linear(float* color, const sw_texture_t* tex, float u, float v) +{ + // REVIEW: With a bit more cleverness we could clearly reduce the + // number of operations here, but for now it works fine. + + float xf = u * tex->width - 0.5f; + float yf = v * tex->height - 0.5f; + + int x0 = (int)floorf(xf); + int y0 = (int)floorf(yf); + + float fx = xf - x0; + float fy = yf - y0; + + int x1 = x0 + 1; + int y1 = y0 + 1; + + if (tex->sWrap == SW_CLAMP) { + x0 = x0 > tex->wMinus1 ? tex->wMinus1 : x0; + x1 = x1 > tex->wMinus1 ? tex->wMinus1 : x1; + } + else { + x0 = (x0 % tex->width + tex->width) % tex->width; + x1 = (x1 % tex->width + tex->width) % tex->width; + } + + if (tex->tWrap == SW_CLAMP) { + y0 = y0 > tex->hMinus1 ? tex->hMinus1 : y0; + y1 = y1 > tex->hMinus1 ? tex->hMinus1 : y1; + } + else { + y0 = (y0 % tex->height + tex->height) % tex->height; + y1 = (y1 % tex->height + tex->height) % tex->height; + } + + float c00[4], c10[4], c01[4], c11[4]; + sw_get_pixel(c00, tex->pixels.cptr, y0 * tex->width + x0, tex->format); + sw_get_pixel(c10, tex->pixels.cptr, y0 * tex->width + x1, tex->format); + sw_get_pixel(c01, tex->pixels.cptr, y1 * tex->width + x0, tex->format); + sw_get_pixel(c11, tex->pixels.cptr, y1 * tex->width + x1, tex->format); + + for (int i = 0; i < 4; i++) { + float t = c00[i] + fx * (c10[i] - c00[i]); + float b = c01[i] + fx * (c11[i] - c01[i]); + color[i] = t + fy * (b - t); + } +} + +static inline void sw_texture_sample(float* color, const sw_texture_t* tex, float u, float v, + float duDx, float duDy, float dvDx, float dvDy) +{ + // Previous method: There is no need to compute the square root + // because using the squared value, the comparison remains `L2 > 1.0f * 1.0f` + //float du = sqrtf(duDx * duDx + duDy * duDy); + //float dv = sqrtf(dvDx * dvDx + dvDy * dvDy); + //float L = (du > dv) ? du : dv; + + // Calculate the derivatives for each axis + float du2 = duDx * duDx + duDy * duDy; + float dv2 = dvDx * dvDx + dvDy * dvDy; + float L2 = (du2 > dv2) ? du2 : dv2; + + SWfilter filter = (L2 > 1.0f) + ? tex->minFilter : tex->magFilter; + + switch (filter) { + case SW_NEAREST: + sw_texture_sample_nearest(color, tex, u, v); + break; + case SW_LINEAR: + sw_texture_sample_linear(color, tex, u, v); + break; + } +} + +/* === Color Blending Functions === */ + +static inline void sw_factor_zero(float* SW_RESTRICT factor, const float* SW_RESTRICT src, const float* SW_RESTRICT dst) +{ + factor[0] = factor[1] = factor[2] = factor[3] = 0.0f; +} + +static inline void sw_factor_one(float* SW_RESTRICT factor, const float* SW_RESTRICT src, const float* SW_RESTRICT dst) +{ + factor[0] = factor[1] = factor[2] = factor[3] = 1.0f; +} + +static inline void sw_factor_src_color(float* SW_RESTRICT factor, const float* SW_RESTRICT src, const float* SW_RESTRICT dst) +{ + factor[0] = src[0]; factor[1] = src[1]; factor[2] = src[2]; factor[3] = src[3]; +} + +static inline void sw_factor_one_minus_src_color(float* SW_RESTRICT factor, const float* SW_RESTRICT src, const float* SW_RESTRICT dst) +{ + factor[0] = 1.0f - src[0]; factor[1] = 1.0f - src[1]; + factor[2] = 1.0f - src[2]; factor[3] = 1.0f - src[3]; +} + +static inline void sw_factor_src_alpha(float* SW_RESTRICT factor, const float* SW_RESTRICT src, const float* SW_RESTRICT dst) +{ + factor[0] = factor[1] = factor[2] = factor[3] = src[3]; +} + +static inline void sw_factor_one_minus_src_alpha(float* SW_RESTRICT factor, const float* SW_RESTRICT src, const float* SW_RESTRICT dst) +{ + float inv_alpha = 1.0f - src[3]; + factor[0] = factor[1] = factor[2] = factor[3] = inv_alpha; +} + +static inline void sw_factor_dst_alpha(float* SW_RESTRICT factor, const float* SW_RESTRICT src, const float* SW_RESTRICT dst) +{ + factor[0] = factor[1] = factor[2] = factor[3] = dst[3]; +} + +static inline void sw_factor_one_minus_dst_alpha(float* SW_RESTRICT factor, const float* SW_RESTRICT src, const float* SW_RESTRICT dst) +{ + float inv_alpha = 1.0f - dst[3]; + factor[0] = factor[1] = factor[2] = factor[3] = inv_alpha; +} + +static inline void sw_factor_dst_color(float* SW_RESTRICT factor, const float* SW_RESTRICT src, const float* SW_RESTRICT dst) +{ + factor[0] = dst[0]; factor[1] = dst[1]; factor[2] = dst[2]; factor[3] = dst[3]; +} + +static inline void sw_factor_one_minus_dst_color(float* SW_RESTRICT factor, const float* SW_RESTRICT src, const float* SW_RESTRICT dst) +{ + factor[0] = 1.0f - dst[0]; factor[1] = 1.0f - dst[1]; + factor[2] = 1.0f - dst[2]; factor[3] = 1.0f - dst[3]; +} + +static inline void sw_factor_src_alpha_saturate(float* SW_RESTRICT factor, const float* SW_RESTRICT src, const float* SW_RESTRICT dst) +{ + factor[0] = factor[1] = factor[2] = 1.0f; + factor[3] = (src[3] < 1.0f) ? src[3] : 1.0f; +} + +static inline void sw_blend_colors(float* SW_RESTRICT dst/*[4]*/, const float* SW_RESTRICT src/*[4]*/) +{ + float srcFactor[4], dstFactor[4]; + + RLSW.srcFactorFunc(srcFactor, src, dst); + RLSW.dstFactorFunc(dstFactor, src, dst); + + dst[0] = srcFactor[0] * src[0] + dstFactor[0] * dst[0]; + dst[1] = srcFactor[1] * src[1] + dstFactor[1] * dst[1]; + dst[2] = srcFactor[2] * src[2] + dstFactor[2] * dst[2]; + dst[3] = srcFactor[3] * src[3] + dstFactor[3] * dst[3]; +} + +/* === Projection Helper Functions === */ + +static inline void sw_project_ndc_to_screen(float screen[2], const float ndc[4]) +{ + screen[0] = RLSW.vpCenter[0] + ndc[0] * RLSW.vpHalfSize[0]; + screen[1] = RLSW.vpCenter[1] - ndc[1] * RLSW.vpHalfSize[1]; +} + +/* === Polygon Clipping Part === */ + +#define DEFINE_CLIP_FUNC(name, FUNC_IS_INSIDE, FUNC_COMPUTE_T) \ +static inline int sw_clip_##name( \ + sw_vertex_t output[SW_MAX_CLIPPED_POLYGON_VERTICES], \ + const sw_vertex_t input[SW_MAX_CLIPPED_POLYGON_VERTICES], \ + int n) \ +{ \ + const sw_vertex_t *prev = &input[n - 1]; \ + int prevInside = FUNC_IS_INSIDE(prev->homogeneous); \ + int outputCount = 0; \ + \ + for (int i = 0; i < n; i++) { \ + const sw_vertex_t *curr = &input[i]; \ + int currInside = FUNC_IS_INSIDE(curr->homogeneous); \ + \ + /* If transition between interior/exterior, calculate intersection point */ \ + if (prevInside != currInside) { \ + float t = FUNC_COMPUTE_T(prev->homogeneous, curr->homogeneous); \ + sw_lerp_vertex_PTCH(&output[outputCount++], prev, curr, t); \ + } \ + \ + /* If current vertex inside, add it */ \ + if (currInside) { \ + output[outputCount++] = *curr; \ + } \ + \ + prev = curr; \ + prevInside = currInside; \ + } \ + \ + return outputCount; \ +} + +// Frustum clip functions + +#define IS_INSIDE_PLANE_W(h) ((h)[3] >= SW_CLIP_EPSILON) +#define IS_INSIDE_PLANE_X_POS(h) ((h)[0] <= (h)[3]) +#define IS_INSIDE_PLANE_X_NEG(h) (-(h)[0] <= (h)[3]) +#define IS_INSIDE_PLANE_Y_POS(h) ((h)[1] <= (h)[3]) +#define IS_INSIDE_PLANE_Y_NEG(h) (-(h)[1] <= (h)[3]) +#define IS_INSIDE_PLANE_Z_POS(h) ((h)[2] <= (h)[3]) +#define IS_INSIDE_PLANE_Z_NEG(h) (-(h)[2] <= (h)[3]) + +#define COMPUTE_T_PLANE_W(hPrev, hCurr) ((SW_CLIP_EPSILON - (hPrev)[3]) / ((hCurr)[3] - (hPrev)[3])) +#define COMPUTE_T_PLANE_X_POS(hPrev, hCurr) (((hPrev)[3] - (hPrev)[0]) / (((hPrev)[3] - (hPrev)[0]) - ((hCurr)[3] - (hCurr)[0]))) +#define COMPUTE_T_PLANE_X_NEG(hPrev, hCurr) (((hPrev)[3] + (hPrev)[0]) / (((hPrev)[3] + (hPrev)[0]) - ((hCurr)[3] + (hCurr)[0]))) +#define COMPUTE_T_PLANE_Y_POS(hPrev, hCurr) (((hPrev)[3] - (hPrev)[1]) / (((hPrev)[3] - (hPrev)[1]) - ((hCurr)[3] - (hCurr)[1]))) +#define COMPUTE_T_PLANE_Y_NEG(hPrev, hCurr) (((hPrev)[3] + (hPrev)[1]) / (((hPrev)[3] + (hPrev)[1]) - ((hCurr)[3] + (hCurr)[1]))) +#define COMPUTE_T_PLANE_Z_POS(hPrev, hCurr) (((hPrev)[3] - (hPrev)[2]) / (((hPrev)[3] - (hPrev)[2]) - ((hCurr)[3] - (hCurr)[2]))) +#define COMPUTE_T_PLANE_Z_NEG(hPrev, hCurr) (((hPrev)[3] + (hPrev)[2]) / (((hPrev)[3] + (hPrev)[2]) - ((hCurr)[3] + (hCurr)[2]))) + +DEFINE_CLIP_FUNC(w, IS_INSIDE_PLANE_W, COMPUTE_T_PLANE_W) +DEFINE_CLIP_FUNC(x_pos, IS_INSIDE_PLANE_X_POS, COMPUTE_T_PLANE_X_POS) +DEFINE_CLIP_FUNC(x_neg, IS_INSIDE_PLANE_X_NEG, COMPUTE_T_PLANE_X_NEG) +DEFINE_CLIP_FUNC(y_pos, IS_INSIDE_PLANE_Y_POS, COMPUTE_T_PLANE_Y_POS) +DEFINE_CLIP_FUNC(y_neg, IS_INSIDE_PLANE_Y_NEG, COMPUTE_T_PLANE_Y_NEG) +DEFINE_CLIP_FUNC(z_pos, IS_INSIDE_PLANE_Z_POS, COMPUTE_T_PLANE_Z_POS) +DEFINE_CLIP_FUNC(z_neg, IS_INSIDE_PLANE_Z_NEG, COMPUTE_T_PLANE_Z_NEG) + +// Scissor clip functions + +#define COMPUTE_T_SCISSOR_X_MIN(hPrev, hCurr) (((RLSW.scClipMin[0]) * (hPrev)[3] - (hPrev)[0]) / (((hCurr)[0] - (RLSW.scClipMin[0]) * (hCurr)[3]) - ((hPrev)[0] - (RLSW.scClipMin[0]) * (hPrev)[3]))) +#define COMPUTE_T_SCISSOR_X_MAX(hPrev, hCurr) (((RLSW.scClipMax[0]) * (hPrev)[3] - (hPrev)[0]) / (((hCurr)[0] - (RLSW.scClipMax[0]) * (hCurr)[3]) - ((hPrev)[0] - (RLSW.scClipMax[0]) * (hPrev)[3]))) +#define COMPUTE_T_SCISSOR_Y_MIN(hPrev, hCurr) (((RLSW.scClipMin[1]) * (hPrev)[3] - (hPrev)[1]) / (((hCurr)[1] - (RLSW.scClipMin[1]) * (hCurr)[3]) - ((hPrev)[1] - (RLSW.scClipMin[1]) * (hPrev)[3]))) +#define COMPUTE_T_SCISSOR_Y_MAX(hPrev, hCurr) (((RLSW.scClipMax[1]) * (hPrev)[3] - (hPrev)[1]) / (((hCurr)[1] - (RLSW.scClipMax[1]) * (hCurr)[3]) - ((hPrev)[1] - (RLSW.scClipMax[1]) * (hPrev)[3]))) + +#define IS_INSIDE_SCISSOR_X_MIN(h) ((h)[0] >= (RLSW.scClipMin[0]) * (h)[3]) +#define IS_INSIDE_SCISSOR_X_MAX(h) ((h)[0] <= (RLSW.scClipMax[0]) * (h)[3]) +#define IS_INSIDE_SCISSOR_Y_MIN(h) ((h)[1] >= (RLSW.scClipMin[1]) * (h)[3]) +#define IS_INSIDE_SCISSOR_Y_MAX(h) ((h)[1] <= (RLSW.scClipMax[1]) * (h)[3]) + +DEFINE_CLIP_FUNC(scissor_x_min, IS_INSIDE_SCISSOR_X_MIN, COMPUTE_T_SCISSOR_X_MIN) +DEFINE_CLIP_FUNC(scissor_x_max, IS_INSIDE_SCISSOR_X_MAX, COMPUTE_T_SCISSOR_X_MAX) +DEFINE_CLIP_FUNC(scissor_y_min, IS_INSIDE_SCISSOR_Y_MIN, COMPUTE_T_SCISSOR_Y_MIN) +DEFINE_CLIP_FUNC(scissor_y_max, IS_INSIDE_SCISSOR_Y_MAX, COMPUTE_T_SCISSOR_Y_MAX) + +// Main clip function + +static inline bool sw_polygon_clip(sw_vertex_t polygon[SW_MAX_CLIPPED_POLYGON_VERTICES], int* vertexCounter) +{ + static sw_vertex_t tmp[SW_MAX_CLIPPED_POLYGON_VERTICES]; + + int n = *vertexCounter; + + #define CLIP_AGAINST_PLANE(FUNC_CLIP) \ + { \ + n = FUNC_CLIP(tmp, polygon, n); \ + if (n < 3) { \ + *vertexCounter = 0; \ + return false; \ + } \ + for (int i = 0; i < n; i++) { \ + polygon[i] = tmp[i]; \ + } \ + } + + CLIP_AGAINST_PLANE(sw_clip_w); + CLIP_AGAINST_PLANE(sw_clip_x_pos); + CLIP_AGAINST_PLANE(sw_clip_x_neg); + CLIP_AGAINST_PLANE(sw_clip_y_pos); + CLIP_AGAINST_PLANE(sw_clip_y_neg); + CLIP_AGAINST_PLANE(sw_clip_z_pos); + CLIP_AGAINST_PLANE(sw_clip_z_neg); + + if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST) { + CLIP_AGAINST_PLANE(sw_clip_scissor_x_min); + CLIP_AGAINST_PLANE(sw_clip_scissor_x_max); + CLIP_AGAINST_PLANE(sw_clip_scissor_y_min); + CLIP_AGAINST_PLANE(sw_clip_scissor_y_max); + } + + *vertexCounter = n; + + return (n >= 3); +} + +/* === Triangle Rendering Part === */ + +static inline bool sw_triangle_face_culling(void) +{ + // NOTE: Face culling is done before clipping to avoid unnecessary computations. + // To handle triangles crossing the w=0 plane correctly, + // we perform the winding order test in homogeneous coordinates directly, + // before the perspective division (division by w). + // This test determines the orientation of the triangle in the (x,y,w) plane, + // which corresponds to the projected 2D winding order sign, + // even with negative w values. + + // Preload homogeneous coordinates into local variables + const float* h0 = RLSW.vertexBuffer[0].homogeneous; + const float* h1 = RLSW.vertexBuffer[1].homogeneous; + const float* h2 = RLSW.vertexBuffer[2].homogeneous; + + // Compute a value proportional to the signed area in the projected 2D plane, + // calculated directly using homogeneous coordinates BEFORE division by w. + // This is the determinant of the matrix formed by the (x, y, w) components + // of the vertices, which correctly captures the winding order in homogeneous + // space and its relationship to the projected 2D winding order, even with + // negative w values. + // The determinant formula used here is: + // h0.x * (h1.y * h2.w - h2.y * h1.w) + + // h1.x * (h2.y * h0.w - h0.y * h2.w) + + // h2.x * (h0.y * h1.w - h1.y * h0.w) + + const float hSgnArea = + h0[0] * (h1[1] * h2[3] - h2[1] * h1[3]) + + h1[0] * (h2[1] * h0[3] - h0[1] * h2[3]) + + h2[0] * (h0[1] * h1[3] - h1[1] * h0[3]); + + // Discard the triangle if its winding order (determined by the sign + // of the homogeneous area/determinant) matches the culled direction. + // A positive hSgnArea typically corresponds to a counter-clockwise + // winding in the projected space when all w > 0. + // This test is robust for points with w > 0 or w < 0, correctly + // capturing the change in orientation when crossing the w=0 plane. + + // The culling logic remains the same based on the signed area/determinant. + // A value of 0 for hSgnArea means the points are collinear in (x, y, w) + // space, which corresponds to a degenerate triangle projection. + // Such triangles are typically not culled by this test (0 < 0 is false, 0 > 0 is false) + // and should be handled by the clipper if necessary. + return (RLSW.cullFace == SW_FRONT) + ? (hSgnArea < 0) // Cull if winding is "clockwise" in the projected sense + : (hSgnArea > 0); // Cull if winding is "counter-clockwise" in the projected sense +} + +static inline void sw_triangle_clip_and_project(void) +{ + sw_vertex_t* polygon = RLSW.vertexBuffer; + int* vertexCounter = &RLSW.vertexCounter; + + if (sw_polygon_clip(polygon, vertexCounter)) { + + // Transformation to screen space and normalization + for (int i = 0; i < *vertexCounter; i++) { + sw_vertex_t *v = &polygon[i]; + + // Calculation of the reciprocal of W for normalization + // as well as perspective-correct attributes + const float invW = 1.0f / v->homogeneous[3]; + v->homogeneous[3] = invW; + + // Division of XYZ coordinates by weight + v->homogeneous[0] *= invW; + v->homogeneous[1] *= invW; + v->homogeneous[2] *= invW; + + // Division of texture coordinates (perspective-correct) + v->texcoord[0] *= invW; + v->texcoord[1] *= invW; + + // Division of colors (perspective-correct) + v->color[0] *= invW; + v->color[1] *= invW; + v->color[2] *= invW; + v->color[3] *= invW; + + // Transformation to screen space + sw_project_ndc_to_screen(v->screen, v->homogeneous); + } + } +} + +#define DEFINE_TRIANGLE_RASTER_SCANLINE(FUNC_NAME, ENABLE_TEXTURE, ENABLE_DEPTH_TEST, ENABLE_COLOR_BLEND) \ +static inline void FUNC_NAME(const sw_texture_t* tex, const sw_vertex_t* start, \ + const sw_vertex_t* end, float duDy, float dvDy) \ +{ \ + /* Convert and center the screen coordinates */ \ + \ + int xStart = (int)(start->screen[0] + 0.5f); \ + int xEnd = (int)(end->screen[0] + 0.5f); \ + int y = (int)start->screen[1]; \ + \ + /* Compute the inverse horizontal distance along the X axis */ \ + \ + float dx = end->screen[0] - start->screen[0]; \ + if (fabsf(dx) < 1e-6f) return; \ + float dxRcp = 1.0f / dx; \ + \ + /* Compute the interpolation steps along the X axis */ \ + \ + float dzDx = (end->homogeneous[2] - start->homogeneous[2]) * dxRcp; \ + float dwDx = (end->homogeneous[3] - start->homogeneous[3]) * dxRcp; \ + \ + float dcDx[4]; \ + dcDx[0] = (end->color[0] - start->color[0]) * dxRcp; \ + dcDx[1] = (end->color[1] - start->color[1]) * dxRcp; \ + dcDx[2] = (end->color[2] - start->color[2]) * dxRcp; \ + dcDx[3] = (end->color[3] - start->color[3]) * dxRcp; \ + \ + float duDx, dvDx; \ + if (ENABLE_TEXTURE) { \ + duDx = (end->texcoord[0] - start->texcoord[0]) * dxRcp; \ + dvDx = (end->texcoord[1] - start->texcoord[1]) * dxRcp; \ + } \ + \ + /* Initializing the interpolation starting values */ \ + \ + float z = start->homogeneous[2]; \ + float w = start->homogeneous[3]; \ + \ + float color[4]; \ + color[0] = start->color[0]; \ + color[1] = start->color[1]; \ + color[2] = start->color[2]; \ + color[3] = start->color[3]; \ + \ + float u, v; \ + if (ENABLE_TEXTURE) { \ + u = start->texcoord[0]; \ + v = start->texcoord[1]; \ + } \ + \ + /* Pre-calculate the starting pointers for the framebuffer row */ \ + \ + void* cptr = sw_framebuffer_get_color_addr( \ + RLSW.framebuffer.color, y * RLSW.framebuffer.width + xStart); \ + \ + void* dptr = sw_framebuffer_get_depth_addr( \ + RLSW.framebuffer.depth, y * RLSW.framebuffer.width + xStart); \ + \ + /* Scanline rasterization */ \ + \ + for (int x = xStart; x < xEnd; x++) \ + { \ + /* Test and write depth */ \ + \ + if (ENABLE_DEPTH_TEST) \ + { \ + /* TODO: Implement different depth funcs? */ \ + float depth = sw_framebuffer_read_depth(dptr); \ + if (z > depth) goto discard; \ + } \ + \ + sw_framebuffer_write_depth(dptr, z); \ + \ + /* Pixel color computation */ \ + \ + float wRcp = 1.0f / w; \ + \ + float srcColor[4] = { \ + color[0] * wRcp, \ + color[1] * wRcp, \ + color[2] * wRcp, \ + color[3] * wRcp \ + }; \ + \ + if (ENABLE_TEXTURE) \ + { \ + float texColor[4]; \ + float s = u * wRcp; \ + float t = v * wRcp; \ + sw_texture_sample(texColor, tex, s, t, duDx, duDy, dvDx, dvDy); \ + srcColor[0] *= texColor[0]; \ + srcColor[1] *= texColor[1]; \ + srcColor[2] *= texColor[2]; \ + srcColor[3] *= texColor[3]; \ + } \ + \ + if (ENABLE_COLOR_BLEND) \ + { \ + float dstColor[4]; \ + sw_framebuffer_read_color(dstColor, cptr); \ + \ + sw_blend_colors(dstColor, srcColor); \ + dstColor[0] = sw_saturate(dstColor[0]); \ + dstColor[1] = sw_saturate(dstColor[1]); \ + dstColor[2] = sw_saturate(dstColor[2]); \ + \ + sw_framebuffer_write_color(cptr, dstColor); \ + } \ + else \ + { \ + sw_framebuffer_write_color(cptr, srcColor); \ + } \ + \ + /* Increment the interpolation parameter, UVs, and pointers */ \ + \ + discard: \ + \ + z += dzDx; \ + w += dwDx; \ + color[0] += dcDx[0]; \ + color[1] += dcDx[1]; \ + color[2] += dcDx[2]; \ + color[3] += dcDx[3]; \ + if (ENABLE_TEXTURE) { \ + u += duDx; \ + v += dvDx; \ + } \ + \ + sw_framebuffer_inc_color_addr(&cptr); \ + sw_framebuffer_inc_depth_addr(&dptr); \ + } \ +} + +#define DEFINE_TRIANGLE_RASTER(FUNC_NAME, FUNC_SCANLINE, ENABLE_TEXTURE) \ +static inline void FUNC_NAME(const sw_vertex_t* v0, const sw_vertex_t* v1, const sw_vertex_t* v2, \ + const sw_texture_t* tex) \ +{ \ + /* Swap vertices by increasing y */ \ + \ + if (v0->screen[1] > v1->screen[1]) { const sw_vertex_t* tmp = v0; v0 = v1; v1 = tmp; } \ + if (v1->screen[1] > v2->screen[1]) { const sw_vertex_t* tmp = v1; v1 = v2; v2 = tmp; } \ + if (v0->screen[1] > v1->screen[1]) { const sw_vertex_t* tmp = v0; v0 = v1; v1 = tmp; } \ + \ + /* Extracting coordinates from the sorted vertices */ \ + \ + float x0 = v0->screen[0], y0 = v0->screen[1]; \ + float x1 = v1->screen[0], y1 = v1->screen[1]; \ + float x2 = v2->screen[0], y2 = v2->screen[1]; \ + \ + /* Compute height differences */ \ + \ + float h02 = y2 - y0; \ + float h01 = y1 - y0; \ + float h12 = y2 - y1; \ + \ + if (h02 < 1e-6f) { \ + return; \ + } \ + \ + /* Precompute the inverse values without additional checks */ \ + \ + float invH02 = 1.0f / h02; \ + float invH01 = (h01 > 1e-6f) ? 1.0f / h01 : 0.0f; \ + float invH12 = (h12 > 1e-6f) ? 1.0f / h12 : 0.0f; \ + \ + /* Pre-calculation of slopes */ \ + \ + float dx02 = (x2 - x0) * invH02; \ + float dx01 = (x1 - x0) * invH01; \ + float dx12 = (x2 - x1) * invH12; \ + \ + /* Y bounds (vertical clipping) */ \ + \ + int yTop = (int)(y0 + 0.5f); \ + int yMiddle = (int)(y1 + 0.5f); \ + int yBottom = (int)(y2 + 0.5f); \ + \ + /* Compute gradients for each side of the triangle */ \ + \ + sw_vertex_t vDy02, vDy01, vDy12; \ + sw_get_vertex_grad_PTCH(&vDy02, v0, v2, invH02); \ + sw_get_vertex_grad_PTCH(&vDy01, v0, v1, invH01); \ + sw_get_vertex_grad_PTCH(&vDy12, v1, v2, invH12); \ + \ + /* Initializing scanline variables */ \ + \ + sw_vertex_t vLeft = *v0; \ + vLeft.screen[0] = x0; \ + \ + sw_vertex_t vRight = *v0; \ + vRight.screen[0] = x0; \ + \ + /* Scanline for the upper part of the triangle */ \ + \ + for (int y = yTop; y < yMiddle; y++) \ + { \ + vLeft.screen[1] = vRight.screen[1] = y; \ + \ + if (vLeft.screen[0] < vRight.screen[0]) { \ + FUNC_SCANLINE(tex, &vLeft, &vRight, vDy02.texcoord[0], vDy02.texcoord[1]); \ + } \ + else { \ + FUNC_SCANLINE(tex, &vRight, &vLeft, vDy02.texcoord[0], vDy02.texcoord[1]); \ + } \ + \ + sw_add_vertex_grad_PTCH(&vLeft, &vDy02); \ + vLeft.screen[0] += dx02; \ + \ + sw_add_vertex_grad_PTCH(&vRight, &vDy01); \ + vRight.screen[0] += dx01; \ + } \ + \ + /* Scanline for the lower part of the triangle */ \ + \ + vRight = *v1, vRight.screen[0] = x1; \ + \ + for (int y = yMiddle; y < yBottom; y++) \ + { \ + vLeft.screen[1] = vRight.screen[1] = y; \ + \ + if (vLeft.screen[0] < vRight.screen[0]) { \ + FUNC_SCANLINE(tex, &vLeft, &vRight, vDy02.texcoord[0], vDy02.texcoord[1]); \ + } \ + else { \ + FUNC_SCANLINE(tex, &vRight, &vLeft, vDy02.texcoord[0], vDy02.texcoord[1]); \ + } \ + \ + sw_add_vertex_grad_PTCH(&vLeft, &vDy02); \ + vLeft.screen[0] += dx02; \ + \ + sw_add_vertex_grad_PTCH(&vRight, &vDy12); \ + vRight.screen[0] += dx12; \ + } \ +} + +DEFINE_TRIANGLE_RASTER_SCANLINE(sw_triangle_raster_scanline, 0, 0, 0) +DEFINE_TRIANGLE_RASTER_SCANLINE(sw_triangle_raster_scanline_TEX, 1, 0, 0) +DEFINE_TRIANGLE_RASTER_SCANLINE(sw_triangle_raster_scanline_DEPTH, 0, 1, 0) +DEFINE_TRIANGLE_RASTER_SCANLINE(sw_triangle_raster_scanline_BLEND, 0, 0, 1) +DEFINE_TRIANGLE_RASTER_SCANLINE(sw_triangle_raster_scanline_TEX_DEPTH, 1, 1, 0) +DEFINE_TRIANGLE_RASTER_SCANLINE(sw_triangle_raster_scanline_TEX_BLEND, 1, 0, 1) +DEFINE_TRIANGLE_RASTER_SCANLINE(sw_triangle_raster_scanline_DEPTH_BLEND, 0, 1, 1) +DEFINE_TRIANGLE_RASTER_SCANLINE(sw_triangle_raster_scanline_TEX_DEPTH_BLEND, 1, 1, 1) + +DEFINE_TRIANGLE_RASTER(sw_triangle_raster, sw_triangle_raster_scanline, false) +DEFINE_TRIANGLE_RASTER(sw_triangle_raster_TEX, sw_triangle_raster_scanline_TEX, true) +DEFINE_TRIANGLE_RASTER(sw_triangle_raster_DEPTH, sw_triangle_raster_scanline_DEPTH, false) +DEFINE_TRIANGLE_RASTER(sw_triangle_raster_BLEND, sw_triangle_raster_scanline_BLEND, false) +DEFINE_TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH, sw_triangle_raster_scanline_TEX_DEPTH, true) +DEFINE_TRIANGLE_RASTER(sw_triangle_raster_TEX_BLEND, sw_triangle_raster_scanline_TEX_BLEND, true) +DEFINE_TRIANGLE_RASTER(sw_triangle_raster_DEPTH_BLEND, sw_triangle_raster_scanline_DEPTH_BLEND, false) +DEFINE_TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH_BLEND, sw_triangle_raster_scanline_TEX_DEPTH_BLEND, true) + +static inline void sw_triangle_render(void) +{ + if (RLSW.stateFlags & SW_STATE_CULL_FACE) { + if (!sw_triangle_face_culling()) { + return; + } + } + + sw_triangle_clip_and_project(); + + if (RLSW.vertexCounter < 3) { + return; + } + +# define TRIANGLE_RASTER(RASTER_FUNC) \ + { \ + for (int i = 0; i < RLSW.vertexCounter - 2; i++) { \ + RASTER_FUNC( \ + &RLSW.vertexBuffer[0], \ + &RLSW.vertexBuffer[i + 1], \ + &RLSW.vertexBuffer[i + 2], \ + &RLSW.loadedTextures[RLSW.currentTexture] \ + ); \ + } \ + } + + if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) { + TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH_BLEND) + } + else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) { + TRIANGLE_RASTER(sw_triangle_raster_DEPTH_BLEND) + } + else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_BLEND)) { + TRIANGLE_RASTER(sw_triangle_raster_TEX_BLEND) + } + else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST)) { + TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH) + } + else if (SW_STATE_CHECK(SW_STATE_BLEND)) { + TRIANGLE_RASTER(sw_triangle_raster_BLEND) + } + else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST)) { + TRIANGLE_RASTER(sw_triangle_raster_DEPTH) + } + else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D)) { + TRIANGLE_RASTER(sw_triangle_raster_TEX) + } + else { + TRIANGLE_RASTER(sw_triangle_raster) + } + +# undef TRIANGLE_RASTER +} + +/* === Quad Rendering Part === */ + +static inline bool sw_quad_face_culling(void) +{ + // NOTE: Face culling is done before clipping to avoid unnecessary computations. + // To handle quads crossing the w=0 plane correctly, + // we perform the winding order test in homogeneous coordinates directly, + // before the perspective division (division by w). + // For a convex quad with vertices P0, P1, P2, P3 in sequential order, + // the winding order of the quad is the same as the winding order + // of the triangle P0 P1 P2. We use the homogeneous triangle + // winding test on this first triangle. + + // Preload homogeneous coordinates into local variables + const float* h0 = RLSW.vertexBuffer[0].homogeneous; + const float* h1 = RLSW.vertexBuffer[1].homogeneous; + const float* h2 = RLSW.vertexBuffer[2].homogeneous; + + // NOTE: h3 is not needed for this test + // const float* h3 = RLSW.vertexBuffer[3].homogeneous; + + // Compute a value proportional to the signed area of the triangle P0 P1 P2 + // in the projected 2D plane, calculated directly using homogeneous coordinates + // BEFORE division by w. + // This is the determinant of the matrix formed by the (x, y, w) components + // of the vertices P0, P1, and P2. Its sign correctly indicates the winding order + // in homogeneous space and its relationship to the projected 2D winding order, + // even with negative w values. + // The determinant formula used here is: + // h0.x * (h1.y * h2.w - h2.y * h1.w) + + // h1.x * (h2.y * h0.w - h0.y * h2.w) + + // h2.x * (h0.y * h1.w - h1.y * h0.w) + + const float hSgnArea = + h0[0] * (h1[1] * h2[3] - h2[1] * h1[3]) + + h1[0] * (h2[1] * h0[3] - h0[1] * h2[3]) + + h2[0] * (h0[1] * h1[3] - h1[1] * h0[3]); + + // Perform face culling based on the winding order determined by the sign + // of the homogeneous area/determinant of triangle P0 P1 P2. + // This test is robust for points with w > 0 or w < 0 within the triangle, + // correctly capturing the change in orientation when crossing the w=0 plane. + + // A positive hSgnArea typically corresponds to a counter-clockwise + // winding in the projected space when all w > 0. + // A value of 0 for hSgnArea means P0, P1, P2 are collinear in (x, y, w) + // space, which corresponds to a degenerate triangle projection. + // Such quads might also be degenerate or non-planar. They are typically + // not culled by this test (0 < 0 is false, 0 > 0 is false) + // and should be handled by the clipper if necessary. + + return (RLSW.cullFace == SW_FRONT) + ? (hSgnArea < 0.0f) // Cull if winding is "clockwise" in the projected sense + : (hSgnArea > 0.0f); // Cull if winding is "counter-clockwise" in the projected sense +} + +static inline void sw_quad_clip_and_project(void) +{ + sw_vertex_t* polygon = RLSW.vertexBuffer; + int* vertexCounter = &RLSW.vertexCounter; + + if (sw_polygon_clip(polygon, vertexCounter)) { + + // Transformation to screen space and normalization + for (int i = 0; i < *vertexCounter; i++) { + sw_vertex_t *v = &polygon[i]; + + // Calculation of the reciprocal of W for normalization + // as well as perspective-correct attributes + const float invW = 1.0f / v->homogeneous[3]; + v->homogeneous[3] = invW; + + // Division of XYZ coordinates by weight + v->homogeneous[0] *= invW; + v->homogeneous[1] *= invW; + v->homogeneous[2] *= invW; + + // Division of texture coordinates (perspective-correct) + v->texcoord[0] *= invW; + v->texcoord[1] *= invW; + + // Division of colors (perspective-correct) + v->color[0] *= invW; + v->color[1] *= invW; + v->color[2] *= invW; + v->color[3] *= invW; + + // Transformation to screen space + sw_project_ndc_to_screen(v->screen, v->homogeneous); + } + } +} + +static inline bool sw_quad_is_axis_aligned(void) +{ + int horizontal = 0; + int vertical = 0; + + for (int i = 0; i < 4; i++) + { + if (RLSW.vertexBuffer[i].homogeneous[3] != 1.0f) { + return false; + } + + const float* v0 = RLSW.vertexBuffer[i].position; + const float* v1 = RLSW.vertexBuffer[(i + 1) % 4].position; + + 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++; + } + else { + // Diagonal edge -> not axis-aligned + return false; + } + } + + return (horizontal == 2 && vertical == 2); +} + +static inline void sw_quad_sort_cw(const sw_vertex_t** output) +{ + // Sort 4 quad vertices into clockwise order with fixed layout: + // + // v0 -- v1 + // | | + // v3 -- v2 + // + // The goal is: + // - v0: top-left (minimum Y, then minimum X) + // - v1: top-right (minimum Y row, maximum X) + // - v2: bottom-right (maximum Y, maximum X) + // - v3: bottom-left (maximum Y, minimum X) + + const sw_vertex_t* input = RLSW.vertexBuffer; + + // Separate vertices into top and bottom based on Y-coordinate + const sw_vertex_t* top[2] = {NULL, NULL}; + const sw_vertex_t* bottom[2] = {NULL, NULL}; + int topCount = 0, bottomCount = 0; + + // Find minimum and maximum Y + float minY = input[0].screen[1]; + float maxY = input[0].screen[1]; + + for (int i = 1; i < 4; i++) { + if (input[i].screen[1] < minY) minY = input[i].screen[1]; + if (input[i].screen[1] > maxY) maxY = input[i].screen[1]; + } + + // 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 we don't have enough top/bottom vertices (e.g., Y values are all different), + // classify vertices as top or bottom based on whether they're closer to minY or maxY + for (int i = 0; i < 4; i++) { + if (topCount < 2 && &input[i] != top[0] && &input[i] != bottom[0] && &input[i] != bottom[1]) { + if (fabs(input[i].screen[1] - minY) <= fabs(input[i].screen[1] - maxY)) { + top[topCount++] = &input[i]; + } + } + if (bottomCount < 2 && &input[i] != top[0] && &input[i] != top[1] && &input[i] != bottom[0]) { + if (fabs(input[i].screen[1] - maxY) < fabs(input[i].screen[1] - minY)) { + bottom[bottomCount++] = &input[i]; + } + } + } + + // Sort top vertices by X (left to right) + if (topCount == 2 && top[0]->screen[0] > top[1]->screen[0]) { + const sw_vertex_t* temp = top[0]; + top[0] = top[1]; + top[1] = temp; + } + + // Sort bottom vertices by X (left to right) + if (bottomCount == 2 && bottom[0]->screen[0] > bottom[1]->screen[0]) { + const sw_vertex_t* temp = bottom[0]; + bottom[0] = bottom[1]; + bottom[1] = temp; + } + + // Assign vertices in clockwise order as per the required layout + output[0] = top[0]; // v0: top-left + output[1] = top[topCount-1]; // v1: top-right + output[2] = bottom[bottomCount-1]; // v2: bottom-right + output[3] = bottom[0]; // v3: bottom-left +} + +// REVIEW: Could a perfectly aligned quad, where one of the four points has a different depth, still appear perfectly aligned from a certain point of view? +// Because in that case, we would still need to perform perspective division for textures and colors... +#define DEFINE_QUAD_RASTER_AXIS_ALIGNED(FUNC_NAME, ENABLE_TEXTURE, ENABLE_DEPTH_TEST, ENABLE_COLOR_BLEND) \ +static inline void FUNC_NAME(void) \ +{ \ + const sw_vertex_t* sortedVerts[4]; \ + sw_quad_sort_cw(sortedVerts); \ + \ + const sw_vertex_t* v0 = sortedVerts[0]; \ + const sw_vertex_t* v1 = sortedVerts[1]; \ + const sw_vertex_t* v2 = sortedVerts[2]; \ + const sw_vertex_t* v3 = sortedVerts[3]; \ + \ + /* Screen bounds (axis-aligned) */ \ + \ + int xMin = (int)(v0->screen[0] + 0.5f); \ + int yMin = (int)(v0->screen[1] + 0.5f); \ + int xMax = (int)(v2->screen[0] + 0.5f); \ + int yMax = (int)(v2->screen[1] + 0.5f); \ + \ + int width = xMax - xMin; \ + int height = yMax - yMin; \ + \ + 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; \ + \ + /* Calculation of vertex gradients in X and Y */ \ + \ + float tcDx[2], tcDy[2]; \ + if (ENABLE_TEXTURE) { \ + tcDx[0] = (v1->texcoord[0] - v0->texcoord[0]) * wRcp; \ + tcDx[1] = (v1->texcoord[1] - v0->texcoord[1]) * wRcp; \ + tcDy[0] = (v3->texcoord[0] - v0->texcoord[0]) * hRcp; \ + tcDy[1] = (v3->texcoord[1] - v0->texcoord[1]) * hRcp; \ + } \ + \ + float cDx[4], cDy[4]; \ + cDx[0] = (v1->color[0] - v0->color[0]) * wRcp; \ + cDx[1] = (v1->color[1] - v0->color[1]) * wRcp; \ + cDx[2] = (v1->color[2] - v0->color[2]) * wRcp; \ + cDx[3] = (v1->color[3] - v0->color[3]) * wRcp; \ + cDy[0] = (v3->color[0] - v0->color[0]) * hRcp; \ + cDy[1] = (v3->color[1] - v0->color[1]) * hRcp; \ + cDy[2] = (v3->color[2] - v0->color[2]) * hRcp; \ + cDy[3] = (v3->color[3] - v0->color[3]) * hRcp; \ + \ + float zDx, zDy; \ + zDx = (v1->homogeneous[2] - v0->homogeneous[2]) * wRcp; \ + zDy = (v3->homogeneous[2] - v0->homogeneous[2]) * hRcp; \ + \ + /* Start of quad rasterization */ \ + \ + const sw_texture_t* tex; \ + if (ENABLE_TEXTURE) { \ + tex = &RLSW.loadedTextures[RLSW.currentTexture]; \ + } \ + \ + void* cDstBase = RLSW.framebuffer.color; \ + void* dDstBase = RLSW.framebuffer.depth; \ + int wDst = RLSW.framebuffer.width; \ + \ + float zScanline = v0->homogeneous[2]; \ + float uScanline = v0->texcoord[0]; \ + float vScanline = v0->texcoord[1]; \ + \ + float colorScanline[4] = { \ + v0->color[0], \ + v0->color[1], \ + v0->color[2], \ + v0->color[3] \ + }; \ + \ + for (int y = yMin; y < yMax; y++) \ + { \ + void* cptr = sw_framebuffer_get_color_addr(cDstBase, y * wDst + xMin); \ + void* dptr = sw_framebuffer_get_depth_addr(dDstBase, y * wDst + xMin); \ + \ + float z = zScanline; \ + float u = uScanline; \ + float v = vScanline; \ + \ + float color[4] = { \ + colorScanline[0], \ + colorScanline[1], \ + colorScanline[2], \ + colorScanline[3] \ + }; \ + \ + /* Scanline rasterization */ \ + \ + for (int x = xMin; x < xMax; x++) \ + { \ + /* Test and write depth */ \ + \ + if (ENABLE_DEPTH_TEST) \ + { \ + /* TODO: Implement different depth funcs? */ \ + float depth = sw_framebuffer_read_depth(dptr); \ + if (z > depth) goto discard; \ + } \ + \ + sw_framebuffer_write_depth(dptr, z); \ + \ + /* Pixel color computation */ \ + \ + float srcColor[4] = { \ + color[0], \ + color[1], \ + color[2], \ + color[3] \ + }; \ + \ + if (ENABLE_TEXTURE) \ + { \ + float texColor[4]; \ + sw_texture_sample(texColor, tex, u, v, tcDx[0], tcDy[0], tcDx[1], tcDy[1]); \ + srcColor[0] *= texColor[0]; \ + srcColor[1] *= texColor[1]; \ + srcColor[2] *= texColor[2]; \ + srcColor[3] *= texColor[3]; \ + } \ + \ + if (ENABLE_COLOR_BLEND) \ + { \ + float dstColor[4]; \ + sw_framebuffer_read_color(dstColor, cptr); \ + \ + sw_blend_colors(dstColor, srcColor); \ + dstColor[0] = sw_saturate(dstColor[0]); \ + dstColor[1] = sw_saturate(dstColor[1]); \ + dstColor[2] = sw_saturate(dstColor[2]); \ + dstColor[3] = sw_saturate(dstColor[3]); \ + \ + sw_framebuffer_write_color(cptr, dstColor); \ + } \ + else \ + { \ + sw_framebuffer_write_color(cptr, srcColor); \ + } \ + \ + discard: \ + \ + z += zDx; \ + \ + color[0] += cDx[0]; \ + color[1] += cDx[1]; \ + color[2] += cDx[2]; \ + color[3] += cDx[3]; \ + \ + if (ENABLE_TEXTURE) { \ + u += tcDx[0]; \ + v += tcDx[1]; \ + } \ + \ + sw_framebuffer_inc_color_addr(&cptr); \ + sw_framebuffer_inc_depth_addr(&dptr); \ + } \ + \ + zScanline += zDy; \ + \ + colorScanline[0] += cDy[0]; \ + colorScanline[1] += cDy[1]; \ + colorScanline[2] += cDy[2]; \ + colorScanline[3] += cDy[3]; \ + \ + if (ENABLE_TEXTURE) { \ + uScanline += tcDy[0]; \ + vScanline += tcDy[1]; \ + } \ + } \ +} + +DEFINE_QUAD_RASTER_AXIS_ALIGNED(sw_quad_raster_axis_aligned, 0, 0, 0) +DEFINE_QUAD_RASTER_AXIS_ALIGNED(sw_quad_raster_axis_aligned_TEX, 1, 0, 0) +DEFINE_QUAD_RASTER_AXIS_ALIGNED(sw_quad_raster_axis_aligned_DEPTH, 0, 1, 0) +DEFINE_QUAD_RASTER_AXIS_ALIGNED(sw_quad_raster_axis_aligned_BLEND, 0, 0, 1) +DEFINE_QUAD_RASTER_AXIS_ALIGNED(sw_quad_raster_axis_aligned_TEX_DEPTH, 1, 1, 0) +DEFINE_QUAD_RASTER_AXIS_ALIGNED(sw_quad_raster_axis_aligned_TEX_BLEND, 1, 0, 1) +DEFINE_QUAD_RASTER_AXIS_ALIGNED(sw_quad_raster_axis_aligned_DEPTH_BLEND, 0, 1, 1) +DEFINE_QUAD_RASTER_AXIS_ALIGNED(sw_quad_raster_axis_aligned_TEX_DEPTH_BLEND, 1, 1, 1) + +static inline void sw_quad_render(void) +{ + if (RLSW.stateFlags & SW_STATE_CULL_FACE) { + if (!sw_quad_face_culling()) { + return; + } + } + + sw_quad_clip_and_project(); + + if (RLSW.vertexCounter < 3) { + return; + } + + 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(); + } + else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_BLEND)) { + sw_quad_raster_axis_aligned_TEX_BLEND(); + } + else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST)) { + sw_quad_raster_axis_aligned_TEX_DEPTH(); + } + else if (SW_STATE_CHECK(SW_STATE_BLEND)) { + sw_quad_raster_axis_aligned_BLEND(); + } + else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST)) { + sw_quad_raster_axis_aligned_DEPTH(); + } + else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D)) { + sw_quad_raster_axis_aligned_TEX(); + } + else { + sw_quad_raster_axis_aligned(); + } + return; + } + +# define TRIANGLE_RASTER(RASTER_FUNC) \ + { \ + for (int i = 0; i < RLSW.vertexCounter - 2; i++) { \ + RASTER_FUNC( \ + &RLSW.vertexBuffer[0], \ + &RLSW.vertexBuffer[i + 1], \ + &RLSW.vertexBuffer[i + 2], \ + &RLSW.loadedTextures[RLSW.currentTexture] \ + ); \ + } \ + } + + if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) { + TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH_BLEND) + } + else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) { + TRIANGLE_RASTER(sw_triangle_raster_DEPTH_BLEND) + } + else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_BLEND)) { + TRIANGLE_RASTER(sw_triangle_raster_TEX_BLEND) + } + else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST)) { + TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH) + } + else if (SW_STATE_CHECK(SW_STATE_BLEND)) { + TRIANGLE_RASTER(sw_triangle_raster_BLEND) + } + else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST)) { + TRIANGLE_RASTER(sw_triangle_raster_DEPTH) + } + else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D)) { + TRIANGLE_RASTER(sw_triangle_raster_TEX) + } + else { + TRIANGLE_RASTER(sw_triangle_raster) + } + +# undef TRIANGLE_RASTER +} + +/* === Line Rendering Part === */ + +static inline bool sw_line_clip_coord(float q, float p, float* t0, float* t1) +{ + if (fabsf(p) < SW_CLIP_EPSILON) { + // Check if the line is entirely outside the window + if (q < -SW_CLIP_EPSILON) return 0; // Completely outside + return 1; // Completely inside or on the edges + } + + const float r = q / p; + + if (p < 0) { + if (r > *t1) return 0; + if (r > *t0) *t0 = r; + } + else { + if (r < *t0) return 0; + if (r < *t1) *t1 = r; + } + + return 1; +} + +static inline bool sw_line_clip(sw_vertex_t* v0, sw_vertex_t* v1) +{ + float t0 = 0.0f, t1 = 1.0f; + float dH[4], dC[4]; + + for (int i = 0; i < 4; i++) { + dH[i] = v1->homogeneous[i] - v0->homogeneous[i]; + dC[i] = v1->color[i] - v0->color[i]; + } + + // Clipping Liang-Barsky + if (!sw_line_clip_coord(v0->homogeneous[3] - v0->homogeneous[0], -dH[3] + dH[0], &t0, &t1)) return false; + if (!sw_line_clip_coord(v0->homogeneous[3] + v0->homogeneous[0], -dH[3] - dH[0], &t0, &t1)) return false; + if (!sw_line_clip_coord(v0->homogeneous[3] - v0->homogeneous[1], -dH[3] + dH[1], &t0, &t1)) return false; + if (!sw_line_clip_coord(v0->homogeneous[3] + v0->homogeneous[1], -dH[3] - dH[1], &t0, &t1)) return false; + if (!sw_line_clip_coord(v0->homogeneous[3] - v0->homogeneous[2], -dH[3] + dH[2], &t0, &t1)) return false; + if (!sw_line_clip_coord(v0->homogeneous[3] + v0->homogeneous[2], -dH[3] - dH[2], &t0, &t1)) return false; + + // Clipping Scissor + if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST) { + if (!sw_line_clip_coord(v0->homogeneous[0] - RLSW.scClipMin[0] * v0->homogeneous[3], RLSW.scClipMin[0] * dH[3] - dH[0], &t0, &t1)) return false; + if (!sw_line_clip_coord(RLSW.scClipMax[0] * v0->homogeneous[3] - v0->homogeneous[0], dH[0] - RLSW.scClipMax[0] * dH[3], &t0, &t1)) return false; + if (!sw_line_clip_coord(v0->homogeneous[1] - RLSW.scClipMin[1] * v0->homogeneous[3], RLSW.scClipMin[1] * dH[3] - dH[1], &t0, &t1)) return false; + if (!sw_line_clip_coord(RLSW.scClipMax[1] * v0->homogeneous[3] - v0->homogeneous[1], dH[1] - RLSW.scClipMax[1] * dH[3], &t0, &t1)) return false; + } + + // Interpolation of new coordinates + if (t1 < 1.0f) { + for (int i = 0; i < 4; i++) { + v1->homogeneous[i] = v0->homogeneous[i] + t1 * dH[i]; + v1->color[i] = v0->color[i] + t1 * dC[i]; + } + } + if (t0 > 0.0f) { + for (int i = 0; i < 4; i++) { + v0->homogeneous[i] += t0 * dH[i]; + v0->color[i] += t0 * dC[i]; + } + } + + return true; +} + +static inline bool sw_line_clip_and_project(sw_vertex_t* v0, sw_vertex_t* v1) +{ + if (!sw_line_clip(v0, v1)) { + return false; + } + + // Convert homogeneous coordinates to NDC + v0->homogeneous[3] = 1.0f / v0->homogeneous[3]; + v1->homogeneous[3] = 1.0f / v1->homogeneous[3]; + for (int i = 0; i < 3; i++) { + v0->homogeneous[i] *= v0->homogeneous[3]; + v1->homogeneous[i] *= v1->homogeneous[3]; + } + + // Convert NDC coordinates to screen space + sw_project_ndc_to_screen(v0->screen, v0->homogeneous); + sw_project_ndc_to_screen(v1->screen, v1->homogeneous); + + return true; +} + +#define DEFINE_LINE_RASTER(FUNC_NAME, ENABLE_DEPTH_TEST, ENABLE_COLOR_BLEND) \ +static inline void FUNC_NAME(const sw_vertex_t* v0, const sw_vertex_t* v1) \ +{ \ + int x1 = (int)(v0->screen[0] + 0.5f); \ + int y1 = (int)(v0->screen[1] + 0.5f); \ + int x2 = (int)(v1->screen[0] + 0.5f); \ + int y2 = (int)(v1->screen[1] + 0.5f); \ + \ + int dx = x2 - x1; \ + int dy = y2 - y1; \ + \ + /* Handling of lines that are more horizontal or vertical */ \ + \ + if (dx == 0 && dy == 0) { \ + /* TODO: A point should be rendered here */ \ + return; \ + } \ + \ + bool yLonger = (abs(dy) > abs(dx)); \ + int longLen, shortLen; \ + \ + if (yLonger) { \ + longLen = dy; \ + shortLen = dx; \ + } \ + else { \ + longLen = dx; \ + shortLen = dy; \ + } \ + \ + /* Handling of traversal direction */ \ + \ + int sgnInc = (longLen < 0) ? -1 : 1; \ + int abslongLen = abs(longLen); \ + \ + /* Calculation of the increment step for the shorter coordinate */ \ + \ + int decInc = 0; \ + if (abslongLen != 0) { \ + decInc = (shortLen << 16) / abslongLen; \ + } \ + \ + float longLenRcp = (abslongLen != 0) ? (1.0f / abslongLen) : 0.0f; \ + \ + /* Calculation of interpolation steps */ \ + \ + const float zStep = (v1->homogeneous[2] - v0->homogeneous[2]) * longLenRcp; \ + const float rStep = (v1->color[0] - v0->color[0]) * longLenRcp; \ + const float gStep = (v1->color[1] - v0->color[1]) * longLenRcp; \ + const float bStep = (v1->color[2] - v0->color[2]) * longLenRcp; \ + const float aStep = (v1->color[3] - v0->color[3]) * longLenRcp; \ + \ + float z = v0->homogeneous[2]; \ + \ + float color[4] = { \ + v0->color[0], \ + v0->color[1], \ + v0->color[2], \ + v0->color[3] \ + }; \ + \ + const int fbWidth = RLSW.framebuffer.width; \ + void* cBuffer = RLSW.framebuffer.color; \ + void* dBuffer = RLSW.framebuffer.depth; \ + \ + int j = 0; \ + \ + if (yLonger) \ + { \ + for (int i = 0; i != longLen; i += sgnInc) \ + { \ + int offset = (y1 + i) * fbWidth + (x1 + (j >> 16)); \ + \ + void* dptr = sw_framebuffer_get_depth_addr(dBuffer, offset); \ + \ + if (ENABLE_DEPTH_TEST) { \ + float depth = sw_framebuffer_read_depth(dptr); \ + if (z > depth) goto discardA; \ + } \ + \ + sw_framebuffer_write_depth(dptr, z); \ + \ + void* cptr = sw_framebuffer_get_color_addr(cBuffer, offset); \ + \ + if (ENABLE_COLOR_BLEND) \ + { \ + float dstColor[4]; \ + sw_framebuffer_read_color(dstColor, cptr); \ + \ + sw_blend_colors(dstColor, color); \ + sw_framebuffer_write_color(cptr, dstColor); \ + } \ + else \ + { \ + sw_framebuffer_write_color(cptr, color); \ + } \ + \ + discardA: \ + j += decInc; \ + z += zStep; \ + color[0] += rStep; \ + color[1] += gStep; \ + color[2] += bStep; \ + color[3] += aStep; \ + } \ + } \ + else \ + { \ + for (int i = 0; i != longLen; i += sgnInc) \ + { \ + int offset = (y1 + (j >> 16)) * fbWidth + (x1 + i); \ + \ + void* dptr = sw_framebuffer_get_depth_addr(dBuffer, offset); \ + \ + if (ENABLE_DEPTH_TEST) { \ + float depth = sw_framebuffer_read_depth(dptr); \ + if (z > depth) goto discardB; \ + } \ + \ + sw_framebuffer_write_depth(dptr, z); \ + \ + void* cptr = sw_framebuffer_get_color_addr(cBuffer, offset); \ + \ + if (ENABLE_COLOR_BLEND) \ + { \ + float dstColor[4]; \ + sw_framebuffer_read_color(dstColor, cptr); \ + \ + sw_blend_colors(dstColor, color); \ + sw_framebuffer_write_color(cptr, dstColor); \ + } \ + else \ + { \ + sw_framebuffer_write_color(cptr, color); \ + } \ + \ + discardB: \ + j += decInc; \ + z += zStep; \ + color[0] += rStep; \ + color[1] += gStep; \ + color[2] += bStep; \ + color[3] += aStep; \ + } \ + } \ +} + +#define DEFINE_LINE_THICK_RASTER(FUNC_NAME, RASTER_FUNC) \ +void FUNC_NAME(const sw_vertex_t* v1, const sw_vertex_t* v2) \ +{ \ + sw_vertex_t tv1, tv2; \ + \ + int x1 = (int)v1->screen[0]; \ + int y1 = (int)v1->screen[1]; \ + int x2 = (int)v2->screen[0]; \ + int y2 = (int)v2->screen[1]; \ + \ + int dx = x2 - x1; \ + int dy = y2 - y1; \ + \ + RASTER_FUNC(v1, v2); \ + \ + if (dx != 0 && abs(dy / dx) < 1) { \ + int wy = (int)((RLSW.lineWidth - 1.0f) * abs(dx) / sqrtf(dx * dx + dy * dy)); \ + wy >>= 1; /* Division by 2 via bit shift */ \ + for (int i = 1; i <= wy; i++) { \ + tv1 = *v1, tv2 = *v2; \ + tv1.screen[1] -= i; \ + tv2.screen[1] -= i; \ + RASTER_FUNC(&tv1, &tv2); \ + tv1 = *v1, tv2 = *v2; \ + tv1.screen[1] += i; \ + tv2.screen[1] += i; \ + RASTER_FUNC(&tv1, &tv2); \ + } \ + } \ + else if (dy != 0) { \ + int wx = (int)((RLSW.lineWidth - 1.0f) * abs(dy) / sqrtf(dx * dx + dy * dy)); \ + wx >>= 1; /* Division by 2 via bit shift */ \ + for (int i = 1; i <= wx; i++) { \ + tv1 = *v1, tv2 = *v2; \ + tv1.screen[0] -= i; \ + tv2.screen[0] -= i; \ + RASTER_FUNC(&tv1, &tv2); \ + tv1 = *v1, tv2 = *v2; \ + tv1.screen[0] += i; \ + tv2.screen[0] += i; \ + RASTER_FUNC(&tv1, &tv2); \ + } \ + } \ +} + +DEFINE_LINE_RASTER(sw_line_raster, 0, 0) +DEFINE_LINE_RASTER(sw_line_raster_DEPTH, 1, 0) +DEFINE_LINE_RASTER(sw_line_raster_BLEND, 0, 1) +DEFINE_LINE_RASTER(sw_line_raster_DEPTH_BLEND, 1, 1) + +DEFINE_LINE_THICK_RASTER(sw_line_thick_raster, sw_line_raster) +DEFINE_LINE_THICK_RASTER(sw_line_thick_raster_DEPTH, sw_line_raster_DEPTH) +DEFINE_LINE_THICK_RASTER(sw_line_thick_raster_BLEND, sw_line_raster_BLEND) +DEFINE_LINE_THICK_RASTER(sw_line_thick_raster_DEPTH_BLEND, sw_line_raster_DEPTH_BLEND) + +static inline void sw_line_render(sw_vertex_t* vertices) +{ + if (!sw_line_clip_and_project(&vertices[0], &vertices[1])) { + return; + } + + if (RLSW.lineWidth >= 2.0f) { + if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) { + sw_line_thick_raster_DEPTH_BLEND(&vertices[0], &vertices[1]); + } + else if (SW_STATE_CHECK(SW_STATE_BLEND)) { + sw_line_thick_raster_BLEND(&vertices[0], &vertices[1]); + } + else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST)) { + sw_line_thick_raster_DEPTH(&vertices[0], &vertices[1]); + } + else { + sw_line_thick_raster(&vertices[0], &vertices[1]); + } + } + else { + if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) { + sw_line_raster_DEPTH_BLEND(&vertices[0], &vertices[1]); + } + else if (SW_STATE_CHECK(SW_STATE_BLEND)) { + sw_line_raster_BLEND(&vertices[0], &vertices[1]); + } + else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST)) { + sw_line_raster_DEPTH(&vertices[0], &vertices[1]); + } + else { + sw_line_raster(&vertices[0], &vertices[1]); + } + } +} + +/* === Point Rendering Part === */ + +static inline bool sw_point_clip_and_project(sw_vertex_t* v) +{ + if (v->homogeneous[3] != 1.0f) { + for (int_fast8_t i = 0; i < 3; i++) { + if (v->homogeneous[i] < -v->homogeneous[3] || v->homogeneous[i] > v->homogeneous[3]) { + return false; + } + } + v->homogeneous[3] = 1.0f / v->homogeneous[3]; + v->homogeneous[0] *= v->homogeneous[3]; + v->homogeneous[1] *= v->homogeneous[3]; + v->homogeneous[2] *= v->homogeneous[3]; + } + + sw_project_ndc_to_screen(v->screen, v->homogeneous); + + const int *min, *max; + + if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST) { + min = RLSW.scMin; + max = RLSW.scMax; + } + else { + min = RLSW.vpMin; + max = RLSW.vpMax; + } + + bool insideX = v->screen[0] - RLSW.pointRadius < max[0] + && v->screen[0] + RLSW.pointRadius > min[0]; + + bool insideY = v->screen[1] - RLSW.pointRadius < max[1] + && v->screen[1] + RLSW.pointRadius > min[1]; + + return insideX && insideY; +} + +#define DEFINE_POINT_RASTER(FUNC_NAME, ENABLE_DEPTH_TEST, ENABLE_COLOR_BLEND, CHECK_BOUNDS) \ +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; \ + } \ + 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; \ + } \ + \ + int offset = y * RLSW.framebuffer.width + x; \ + \ + void* dptr = sw_framebuffer_get_depth_addr( \ + RLSW.framebuffer.depth, offset \ + ); \ + \ + if (ENABLE_DEPTH_TEST) \ + { \ + float depth = sw_framebuffer_read_depth(dptr); \ + if (z > depth) return; \ + } \ + \ + sw_framebuffer_write_depth(dptr, z); \ + \ + void* cptr = sw_framebuffer_get_color_addr( \ + RLSW.framebuffer.color, offset \ + ); \ + \ + if (ENABLE_COLOR_BLEND) \ + { \ + float dstColor[4]; \ + sw_framebuffer_read_color(dstColor, cptr); \ + \ + sw_blend_colors(dstColor, color); \ + sw_framebuffer_write_color(cptr, dstColor); \ + } \ + else \ + { \ + sw_framebuffer_write_color(cptr, color); \ + } \ +} + +#define DEFINE_POINT_THICK_RASTER(FUNC_NAME, RASTER_FUNC) \ +static inline void FUNC_NAME(sw_vertex_t* v) \ +{ \ + int cx = v->screen[0]; \ + int cy = v->screen[1]; \ + float cz = v->homogeneous[2]; \ + int radius = RLSW.pointRadius; \ + const float* color = v->color; \ + \ + int x = 0; \ + int y = radius; \ + int d = 3 - 2 * radius; \ + \ + while (x <= y) { \ + for (int i = -x; i <= x; i++) { \ + RASTER_FUNC(cx + i, cy + y, cz, color); \ + RASTER_FUNC(cx + i, cy - y, cz, color); \ + } \ + for (int i = -y; i <= y; i++) { \ + RASTER_FUNC(cx + i, cy + x, cz, color); \ + RASTER_FUNC(cx + i, cy - x, cz, color); \ + } \ + if (d > 0) { \ + y--; \ + d = d + 4 * (x - y) + 10; \ + } \ + else { \ + d = d + 4 * x + 6; \ + } \ + x++; \ + } \ +} + +DEFINE_POINT_RASTER(sw_point_raster, 0, 0, 0) +DEFINE_POINT_RASTER(sw_point_raster_DEPTH, 1, 0, 0) +DEFINE_POINT_RASTER(sw_point_raster_BLEND, 0, 1, 0) +DEFINE_POINT_RASTER(sw_point_raster_DEPTH_BLEND, 1, 1, 0) + +DEFINE_POINT_RASTER(sw_point_raster_CHECK, 0, 0, 1) +DEFINE_POINT_RASTER(sw_point_raster_DEPTH_CHECK, 1, 0, 1) +DEFINE_POINT_RASTER(sw_point_raster_BLEND_CHECK, 0, 1, 1) +DEFINE_POINT_RASTER(sw_point_raster_DEPTH_BLEND_CHECK, 1, 1, 1) + +DEFINE_POINT_RASTER(sw_point_raster_CHECK_SCISSOR, 0, 0, SW_SCISSOR_TEST) +DEFINE_POINT_RASTER(sw_point_raster_DEPTH_CHECK_SCISSOR, 1, 0, SW_SCISSOR_TEST) +DEFINE_POINT_RASTER(sw_point_raster_BLEND_CHECK_SCISSOR, 0, 1, SW_SCISSOR_TEST) +DEFINE_POINT_RASTER(sw_point_raster_DEPTH_BLEND_CHECK_SCISSOR, 1, 1, SW_SCISSOR_TEST) + +DEFINE_POINT_THICK_RASTER(sw_point_thick_raster, sw_point_raster_CHECK) +DEFINE_POINT_THICK_RASTER(sw_point_thick_raster_DEPTH, sw_point_raster_DEPTH_CHECK) +DEFINE_POINT_THICK_RASTER(sw_point_thick_raster_BLEND, sw_point_raster_BLEND_CHECK) +DEFINE_POINT_THICK_RASTER(sw_point_thick_raster_DEPTH_BLEND, sw_point_raster_DEPTH_BLEND_CHECK) + +DEFINE_POINT_THICK_RASTER(sw_point_thick_raster_SCISSOR, sw_point_raster_CHECK_SCISSOR) +DEFINE_POINT_THICK_RASTER(sw_point_thick_raster_DEPTH_SCISSOR, sw_point_raster_DEPTH_CHECK_SCISSOR) +DEFINE_POINT_THICK_RASTER(sw_point_thick_raster_BLEND_SCISSOR, sw_point_raster_BLEND_CHECK_SCISSOR) +DEFINE_POINT_THICK_RASTER(sw_point_thick_raster_DEPTH_BLEND_SCISSOR, sw_point_raster_DEPTH_BLEND_CHECK_SCISSOR) + +static inline void sw_point_render(sw_vertex_t* v) +{ + if (!sw_point_clip_and_project(v)) { + return; + } + + if (RLSW.pointRadius >= 1.0f) { + if (SW_STATE_CHECK(SW_STATE_SCISSOR_TEST)) { + if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) { + sw_point_thick_raster_DEPTH_BLEND_SCISSOR(v); + } + else if (SW_STATE_CHECK(SW_STATE_BLEND)) { + sw_point_thick_raster_BLEND_SCISSOR(v); + } + else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST)) { + sw_point_thick_raster_DEPTH_SCISSOR(v); + } + else { + sw_point_thick_raster_SCISSOR(v); + } + } + else { + if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) { + sw_point_thick_raster_DEPTH_BLEND(v); + } + else if (SW_STATE_CHECK(SW_STATE_BLEND)) { + sw_point_thick_raster_BLEND(v); + } + else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST)) { + sw_point_thick_raster_DEPTH(v); + } + else { + sw_point_thick_raster(v); + } + } + } + else { + if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) { + sw_point_raster_DEPTH_BLEND( + v->screen[0], v->screen[1], + v->homogeneous[2], v->color + ); + } + else if (SW_STATE_CHECK(SW_STATE_BLEND)) { + sw_point_raster_BLEND( + v->screen[0], v->screen[1], + v->homogeneous[2], v->color + ); + } + else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST)) { + sw_point_raster_DEPTH( + v->screen[0], v->screen[1], + v->homogeneous[2], v->color + ); + } + else { + sw_point_raster( + v->screen[0], v->screen[1], + v->homogeneous[2], v->color + ); + } + } +} + +/* === Polygon Modes Rendering Part === */ + +static inline void sw_poly_point_render(void) +{ + for (int i = 0; i < RLSW.vertexCounter; i++) { + sw_point_render(&RLSW.vertexBuffer[i]); + } +} + +static inline void sw_poly_line_render(void) +{ + const sw_vertex_t* vertices = RLSW.vertexBuffer; + int cm1 = RLSW.vertexCounter - 1; + + for (int i = 0; i < cm1; i++) { + sw_line_render((sw_vertex_t[2]){ + vertices[i], vertices[i + 1] + }); + } + + sw_line_render((sw_vertex_t[2]){ + vertices[cm1], vertices[0] + }); +} + +static inline void sw_poly_fill_render(void) +{ + switch (RLSW.drawMode) { + case SW_POINTS: + sw_point_render(&RLSW.vertexBuffer[0]); + break; + case SW_LINES: + sw_line_render(RLSW.vertexBuffer); + break; + case SW_TRIANGLES: + sw_triangle_render(); + break; + case SW_QUADS: + sw_quad_render(); + break; + } +} + +/* === Some Validity Check Helper === */ + +static inline bool sw_is_texture_valid(uint32_t id) +{ + bool valid = true; + + if (id == 0) valid = false; + else if (id >= SW_MAX_TEXTURES) valid = false; + else if (RLSW.loadedTextures[id].pixels.cptr == 0) valid = false; + + return true; +} + +static inline bool sw_is_texture_filter_valid(int filter) +{ + return (filter == SW_NEAREST || filter == SW_LINEAR); +} + +static inline bool sw_is_texture_wrap_valid(int wrap) +{ + return (wrap == SW_REPEAT || wrap == SW_CLAMP); +} + +static inline bool sw_is_draw_mode_valid(int mode) +{ + bool result = false; + + switch (mode) { + case SW_POINTS: + case SW_LINES: + case SW_TRIANGLES: + case SW_QUADS: + result = true; + break; + default: + break; + } + + return result; +} + +static inline bool sw_is_poly_mode_valid(int mode) +{ + bool result = false; + + switch (mode) { + case SW_POINT: + case SW_LINE: + case SW_FILL: + result = true; + break; + default: + break; + } + + return result; +} + +static inline bool sw_is_face_valid(int face) +{ + return (face == SW_FRONT || face == SW_BACK); +} + +static inline bool sw_is_blend_src_factor_valid(int blend) +{ + bool result = false; + + switch (blend) { + case SW_ZERO: + case SW_ONE: + case SW_SRC_COLOR: + case SW_ONE_MINUS_SRC_COLOR: + case SW_SRC_ALPHA: + case SW_ONE_MINUS_SRC_ALPHA: + case SW_DST_ALPHA: + case SW_ONE_MINUS_DST_ALPHA: + case SW_DST_COLOR: + case SW_ONE_MINUS_DST_COLOR: + case SW_SRC_ALPHA_SATURATE: + result = true; + break; + default: + break; + } + + return result; +} + +static inline bool sw_is_blend_dst_factor_valid(int blend) +{ + bool result = false; + + switch (blend) { + case SW_ZERO: + case SW_ONE: + case SW_SRC_COLOR: + case SW_ONE_MINUS_SRC_COLOR: + case SW_SRC_ALPHA: + case SW_ONE_MINUS_SRC_ALPHA: + case SW_DST_ALPHA: + case SW_ONE_MINUS_DST_ALPHA: + case SW_DST_COLOR: + case SW_ONE_MINUS_DST_COLOR: + result = true; + break; + default: + break; + } + + return result; +} + +/* === Public Implementation === */ + +bool swInit(int w, int h) +{ + if (!sw_framebuffer_load(w, h)) { + swClose(); return false; + } + + swViewport(0, 0, w, h); + swScissor(0, 0, w, h); + + RLSW.loadedTextures = SW_MALLOC(SW_MAX_TEXTURES * sizeof(sw_texture_t)); + if (RLSW.loadedTextures == NULL) { swClose(); return false; } + + RLSW.freeTextureIds = SW_MALLOC(SW_MAX_TEXTURES * sizeof(uint32_t)); + if (RLSW.loadedTextures == NULL) { swClose(); return false; } + + RLSW.clearColor[0] = 0.0f; + RLSW.clearColor[1] = 0.0f; + RLSW.clearColor[2] = 0.0f; + RLSW.clearColor[3] = 1.0f; + RLSW.clearDepth = 1.0f; + + RLSW.currentMatrixMode = SW_MODELVIEW; + RLSW.currentMatrix = &RLSW.stackModelview[0]; + + sw_matrix_id(RLSW.stackProjection[0]); + sw_matrix_id(RLSW.stackModelview[0]); + sw_matrix_id(RLSW.stackTexture[0]); + sw_matrix_id(RLSW.matMVP); + + RLSW.stackProjectionCounter = 1; + RLSW.stackModelviewCounter = 1; + RLSW.stackTextureCounter = 1; + RLSW.isDirtyMVP = false; + + RLSW.current.texcoord[0] = 0.0f; + RLSW.current.texcoord[1] = 0.0f; + + RLSW.current.color[0] = 1.0f; + RLSW.current.color[1] = 1.0f; + RLSW.current.color[2] = 1.0f; + RLSW.current.color[3] = 1.0f; + + RLSW.srcFactor = SW_SRC_ALPHA; + RLSW.dstFactor = SW_ONE_MINUS_SRC_ALPHA; + + RLSW.srcFactorFunc = sw_factor_src_alpha; + RLSW.dstFactorFunc = sw_factor_one_minus_src_alpha; + + RLSW.polyMode = SW_FILL; + RLSW.cullFace = SW_BACK; + + static const float defTex[3*2*2] = + { + 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, + }; + + RLSW.loadedTextures[0].pixels.cptr = defTex; + RLSW.loadedTextures[0].width = 2; + RLSW.loadedTextures[0].height = 2; + RLSW.loadedTextures[0].wMinus1 = 1; + RLSW.loadedTextures[0].hMinus1 = 1; + RLSW.loadedTextures[0].format = SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32; + RLSW.loadedTextures[0].minFilter = SW_NEAREST; + RLSW.loadedTextures[0].magFilter = SW_NEAREST; + RLSW.loadedTextures[0].sWrap = SW_REPEAT; + RLSW.loadedTextures[0].tWrap = SW_REPEAT; + RLSW.loadedTextures[0].tx = 0.5f; + RLSW.loadedTextures[0].ty = 0.5f; + RLSW.loadedTextures[0].copy = false; + + RLSW.loadedTextureCount = 1; + + return true; +} + +void swClose(void) +{ + for (int i = 1; i < RLSW.loadedTextureCount; i++) { + sw_texture_t* texture = &RLSW.loadedTextures[i]; + if (sw_is_texture_valid(i) && texture->copy) { + SW_FREE(texture->pixels.ptr); + } + } + + SW_FREE(RLSW.framebuffer.color); + SW_FREE(RLSW.framebuffer.depth); + SW_FREE(RLSW.loadedTextures); + SW_FREE(RLSW.freeTextureIds); + + RLSW = (sw_context_t) { 0 }; +} + +bool swResizeFramebuffer(int w, int h) +{ + return sw_framebuffer_resize(w, h); +} + +void swCopyFramebuffer(int x, int y, int w, int h, SWformat format, SWtype type, void* pixels) +{ + sw_pixelformat_t pFormat = sw_get_pixel_format(format, type); + + if (w <= 0) { + RLSW.errCode = SW_INVALID_VALUE; + return; + } + + if (h <= 0) { + RLSW.errCode = SW_INVALID_VALUE; + return; + } + + if (w > RLSW.framebuffer.width) + w = RLSW.framebuffer.width; + + if (h > RLSW.framebuffer.height) + h = RLSW.framebuffer.height; + + x = sw_clampi(x, 0, w); + y = sw_clampi(y, 0, h); + + switch (pFormat) { + case SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: + sw_framebuffer_copy_to_GRAYALPHA(x, y, w, h, pixels); + break; + case SW_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: + sw_framebuffer_copy_to_GRAYALPHA(x, y, w, h, pixels); + break; + case SW_PIXELFORMAT_UNCOMPRESSED_R5G6B5: + sw_framebuffer_copy_to_R5G6B5(x, y, w, h, pixels); + break; + case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8: + sw_framebuffer_copy_to_R8G8B8(x, y, w, h, pixels); + break; + case SW_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: + sw_framebuffer_copy_to_R5G5B5A1(x, y, w, h, pixels); + break; + case SW_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: + sw_framebuffer_copy_to_R4G4B4A4(x, y, w, h, pixels); + break; + case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: + sw_framebuffer_copy_to_R8G8B8A8(x, y, w, h, pixels); + break; + case SW_PIXELFORMAT_UNCOMPRESSED_R32: + sw_framebuffer_copy_to_R32(x, y, w, h, pixels); + break; + case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32: + sw_framebuffer_copy_to_R32G32B32(x, y, w, h, pixels); + break; + case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: + sw_framebuffer_copy_to_R32G32B32A32(x, y, w, h, pixels); + break; + case SW_PIXELFORMAT_UNCOMPRESSED_R16: + sw_framebuffer_copy_to_R16(x, y, w, h, pixels); + break; + case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16: + sw_framebuffer_copy_to_R16G16B16(x, y, w, h, pixels); + break; + case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: + sw_framebuffer_copy_to_R16G16B16A16(x, y, w, h, pixels); + break; + default: + RLSW.errCode = SW_INVALID_ENUM; + break; + } +} + +void swBlitFramebuffer(int xDst, int yDst, int wDst, int hDst, + int xSrc, int ySrc, int wSrc, int hSrc, + SWformat format, SWtype type, void* pixels) +{ + sw_pixelformat_t pFormat = sw_get_pixel_format(format, type); + + if (wSrc <= 0) { + RLSW.errCode = SW_INVALID_VALUE; + return; + } + + if (hSrc <= 0) { + RLSW.errCode = SW_INVALID_VALUE; + return; + } + + if (wSrc > RLSW.framebuffer.width) + wSrc = RLSW.framebuffer.width; + + if (hSrc > RLSW.framebuffer.height) + hSrc = RLSW.framebuffer.height; + + xSrc = sw_clampi(xSrc, 0, wSrc); + ySrc = sw_clampi(ySrc, 0, hSrc); + + switch (pFormat) { + case SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: + sw_framebuffer_blit_to_GRAYALPHA(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); + break; + case SW_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: + sw_framebuffer_blit_to_GRAYALPHA(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); + break; + case SW_PIXELFORMAT_UNCOMPRESSED_R5G6B5: + sw_framebuffer_blit_to_R5G6B5(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); + break; + case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8: + sw_framebuffer_blit_to_R8G8B8(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); + break; + case SW_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: + sw_framebuffer_blit_to_R5G5B5A1(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); + break; + case SW_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: + sw_framebuffer_blit_to_R4G4B4A4(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); + break; + case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: + sw_framebuffer_blit_to_R8G8B8A8(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); + break; + case SW_PIXELFORMAT_UNCOMPRESSED_R32: + sw_framebuffer_blit_to_R32(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); + break; + case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32: + sw_framebuffer_blit_to_R32G32B32(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); + break; + case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: + sw_framebuffer_blit_to_R32G32B32A32(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); + break; + case SW_PIXELFORMAT_UNCOMPRESSED_R16: + sw_framebuffer_blit_to_R16(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); + break; + case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16: + sw_framebuffer_blit_to_R16G16B16(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); + break; + case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: + sw_framebuffer_blit_to_R16G16B16A16(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); + break; + default: + RLSW.errCode = SW_INVALID_ENUM; + break; + } +} + +void* swGetColorBuffer(int* w, int* h) +{ + if (w) *w = RLSW.framebuffer.width; + if (h) *h = RLSW.framebuffer.height; + + return RLSW.framebuffer.color; +} + +void swEnable(SWstate state) +{ + switch (state) { + case SW_SCISSOR_TEST: + RLSW.stateFlags |= SW_STATE_SCISSOR_TEST; + break; + case SW_TEXTURE_2D: + RLSW.stateFlags |= SW_STATE_TEXTURE_2D; + break; + case SW_DEPTH_TEST: + RLSW.stateFlags |= SW_STATE_DEPTH_TEST; + break; + case SW_CULL_FACE: + RLSW.stateFlags |= SW_STATE_CULL_FACE; + break; + case SW_BLEND: + RLSW.stateFlags |= SW_STATE_BLEND; + break; + default: + RLSW.errCode = SW_INVALID_ENUM; + break; + } +} + +void swDisable(SWstate state) +{ + switch (state) { + case SW_SCISSOR_TEST: + RLSW.stateFlags &= ~SW_STATE_SCISSOR_TEST; + break; + case SW_TEXTURE_2D: + RLSW.stateFlags &= ~SW_STATE_TEXTURE_2D; + break; + case SW_DEPTH_TEST: + RLSW.stateFlags &= ~SW_STATE_DEPTH_TEST; + break; + case SW_CULL_FACE: + RLSW.stateFlags &= ~SW_STATE_CULL_FACE; + break; + case SW_BLEND: + RLSW.stateFlags &= ~SW_STATE_BLEND; + break; + default: + RLSW.errCode = SW_INVALID_ENUM; + break; + } +} + +void swGetIntegerv(SWget name, int* v) +{ + switch (name) { + case SW_MODELVIEW_STACK_DEPTH: + *v = SW_MODELVIEW_STACK_DEPTH; + break; + case SW_PROJECTION_STACK_DEPTH: + *v = SW_PROJECTION_STACK_DEPTH; + break; + case SW_TEXTURE_STACK_DEPTH: + *v = SW_TEXTURE_STACK_DEPTH; + break; + default: + RLSW.errCode = SW_INVALID_ENUM; + break; + } +} + +void swGetFloatv(SWget name, float* v) +{ + switch (name) { + case SW_COLOR_CLEAR_VALUE: + v[0] = RLSW.clearColor[0]; + v[1] = RLSW.clearColor[1]; + v[2] = RLSW.clearColor[2]; + v[3] = RLSW.clearColor[3]; + break; + case SW_CURRENT_COLOR: + v[0] = RLSW.vertexBuffer[RLSW.vertexCounter - 1].color[0]; + v[1] = RLSW.vertexBuffer[RLSW.vertexCounter - 1].color[1]; + v[2] = RLSW.vertexBuffer[RLSW.vertexCounter - 1].color[2]; + v[3] = RLSW.vertexBuffer[RLSW.vertexCounter - 1].color[3]; + break; + case SW_CURRENT_TEXTURE_COORDS: + v[0] = RLSW.vertexBuffer[RLSW.vertexCounter - 1].texcoord[0]; + v[1] = RLSW.vertexBuffer[RLSW.vertexCounter - 1].texcoord[1]; + break; + case SW_POINT_SIZE: + v[0] = 2.0f * RLSW.pointRadius; + break; + case SW_LINE_WIDTH: + v[0] = RLSW.lineWidth; + break; + case SW_MODELVIEW_MATRIX: + for (int i = 0; i < 16; i++) { + v[i] = RLSW.stackModelview[RLSW.stackModelviewCounter - 1][i]; + } + break; + case SW_PROJECTION_MATRIX: + for (int i = 0; i < 16; i++) { + v[i] = RLSW.stackProjection[RLSW.stackProjectionCounter - 1][i]; + } + break; + case SW_TEXTURE_MATRIX: + for (int i = 0; i < 16; i++) { + v[i] = RLSW.stackTexture[RLSW.stackTextureCounter - 1][i]; + } + break; + default: + RLSW.errCode = SW_INVALID_ENUM; + break; + } +} + +const char* swGetString(SWget name) +{ + const char* result = NULL; + + switch (name) { + case SW_VENDOR: + result = "RLSW Header"; + break; + case SW_RENDERER: + result = "RLSW Software Renderer"; + break; + case SW_VERSION: + result = "RLSW 1.0"; + break; + case SW_EXTENSIONS: + result = "None"; + break; + default: + RLSW.errCode = SW_INVALID_ENUM; + break; + } + + return result; +} + +SWerrcode swGetError(void) +{ + SWerrcode ret = RLSW.errCode; + RLSW.errCode = SW_NO_ERROR; + return ret; +} + +void swViewport(int x, int y, int width, int height) +{ + if (width < 0 || height < 0) { + RLSW.errCode = SW_INVALID_VALUE; + return; + } + + RLSW.vpSize[0] = width; + RLSW.vpSize[1] = height; + + RLSW.vpHalfSize[0] = (int)(width / 2.0f + 0.5f); + RLSW.vpHalfSize[1] = (int)(height / 2.0f + 0.5f); + + RLSW.vpCenter[0] = x + RLSW.vpHalfSize[0]; + RLSW.vpCenter[1] = y + RLSW.vpHalfSize[1]; + + RLSW.vpMin[0] = sw_clampi(x, 0, RLSW.framebuffer.width - 1); + RLSW.vpMin[1] = sw_clampi(y, 0, RLSW.framebuffer.height - 1); + RLSW.vpMax[0] = sw_clampi(x + width, 0, RLSW.framebuffer.width - 1); + RLSW.vpMax[1] = sw_clampi(y + height, 0, RLSW.framebuffer.height - 1); +} + +void swScissor(int x, int y, int width, int height) +{ + if (width < 0 || height < 0) { + RLSW.errCode = SW_INVALID_VALUE; + return; + } + + RLSW.scMin[0] = sw_clampi(x, 0, RLSW.framebuffer.width - 1); + RLSW.scMin[1] = sw_clampi(y, 0, RLSW.framebuffer.height - 1); + RLSW.scMax[0] = sw_clampi(x + width, 0, RLSW.framebuffer.width - 1); + RLSW.scMax[1] = sw_clampi(y + height, 0, RLSW.framebuffer.height - 1); + + RLSW.scClipMin[0] = (2.0f * (float)RLSW.scMin[0] / (float)RLSW.vpSize[0]) - 1.0f; + RLSW.scClipMax[0] = (2.0f * (float)RLSW.scMax[0] / (float)RLSW.vpSize[0]) - 1.0f; + RLSW.scClipMax[1] = 1.0f - (2.0f * (float)RLSW.scMin[1] / (float)RLSW.vpSize[1]); + RLSW.scClipMin[1] = 1.0f - (2.0f * (float)RLSW.scMax[1] / (float)RLSW.vpSize[1]); +} + +void swClearColor(float r, float g, float b, float a) +{ + RLSW.clearColor[0] = r; + RLSW.clearColor[1] = g; + RLSW.clearColor[2] = b; + RLSW.clearColor[3] = a; +} + +void swClear(uint32_t bitmask) +{ + int size = RLSW.framebuffer.width * RLSW.framebuffer.height; + + if ((bitmask & (SW_COLOR_BUFFER_BIT | SW_DEPTH_BUFFER_BIT)) == (SW_COLOR_BUFFER_BIT | SW_DEPTH_BUFFER_BIT)) { + sw_framebuffer_fill( + RLSW.framebuffer.color, RLSW.framebuffer.depth, + size, RLSW.clearColor, RLSW.clearDepth + ); + } + else if (bitmask & (SW_COLOR_BUFFER_BIT)) { + sw_framebuffer_fill_color(RLSW.framebuffer.color, size, RLSW.clearColor); + } + else if (bitmask & SW_DEPTH_BUFFER_BIT) { + sw_framebuffer_fill_depth(RLSW.framebuffer.depth, size, RLSW.clearDepth); + } +} + +void swBlendFunc(SWfactor sfactor, SWfactor dfactor) +{ + if (!sw_is_blend_src_factor_valid(sfactor) + || !sw_is_blend_dst_factor_valid(dfactor)) { + RLSW.errCode = SW_INVALID_ENUM; + return; + } + RLSW.srcFactor = sfactor; + RLSW.dstFactor = dfactor; + + switch (sfactor) { + case SW_ZERO: + RLSW.srcFactorFunc = sw_factor_zero; + break; + case SW_ONE: + RLSW.srcFactorFunc = sw_factor_one; + break; + case SW_SRC_COLOR: + RLSW.srcFactorFunc = sw_factor_src_color; + break; + case SW_ONE_MINUS_SRC_COLOR: + RLSW.srcFactorFunc = sw_factor_one_minus_src_color; + break; + case SW_SRC_ALPHA: + RLSW.srcFactorFunc = sw_factor_src_alpha; + break; + case SW_ONE_MINUS_SRC_ALPHA: + RLSW.srcFactorFunc = sw_factor_one_minus_src_alpha; + break; + case SW_DST_ALPHA: + RLSW.srcFactorFunc = sw_factor_dst_alpha; + break; + case SW_ONE_MINUS_DST_ALPHA: + RLSW.srcFactorFunc = sw_factor_one_minus_dst_alpha; + break; + case SW_DST_COLOR: + RLSW.srcFactorFunc = sw_factor_dst_color; + break; + case SW_ONE_MINUS_DST_COLOR: + RLSW.srcFactorFunc = sw_factor_one_minus_dst_color; + break; + case SW_SRC_ALPHA_SATURATE: + RLSW.srcFactorFunc = sw_factor_src_alpha_saturate; + break; + } + + switch (dfactor) { + case SW_ZERO: + RLSW.dstFactorFunc = sw_factor_zero; + break; + case SW_ONE: + RLSW.dstFactorFunc = sw_factor_one; + break; + case SW_SRC_COLOR: + RLSW.dstFactorFunc = sw_factor_src_color; + break; + case SW_ONE_MINUS_SRC_COLOR: + RLSW.dstFactorFunc = sw_factor_one_minus_src_color; + break; + case SW_SRC_ALPHA: + RLSW.dstFactorFunc = sw_factor_src_alpha; + break; + case SW_ONE_MINUS_SRC_ALPHA: + RLSW.dstFactorFunc = sw_factor_one_minus_src_alpha; + break; + case SW_DST_ALPHA: + RLSW.dstFactorFunc = sw_factor_dst_alpha; + break; + case SW_ONE_MINUS_DST_ALPHA: + RLSW.dstFactorFunc = sw_factor_one_minus_dst_alpha; + break; + case SW_DST_COLOR: + RLSW.dstFactorFunc = sw_factor_dst_color; + break; + case SW_ONE_MINUS_DST_COLOR: + RLSW.dstFactorFunc = sw_factor_one_minus_dst_color; + break; + case SW_SRC_ALPHA_SATURATE: + // NOTE: Should never be reached + break; + } +} + +void swPolygonMode(SWpoly mode) +{ + if (!sw_is_poly_mode_valid(mode)) { + RLSW.errCode = SW_INVALID_ENUM; + return; + } + RLSW.polyMode = mode; +} + +void swCullFace(SWface face) +{ + if (!sw_is_face_valid(face)) { + RLSW.errCode = SW_INVALID_ENUM; + return; + } + RLSW.cullFace = face; +} + +void swPointSize(float size) +{ + RLSW.pointRadius = floorf(size * 0.5f); +} + +void swLineWidth(float width) +{ + RLSW.lineWidth = roundf(width); +} + +void swMatrixMode(SWmatrix mode) +{ + switch (mode) { + case SW_PROJECTION: + RLSW.currentMatrix = &RLSW.stackProjection[RLSW.stackProjectionCounter - 1]; + break; + case SW_MODELVIEW: + RLSW.currentMatrix = &RLSW.stackModelview[RLSW.stackModelviewCounter - 1]; + break; + case SW_TEXTURE: + RLSW.currentMatrix = &RLSW.stackTexture[RLSW.stackTextureCounter - 1]; + break; + default: + RLSW.errCode = SW_INVALID_ENUM; + return; + } + + RLSW.currentMatrixMode = mode; +} + +void swPushMatrix(void) +{ + switch (RLSW.currentMatrixMode) { + case SW_PROJECTION: + { + if (RLSW.stackProjectionCounter >= SW_MAX_PROJECTION_STACK_SIZE) { + RLSW.errCode = SW_STACK_OVERFLOW; + return; + } + + int iOld = RLSW.stackProjectionCounter - 1; + int iNew = RLSW.stackProjectionCounter++; + + for (int i = 0; i < 16; i++) { + RLSW.stackProjection[iNew][i] = RLSW.stackProjection[iOld][i]; + } + + RLSW.currentMatrix = &RLSW.stackProjection[iNew]; + } + break; + case SW_MODELVIEW: + { + if (RLSW.stackModelviewCounter >= SW_MAX_MODELVIEW_STACK_SIZE) { + RLSW.errCode = SW_STACK_OVERFLOW; + return; + } + + int iOld = RLSW.stackModelviewCounter - 1; + int iNew = RLSW.stackModelviewCounter++; + + for (int i = 0; i < 16; i++) { + RLSW.stackModelview[iNew][i] = RLSW.stackModelview[iOld][i]; + } + + RLSW.currentMatrix = &RLSW.stackModelview[iNew]; + } + break; + case SW_TEXTURE: + { + if (RLSW.stackTextureCounter >= SW_MAX_TEXTURE_STACK_SIZE) { + RLSW.errCode = SW_STACK_OVERFLOW; + return; + } + + int iOld = RLSW.stackTextureCounter - 1; + int iNew = RLSW.stackTextureCounter++; + + for (int i = 0; i < 16; i++) { + RLSW.stackTexture[iNew][i] = RLSW.stackTexture[iOld][i]; + } + + RLSW.currentMatrix = &RLSW.stackTexture[iNew]; + } + break; + } +} + +void swPopMatrix(void) +{ + switch (RLSW.currentMatrixMode) { + case SW_PROJECTION: + { + if (RLSW.stackProjectionCounter <= 0) { + RLSW.errCode = SW_STACK_UNDERFLOW; + return; + } + + RLSW.currentMatrix = &RLSW.stackProjection[--RLSW.stackProjectionCounter]; + RLSW.isDirtyMVP = true; //< The MVP is considered to have been changed + } + break; + case SW_MODELVIEW: + { + if (RLSW.stackModelviewCounter <= 0) { + RLSW.errCode = SW_STACK_UNDERFLOW; + return; + } + + RLSW.currentMatrix = &RLSW.stackModelview[--RLSW.stackModelviewCounter]; + RLSW.isDirtyMVP = true; //< The MVP is considered to have been changed + } + break; + case SW_TEXTURE: + { + if (RLSW.stackTextureCounter <= 0) { + RLSW.errCode = SW_STACK_UNDERFLOW; + return; + } + + RLSW.currentMatrix = &RLSW.stackTexture[--RLSW.stackTextureCounter]; + } + break; + } +} + +void swLoadIdentity(void) +{ + sw_matrix_id(*RLSW.currentMatrix); + if (RLSW.currentMatrixMode != SW_TEXTURE) { + RLSW.isDirtyMVP = true; + } +} + +void swTranslatef(float x, float y, float z) +{ + sw_matrix_t mat; + sw_matrix_id(mat); + + mat[12] = x; + mat[13] = y; + mat[14] = z; + + sw_matrix_mul(*RLSW.currentMatrix, mat, *RLSW.currentMatrix); + + if (RLSW.currentMatrixMode != SW_TEXTURE) { + RLSW.isDirtyMVP = true; + } +} + +void swRotatef(float angle, float x, float y, float z) +{ + angle *= SW_DEG2RAD; + + float lengthSq = x*x + y*y + z*z; + + if (lengthSq != 1.0f && lengthSq != 0.0f) { + float invLength = 1.0f/sqrtf(lengthSq); + x *= invLength; + y *= invLength; + z *= invLength; + } + + float sinres = sinf(angle); + float cosres = cosf(angle); + float t = 1.0f - cosres; + + sw_matrix_t mat; + + mat[0] = x*x*t + cosres; + mat[1] = y*x*t + z*sinres; + mat[2] = z*x*t - y*sinres; + mat[3] = 0.0f; + + mat[4] = x*y*t - z*sinres; + mat[5] = y*y*t + cosres; + mat[6] = z*y*t + x*sinres; + mat[7] = 0.0f; + + mat[8] = x*z*t + y*sinres; + mat[9] = y*z*t - x*sinres; + mat[10] = z*z*t + cosres; + mat[11] = 0.0f; + + mat[12] = 0.0f; + mat[13] = 0.0f; + mat[14] = 0.0f; + mat[15] = 1.0f; + + sw_matrix_mul(*RLSW.currentMatrix, mat, *RLSW.currentMatrix); + + if (RLSW.currentMatrixMode != SW_TEXTURE) { + RLSW.isDirtyMVP = true; + } +} + +void swScalef(float x, float y, float z) +{ + sw_matrix_t mat; + + mat[0] = x, mat[1] = 0, mat[2] = 0, mat[3] = 0; + mat[4] = 0, mat[5] = y, mat[6] = 0, mat[7] = 0; + mat[8] = 0, mat[9] = 0, mat[10] = z, mat[11] = 0; + mat[12] = 0, mat[13] = 0, mat[14] = 0, mat[15] = 1; + + sw_matrix_mul(*RLSW.currentMatrix, mat, *RLSW.currentMatrix); + + if (RLSW.currentMatrixMode != SW_TEXTURE) { + RLSW.isDirtyMVP = true; + } +} + +void swMultMatrixf(const float* mat) +{ + sw_matrix_mul(*RLSW.currentMatrix, mat, *RLSW.currentMatrix); + + if (RLSW.currentMatrixMode != SW_TEXTURE) { + RLSW.isDirtyMVP = true; + } +} + +void swFrustum(double left, double right, double bottom, double top, double znear, double zfar) +{ + sw_matrix_t mat; + + double rl = right - left; + double tb = top - bottom; + double fn = zfar - znear; + + mat[0] = (znear*2.0)/rl; + mat[1] = 0.0f; + mat[2] = 0.0f; + mat[3] = 0.0f; + + mat[4] = 0.0f; + mat[5] = (znear*2.0)/tb; + mat[6] = 0.0f; + mat[7] = 0.0f; + + mat[8] = (right + left)/rl; + mat[9] = (top + bottom)/tb; + mat[10] = -(zfar + znear)/fn; + mat[11] = -1.0f; + + mat[12] = 0.0f; + mat[13] = 0.0f; + mat[14] = -(zfar*znear*2.0)/fn; + mat[15] = 0.0f; + + sw_matrix_mul(*RLSW.currentMatrix, *RLSW.currentMatrix, mat); + + if (RLSW.currentMatrixMode != SW_TEXTURE) { + RLSW.isDirtyMVP = true; + } +} + +void swOrtho(double left, double right, double bottom, double top, double znear, double zfar) +{ + sw_matrix_t mat; + + double rl = right - left; + double tb = top - bottom; + double fn = zfar - znear; + + mat[0] = 2.0f/rl; + mat[1] = 0.0f; + mat[2] = 0.0f; + mat[3] = 0.0f; + + mat[4] = 0.0f; + mat[5] = 2.0f/tb; + mat[6] = 0.0f; + mat[7] = 0.0f; + + mat[8] = 0.0f; + mat[9] = 0.0f; + mat[10] = -2.0f/fn; + mat[11] = 0.0f; + + mat[12] = -(left + right)/rl; + mat[13] = -(top + bottom)/tb; + mat[14] = -(zfar + znear)/fn; + mat[15] = 1.0f; + + sw_matrix_mul(*RLSW.currentMatrix, *RLSW.currentMatrix, mat); + + if (RLSW.currentMatrixMode != SW_TEXTURE) { + RLSW.isDirtyMVP = true; + } +} + +void swBegin(SWdraw mode) +{ + /* --- Check if the draw mode is valid --- */ + + if (!sw_is_draw_mode_valid(mode)) { + RLSW.errCode = SW_INVALID_ENUM; + return; + } + + /* --- Recalculate the MVP if this is needed --- */ + + if (RLSW.isDirtyMVP) { + sw_matrix_mul_rst( + RLSW.matMVP, + RLSW.stackModelview[RLSW.stackModelviewCounter - 1], + RLSW.stackProjection[RLSW.stackProjectionCounter - 1] + ); + RLSW.isDirtyMVP = false; + } + + /* --- Obtaining the number of vertices needed for this primitive --- */ + + switch (mode) { + case SW_POINTS: + RLSW.reqVertices = 1; + break; + case SW_LINES: + RLSW.reqVertices = 2; + break; + case SW_TRIANGLES: + RLSW.reqVertices = 3; + break; + case SW_QUADS: + RLSW.reqVertices = 4; + break; + } + + /* --- Initialize some values --- */ + + RLSW.vertexCounter = 0; + RLSW.drawMode = mode; +} + +void swEnd(void) +{ + RLSW.drawMode = 0; +} + +void swVertex2i(int x, int y) +{ + const float v[4] = { (float)x, (float)y, 0.0f, 1.0f }; + swVertex4fv(v); +} + +void swVertex2f(float x, float y) +{ + const float v[4] = { x, y, 0.0f, 1.0f }; + swVertex4fv(v); +} + +void swVertex2fv(const float* v) +{ + const float v4[4] = { v[0], v[1], 0.0f, 1.0f }; + swVertex4fv(v4); +} + +void swVertex3i(int x, int y, int z) +{ + const float v[4] = { (float)x, (float)y, (float)z, 1.0f }; + swVertex4fv(v); +} + +void swVertex3f(float x, float y, float z) +{ + const float v[4] = { x, y, z, 1.0f }; + swVertex4fv(v); +} + +void swVertex3fv(const float* v) +{ + const float v4[4] = { v[0], v[1], v[2], 1.0f }; + swVertex4fv(v4); +} + +void swVertex4i(int x, int y, int z, int w) +{ + const float v[4] = { (float)x, (float)y, (float)z, (float)w }; + swVertex4fv(v); +} + +void swVertex4f(float x, float y, float z, float w) +{ + const float v[4] = { x, y, z, w }; + swVertex4fv(v); +} + +void swVertex4fv(const float* v) +{ + /* --- Copy the position in the current vertex --- */ + + sw_vertex_t* vertex = &RLSW.vertexBuffer[RLSW.vertexCounter++]; + + for (int i = 0; i < 4; i++) { + vertex->position[i] = v[i]; + } + + /* --- Copy additonal vertex data --- */ + + for (int i = 0; i < 2; i++) { + vertex->texcoord[i] = RLSW.current.texcoord[i]; + } + + for (int i = 0; i < 4; i++) { + vertex->color[i] = RLSW.current.color[i]; + } + + /* --- Calculation of homogeneous coordinates --- */ + + const float* m = RLSW.matMVP; + + vertex->homogeneous[0] = m[0] * v[0] + m[4] * v[1] + m[8] * v[2] + m[12] * v[3]; + vertex->homogeneous[1] = m[1] * v[0] + m[5] * v[1] + m[9] * v[2] + m[13] * v[3]; + vertex->homogeneous[2] = m[2] * v[0] + m[6] * v[1] + m[10] * v[2] + m[14] * v[3]; + vertex->homogeneous[3] = m[3] * v[0] + m[7] * v[1] + m[11] * v[2] + m[15] * v[3]; + + /* --- Immediate rendering of the primitive if the required number is reached --- */ + + if (RLSW.vertexCounter == RLSW.reqVertices) { + switch (RLSW.polyMode) { + case SW_FILL: + sw_poly_fill_render(); + break; + case SW_LINE: + sw_poly_line_render(); + break; + case SW_POINT: + sw_poly_point_render(); + break; + } + RLSW.vertexCounter = 0; + } +} + +void swColor3ub(uint8_t r, uint8_t g, uint8_t b) +{ + float cv[4]; + cv[0] = (float)r / 255; + cv[1] = (float)g / 255; + cv[2] = (float)b / 255; + cv[3] = 1.0f; + + swColor4fv(cv); +} + +void swColor3ubv(const uint8_t* v) +{ + float cv[4]; + cv[0] = (float)v[0] / 255; + cv[1] = (float)v[1] / 255; + cv[2] = (float)v[2] / 255; + cv[3] = 1.0f; + + swColor4fv(cv); +} + +void swColor3f(float r, float g, float b) +{ + float cv[4]; + cv[0] = r; + cv[1] = g; + cv[2] = b; + cv[3] = 1.0f; + + swColor4fv(cv); +} + +void swColor3fv(const float* v) +{ + float cv[4]; + cv[0] = v[0]; + cv[1] = v[1]; + cv[2] = v[2]; + cv[3] = 1.0f; + + swColor4fv(cv); +} + +void swColor4ub(uint8_t r, uint8_t g, uint8_t b, uint8_t a) +{ + float cv[4]; + cv[0] = (float)r / 255; + cv[1] = (float)g / 255; + cv[2] = (float)b / 255; + cv[3] = (float)a / 255; + + swColor4fv(cv); +} + +void swColor4ubv(const uint8_t* v) +{ + float cv[4]; + cv[0] = (float)v[0] / 255; + cv[1] = (float)v[1] / 255; + cv[2] = (float)v[2] / 255; + cv[3] = (float)v[3] / 255; + + swColor4fv(cv); +} + +void swColor4f(float r, float g, float b, float a) +{ + float cv[4]; + cv[0] = r; + cv[1] = g; + cv[2] = b; + cv[3] = a; + + swColor4fv(cv); +} + +void swColor4fv(const float* v) +{ + for (int i = 0; i < 4; i++) { + RLSW.current.color[i] = v[i]; + } +} + +void swTexCoord2f(float u, float v) +{ + const float* m = RLSW.stackTexture[RLSW.stackTextureCounter - 1]; + + RLSW.current.texcoord[0] = m[0] * u + m[4] * v + m[12]; + RLSW.current.texcoord[1] = m[1] * u + m[5] * v + m[13]; +} + +void swTexCoord2fv(const float* v) +{ + const float* m = RLSW.stackTexture[RLSW.stackTextureCounter - 1]; + + RLSW.current.texcoord[0] = m[0] * v[0] + m[4] * v[1] + m[12]; + RLSW.current.texcoord[1] = m[1] * v[0] + m[5] * v[1] + m[13]; +} + +void swBindArray(SWarray type, void *buffer) +{ + switch (type) { + case SW_VERTEX_ARRAY: + RLSW.array.positions = buffer; + break; + case SW_TEXTURE_COORD_ARRAY: + RLSW.array.texcoords = buffer; + break; + case SW_COLOR_ARRAY: + RLSW.array.colors = buffer; + break; + default: + break; + } +} + +void swDrawArrays(SWdraw mode, int offset, int count) +{ + if (RLSW.array.positions == 0) { + RLSW.errCode = SW_INVALID_OPERATION; + return; + } + + swBegin(mode); + { + swTexCoord2f(0.0f, 0.0f); + swColor4f(1.0f, 1.0f, 1.0f, 1.0f); + + for (int i = offset; i < count; i++) { + if (RLSW.array.texcoords) swTexCoord2fv(RLSW.array.texcoords + 2 * i); + if (RLSW.array.colors) swColor4ubv(RLSW.array.colors + 4 * i); + swVertex3fv(RLSW.array.positions + 3 * i); + } + } + swEnd(); +} + +void swGenTextures(int count, uint32_t* textures) +{ + if (count == 0 || textures == NULL) { + return; + } + + for (int i = 0; i < count; i++) { + if (RLSW.loadedTextureCount >= SW_MAX_TEXTURES) { + RLSW.errCode = SW_STACK_OVERFLOW; //< Out of memory, not really stack overflow + return; + } + uint32_t id = 0; + if (RLSW.freeTextureIdCount > 0) { + id = RLSW.freeTextureIds[--RLSW.freeTextureIdCount]; + } + else { + id = RLSW.loadedTextureCount++; + } + RLSW.loadedTextures[id] = RLSW.loadedTextures[0]; + textures[i] = id; + } +} + +void swDeleteTextures(int count, uint32_t* textures) +{ + if (count == 0 || textures == NULL) { + return; + } + + for (int i = 0; i < count; i++) { + if (!sw_is_texture_valid(textures[i])) { + RLSW.errCode = SW_INVALID_VALUE; + continue; + } + if (RLSW.loadedTextures[textures[i]].copy) { + SW_FREE(RLSW.loadedTextures[textures[i]].pixels.ptr); + } + RLSW.loadedTextures[textures[i]].pixels.cptr = NULL; + RLSW.freeTextureIds[RLSW.freeTextureIdCount++] = textures[i]; + } +} + +void swTexImage2D(int width, int height, SWformat format, SWtype type, bool copy, const void* data) +{ + uint32_t id = RLSW.currentTexture; + + if (!sw_is_texture_valid(id)) { + RLSW.errCode = SW_INVALID_VALUE; + return; + } + + int pixelFormat = sw_get_pixel_format(format, type); + + if (pixelFormat <= SW_PIXELFORMAT_UNKNOWN) { + RLSW.errCode = SW_INVALID_ENUM; + return; + } + + sw_texture_t* texture = &RLSW.loadedTextures[id]; + + if (copy) { + int bytes = sw_get_pixel_bytes(pixelFormat); + int size = bytes * width * height; + texture->pixels.ptr = SW_MALLOC(size); + if (texture->pixels.ptr == NULL) { + RLSW.errCode = SW_STACK_OVERFLOW; //< Out of memory... + return; + } + for (int i = 0; i < size; i++) { + ((uint8_t*)texture->pixels.ptr)[i] = ((uint8_t*)data)[i]; + } + } + else { + texture->pixels.cptr = data; + } + + texture->width = width; + texture->height = height; + texture->wMinus1 = width - 1; + texture->hMinus1 = height - 1; + texture->format = pixelFormat; + texture->tx = 1.0f / width; + texture->ty = 1.0f / height; + texture->copy = copy; +} + +void swTexParameteri(int param, int value) +{ + uint32_t id = RLSW.currentTexture; + + if (!sw_is_texture_valid(id)) { + RLSW.errCode = SW_INVALID_VALUE; + return; + } + + sw_texture_t* texture = &RLSW.loadedTextures[id]; + + switch (param) { + + case SW_TEXTURE_MIN_FILTER: + if (!sw_is_texture_filter_valid(value)) { + RLSW.errCode = SW_INVALID_ENUM; + return; + } + texture->minFilter = value; + break; + + case SW_TEXTURE_MAG_FILTER: + if (!sw_is_texture_filter_valid(value)) { + RLSW.errCode = SW_INVALID_ENUM; + return; + } + texture->magFilter = value; + break; + + case SW_TEXTURE_WRAP_S: + if (!sw_is_texture_wrap_valid(value)) { + RLSW.errCode = SW_INVALID_ENUM; + return; + } + texture->sWrap = value; + break; + + case SW_TEXTURE_WRAP_T: + if (!sw_is_texture_wrap_valid(value)) { + RLSW.errCode = SW_INVALID_ENUM; + return; + } + texture->tWrap = value; + break; + + default: + RLSW.errCode = SW_INVALID_ENUM; + return; + + } +} + +void swBindTexture(uint32_t id) +{ + if (id >= SW_MAX_TEXTURES) { + RLSW.errCode = SW_INVALID_VALUE; + return; + } + + if (RLSW.loadedTextures[id].pixels.cptr == NULL) { + RLSW.errCode = SW_INVALID_OPERATION; + return; + } + + RLSW.currentTexture = id; +} + +#endif // RLSW_IMPL diff --git a/src/platforms/rcore_desktop_sdl.c b/src/platforms/rcore_desktop_sdl.c index 71265e718..00a6ccc47 100644 --- a/src/platforms/rcore_desktop_sdl.c +++ b/src/platforms/rcore_desktop_sdl.c @@ -63,18 +63,20 @@ #include "SDL.h" #endif -#if defined(GRAPHICS_API_OPENGL_ES2) - // It seems it does not need to be included to work - //#include "SDL_opengles2.h" -#else - // SDL OpenGL functionality (if required, instead of internal renderer) - #ifdef USING_SDL3_PROJECT - #include "SDL3/SDL_opengl.h" - #elif USING_SDL2_PROJECT - #include "SDL2/SDL_opengl.h" - #else - #include "SDL_opengl.h" - #endif +#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE) + #if defined(GRAPHICS_API_OPENGL_ES2) + // It seems it does not need to be included to work + //#include "SDL_opengles2.h" + #else + // SDL OpenGL functionality (if required, instead of internal renderer) + #ifdef USING_SDL3_PROJECT + #include "SDL3/SDL_opengl.h" + #elif USING_SDL2_PROJECT + #include "SDL2/SDL_opengl.h" + #else + #include "SDL_opengl.h" + #endif + #endif #endif //---------------------------------------------------------------------------------- @@ -1229,7 +1231,14 @@ void DisableCursor(void) // Swap back buffer with front buffer (screen drawing) void SwapScreenBuffer(void) { +#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE) + // NOTE: We use a preprocessor condition here because `rlCopyFramebuffer` is only declared for software rendering + SDL_Surface* surface = SDL_GetWindowSurface(platform.window); + rlCopyFramebuffer(0, 0, CORE.Window.render.width, CORE.Window.render.height, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, surface->pixels); + SDL_UpdateWindowSurface(platform.window); +#else SDL_GL_SwapWindow(platform.window); +#endif } //---------------------------------------------------------------------------------- @@ -1577,13 +1586,15 @@ void PollInputEvents(void) if (CORE.Input.Keyboard.charPressedQueueCount < MAX_CHAR_PRESSED_QUEUE) { // Add character (codepoint) to the queue - #if defined(USING_VERSION_SDL3) + + #if defined(USING_VERSION_SDL3) size_t textLen = strlen(event.text.text); unsigned int codepoint = (unsigned int)SDL_StepUTF8(&event.text.text, &textLen); - #else + #else int codepointSize = 0; int codepoint = GetCodepointNextSDL(event.text.text, &codepointSize); - #endif + #endif + CORE.Input.Keyboard.charPressedQueue[CORE.Input.Keyboard.charPressedQueueCount] = codepoint; CORE.Input.Keyboard.charPressedQueueCount++; } @@ -1887,7 +1898,6 @@ int InitPlatform(void) //---------------------------------------------------------------------------- unsigned int flags = 0; flags |= SDL_WINDOW_SHOWN; - flags |= SDL_WINDOW_OPENGL; flags |= SDL_WINDOW_INPUT_FOCUS; flags |= SDL_WINDOW_MOUSE_FOCUS; flags |= SDL_WINDOW_MOUSE_CAPTURE; // Window has mouse captured @@ -1922,44 +1932,50 @@ int InitPlatform(void) // NOTE: Some OpenGL context attributes must be set before window creation - // Check selection OpenGL version - if (rlGetVersion() == RL_OPENGL_21) + if (rlGetVersion() != RL_OPENGL_11_SOFTWARE) { - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1); - } - else if (rlGetVersion() == RL_OPENGL_33) - { - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); - } - else if (rlGetVersion() == RL_OPENGL_43) - { - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); -#if defined(RLGL_ENABLE_OPENGL_DEBUG_CONTEXT) - SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG); // Enable OpenGL Debug Context -#endif - } - else if (rlGetVersion() == RL_OPENGL_ES_20) // Request OpenGL ES 2.0 context - { - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); - } - else if (rlGetVersion() == RL_OPENGL_ES_30) // Request OpenGL ES 3.0 context - { - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); - } + // Add the flag telling the window to use an OpenGL context + flags |= SDL_WINDOW_OPENGL; - if (CORE.Window.flags & FLAG_MSAA_4X_HINT) - { - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4); + // Check selection OpenGL version + if (rlGetVersion() == RL_OPENGL_21) + { + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1); + } + else if (rlGetVersion() == RL_OPENGL_33) + { + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); + } + else if (rlGetVersion() == RL_OPENGL_43) + { + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); + #if defined(RLGL_ENABLE_OPENGL_DEBUG_CONTEXT) + SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG); // Enable OpenGL Debug Context + #endif + } + else if (rlGetVersion() == RL_OPENGL_ES_20) // Request OpenGL ES 2.0 context + { + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); + } + else if (rlGetVersion() == RL_OPENGL_ES_30) // Request OpenGL ES 3.0 context + { + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); + } + + if (CORE.Window.flags & FLAG_MSAA_4X_HINT) + { + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4); + } } // Init window @@ -1970,10 +1986,12 @@ int InitPlatform(void) #endif // Init OpenGL context - platform.glContext = SDL_GL_CreateContext(platform.window); + if (rlGetVersion() != RL_OPENGL_11_SOFTWARE) + { + platform.glContext = SDL_GL_CreateContext(platform.window); + } - // Check window and glContext have been initialized successfully - if ((platform.window != NULL) && (platform.glContext != NULL)) + if ((platform.window != NULL) && ((rlGetVersion() == RL_OPENGL_11_SOFTWARE) || (platform.glContext != NULL))) { CORE.Window.ready = true; @@ -1994,8 +2012,14 @@ 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); - if (CORE.Window.flags & FLAG_VSYNC_HINT) SDL_GL_SetSwapInterval(1); - else SDL_GL_SetSwapInterval(0); + if (platform.glContext != NULL) + { + SDL_GL_SetSwapInterval((CORE.Window.flags & FLAG_VSYNC_HINT)? 1 : 0); + + // Load OpenGL extensions + // NOTE: GL procedures address loader is required to load extensions + rlLoadExtensions(SDL_GL_GetProcAddress); + } } else { @@ -2003,9 +2027,6 @@ int InitPlatform(void) return -1; } - // Load OpenGL extensions - // NOTE: GL procedures address loader is required to load extensions - rlLoadExtensions(SDL_GL_GetProcAddress); //---------------------------------------------------------------------------- // Initialize input events system @@ -2077,7 +2098,7 @@ int InitPlatform(void) void ClosePlatform(void) { SDL_FreeCursor(platform.cursor); // Free cursor - SDL_GL_DeleteContext(platform.glContext); // Deinitialize OpenGL context + if (platform.glContext != NULL) SDL_GL_DeleteContext(platform.glContext); // Deinitialize OpenGL context SDL_DestroyWindow(platform.window); SDL_Quit(); // Deinitialize SDL internal global state } diff --git a/src/platforms/rcore_drm.c b/src/platforms/rcore_drm.c index a399092ad..fe0ac5fd8 100644 --- a/src/platforms/rcore_drm.c +++ b/src/platforms/rcore_drm.c @@ -65,12 +65,17 @@ // so the enum KEY_F12 from raylib is used #undef KEY_F12 -#include // Generic Buffer Management (native platform for EGL on DRM) #include // Direct Rendering Manager user-level library interface #include // Direct Rendering Manager mode setting (KMS) interface -#include "EGL/egl.h" // Native platform windowing system interface -#include "EGL/eglext.h" // EGL extensions +#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE) + #include // Generic Buffer Management (native platform for EGL on DRM) + #include "EGL/egl.h" // Native platform windowing system interface + #include "EGL/eglext.h" // EGL extensions +#else + #include // For mmap when copying to the dumb buffer + #include // For the conversion of certain error messages +#endif // NOTE: DRM cache enables triple buffered DRM caching #if defined(SUPPORT_DRM_CACHE) @@ -103,15 +108,19 @@ typedef struct { drmModeConnector *connector; // Direct Rendering Manager (DRM) mode connector drmModeCrtc *crtc; // CRT Controller int modeIndex; // Index of the used mode of connector->modes + uint32_t prevFB; // Previous DRM framebufer (during frame swapping) + +#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE) struct gbm_device *gbmDevice; // GBM device struct gbm_surface *gbmSurface; // GBM surface struct gbm_bo *prevBO; // Previous GBM buffer object (during frame swapping) - uint32_t prevFB; // Previous GBM framebufer (during frame swapping) - EGLDisplay device; // Native display device (physical screen connection) EGLSurface surface; // Surface to draw on, framebuffers (connected to context) EGLContext context; // Graphic context, mode in which drawing can be done EGLConfig config; // Graphic config +#else + uint32_t prevDumbHandle; // Handle to the previous dumb buffer (during frame swapping) +#endif // Keyboard data int defaultKeyboardMode; // Default keyboard mode @@ -780,6 +789,8 @@ void SwapScreenBuffer() // Swap back buffer with front buffer (screen drawing) void SwapScreenBuffer(void) { +#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE) + // Hardware rendering buffer swap with EGL eglSwapBuffers(platform.device, platform.surface); if (!platform.gbmSurface || (-1 == platform.fd) || !platform.connector || !platform.crtc) TRACELOG(LOG_ERROR, "DISPLAY: DRM initialization failed to swap"); @@ -805,6 +816,209 @@ void SwapScreenBuffer(void) if (platform.prevBO) gbm_surface_release_buffer(platform.gbmSurface, platform.prevBO); platform.prevBO = bo; +#else + // Software rendering buffer swap + if ((-1 == platform.fd) || !platform.connector || (platform.modeIndex < 0)) + { + TRACELOG(LOG_ERROR, "DISPLAY: DRM initialization failed to swap"); + return; + } + + // Get the software rendered color buffer + int bufferWidth, bufferHeight; + void *colorBuffer = swGetColorBuffer(&bufferWidth, &bufferHeight); + if (!colorBuffer) + { + TRACELOG(LOG_ERROR, "DISPLAY: Failed to get software color buffer"); + return; + } + + // Retrieving the dimensions of the display mode used + drmModeModeInfo *mode = &platform.connector->modes[platform.modeIndex]; + uint32_t width = mode->hdisplay; + uint32_t height = mode->vdisplay; + + // Dumb buffers use a fixed format based on bpp +#if SW_COLOR_BUFFER_BITS == 24 + const uint32_t bpp = 32; // 32 bits per pixel (XRGB8888 format) + const uint32_t depth = 24; // Color depth, here only 24 bits, alpha is not used +#else + // REVIEW: Not sure how it will be interpreted (RGB or RGBA?) + const uint32_t bpp = SW_COLOR_BUFFER_BITS; + const uint32_t depth = SW_COLOR_BUFFER_BITS; +#endif + + // Create a dumb buffer for software rendering + struct drm_mode_create_dumb creq = {0}; + creq.width = width; + creq.height = height; + creq.bpp = bpp; + + int result = drmIoctl(platform.fd, DRM_IOCTL_MODE_CREATE_DUMB, &creq); + if (result < 0) + { + TRACELOG(LOG_ERROR, "DISPLAY: Failed to create dumb buffer: %s", strerror(errno)); + return; + } + + // 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) + { + TRACELOG(LOG_ERROR, "DISPLAY: drmModeAddFB() failed with result: %d (%s)", result, strerror(errno)); + struct drm_mode_destroy_dumb dreq = {0}; + dreq.handle = creq.handle; + drmIoctl(platform.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq); + return; + } + + // Map the dumb buffer to copy our software rendered buffer + struct drm_mode_map_dumb mreq = {0}; + mreq.handle = creq.handle; + result = drmIoctl(platform.fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq); + if (result != 0) + { + TRACELOG(LOG_ERROR, "DISPLAY: Failed to map dumb buffer: %s", strerror(errno)); + drmModeRmFB(platform.fd, fb); + struct drm_mode_destroy_dumb dreq = {0}; + dreq.handle = creq.handle; + drmIoctl(platform.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq); + return; + } + + // Map the buffer into userspace + void *dumbBuffer = mmap(0, creq.size, PROT_READ | PROT_WRITE, MAP_SHARED, platform.fd, mreq.offset); + if (dumbBuffer == MAP_FAILED) + { + TRACELOG(LOG_ERROR, "DISPLAY: Failed to mmap dumb buffer: %s", strerror(errno)); + drmModeRmFB(platform.fd, fb); + struct drm_mode_destroy_dumb dreq = {0}; + dreq.handle = creq.handle; + drmIoctl(platform.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq); + return; + } + + // Copy the software rendered buffer to the dumb buffer with scaling if needed + if (bufferWidth == width && bufferHeight == height) + { + // Direct copy if sizes match + swCopyFramebuffer(0, 0, bufferWidth, bufferHeight, SW_RGBA, SW_UNSIGNED_BYTE, dumbBuffer); + } + else + { + // Scale the software buffer to match the display mode + swBlitFramebuffer(0, 0, width, height, 0, 0, bufferWidth, bufferHeight, SW_RGBA, SW_UNSIGNED_BYTE, dumbBuffer); + } + + // Unmap the buffer + munmap(dumbBuffer, creq.size); + + // Find a CRTC compatible with the connector + uint32_t crtcId = 0; + if (platform.crtc) + { + crtcId = platform.crtc->crtc_id; + } + else + { + // Find a CRTC that's compatible with this connector + drmModeRes *res = drmModeGetResources(platform.fd); + if (!res) + { + TRACELOG(LOG_ERROR, "DISPLAY: Failed to get DRM resources"); + drmModeRmFB(platform.fd, fb); + struct drm_mode_destroy_dumb dreq = {0}; + dreq.handle = creq.handle; + drmIoctl(platform.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq); + return; + } + + // Check which CRTCs are compatible with this connector + drmModeEncoder *encoder = NULL; + if (platform.connector->encoder_id) + { + encoder = drmModeGetEncoder(platform.fd, platform.connector->encoder_id); + } + + if (encoder && encoder->crtc_id) + { + crtcId = encoder->crtc_id; + platform.crtc = drmModeGetCrtc(platform.fd, crtcId); + } + else + { + // Find a free CRTC + for (int i = 0; i < res->count_crtcs; i++) + { + drmModeCrtc *crtc = drmModeGetCrtc(platform.fd, res->crtcs[i]); + if (crtc && !crtc->buffer_id) // CRTC is free + { + crtcId = res->crtcs[i]; + if (platform.crtc) drmModeFreeCrtc(platform.crtc); + platform.crtc = crtc; + break; + } + if (crtc) drmModeFreeCrtc(crtc); + } + } + + if (encoder) drmModeFreeEncoder(encoder); + drmModeFreeResources(res); + + if (!crtcId) + { + TRACELOG(LOG_ERROR, "DISPLAY: No compatible CRTC found"); + drmModeRmFB(platform.fd, fb); + struct drm_mode_destroy_dumb dreq = {0}; + dreq.handle = creq.handle; + drmIoctl(platform.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq); + return; + } + } + + // Set CRTC with better error handling + result = drmModeSetCrtc(platform.fd, crtcId, fb, 0, 0, + &platform.connector->connector_id, 1, + mode); + 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; + drmIoctl(platform.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq); + return; + } + + // Clean up previous framebuffer + if (platform.prevFB) + { + result = drmModeRmFB(platform.fd, platform.prevFB); + if (result != 0) + { + TRACELOG(LOG_WARNING, "DISPLAY: drmModeRmFB() failed with result: %d", result); + } + } + + platform.prevFB = fb; + + // Clean up previous dumb buffer + if (platform.prevDumbHandle) + { + struct drm_mode_destroy_dumb dreq = {0}; + dreq.handle = platform.prevDumbHandle; + drmIoctl(platform.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq); + } + + platform.prevDumbHandle = creq.handle; +#endif } #endif // SUPPORT_DRM_CACHE @@ -950,10 +1164,15 @@ int InitPlatform(void) platform.connector = NULL; platform.modeIndex = -1; platform.crtc = NULL; + platform.prevFB = 0; + +#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE) platform.gbmDevice = NULL; platform.gbmSurface = NULL; platform.prevBO = NULL; - platform.prevFB = 0; +#else + platform.prevDumbHandle = 0; +#endif // Initialize graphic device: display/window and graphic context //---------------------------------------------------------------------------- @@ -965,11 +1184,12 @@ int InitPlatform(void) if (platform.fd != -1) TRACELOG(LOG_INFO, "DISPLAY: Default graphic device DRM opened successfully"); #else TRACELOG(LOG_WARNING, "DISPLAY: No graphic card set, trying platform-gpu-card"); - platform.fd = open("/dev/dri/by-path/platform-gpu-card", O_RDWR); // VideoCore VI (Raspberry Pi 4) + platform.fd = open("/dev/dri/by-path/platform-gpu-card", O_RDWR); // VideoCore VI (Raspberry Pi 4) if (platform.fd != -1) TRACELOG(LOG_INFO, "DISPLAY: platform-gpu-card opened successfully"); if ((platform.fd == -1) || (drmModeGetResources(platform.fd) == NULL)) { + if (platform.fd != -1) close(platform.fd); TRACELOG(LOG_WARNING, "DISPLAY: Failed to open platform-gpu-card, trying card1"); platform.fd = open("/dev/dri/card1", O_RDWR); // Other Embedded if (platform.fd != -1) TRACELOG(LOG_INFO, "DISPLAY: card1 opened successfully"); @@ -977,10 +1197,19 @@ int InitPlatform(void) if ((platform.fd == -1) || (drmModeGetResources(platform.fd) == NULL)) { + if (platform.fd != -1) close(platform.fd); TRACELOG(LOG_WARNING, "DISPLAY: Failed to open graphic card1, trying card0"); platform.fd = open("/dev/dri/card0", O_RDWR); // VideoCore IV (Raspberry Pi 1-3) if (platform.fd != -1) TRACELOG(LOG_INFO, "DISPLAY: card0 opened successfully"); } + + if ((platform.fd == -1) || (drmModeGetResources(platform.fd) == NULL)) + { + if (platform.fd != -1) close(platform.fd); + TRACELOG(LOG_WARNING, "DISPLAY: Failed to open graphic card0, trying card2"); + platform.fd = open("/dev/dri/card2", O_RDWR); + if (platform.fd != -1) TRACELOG(LOG_INFO, "DISPLAY: card2 opened successfully"); + } #endif if (platform.fd == -1) @@ -993,29 +1222,58 @@ int InitPlatform(void) if (!res) { TRACELOG(LOG_WARNING, "DISPLAY: Failed get DRM resources"); + close(platform.fd); return -1; } TRACELOG(LOG_TRACE, "DISPLAY: Connectors found: %i", res->count_connectors); + // Connector detection for (size_t i = 0; i < res->count_connectors; i++) { TRACELOG(LOG_TRACE, "DISPLAY: Connector index %i", i); drmModeConnector *con = drmModeGetConnector(platform.fd, res->connectors[i]); - TRACELOG(LOG_TRACE, "DISPLAY: Connector modes detected: %i", con->count_modes); + if (!con) + { + TRACELOG(LOG_WARNING, "DISPLAY: Failed to get connector %i", i); + continue; + } + + TRACELOG(LOG_TRACE, "DISPLAY: Connector %i modes detected: %i", i, con->count_modes); + 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"); // In certain cases the status of the conneciton is reported as UKNOWN, but it is still connected // This might be a hardware or software limitation like on Raspberry Pi Zero with composite output - if (((con->connection == DRM_MODE_CONNECTED) || (con->connection == DRM_MODE_UNKNOWNCONNECTION)) && (con->encoder_id)) + // WARNING: Accept CONNECTED, UNKNOWN and even those without encoder_id connectors for software mode + if (((con->connection == DRM_MODE_CONNECTED) || (con->connection == DRM_MODE_UNKNOWNCONNECTION)) && (con->count_modes > 0)//(con->encoder_id)) { - TRACELOG(LOG_TRACE, "DISPLAY: DRM mode connected"); +#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE) + // For hardware rendering, we need an encoder_id + if (con->encoder_id) + { + TRACELOG(LOG_TRACE, "DISPLAY: DRM connector %i connected with encoder", i); + platform.connector = con; + break; + } + else + { + TRACELOG(LOG_TRACE, "DISPLAY: DRM connector %i connected but no encoder", i); + } +#else + // For software rendering, we can accept even without encoder_id + TRACELOG(LOG_TRACE, "DISPLAY: DRM connector %i suitable for software rendering", i); platform.connector = con; break; +#endif } - else + + if (!platform.connector) { - TRACELOG(LOG_TRACE, "DISPLAY: DRM mode NOT connected (deleting)"); + TRACELOG(LOG_TRACE, "DISPLAY: DRM connector %i NOT suitable (deleting)", i); drmModeFreeConnector(con); } } @@ -1024,14 +1282,18 @@ int InitPlatform(void) { TRACELOG(LOG_WARNING, "DISPLAY: No suitable DRM connector found"); drmModeFreeResources(res); + close(platform.fd); return -1; } +#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE) drmModeEncoder *enc = drmModeGetEncoder(platform.fd, platform.connector->encoder_id); if (!enc) { TRACELOG(LOG_WARNING, "DISPLAY: Failed to get DRM mode encoder"); + drmModeFreeConnector(platform.connector); drmModeFreeResources(res); + close(platform.fd); return -1; } @@ -1040,7 +1302,9 @@ int InitPlatform(void) { TRACELOG(LOG_WARNING, "DISPLAY: Failed to get DRM mode crtc"); drmModeFreeEncoder(enc); + drmModeFreeConnector(platform.connector); drmModeFreeResources(res); + close(platform.fd); return -1; } @@ -1055,7 +1319,9 @@ int InitPlatform(void) { TRACELOG(LOG_WARNING, "DISPLAY: No matching DRM connector mode found"); drmModeFreeEncoder(enc); + drmModeFreeConnector(platform.connector); drmModeFreeResources(res); + close(platform.fd); return -1; } @@ -1064,7 +1330,7 @@ int InitPlatform(void) } const bool allowInterlaced = CORE.Window.flags & FLAG_INTERLACED_HINT; - const int fps = (CORE.Time.target > 0)? (1.0/CORE.Time.target) : 60; + const int fps = (CORE.Time.target > 0) ? (1.0/CORE.Time.target) : 60; // Try to find an exact matching mode platform.modeIndex = FindExactConnectorMode(platform.connector, CORE.Window.screen.width, CORE.Window.screen.height, fps, allowInterlaced); @@ -1083,7 +1349,9 @@ int InitPlatform(void) { TRACELOG(LOG_WARNING, "DISPLAY: Failed to find a suitable DRM connector mode"); drmModeFreeEncoder(enc); + drmModeFreeConnector(platform.connector); drmModeFreeResources(res); + close(platform.fd); return -1; } @@ -1092,19 +1360,45 @@ int InitPlatform(void) TRACELOG(LOG_INFO, "DISPLAY: Selected DRM connector mode %s (%ux%u%c@%u)", platform.connector->modes[platform.modeIndex].name, platform.connector->modes[platform.modeIndex].hdisplay, platform.connector->modes[platform.modeIndex].vdisplay, - (platform.connector->modes[platform.modeIndex].flags & DRM_MODE_FLAG_INTERLACE)? 'i' : 'p', + (platform.connector->modes[platform.modeIndex].flags & DRM_MODE_FLAG_INTERLACE) ? 'i' : 'p', platform.connector->modes[platform.modeIndex].vrefresh); + drmModeFreeEncoder(enc); + enc = NULL; +#else + // For software rendering, the first available mode can be used + if (platform.connector->count_modes > 0) + { + 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", + platform.connector->modes[0].name, + 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); + } + else + { + TRACELOG(LOG_WARNING, "DISPLAY: No modes available for connector"); + drmModeFreeConnector(platform.connector); + drmModeFreeResources(res); + close(platform.fd); + return -1; + } +#endif + // Use the width and height of the surface for render CORE.Window.render.width = CORE.Window.screen.width; CORE.Window.render.height = CORE.Window.screen.height; - drmModeFreeEncoder(enc); - enc = NULL; - drmModeFreeResources(res); res = NULL; +#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE) + // Hardware rendering initialization with EGL platform.gbmDevice = gbm_create_device(platform.fd); if (!platform.gbmDevice) { @@ -1273,6 +1567,32 @@ int InitPlatform(void) return -1; } + // Load OpenGL extensions + // NOTE: GL procedures address loader is required to load extensions + rlLoadExtensions(eglGetProcAddress); +#else + // At this point we need to manage render size vs screen size + // NOTE: This function use and modify global module variables: + // -> CORE.Window.screen.width/CORE.Window.screen.height + // -> CORE.Window.render.width/CORE.Window.render.height + // -> CORE.Window.screenScale + SetupFramebuffer(CORE.Window.display.width, CORE.Window.display.height); + + // Setup window ready state for software rendering + CORE.Window.ready = true; + + 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 (Software Rendering)"); + TRACELOG(LOG_INFO, " > Display size: %i x %i", CORE.Window.display.width, CORE.Window.display.height); + TRACELOG(LOG_INFO, " > Screen size: %i x %i", CORE.Window.screen.width, CORE.Window.screen.height); + 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); +#endif + if ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0) MinimizeWindow(); // If graphic device is no properly initialized, we end program @@ -1285,12 +1605,8 @@ int InitPlatform(void) CORE.Window.flags |= FLAG_WINDOW_MAXIMIZED; // true CORE.Window.flags &= ~FLAG_WINDOW_UNFOCUSED; // false - // Load OpenGL extensions - // NOTE: GL procedures address loader is required to load extensions - rlLoadExtensions(eglGetProcAddress); //---------------------------------------------------------------------------- - - // Initialize timming system + // Initialize timing system //---------------------------------------------------------------------------- // NOTE: timming system must be initialized before the input events system InitTimer(); @@ -1336,6 +1652,7 @@ void ClosePlatform(void) platform.prevFB = 0; } +#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE) if (platform.prevBO) { gbm_surface_release_buffer(platform.gbmSurface, platform.prevBO); @@ -1353,6 +1670,7 @@ void ClosePlatform(void) gbm_device_destroy(platform.gbmDevice); platform.gbmDevice = NULL; } +#endif if (platform.crtc) { @@ -1374,6 +1692,7 @@ void ClosePlatform(void) platform.fd = -1; } +#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE) // Close surface, context and display if (platform.device != EGL_NO_DISPLAY) { @@ -1392,6 +1711,7 @@ void ClosePlatform(void) eglTerminate(platform.device); platform.device = EGL_NO_DISPLAY; } +#endif CORE.Window.shouldClose = true; // Added to force threads to exit when the close window is called diff --git a/src/rlgl.h b/src/rlgl.h index 2a1a5d5f8..5e8cf2bfa 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -149,7 +149,8 @@ #endif // Security check in case no GRAPHICS_API_OPENGL_* defined -#if !defined(GRAPHICS_API_OPENGL_11) && \ +#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE) && \ + !defined(GRAPHICS_API_OPENGL_11) && \ !defined(GRAPHICS_API_OPENGL_21) && \ !defined(GRAPHICS_API_OPENGL_33) && \ !defined(GRAPHICS_API_OPENGL_43) && \ @@ -159,7 +160,7 @@ #endif // Security check in case multiple GRAPHICS_API_OPENGL_* defined -#if defined(GRAPHICS_API_OPENGL_11) +#if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_11_SOFTWARE) #if defined(GRAPHICS_API_OPENGL_21) #undef GRAPHICS_API_OPENGL_21 #endif @@ -174,6 +175,11 @@ #endif #endif +// Software implementation uses OpenGL 1.1 functionality +#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE) + #define GRAPHICS_API_OPENGL_11 +#endif + // OpenGL 2.1 uses most of OpenGL 3.3 Core functionality // WARNING: Specific parts are checked with #if defines #if defined(GRAPHICS_API_OPENGL_21) @@ -427,7 +433,8 @@ typedef struct rlRenderBatch { // OpenGL version typedef enum { - RL_OPENGL_11 = 1, // OpenGL 1.1 + RL_OPENGL_11_SOFTWARE = 0, // Software rendering + RL_OPENGL_11, // OpenGL 1.1 RL_OPENGL_21, // OpenGL 2.1 (GLSL 120) RL_OPENGL_33, // OpenGL 3.3 (GLSL 330) RL_OPENGL_43, // OpenGL 4.3 (using GLSL 330) @@ -768,6 +775,10 @@ RLAPI unsigned int rlLoadFramebuffer(void); // Loa RLAPI void rlFramebufferAttach(unsigned int fboId, unsigned int texId, int attachType, int texType, int mipLevel); // Attach texture/renderbuffer to a framebuffer RLAPI bool rlFramebufferComplete(unsigned int id); // Verify framebuffer is complete RLAPI void rlUnloadFramebuffer(unsigned int id); // Delete framebuffer from GPU +#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE) +RLAPI void rlCopyFramebuffer(int x, int y, int w, int h, int format, void* pixels); +RLAPI void rlResizeFramebuffer(int width, int height); +#endif // Shaders management RLAPI unsigned int rlLoadShaderCode(const char *vsCode, const char *fsCode); // Load shader from code strings @@ -834,24 +845,32 @@ RLAPI void rlLoadDrawQuad(void); // Load and draw a quad #endif #if defined(GRAPHICS_API_OPENGL_11) - #if defined(__APPLE__) - #include // OpenGL 1.1 library for OSX - #include // OpenGL extensions library + #if defined(GRAPHICS_API_OPENGL_11_SOFTWARE) + #define RLSW_IMPL + #define SW_MALLOC(sz) RL_MALLOC(sz) + #define SW_REALLOC(ptr, newSz) RL_REALLOC(ptr, newSz) + #define SW_FREE(ptr) RL_FREE(ptr) + #include "external/rlsw.h" // OpenGL 1.1 software implementation #else - // APIENTRY for OpenGL function pointer declarations is required - #if !defined(APIENTRY) - #if defined(_WIN32) - #define APIENTRY __stdcall - #else - #define APIENTRY + #if defined(__APPLE__) + #include // OpenGL 1.1 library for OSX + #include // OpenGL extensions library + #else + // APIENTRY for OpenGL function pointer declarations is required + #if !defined(APIENTRY) + #if defined(_WIN32) + #define APIENTRY __stdcall + #else + #define APIENTRY + #endif + #endif + // WINGDIAPI definition. Some Windows OpenGL headers need it + #if !defined(WINGDIAPI) && defined(_WIN32) + #define WINGDIAPI __declspec(dllimport) #endif - #endif - // WINGDIAPI definition. Some Windows OpenGL headers need it - #if !defined(WINGDIAPI) && defined(_WIN32) - #define WINGDIAPI __declspec(dllimport) - #endif - #include // OpenGL 1.1 library + #include // OpenGL 1.1 library + #endif #endif #endif @@ -2337,6 +2356,14 @@ void rlglInit(int width, int height) glShadeModel(GL_SMOOTH); // Smooth shading between vertex (vertex colors interpolation) #endif +#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE) + if (!swInit(width, height)) + { + TRACELOG(RL_LOG_ERROR, "RLGL: Software renderer initialization failed!"); + exit(-1); + } +#endif + #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) // Store screen size into global variables RLGL.State.framebufferWidth = width; @@ -2363,6 +2390,10 @@ void rlglClose(void) glDeleteTextures(1, &RLGL.State.defaultTextureId); // Unload default texture TRACELOG(RL_LOG_INFO, "TEXTURE: [ID %i] Default texture unloaded successfully", RLGL.State.defaultTextureId); #endif + +#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE) + swClose(); +#endif } // Load OpenGL extensions @@ -2672,7 +2703,9 @@ void *rlGetProcAddress(const char *procName) int rlGetVersion(void) { int glVersion = 0; -#if defined(GRAPHICS_API_OPENGL_11) +#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE) + glVersion = RL_OPENGL_11_SOFTWARE; +#elif defined(GRAPHICS_API_OPENGL_11) glVersion = RL_OPENGL_11; #endif #if defined(GRAPHICS_API_OPENGL_21) @@ -3713,6 +3746,20 @@ void *rlReadTexturePixels(unsigned int id, int width, int height, int format) return pixels; } +#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE) +void rlCopyFramebuffer(int x, int y, int w, int h, int format, void* pixels) +{ + unsigned int glInternalFormat, glFormat, glType; + rlGetGlTextureFormats(format, &glInternalFormat, &glFormat, &glType); + swCopyFramebuffer(x, y, w, h, glFormat, glType, pixels); +} + +void rlResizeFramebuffer(int width, int height) +{ + swResizeFramebuffer(width, height); +} +#endif + // Read screen pixel data (color buffer) unsigned char *rlReadScreenPixels(int width, int height) { @@ -5313,4 +5360,4 @@ static Matrix rlMatrixInvert(Matrix mat) } #endif -#endif // RLGL_IMPLEMENTATION +#endif // RLGL_IMPLEMENTATION \ No newline at end of file diff --git a/src/rmodels.c b/src/rmodels.c index c54ef03fa..9ded580c3 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -1429,7 +1429,7 @@ void UpdateMeshBuffer(Mesh mesh, int index, const void *data, int dataSize, int // Draw a 3d mesh with material and transform void DrawMesh(Mesh mesh, Material material, Matrix transform) { -#if defined(GRAPHICS_API_OPENGL_11) +#if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_11_SOFTWARE) #define GL_VERTEX_ARRAY 0x8074 #define GL_NORMAL_ARRAY 0x8075 #define GL_COLOR_ARRAY 0x8076 From 43c81d216c8c26839ce781d484d906a83e5341fc Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 29 Sep 2025 11:00:35 +0200 Subject: [PATCH 046/167] REVIEWED: VS2022: New example `core_input_actions` UUID --- .../examples/core_input_actions.vcxproj | 2 +- projects/VS2022/raylib.sln | 52 +++++++++---------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/projects/VS2022/examples/core_input_actions.vcxproj b/projects/VS2022/examples/core_input_actions.vcxproj index 8b64adc77..9b43826f8 100644 --- a/projects/VS2022/examples/core_input_actions.vcxproj +++ b/projects/VS2022/examples/core_input_actions.vcxproj @@ -51,7 +51,7 @@ - {6B1A933E-71B8-4C1F-9E79-02D98830E671} + {718FCBD0-591D-448C-B7D5-9F1CA8544E7B} Win32Proj core_input_actions 10.0 diff --git a/projects/VS2022/raylib.sln b/projects/VS2022/raylib.sln index faca55fa0..c0295d4c6 100644 --- a/projects/VS2022/raylib.sln +++ b/projects/VS2022/raylib.sln @@ -345,7 +345,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "text_inline_styling", "exam EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_undo_redo", "examples\core_undo_redo.vcxproj", "{3B27F358-2679-4F38-B297-17B536F580BB}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_input_actions", "examples\core_input_actions.vcxproj", "{6B1A933E-71B8-4C1F-9E79-02D98830E671}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_input_actions", "examples\core_input_actions.vcxproj", "{718FCBD0-591D-448C-B7D5-9F1CA8544E7B}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -4249,30 +4249,30 @@ Global {3B27F358-2679-4F38-B297-17B536F580BB}.Release|x64.Build.0 = Release|x64 {3B27F358-2679-4F38-B297-17B536F580BB}.Release|x86.ActiveCfg = Release|Win32 {3B27F358-2679-4F38-B297-17B536F580BB}.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 + {718FCBD0-591D-448C-B7D5-9F1CA8544E7B}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 + {718FCBD0-591D-448C-B7D5-9F1CA8544E7B}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 + {718FCBD0-591D-448C-B7D5-9F1CA8544E7B}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {718FCBD0-591D-448C-B7D5-9F1CA8544E7B}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {718FCBD0-591D-448C-B7D5-9F1CA8544E7B}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {718FCBD0-591D-448C-B7D5-9F1CA8544E7B}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {718FCBD0-591D-448C-B7D5-9F1CA8544E7B}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {718FCBD0-591D-448C-B7D5-9F1CA8544E7B}.Debug|ARM64.Build.0 = Debug|ARM64 + {718FCBD0-591D-448C-B7D5-9F1CA8544E7B}.Debug|x64.ActiveCfg = Debug|x64 + {718FCBD0-591D-448C-B7D5-9F1CA8544E7B}.Debug|x64.Build.0 = Debug|x64 + {718FCBD0-591D-448C-B7D5-9F1CA8544E7B}.Debug|x86.ActiveCfg = Debug|Win32 + {718FCBD0-591D-448C-B7D5-9F1CA8544E7B}.Debug|x86.Build.0 = Debug|Win32 + {718FCBD0-591D-448C-B7D5-9F1CA8544E7B}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 + {718FCBD0-591D-448C-B7D5-9F1CA8544E7B}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 + {718FCBD0-591D-448C-B7D5-9F1CA8544E7B}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {718FCBD0-591D-448C-B7D5-9F1CA8544E7B}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {718FCBD0-591D-448C-B7D5-9F1CA8544E7B}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {718FCBD0-591D-448C-B7D5-9F1CA8544E7B}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {718FCBD0-591D-448C-B7D5-9F1CA8544E7B}.Release|ARM64.ActiveCfg = Release|ARM64 + {718FCBD0-591D-448C-B7D5-9F1CA8544E7B}.Release|ARM64.Build.0 = Release|ARM64 + {718FCBD0-591D-448C-B7D5-9F1CA8544E7B}.Release|x64.ActiveCfg = Release|x64 + {718FCBD0-591D-448C-B7D5-9F1CA8544E7B}.Release|x64.Build.0 = Release|x64 + {718FCBD0-591D-448C-B7D5-9F1CA8544E7B}.Release|x86.ActiveCfg = Release|Win32 + {718FCBD0-591D-448C-B7D5-9F1CA8544E7B}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -4447,7 +4447,7 @@ Global {49C67F03-1A56-4F96-B278-39B66EC93678} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} {D496308F-3C3C-40B3-A3ED-EA327D244B3E} = {8D3C83B7-F1E0-4C2E-9E34-EE5F6AB2502A} {3B27F358-2679-4F38-B297-17B536F580BB} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} - {6B1A933E-71B8-4C1F-9E79-02D98830E671} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} + {718FCBD0-591D-448C-B7D5-9F1CA8544E7B} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {E926C768-6307-4423-A1EC-57E95B1FAB29} From 3da2fc1bf876e7a81a058a661bee7b627fca51ba Mon Sep 17 00:00:00 2001 From: Antonio Jose Ramos Marquez Date: Mon, 29 Sep 2025 17:16:51 +0200 Subject: [PATCH 047/167] [rtextures] fix initialization align in Image to avoid issues with some platforms (#5214) --- src/rtextures.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/rtextures.c b/src/rtextures.c index 6366e4645..a85467d8c 100644 --- a/src/rtextures.c +++ b/src/rtextures.c @@ -811,8 +811,8 @@ Image GenImageColor(int width, int height, Color color) .data = pixels, .width = width, .height = height, - .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, - .mipmaps = 1 + .mipmaps = 1, + .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 }; return image; @@ -863,8 +863,8 @@ Image GenImageGradientLinear(int width, int height, int direction, Color start, .data = pixels, .width = width, .height = height, - .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, - .mipmaps = 1 + .mipmaps = 1, + .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 }; return image; @@ -900,8 +900,8 @@ Image GenImageGradientRadial(int width, int height, float density, Color inner, .data = pixels, .width = width, .height = height, - .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, - .mipmaps = 1 + .mipmaps = 1, + .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 }; return image; @@ -949,8 +949,8 @@ Image GenImageGradientSquare(int width, int height, float density, Color inner, .data = pixels, .width = width, .height = height, - .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, - .mipmaps = 1 + .mipmaps = 1, + .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 }; return image; @@ -974,8 +974,8 @@ Image GenImageChecked(int width, int height, int checksX, int checksY, Color col .data = pixels, .width = width, .height = height, - .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, - .mipmaps = 1 + .mipmaps = 1, + .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 }; return image; @@ -997,8 +997,8 @@ Image GenImageWhiteNoise(int width, int height, float factor) .data = pixels, .width = width, .height = height, - .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, - .mipmaps = 1 + .mipmaps = 1, + .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 }; return image; @@ -1048,8 +1048,8 @@ Image GenImagePerlinNoise(int width, int height, int offsetX, int offsetY, float .data = pixels, .width = width, .height = height, - .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, - .mipmaps = 1 + .mipmaps = 1, + .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 }; return image; @@ -1113,8 +1113,8 @@ Image GenImageCellular(int width, int height, int tileSize) .data = pixels, .width = width, .height = height, - .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, - .mipmaps = 1 + .mipmaps = 1, + .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 }; return image; From 317c1eaeeb2bd67e54711639cbb13391dfa44c87 Mon Sep 17 00:00:00 2001 From: Maicon Santana Date: Mon, 29 Sep 2025 16:44:48 +0100 Subject: [PATCH 048/167] Add ascii post processing (#5213) --- .../resources/shaders/glsl100/ascii.fs | 67 ++++++++++ .../resources/shaders/glsl120/ascii.fs | 65 ++++++++++ .../resources/shaders/glsl330/ascii.fs | 66 ++++++++++ examples/shaders/shaders_ascii_effect.c | 119 ++++++++++++++++++ examples/shaders/shaders_ascii_effect.png | Bin 0 -> 45176 bytes 5 files changed, 317 insertions(+) create mode 100644 examples/shaders/resources/shaders/glsl100/ascii.fs create mode 100644 examples/shaders/resources/shaders/glsl120/ascii.fs create mode 100644 examples/shaders/resources/shaders/glsl330/ascii.fs create mode 100644 examples/shaders/shaders_ascii_effect.c create mode 100644 examples/shaders/shaders_ascii_effect.png diff --git a/examples/shaders/resources/shaders/glsl100/ascii.fs b/examples/shaders/resources/shaders/glsl100/ascii.fs new file mode 100644 index 000000000..a4a930c3c --- /dev/null +++ b/examples/shaders/resources/shaders/glsl100/ascii.fs @@ -0,0 +1,67 @@ +#version 100 + +precision mediump float; + +// Input from the vertex shader +varying vec2 fragTexCoord; + +// Output color for the screen +varying vec4 finalColor; + +uniform sampler2D texture0; +uniform vec2 resolution; +uniform float fontSize; + +float greyScale(in vec3 col) { + return dot(col, vec3(0.2126, 0.7152, 0.0722)); +} + +float character(float n, vec2 p) +{ + p = floor(p * vec2(4.0, -4.0) + 2.5); + + // Check if the coordinate is inside the 5x5 grid (0 to 4). + if (clamp(p.x, 0.0, 4.0) == p.x && clamp(p.y, 0.0, 4.0) == p.y) { + + if (int(mod(n / exp2(p.x + 5.0 * p.y), 2.0)) == 1) { + return 1.0; // The bit is on, so draw this part of the character. + } + } + + return 0.0; // The bit is off, or we are outside the grid. +} + +// ----------------------------------------------------------------------------- +// Main shader logic +// ----------------------------------------------------------------------------- +void main() +{ + vec2 charPixelSize = vec2(fontSize, fontSize * 1.8); + vec2 uvCellSize = charPixelSize / resolution; + + vec2 cellUV = floor(fragTexCoord / uvCellSize) * uvCellSize; + + vec3 cellColor = texture2D(texture0, cellUV).rgb; + float gray = greyScale(cellColor); + + float n = 4096; + + // limited character set + if (gray > 0.2) n = 65600.0; // : + if (gray > 0.3) n = 163153.0; // * + if (gray > 0.4) n = 15255086.0; // o + if (gray > 0.5) n = 13121101.0; // & + if (gray > 0.6) n = 15252014.0; // 8 + if (gray > 0.7) n = 13195790.0; // @ + if (gray > 0.8) n = 11512810.0; // # + + vec2 localUV = (fragTexCoord - cellUV) / uvCellSize; // Range [0.0, 1.0] + + vec2 p = localUV * 2.0 - 1.0; + + float charShape = character(n, p); + + vec3 final_col = cellColor * charShape; + + gl_FragColor = vec4(final_col, 1.0); +} \ No newline at end of file diff --git a/examples/shaders/resources/shaders/glsl120/ascii.fs b/examples/shaders/resources/shaders/glsl120/ascii.fs new file mode 100644 index 000000000..3521c8b33 --- /dev/null +++ b/examples/shaders/resources/shaders/glsl120/ascii.fs @@ -0,0 +1,65 @@ +#version 120 + +// Input from the vertex shader +varying vec2 fragTexCoord; + +// Output color for the screen +varying vec4 finalColor; + +uniform sampler2D texture0; +uniform vec2 resolution; +uniform float fontSize; + +float greyScale(in vec3 col) { + return dot(col, vec3(0.2126, 0.7152, 0.0722)); +} + +float character(float n, vec2 p) +{ + p = floor(p * vec2(4.0, -4.0) + 2.5); + + // Check if the coordinate is inside the 5x5 grid (0 to 4). + if (clamp(p.x, 0.0, 4.0) == p.x && clamp(p.y, 0.0, 4.0) == p.y) { + + if (int(mod(n / exp2(p.x + 5.0 * p.y), 2.0)) == 1) { + return 1.0; // The bit is on, so draw this part of the character. + } + } + + return 0.0; // The bit is off, or we are outside the grid. +} + +// ----------------------------------------------------------------------------- +// Main shader logic +// ----------------------------------------------------------------------------- +void main() +{ + vec2 charPixelSize = vec2(fontSize, fontSize * 1.8); + vec2 uvCellSize = charPixelSize / resolution; + + vec2 cellUV = floor(fragTexCoord / uvCellSize) * uvCellSize; + + vec3 cellColor = texture2D(texture0, cellUV).rgb; + float gray = greyScale(cellColor); + + float n = 4096; + + // limited character set + if (gray > 0.2) n = 65600.0; // : + if (gray > 0.3) n = 163153.0; // * + if (gray > 0.4) n = 15255086.0; // o + if (gray > 0.5) n = 13121101.0; // & + if (gray > 0.6) n = 15252014.0; // 8 + if (gray > 0.7) n = 13195790.0; // @ + if (gray > 0.8) n = 11512810.0; // # + + vec2 localUV = (fragTexCoord - cellUV) / uvCellSize; // Range [0.0, 1.0] + + vec2 p = localUV * 2.0 - 1.0; + + float charShape = character(n, p); + + vec3 final_col = cellColor * charShape; + + gl_FragColor = vec4(final_col, 1.0); +} \ No newline at end of file diff --git a/examples/shaders/resources/shaders/glsl330/ascii.fs b/examples/shaders/resources/shaders/glsl330/ascii.fs new file mode 100644 index 000000000..4477f948d --- /dev/null +++ b/examples/shaders/resources/shaders/glsl330/ascii.fs @@ -0,0 +1,66 @@ +#version 330 + +// Input from the vertex shader +in vec2 fragTexCoord; + +// Output color for the screen +out vec4 finalColor; + +uniform sampler2D texture0; +uniform vec2 resolution; +uniform float fontSize; + +float greyScale(in vec3 col) { + return dot(col, vec3(0.2126, 0.7152, 0.0722)); +} + +float character(float n, vec2 p) +{ + p = floor(p * vec2(4.0, -4.0) + 2.5); + + // Check if the coordinate is inside the 5x5 grid (0 to 4). + if (clamp(p.x, 0.0, 4.0) == p.x && clamp(p.y, 0.0, 4.0) == p.y) { + + if (int(mod(n / exp2(p.x + 5.0 * p.y), 2.0)) == 1) { + return 1.0; // The bit is on, so draw this part of the character. + } + } + + return 0.0; // The bit is off, or we are outside the grid. +} + +// ----------------------------------------------------------------------------- +// Main shader logic +// ----------------------------------------------------------------------------- + +void main() +{ + vec2 charPixelSize = vec2(fontSize, fontSize * 1.8); + vec2 uvCellSize = charPixelSize / resolution; + + vec2 cellUV = floor(fragTexCoord / uvCellSize) * uvCellSize; + + vec3 cellColor = texture(texture0, cellUV).rgb; + float gray = greyScale(cellColor); + + float n = 4096; + + // limited character set + if (gray > 0.2) n = 65600.0; // : + if (gray > 0.3) n = 163153.0; // * + if (gray > 0.4) n = 15255086.0; // o + if (gray > 0.5) n = 13121101.0; // & + if (gray > 0.6) n = 15252014.0; // 8 + if (gray > 0.7) n = 13195790.0; // @ + if (gray > 0.8) n = 11512810.0; // # + + vec2 localUV = (fragTexCoord - cellUV) / uvCellSize; // Range [0.0, 1.0] + + vec2 p = localUV * 2.0 - 1.0; + + float charShape = character(n, p); + + vec3 final_col = cellColor * charShape; + + finalColor = vec4(final_col, 1.0); +} \ No newline at end of file diff --git a/examples/shaders/shaders_ascii_effect.c b/examples/shaders/shaders_ascii_effect.c new file mode 100644 index 000000000..c505d8516 --- /dev/null +++ b/examples/shaders/shaders_ascii_effect.c @@ -0,0 +1,119 @@ +/******************************************************************************************* +* +* raylib [shaders] example - ascii effect +* +* Example complexity rating: [★☆☆☆] 1/4 +* +* Example originally created with raylib 5.5, last time updated with raylib 5.6 +* +* Example contributed by Maicon Santana (@maiconpintoabreu) 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 Maicon Santana (@maiconpintoabreu) +* +********************************************************************************************/ + +#include "raylib.h" + +#if defined(PLATFORM_DESKTOP) + #define GLSL_VERSION 330 +#else // PLATFORM_ANDROID, PLATFORM_WEB + #define GLSL_VERSION 100 +#endif + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [shaders] example - ascii effect"); + + // Texture to test static drawing + Texture2D fudesumi = LoadTexture("resources/fudesumi.png"); + // Texture to test moving drawing + Texture2D raysan = LoadTexture("resources/raysan.png"); + + // Load shader to be used on postprocessing + Shader shader = LoadShader(0, TextFormat("resources/shaders/glsl%i/ascii.fs", GLSL_VERSION)); + + // These locations are used to send data to the GPU. + int resolutionLoc = GetShaderLocation(shader, "resolution"); + int fontSizeLoc = GetShaderLocation(shader, "fontSize"); + + // Set the character size for the ASCII effect + float fontSize = 4.0f; + + // Send the updated values to the shader + float resolution[2] = { (float)screenWidth, (float)screenHeight }; + SetShaderValue(shader, resolutionLoc, resolution, SHADER_UNIFORM_VEC2); + SetShaderValue(shader, fontSizeLoc, &fontSize, SHADER_UNIFORM_FLOAT); + + Vector2 circlePos = (Vector2){40.0f, (float)screenHeight * 0.5f}; + float circleSpeed = 1.0f; + + // RenderTexture to apply the postprocessing later + RenderTexture2D target = LoadRenderTexture(screenWidth, screenHeight); + + 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 + //---------------------------------------------------------------------------------- + if (circlePos.x > 200.0f || circlePos.x < 40.0f) { + circleSpeed *= -1; + } + circlePos.x += circleSpeed; + + // Draw + //---------------------------------------------------------------------------------- + + BeginTextureMode(target); + ClearBackground(WHITE); // The background of the scene itself + + DrawTexture(fudesumi, 500, -30, WHITE); // Using custom shader + DrawTextureV(raysan, circlePos, WHITE); + + EndTextureMode(); + BeginDrawing(); + + ClearBackground(RAYWHITE); + + BeginShaderMode(shader); + + // Draw the scene texture (that we rendered earlier) to the screen. + // The shader will process every pixel of this texture. + DrawTextureRec(target.texture, + (Rectangle){ 0, 0, (float)target.texture.width, (float)-target.texture.height }, + (Vector2){ 0, 0 }, + WHITE); + EndShaderMode(); + + DrawRectangle(0, 0, screenWidth, 40, BLACK); + DrawText("Ascii effect", 120, 10, 20, LIGHTGRAY); + DrawFPS(10, 10); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + UnloadShader(shader); // Unload shader + UnloadTexture(fudesumi); // Unload texture + UnloadTexture(raysan); // Unload texture + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} diff --git a/examples/shaders/shaders_ascii_effect.png b/examples/shaders/shaders_ascii_effect.png new file mode 100644 index 0000000000000000000000000000000000000000..eee5cc90b620c14cc111bb9a8348765cb77e827d GIT binary patch literal 45176 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 ntY^P`$Sott Date: Mon, 29 Sep 2025 18:01:42 +0200 Subject: [PATCH 049/167] REVIEWED: example: `shaders_ascii_rendering` --- .../resources/shaders/glsl330/ascii.fs | 43 ++++++++---------- ...cii_effect.c => shaders_ascii_rendering.c} | 36 +++++++-------- ...effect.png => shaders_ascii_rendering.png} | Bin 3 files changed, 37 insertions(+), 42 deletions(-) rename examples/shaders/{shaders_ascii_effect.c => shaders_ascii_rendering.c} (81%) rename examples/shaders/{shaders_ascii_effect.png => shaders_ascii_rendering.png} (100%) diff --git a/examples/shaders/resources/shaders/glsl330/ascii.fs b/examples/shaders/resources/shaders/glsl330/ascii.fs index 4477f948d..014966835 100644 --- a/examples/shaders/resources/shaders/glsl330/ascii.fs +++ b/examples/shaders/resources/shaders/glsl330/ascii.fs @@ -10,42 +10,42 @@ uniform sampler2D texture0; uniform vec2 resolution; uniform float fontSize; -float greyScale(in vec3 col) { +float GreyScale(in vec3 col) +{ return dot(col, vec3(0.2126, 0.7152, 0.0722)); } -float character(float n, vec2 p) +float GetCharacter(float n, vec2 p) { - p = floor(p * vec2(4.0, -4.0) + 2.5); + p = floor(p*vec2(4.0, -4.0) + 2.5); - // Check if the coordinate is inside the 5x5 grid (0 to 4). - if (clamp(p.x, 0.0, 4.0) == p.x && clamp(p.y, 0.0, 4.0) == p.y) { - - if (int(mod(n / exp2(p.x + 5.0 * p.y), 2.0)) == 1) { - return 1.0; // The bit is on, so draw this part of the character. + // Check if the coordinate is inside the 5x5 grid (0 to 4) + if (clamp(p.x, 0.0, 4.0) == p.x && clamp(p.y, 0.0, 4.0) == p.y) + { + if (int(mod(n/exp2(p.x + 5.0 * p.y), 2.0)) == 1) + { + return 1.0; // The bit is on, so draw this part of the character } } - return 0.0; // The bit is off, or we are outside the grid. + return 0.0; // The bit is off, or we are outside the grid } // ----------------------------------------------------------------------------- // Main shader logic // ----------------------------------------------------------------------------- - void main() { - vec2 charPixelSize = vec2(fontSize, fontSize * 1.8); - vec2 uvCellSize = charPixelSize / resolution; - - vec2 cellUV = floor(fragTexCoord / uvCellSize) * uvCellSize; + vec2 charPixelSize = vec2(fontSize, fontSize*1.8); + vec2 uvCellSize = charPixelSize/resolution; + vec2 cellUV = floor(fragTexCoord/uvCellSize)*uvCellSize; vec3 cellColor = texture(texture0, cellUV).rgb; - float gray = greyScale(cellColor); + float gray = GreyScale(cellColor); float n = 4096; - // limited character set + // Limited character set if (gray > 0.2) n = 65600.0; // : if (gray > 0.3) n = 163153.0; // * if (gray > 0.4) n = 15255086.0; // o @@ -54,13 +54,10 @@ void main() if (gray > 0.7) n = 13195790.0; // @ if (gray > 0.8) n = 11512810.0; // # - vec2 localUV = (fragTexCoord - cellUV) / uvCellSize; // Range [0.0, 1.0] + vec2 localUV = (fragTexCoord - cellUV)/uvCellSize; // Range [0.0, 1.0] + vec2 p = localUV*2.0 - 1.0; - vec2 p = localUV * 2.0 - 1.0; + float charShape = GetCharacter(n, p); - float charShape = character(n, p); - - vec3 final_col = cellColor * charShape; - - finalColor = vec4(final_col, 1.0); + finalColor = vec4(cellColor*charShape, 1.0); } \ No newline at end of file diff --git a/examples/shaders/shaders_ascii_effect.c b/examples/shaders/shaders_ascii_rendering.c similarity index 81% rename from examples/shaders/shaders_ascii_effect.c rename to examples/shaders/shaders_ascii_rendering.c index c505d8516..5444caeee 100644 --- a/examples/shaders/shaders_ascii_effect.c +++ b/examples/shaders/shaders_ascii_rendering.c @@ -1,8 +1,8 @@ /******************************************************************************************* * -* raylib [shaders] example - ascii effect +* raylib [shaders] example - ascii rendering * -* Example complexity rating: [★☆☆☆] 1/4 +* Example complexity rating: [★★☆☆] 2/4 * * Example originally created with raylib 5.5, last time updated with raylib 5.6 * @@ -33,7 +33,7 @@ int main(void) const int screenWidth = 800; const int screenHeight = 450; - InitWindow(screenWidth, screenHeight, "raylib [shaders] example - ascii effect"); + InitWindow(screenWidth, screenHeight, "raylib [shaders] example - ascii rendering"); // Texture to test static drawing Texture2D fudesumi = LoadTexture("resources/fudesumi.png"); @@ -43,7 +43,7 @@ int main(void) // Load shader to be used on postprocessing Shader shader = LoadShader(0, TextFormat("resources/shaders/glsl%i/ascii.fs", GLSL_VERSION)); - // These locations are used to send data to the GPU. + // These locations are used to send data to the GPU int resolutionLoc = GetShaderLocation(shader, "resolution"); int fontSizeLoc = GetShaderLocation(shader, "fontSize"); @@ -69,33 +69,31 @@ int main(void) { // Update //---------------------------------------------------------------------------------- - if (circlePos.x > 200.0f || circlePos.x < 40.0f) { - circleSpeed *= -1; - } circlePos.x += circleSpeed; + + if ((circlePos.x > 200.0f) || (circlePos.x < 40.0f)) circleSpeed *= -1; + //---------------------------------------------------------------------------------- // Draw //---------------------------------------------------------------------------------- - + // Draw our scene to a render texture first BeginTextureMode(target); - ClearBackground(WHITE); // The background of the scene itself + ClearBackground(WHITE); - DrawTexture(fudesumi, 500, -30, WHITE); // Using custom shader + DrawTexture(fudesumi, 500, -30, WHITE); DrawTextureV(raysan, circlePos, WHITE); - + EndTextureMode(); + BeginDrawing(); - ClearBackground(RAYWHITE); BeginShaderMode(shader); - - // Draw the scene texture (that we rendered earlier) to the screen. - // The shader will process every pixel of this texture. - DrawTextureRec(target.texture, - (Rectangle){ 0, 0, (float)target.texture.width, (float)-target.texture.height }, - (Vector2){ 0, 0 }, - WHITE); + // Draw the render texture containing scene + // The shader will process every pixel on the screen + DrawTextureRec(target.texture, + (Rectangle){ 0, 0, (float)target.texture.width, (float)-target.texture.height }, + (Vector2){ 0, 0 }, WHITE); EndShaderMode(); DrawRectangle(0, 0, screenWidth, 40, BLACK); diff --git a/examples/shaders/shaders_ascii_effect.png b/examples/shaders/shaders_ascii_rendering.png similarity index 100% rename from examples/shaders/shaders_ascii_effect.png rename to examples/shaders/shaders_ascii_rendering.png From beabb1300d859b8503bdbec098956df3e3843b48 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 29 Sep 2025 18:03:42 +0200 Subject: [PATCH 050/167] Revert "Update miniaudio to v0.11.23 (#5208)" This reverts commit 4cd131cf292bf4f5e06c7db89e9224fe36894330. --- src/external/miniaudio.h | 6147 ++++++++++++-------------------------- 1 file changed, 1983 insertions(+), 4164 deletions(-) diff --git a/src/external/miniaudio.h b/src/external/miniaudio.h index 1e4e2c655..c74bebeb3 100644 --- a/src/external/miniaudio.h +++ b/src/external/miniaudio.h @@ -1,6 +1,6 @@ /* Audio playback and capture library. Choice of public domain or MIT-0. See license statements at the end of this file. -miniaudio - v0.11.23 - 2025-09-11 +miniaudio - v0.11.22 - 2025-02-24 David Reid - mackron@gmail.com @@ -12,10 +12,18 @@ GitHub: https://github.com/mackron/miniaudio /* 1. Introduction =============== -To use miniaudio, just include "miniaudio.h" like any other header and add "miniaudio.c" to your -source tree. If you don't want to add it to your source tree you can compile and link to it like -any other library. Note that ABI compatibility is not guaranteed between versions, even with bug -fix releases, so take care if compiling as a shared object. +To use miniaudio, include "miniaudio.h": + + ```c + #include "miniaudio.h" + ``` + +The implementation is contained in "miniaudio.c". Just compile this like any other source file. You +can include miniaudio.c if you want to compile your project as a single translation unit: + + ```c + #include "miniaudio.c" + ``` miniaudio includes both low level and high level APIs. The low level API is good for those who want to do all of their mixing themselves and only require a light weight interface to the underlying @@ -295,7 +303,7 @@ The engine encapsulates both the resource manager and the node graph to create a use high level API. The resource manager and node graph APIs are covered in more later sections of this manual. -The code below shows how you can initialize an engine using its default configuration. +The code below shows how you can initialize an engine using it's default configuration. ```c ma_result result; @@ -383,7 +391,7 @@ Sounds are not started by default. Start a sound with `ma_sound_start()` and sto `ma_sound_stop()`. When a sound is stopped, it is not rewound to the start. Use `ma_sound_seek_to_pcm_frame(&sound, 0)` to seek back to the start of a sound. By default, starting and stopping sounds happens immediately, but sometimes it might be convenient to schedule the sound -to be started and/or stopped at a specific time. This can be done with the following functions: +the be started and/or stopped at a specific time. This can be done with the following functions: ```c ma_sound_set_start_time_in_pcm_frames() @@ -455,11 +463,6 @@ is at the end, use `ma_sound_at_end()`. Looping of a sound can be controlled wit miniaudio should work cleanly out of the box without the need to download or install any dependencies. See below for platform-specific details. -This library has been designed to be added directly to your source tree which is the preferred way -of using it, but you can compile it as a normal library if that's your preference. Be careful if -compiling as a shared object because miniaudio is not ABI compatible between any release, including -bug fix releases. It's recommended you link statically. - Note that GCC and Clang require `-msse2`, `-mavx2`, etc. for SIMD optimizations. If you get errors about undefined references to `__sync_val_compare_and_swap_8`, `__atomic_load_8`, @@ -529,7 +532,7 @@ you'll need to disable run-time linking with `MA_NO_RUNTIME_LINKING` and link wi The Emscripten build emits Web Audio JavaScript directly and should compile cleanly out of the box. You cannot use `-std=c*` compiler flags, nor `-ansi`. -You can enable the use of AudioWorklets by defining `MA_ENABLE_AUDIO_WORKLETS` and then compiling +You can enable the use of AudioWorkets by defining `MA_ENABLE_AUDIO_WORKLETS` and then compiling with the following options: -sAUDIO_WORKLET=1 -sWASM_WORKERS=1 -sASYNCIFY @@ -878,7 +881,7 @@ read data within a certain range of the underlying data. To do this you can use This is useful if you have a sound bank where many sounds are stored in the same file and you want the data source to only play one of those sub-sounds. Note that once the range is set, everything -that takes a position, such as cursors and loop points, should always be relative to the start of +that takes a position, such as cursors and loop points, should always be relatvie to the start of the range. When the range is set, any previously defined loop point will be reset. Custom loop points can also be used with data sources. By default, data sources will loop after @@ -886,7 +889,7 @@ they reach the end of the data source, but if you need to loop at a specific loc the following: ```c - result = ma_data_source_set_loop_point_in_pcm_frames(pDataSource, loopBegInFrames, loopEndInFrames); + result = ma_data_set_loop_point_in_pcm_frames(pDataSource, loopBegInFrames, loopEndInFrames); if (result != MA_SUCCESS) { return result; // Failed to set the loop point. } @@ -3747,7 +3750,7 @@ extern "C" { #define MA_VERSION_MAJOR 0 #define MA_VERSION_MINOR 11 -#define MA_VERSION_REVISION 23 +#define MA_VERSION_REVISION 22 #define MA_VERSION_STRING MA_XSTRINGIFY(MA_VERSION_MAJOR) "." MA_XSTRINGIFY(MA_VERSION_MINOR) "." MA_XSTRINGIFY(MA_VERSION_REVISION) #if defined(_MSC_VER) && !defined(__clang__) @@ -3854,8 +3857,6 @@ typedef ma_uint16 wchar_t; #define MA_SIZE_MAX 0xFFFFFFFF /* When SIZE_MAX is not defined by the standard library just default to the maximum 32-bit unsigned integer. */ #endif -#define MA_UINT64_MAX (((ma_uint64)0xFFFFFFFF << 32) | (ma_uint64)0xFFFFFFFF) /* Weird shifting syntax is for VC6 compatibility. */ - /* Platform/backend detection. */ #if defined(_WIN32) || defined(__COSMOPOLITAN__) @@ -3864,55 +3865,29 @@ typedef ma_uint16 wchar_t; #define MA_WIN32_UWP #elif defined(WINAPI_FAMILY) && (defined(WINAPI_FAMILY_GAMES) && WINAPI_FAMILY == WINAPI_FAMILY_GAMES) #define MA_WIN32_GDK - #elif defined(NXDK) - #define MA_WIN32_NXDK #else #define MA_WIN32_DESKTOP #endif - - /* The original Xbox. */ - #if defined(NXDK) /* <-- Add other Xbox compiler toolchains here, and then add a toolchain-specific define in case we need to discriminate between them later. */ - #define MA_XBOX - - #if defined(NXDK) - #define MA_XBOX_NXDK - #endif - #endif #endif -#if defined(__MSDOS__) || defined(MSDOS) || defined(_MSDOS) || defined(__DOS__) - #define MA_DOS - - /* No threading allowed on DOS. */ - #ifndef MA_NO_THREADING - #define MA_NO_THREADING - #endif - - /* No runtime linking allowed on DOS. */ - #ifndef MA_NO_RUNTIME_LINKING - #define MA_NO_RUNTIME_LINKING - #endif -#endif -#if !defined(MA_WIN32) && !defined(MA_DOS) /* If it's not Win32, assume POSIX. */ +#if !defined(_WIN32) /* If it's not Win32, assume POSIX. */ #define MA_POSIX - #if !defined(MA_NO_THREADING) - /* - Use the MA_NO_PTHREAD_IN_HEADER option at your own risk. This is intentionally undocumented. - You can use this to avoid including pthread.h in the header section. The downside is that it - results in some fixed sized structures being declared for the various types that are used in - miniaudio. The risk here is that these types might be too small for a given platform. This - risk is yours to take and no support will be offered if you enable this option. - */ - #ifndef MA_NO_PTHREAD_IN_HEADER - #include /* Unfortunate #include, but needed for pthread_t, pthread_mutex_t and pthread_cond_t types. */ - typedef pthread_t ma_pthread_t; - typedef pthread_mutex_t ma_pthread_mutex_t; - typedef pthread_cond_t ma_pthread_cond_t; - #else - typedef ma_uintptr ma_pthread_t; - typedef union ma_pthread_mutex_t { char __data[40]; ma_uint64 __alignment; } ma_pthread_mutex_t; - typedef union ma_pthread_cond_t { char __data[48]; ma_uint64 __alignment; } ma_pthread_cond_t; - #endif + /* + Use the MA_NO_PTHREAD_IN_HEADER option at your own risk. This is intentionally undocumented. + You can use this to avoid including pthread.h in the header section. The downside is that it + results in some fixed sized structures being declared for the various types that are used in + miniaudio. The risk here is that these types might be too small for a given platform. This + risk is yours to take and no support will be offered if you enable this option. + */ + #ifndef MA_NO_PTHREAD_IN_HEADER + #include /* Unfortunate #include, but needed for pthread_t, pthread_mutex_t and pthread_cond_t types. */ + typedef pthread_t ma_pthread_t; + typedef pthread_mutex_t ma_pthread_mutex_t; + typedef pthread_cond_t ma_pthread_cond_t; + #else + typedef ma_uintptr ma_pthread_t; + typedef union ma_pthread_mutex_t { char __data[40]; ma_uint64 __alignment; } ma_pthread_mutex_t; + typedef union ma_pthread_cond_t { char __data[48]; ma_uint64 __alignment; } ma_pthread_cond_t; #endif #if defined(__unix__) @@ -3939,11 +3914,8 @@ typedef ma_uint16 wchar_t; #if defined(__PROSPERO__) #define MA_PROSPERO #endif - #if defined(__3DS__) - #define MA_3DS - #endif - #if defined(__SWITCH__) || defined(__NX__) - #define MA_SWITCH + #if defined(__NX__) + #define MA_NX #endif #if defined(__BEOS__) || defined(__HAIKU__) #define MA_BEOS @@ -3953,13 +3925,12 @@ typedef ma_uint16 wchar_t; #endif #endif -#if !defined(MA_FALLTHROUGH) && defined(__cplusplus) && __cplusplus >= 201703L - #define MA_FALLTHROUGH [[fallthrough]] +#if defined(__has_c_attribute) + #if __has_c_attribute(fallthrough) + #define MA_FALLTHROUGH [[fallthrough]] + #endif #endif -#if !defined(MA_FALLTHROUGH) && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202000L - #define MA_FALLTHROUGH [[fallthrough]] -#endif -#if !defined(MA_FALLTHROUGH) && defined(__has_attribute) +#if !defined(MA_FALLTHROUGH) && defined(__has_attribute) && (defined(__clang__) || defined(__GNUC__)) #if __has_attribute(fallthrough) #define MA_FALLTHROUGH __attribute__((fallthrough)) #endif @@ -3996,7 +3967,7 @@ typedef ma_uint16 wchar_t; #define MA_NO_INLINE __attribute__((noinline)) #else #define MA_INLINE MA_GNUC_INLINE_HINT - #define MA_NO_INLINE + #define MA_NO_INLINE __attribute__((noinline)) #endif #elif defined(__WATCOMC__) #define MA_INLINE __inline @@ -4379,7 +4350,7 @@ typedef struct typedef struct { - ma_uint32 state; + ma_int32 state; } ma_lcg; @@ -6598,7 +6569,7 @@ This section contains the APIs for device playback and capture. Here is where yo ************************************************************************************************************************************************************/ #ifndef MA_NO_DEVICE_IO /* Some backends are only supported on certain platforms. */ -#if defined(MA_WIN32) && !defined(MA_XBOX) +#if defined(MA_WIN32) #define MA_SUPPORT_WASAPI #if defined(MA_WIN32_DESKTOP) /* DirectSound and WinMM backends are only supported on desktops. */ @@ -7455,7 +7426,6 @@ struct ma_context ma_proc snd_pcm_hw_params_set_rate_resample; ma_proc snd_pcm_hw_params_set_rate; ma_proc snd_pcm_hw_params_set_rate_near; - ma_proc snd_pcm_hw_params_set_rate_minmax; ma_proc snd_pcm_hw_params_set_buffer_size_near; ma_proc snd_pcm_hw_params_set_periods_near; ma_proc snd_pcm_hw_params_set_access; @@ -8016,7 +7986,6 @@ struct ma_device /*AAudioStream**/ ma_ptr pStreamPlayback; /*AAudioStream**/ ma_ptr pStreamCapture; ma_mutex rerouteLock; - ma_atomic_bool32 isTearingDown; ma_aaudio_usage usage; ma_aaudio_content_type contentType; ma_aaudio_input_preset inputPreset; @@ -11286,7 +11255,7 @@ typedef struct ma_log* pLog; /* When set to NULL, will use the context's log. */ ma_uint32 listenerCount; /* Must be between 1 and MA_ENGINE_MAX_LISTENERS. */ ma_uint32 channels; /* The number of channels to use when mixing and spatializing. When set to 0, will use the native channel count of the device. */ - ma_uint32 sampleRate; /* The sample rate. When set to 0 will use the native sample rate of the device. */ + ma_uint32 sampleRate; /* The sample rate. When set to 0 will use the native channel count of the device. */ ma_uint32 periodSizeInFrames; /* If set to something other than 0, updates will always be exactly this size. The underlying device may be a different size, but from the perspective of the mixer that won't matter.*/ ma_uint32 periodSizeInMilliseconds; /* Used if periodSizeInFrames is unset. */ ma_uint32 gainSmoothTimeInFrames; /* The number of frames to interpolate the gain of spatialized sounds across. If set to 0, will use gainSmoothTimeInMilliseconds. */ @@ -11450,11 +11419,11 @@ MA_API ma_bool32 ma_sound_is_looping(const ma_sound* pSound); MA_API ma_bool32 ma_sound_at_end(const ma_sound* pSound); MA_API ma_result ma_sound_seek_to_pcm_frame(ma_sound* pSound, ma_uint64 frameIndex); /* Just a wrapper around ma_data_source_seek_to_pcm_frame(). */ MA_API ma_result ma_sound_seek_to_second(ma_sound* pSound, float seekPointInSeconds); /* Abstraction to ma_sound_seek_to_pcm_frame() */ -MA_API ma_result ma_sound_get_data_format(const ma_sound* pSound, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap); -MA_API ma_result ma_sound_get_cursor_in_pcm_frames(const ma_sound* pSound, ma_uint64* pCursor); -MA_API ma_result ma_sound_get_length_in_pcm_frames(const ma_sound* pSound, ma_uint64* pLength); -MA_API ma_result ma_sound_get_cursor_in_seconds(const ma_sound* pSound, float* pCursor); -MA_API ma_result ma_sound_get_length_in_seconds(const ma_sound* pSound, float* pLength); +MA_API ma_result ma_sound_get_data_format(ma_sound* pSound, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap); +MA_API ma_result ma_sound_get_cursor_in_pcm_frames(ma_sound* pSound, ma_uint64* pCursor); +MA_API ma_result ma_sound_get_length_in_pcm_frames(ma_sound* pSound, ma_uint64* pLength); +MA_API ma_result ma_sound_get_cursor_in_seconds(ma_sound* pSound, float* pCursor); +MA_API ma_result ma_sound_get_length_in_seconds(ma_sound* pSound, float* pLength); MA_API ma_result ma_sound_set_end_callback(ma_sound* pSound, ma_sound_end_proc callback, void* pUserData); MA_API ma_result ma_sound_group_init(ma_engine* pEngine, ma_uint32 flags, ma_sound_group* pParentGroup, ma_sound_group* pGroup); @@ -11575,23 +11544,17 @@ IMPLEMENTATION #endif #if !defined(MA_WIN32) - #if !defined(MA_NO_THREADING) - #include - #include /* For pthreads. */ - #endif - - #include /* select() (used for ma_sleep()). */ - #include /* For nanosleep() */ - #include +#include +#include /* select() (used for ma_sleep()). */ +#include #endif -/* For fstat(), etc. */ -#if defined(MA_XBOX_NXDK) - #include /* Suggestion for NXDK: Add a sys/stat.h wrapper for compatibility. */ -#else - #include +#ifdef MA_NX +#include /* For nanosleep() */ #endif +#include /* For fstat(), etc. */ + #ifdef MA_EMSCRIPTEN #include #endif @@ -11898,7 +11861,7 @@ static MA_INLINE ma_bool32 ma_has_neon(void) #endif #ifndef MA_RESTRICT - #if defined(__clang__) || defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95))) + #if defined(__clang__) || defined(__GNUC__) || defined(_MSC_VER) #define MA_RESTRICT __restrict #else #define MA_RESTRICT @@ -11992,7 +11955,7 @@ static void ma_sleep__posix(ma_uint32 milliseconds) (void)milliseconds; MA_ASSERT(MA_FALSE); /* The Emscripten build should never sleep. */ #else - #if (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309L) || defined(MA_SWITCH) + #if (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309L) || defined(MA_NX) struct timespec ts; ts.tv_sec = milliseconds / 1000; ts.tv_nsec = milliseconds % 1000 * 1000000; @@ -12034,7 +11997,7 @@ static MA_INLINE void ma_yield(void) #endif #endif #else - __asm__ __volatile__ ("rep; nop"); + __asm__ __volatile__ ("pause"); #endif #elif (defined(__arm__) && defined(__ARM_ARCH) && __ARM_ARCH >= 7) || defined(_M_ARM64) || (defined(_M_ARM) && _M_ARM >= 7) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6T2__) /* ARM */ @@ -12057,7 +12020,7 @@ static MA_INLINE unsigned int ma_disable_denormals(void) { unsigned int prevState; - #if defined(_MSC_VER) && !defined(MA_XBOX_NXDK) + #if defined(_MSC_VER) { /* Older versions of Visual Studio don't support the "safe" versions of _controlfp_s(). I don't @@ -12080,7 +12043,7 @@ static MA_INLINE unsigned int ma_disable_denormals(void) } #elif defined(MA_X86) || defined(MA_X64) { - #if defined(MA_SUPPORT_SSE2) && defined(__SSE2__) && !(defined(__TINYC__) || defined(__WATCOMC__) || defined(__COSMOPOLITAN__)) /* <-- Add compilers that lack support for _mm_getcsr() and _mm_setcsr() to this list. */ + #if defined(__SSE2__) && !(defined(__TINYC__) || defined(__WATCOMC__) || defined(__COSMOPOLITAN__)) /* <-- Add compilers that lack support for _mm_getcsr() and _mm_setcsr() to this list. */ { prevState = _mm_getcsr(); _mm_setcsr(prevState | MA_MM_DENORMALS_ZERO_MASK | MA_MM_FLUSH_ZERO_MASK); @@ -12104,7 +12067,7 @@ static MA_INLINE unsigned int ma_disable_denormals(void) static MA_INLINE void ma_restore_denormals(unsigned int prevState) { - #if defined(_MSC_VER) && !defined(MA_XBOX_NXDK) + #if defined(_MSC_VER) { /* Older versions of Visual Studio do not support _controlfp_s(). See ma_disable_denormals(). */ #if _MSC_VER <= 1200 @@ -12120,7 +12083,7 @@ static MA_INLINE void ma_restore_denormals(unsigned int prevState) } #elif defined(MA_X86) || defined(MA_X64) { - #if defined(MA_SUPPORT_SSE2) && defined(__SSE2__) && !(defined(__TINYC__) || defined(__WATCOMC__) || defined(__COSMOPOLITAN__)) /* <-- Add compilers that lack support for _mm_getcsr() and _mm_setcsr() to this list. */ + #if defined(__SSE2__) && !(defined(__TINYC__) || defined(__WATCOMC__) || defined(__COSMOPOLITAN__)) /* <-- Add compilers that lack support for _mm_getcsr() and _mm_setcsr() to this list. */ { _mm_setcsr(prevState); } @@ -12756,29 +12719,6 @@ MA_API MA_NO_INLINE int ma_strcmp(const char* str1, const char* str2) return ((unsigned char*)str1)[0] - ((unsigned char*)str2)[0]; } -MA_API MA_NO_INLINE int ma_wcscmp(const wchar_t* str1, const wchar_t* str2) -{ - if (str1 == str2) return 0; - - /* These checks differ from the standard implementation. It's not important, but I prefer it just for sanity. */ - if (str1 == NULL) return -1; - if (str2 == NULL) return 1; - - for (;;) { - if (str1[0] == L'\0') { - break; - } - if (str1[0] != str2[0]) { - break; - } - - str1 += 1; - str2 += 1; - } - - return ((unsigned short*)str1)[0] - ((unsigned short*)str2)[0]; -} - MA_API MA_NO_INLINE int ma_strappend(char* dst, size_t dstSize, const char* srcA, const char* srcB) { int result; @@ -12796,22 +12736,6 @@ MA_API MA_NO_INLINE int ma_strappend(char* dst, size_t dstSize, const char* srcA return result; } -MA_API MA_NO_INLINE size_t ma_wcslen(const wchar_t* str) -{ - const wchar_t* end; - - if (str == NULL) { - return 0; - } - - end = str; - while (end[0] != '\0') { - end += 1; - } - - return end - str; -} - MA_API MA_NO_INLINE char* ma_copy_string(const char* src, const ma_allocation_callbacks* pAllocationCallbacks) { size_t sz; @@ -12834,7 +12758,7 @@ MA_API MA_NO_INLINE char* ma_copy_string(const char* src, const ma_allocation_ca MA_API MA_NO_INLINE wchar_t* ma_copy_string_w(const wchar_t* src, const ma_allocation_callbacks* pAllocationCallbacks) { - size_t sz = ma_wcslen(src)+1; + size_t sz = wcslen(src)+1; wchar_t* dst = (wchar_t*)ma_malloc(sz * sizeof(*dst), pAllocationCallbacks); if (dst == NULL) { return NULL; @@ -13265,7 +13189,7 @@ MA_API ma_result ma_fopen(FILE** ppFile, const char* pFilePath, const char* pOpe return MA_INVALID_ARGS; } -#if (defined(_MSC_VER) && _MSC_VER >= 1400) && !defined(MA_XBOX_NXDK) +#if defined(_MSC_VER) && _MSC_VER >= 1400 err = fopen_s(ppFile, pFilePath, pOpenMode); if (err != 0) { return ma_result_from_errno(err); @@ -13307,7 +13231,7 @@ _wfopen() isn't always available in all compilation environments. This can be reviewed as compatibility issues arise. The preference is to use _wfopen_s() and _wfopen() as opposed to the wcsrtombs() fallback, so if you notice your compiler not detecting this properly I'm happy to look at adding support. */ -#if defined(_WIN32) && !defined(MA_XBOX_NXDK) +#if defined(_WIN32) #if defined(_MSC_VER) || defined(__MINGW64__) || (!defined(__STRICT_ANSI__) && !defined(_NO_EXT_KEYS)) #define MA_HAS_WFOPEN #endif @@ -13323,34 +13247,29 @@ MA_API ma_result ma_wfopen(FILE** ppFile, const wchar_t* pFilePath, const wchar_ return MA_INVALID_ARGS; } - #if defined(MA_HAS_WFOPEN) +#if defined(MA_HAS_WFOPEN) { /* Use _wfopen() on Windows. */ - #if defined(_MSC_VER) && _MSC_VER >= 1400 - { - errno_t err = _wfopen_s(ppFile, pFilePath, pOpenMode); - if (err != 0) { - return ma_result_from_errno(err); - } + #if defined(_MSC_VER) && _MSC_VER >= 1400 + errno_t err = _wfopen_s(ppFile, pFilePath, pOpenMode); + if (err != 0) { + return ma_result_from_errno(err); } - #else - { - *ppFile = _wfopen(pFilePath, pOpenMode); - if (*ppFile == NULL) { - return ma_result_from_errno(errno); - } + #else + *ppFile = _wfopen(pFilePath, pOpenMode); + if (*ppFile == NULL) { + return ma_result_from_errno(errno); } - #endif - + #endif (void)pAllocationCallbacks; } - #elif !defined(MA_XBOX_NXDK) && !defined(MA_DOS) /* If your compiler does not support wcsrtombs(), add it here. */ +#else + /* + Use fopen() on anything other than Windows. Requires a conversion. This is annoying because fopen() is locale specific. The only real way I can + think of to do this is with wcsrtombs(). Note that wcstombs() is apparently not thread-safe because it uses a static global mbstate_t object for + maintaining state. I've checked this with -std=c89 and it works, but if somebody get's a compiler error I'll look into improving compatibility. + */ { - /* - Use fopen() on anything other than Windows. Requires a conversion. This is annoying because fopen() is locale specific. The only real way I can - think of to do this is with wcsrtombs(). Note that wcstombs() is apparently not thread-safe because it uses a static global mbstate_t object for - maintaining state. I've checked this with -std=c89 and it works, but if somebody get's a compiler error I'll look into improving compatibility. - */ mbstate_t mbs; size_t lenMB; const wchar_t* pFilePathTemp = pFilePath; @@ -13391,16 +13310,11 @@ MA_API ma_result ma_wfopen(FILE** ppFile, const wchar_t* pFilePath, const wchar_ ma_free(pFilePathMB, pAllocationCallbacks); } - #else - { - /* Getting here means there is no way to open the file with a wide character string. */ - *ppFile = NULL; - } - #endif if (*ppFile == NULL) { return MA_ERROR; } +#endif return MA_SUCCESS; } @@ -13409,7 +13323,7 @@ MA_API ma_result ma_wfopen(FILE** ppFile, const wchar_t* pFilePath, const wchar_ static MA_INLINE void ma_copy_memory_64(void* dst, const void* src, ma_uint64 sizeInBytes) { -#if MA_SIZE_MAX > 0xFFFFFFFF +#if 0xFFFFFFFFFFFFFFFF <= MA_SIZE_MAX MA_COPY_MEMORY(dst, src, (size_t)sizeInBytes); #else while (sizeInBytes > 0) { @@ -13429,7 +13343,7 @@ static MA_INLINE void ma_copy_memory_64(void* dst, const void* src, ma_uint64 si static MA_INLINE void ma_zero_memory_64(void* dst, ma_uint64 sizeInBytes) { -#if MA_SIZE_MAX > 0xFFFFFFFF +#if 0xFFFFFFFFFFFFFFFF <= MA_SIZE_MAX MA_ZERO_MEMORY(dst, (size_t)sizeInBytes); #else while (sizeInBytes > 0) { @@ -13558,18 +13472,6 @@ static ma_result ma_allocation_callbacks_init_copy(ma_allocation_callbacks* pDst Logging **************************************************************************************************************************************************************/ -#ifndef ma_va_copy - #if !defined(_MSC_VER) || _MSC_VER >= 1800 - #if (defined(__GNUC__) && __GNUC__ < 3) - #define ma_va_copy(dst, src) ((dst) = (src)) /* This is untested. Not sure if this is correct for old GCC. */ - #else - #define ma_va_copy(dst, src) va_copy((dst), (src)) - #endif - #else - #define ma_va_copy(dst, src) ((dst) = (src)) - #endif -#endif - MA_API const char* ma_log_level_to_string(ma_uint32 logLevel) { switch (logLevel) @@ -13810,15 +13712,9 @@ MA_API ma_result ma_log_postv(ma_log* pLog, ma_uint32 level, const char* pFormat int length; char pFormattedMessageStack[1024]; char* pFormattedMessageHeap = NULL; - va_list args2; /* First try formatting into our fixed sized stack allocated buffer. If this is too small we'll fallback to a heap allocation. */ - ma_va_copy(args2, args); - { - length = vsnprintf(pFormattedMessageStack, sizeof(pFormattedMessageStack), pFormat, args2); - } - va_end(args2); - + length = vsnprintf(pFormattedMessageStack, sizeof(pFormattedMessageStack), pFormat, args); if (length < 0) { return MA_INVALID_OPERATION; /* An error occurred when trying to convert the buffer. */ } @@ -13859,10 +13755,17 @@ MA_API ma_result ma_log_postv(ma_log* pLog, ma_uint32 level, const char* pFormat char* pFormattedMessage = NULL; va_list args2; - ma_va_copy(args2, args); + #if _MSC_VER >= 1800 { - formattedLen = ma_vscprintf(&pLog->allocationCallbacks, pFormat, args2); + va_copy(args2, args); } + #else + { + args2 = args; + } + #endif + + formattedLen = ma_vscprintf(&pLog->allocationCallbacks, pFormat, args2); va_end(args2); if (formattedLen <= 0) { @@ -14061,7 +13964,7 @@ miniaudio's purposes. #define MA_LCG_A 48271 #define MA_LCG_C 0 -static ma_lcg g_maLCG = {MA_DEFAULT_LCG_SEED}; /* Non-zero initial seed. Use ma_lcg_seed() to use an explicit seed. */ +static ma_lcg g_maLCG = {MA_DEFAULT_LCG_SEED}; /* Non-zero initial seed. Use ma_seed() to use an explicit seed. */ static MA_INLINE void ma_lcg_seed(ma_lcg* pLCG, ma_int32 seed) { @@ -14110,7 +14013,7 @@ static MA_INLINE ma_int32 ma_lcg_rand_range_s32(ma_lcg* pLCG, ma_int32 lo, ma_in } -#if 0 /* Currently unused. */ + static MA_INLINE void ma_seed(ma_int32 seed) { ma_lcg_seed(&g_maLCG, seed); @@ -14135,7 +14038,6 @@ static MA_INLINE float ma_rand_f32(void) { return ma_lcg_rand_f32(&g_maLCG); } -#endif static MA_INLINE float ma_rand_range_f32(float lo, float hi) { @@ -14195,7 +14097,6 @@ Atomics **************************************************************************************************************************************************************/ /* c89atomic.h begin */ #ifndef ma_atomic_h -#define ma_atomic_h #if defined(__cplusplus) extern "C" { #endif @@ -14207,40 +14108,11 @@ extern "C" { #endif #endif typedef int ma_atomic_memory_order; -#if !defined(MA_ATOMIC_MODERN_MSVC) && \ - !defined(MA_ATOMIC_LEGACY_MSVC) && \ - !defined(MA_ATOMIC_LEGACY_MSVC_ASM) && \ - !defined(MA_ATOMIC_MODERN_GCC) && \ - !defined(MA_ATOMIC_LEGACY_GCC) && \ - !defined(MA_ATOMIC_LEGACY_GCC_ASM) - #if defined(_MSC_VER) || defined(__WATCOMC__) || defined(__DMC__) || defined(__BORLANDC__) - #if (defined(_MSC_VER) && _MSC_VER > 1600) - #define MA_ATOMIC_MODERN_MSVC - #else - #if defined(MA_X64) - #define MA_ATOMIC_LEGACY_MSVC - #else - #define MA_ATOMIC_LEGACY_MSVC_ASM - #endif - #endif - #elif (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))) || defined(__clang__) - #define MA_ATOMIC_MODERN_GCC - #else - #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) - #define MA_ATOMIC_LEGACY_GCC - #else - #define MA_ATOMIC_LEGACY_GCC_ASM - #endif - #endif -#endif -#if defined(MA_ATOMIC_MODERN_MSVC) || defined(MA_ATOMIC_LEGACY_MSVC) - #include - #define ma_atomic_memory_order_relaxed 1 - #define ma_atomic_memory_order_consume 2 - #define ma_atomic_memory_order_acquire 3 - #define ma_atomic_memory_order_release 4 - #define ma_atomic_memory_order_acq_rel 5 - #define ma_atomic_memory_order_seq_cst 6 +#define MA_ATOMIC_HAS_8 +#define MA_ATOMIC_HAS_16 +#define MA_ATOMIC_HAS_32 +#define MA_ATOMIC_HAS_64 +#if (defined(_MSC_VER) ) || defined(__WATCOMC__) || defined(__DMC__) #define MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, intrin, ma_atomicType, msvcType) \ ma_atomicType result; \ switch (order) \ @@ -14266,1501 +14138,720 @@ typedef int ma_atomic_memory_order; } break; \ } \ return result; - typedef ma_uint32 ma_atomic_flag; - static MA_INLINE ma_atomic_flag ma_atomic_flag_test_and_set_explicit(volatile ma_atomic_flag* dst, ma_atomic_memory_order order) - { - #if defined(MA_ARM) - { - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, 1, order, _InterlockedExchange, ma_atomic_flag, long); - } - #else - { - (void)order; - return (ma_atomic_flag)_InterlockedExchange((volatile long*)dst, (long)1); - } - #endif - } - static MA_INLINE void ma_atomic_flag_clear_explicit(volatile ma_atomic_flag* dst, ma_atomic_memory_order order) - { - #if defined(MA_ARM) - { - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, 0, order, _InterlockedExchange, ma_atomic_flag, long); - } - #else - { - (void)order; - _InterlockedExchange((volatile long*)dst, (long)0); - } - #endif - } - static MA_INLINE ma_atomic_flag ma_atomic_flag_load_explicit(volatile const ma_atomic_flag* dst, ma_atomic_memory_order order) - { - (void)order; - return (ma_uint32)_InterlockedCompareExchange((volatile long*)dst, 0, 0); - } -#endif -#if defined(MA_ATOMIC_LEGACY_MSVC_ASM) - #define ma_atomic_memory_order_relaxed 1 - #define ma_atomic_memory_order_consume 2 - #define ma_atomic_memory_order_acquire 3 - #define ma_atomic_memory_order_release 4 - #define ma_atomic_memory_order_acq_rel 5 - #define ma_atomic_memory_order_seq_cst 6 - typedef ma_uint32 ma_atomic_flag; - static MA_INLINE ma_atomic_flag ma_atomic_flag_test_and_set_explicit(volatile ma_atomic_flag* dst, ma_atomic_memory_order order) - { - ma_atomic_flag result = 0; - (void)order; - __asm { - mov ecx, dst - mov eax, 1 - xchg [ecx], eax - mov result, eax - } - return result; - } - static MA_INLINE void ma_atomic_flag_clear_explicit(volatile ma_atomic_flag* dst, ma_atomic_memory_order order) - { - if (order == ma_atomic_memory_order_relaxed) { - __asm { - mov esi, dst - mov dword ptr [esi], 0 - } - } else { - __asm { - mov esi, dst - mov eax, 0 - xchg [esi], eax - } - } - } - static MA_INLINE ma_atomic_flag ma_atomic_flag_load_explicit(volatile const ma_atomic_flag* dst, ma_atomic_memory_order order) - { - ma_atomic_flag result = 0; - if (order == ma_atomic_memory_order_relaxed) { - __asm { - mov esi, dst - mov eax, [esi] - mov result, eax - } - } else if (order <= ma_atomic_memory_order_release) { - __asm { - mov esi, dst - mov eax, [esi] - lock add dword ptr [esp], 0 - mov result, eax - } - } else { - __asm { - lock add dword ptr [esp], 0 - mov esi, dst - mov eax, [esi] - mov result, eax - lock add dword ptr [esp], 0 - } - } - return result; - } -#endif -#if defined(MA_ATOMIC_MODERN_GCC) - #define ma_atomic_memory_order_relaxed __ATOMIC_RELAXED - #define ma_atomic_memory_order_consume __ATOMIC_CONSUME - #define ma_atomic_memory_order_acquire __ATOMIC_ACQUIRE - #define ma_atomic_memory_order_release __ATOMIC_RELEASE - #define ma_atomic_memory_order_acq_rel __ATOMIC_ACQ_REL - #define ma_atomic_memory_order_seq_cst __ATOMIC_SEQ_CST - typedef ma_uint32 ma_atomic_flag; - #define ma_atomic_flag_test_and_set_explicit(dst, order) __atomic_exchange_n(dst, 1, order) - #define ma_atomic_flag_clear_explicit(dst, order) __atomic_store_n(dst, 0, order) - #define ma_atomic_flag_load_explicit(dst, order) __atomic_load_n(dst, order) -#endif -#if defined(MA_ATOMIC_LEGACY_GCC) - #define ma_atomic_memory_order_relaxed 1 - #define ma_atomic_memory_order_consume 2 - #define ma_atomic_memory_order_acquire 3 - #define ma_atomic_memory_order_release 4 - #define ma_atomic_memory_order_acq_rel 5 - #define ma_atomic_memory_order_seq_cst 6 - typedef ma_uint32 ma_atomic_flag; - static MA_INLINE ma_atomic_flag ma_atomic_flag_test_and_set_explicit(volatile ma_atomic_flag* dst, ma_atomic_memory_order order) - { - if (order > ma_atomic_memory_order_acquire) { - __sync_synchronize(); - } - return __sync_lock_test_and_set(dst, 1); - } - static MA_INLINE void ma_atomic_flag_clear_explicit(volatile ma_atomic_flag* dst, ma_atomic_memory_order order) - { - if (order > ma_atomic_memory_order_release) { - __sync_synchronize(); - } - __sync_lock_release(dst); - } - static MA_INLINE ma_atomic_flag ma_atomic_flag_load_explicit(volatile const ma_atomic_flag* dst, ma_atomic_memory_order order) - { - (void)order; - return __sync_val_compare_and_swap((ma_atomic_flag*)dst, 0, 0); - } -#endif -#if defined(MA_ATOMIC_LEGACY_GCC_ASM) - #define ma_atomic_memory_order_relaxed 1 - #define ma_atomic_memory_order_consume 2 - #define ma_atomic_memory_order_acquire 3 - #define ma_atomic_memory_order_release 4 - #define ma_atomic_memory_order_acq_rel 5 - #define ma_atomic_memory_order_seq_cst 6 - #if defined(MA_X86) - #define ma_atomic_thread_fence(order) __asm__ __volatile__("lock; addl $0, (%%esp)" ::: "memory") - #elif defined(MA_X64) - #define ma_atomic_thread_fence(order) __asm__ __volatile__("lock; addq $0, (%%rsp)" ::: "memory") - #else - #error Unsupported architecture. - #endif - #define MA_ATOMIC_XCHG_GCC_X86(instructionSizeSuffix, result, dst, src) \ - __asm__ __volatile__( \ - "xchg"instructionSizeSuffix" %0, %1" \ - : "=r"(result), \ - "=m"(*dst) \ - : "0"(src), \ - "m"(*dst) \ - : "memory" \ - ) - #define MA_ATOMIC_LOAD_RELAXED_GCC_X86(instructionSizeSuffix, result, dst) \ - __asm__ __volatile__( \ - "mov"instructionSizeSuffix" %1, %0" \ - : "=r"(result) \ - : "m"(*dst) \ - ) - #define MA_ATOMIC_LOAD_RELEASE_GCC_X86(instructionSizeSuffix, result, dst) \ - ma_atomic_thread_fence(ma_atomic_memory_order_release); \ - __asm__ __volatile__( \ - "mov"instructionSizeSuffix" %1, %0" \ - : "=r"(result) \ - : "m"(*dst) \ - : "memory" \ - ) - #define MA_ATOMIC_LOAD_SEQ_CST_GCC_X86(instructionSizeSuffix, result, dst) \ - ma_atomic_thread_fence(ma_atomic_memory_order_seq_cst); \ - __asm__ __volatile__( \ - "mov"instructionSizeSuffix" %1, %0" \ - : "=r"(result) \ - : "m"(*dst) \ - : "memory" \ - ); \ - ma_atomic_thread_fence(ma_atomic_memory_order_seq_cst) - typedef ma_uint32 ma_atomic_flag; - static MA_INLINE ma_atomic_flag ma_atomic_flag_test_and_set_explicit(volatile ma_atomic_flag* dst, ma_atomic_memory_order order) - { - ma_atomic_flag result; - #if defined(MA_X86) || defined(MA_X64) - { - (void)order; - MA_ATOMIC_XCHG_GCC_X86("l", result, dst, 1); - } - #else - { - #error Unsupported architecture. - } - #endif - return result; - } - static MA_INLINE void ma_atomic_flag_clear_explicit(volatile ma_atomic_flag* dst, ma_atomic_memory_order order) - { - #if defined(MA_X86) || defined(MA_X64) - { - if (order == ma_atomic_memory_order_relaxed) { - __asm__ __volatile__( - "movl $0, %0" - : "=m"(*dst) - ); - } else if (order == ma_atomic_memory_order_release) { - __asm__ __volatile__( - "movl $0, %0" - : "=m"(*dst) - : - : "memory" - ); - } else { - ma_atomic_flag tmp = 0; - __asm__ __volatile__( - "xchgl %0, %1" - : "=r"(tmp), - "=m"(*dst) - : "0"(tmp), - "m"(*dst) - : "memory" - ); - } - } - #else - { - #error Unsupported architecture. - } - #endif - } - static MA_INLINE ma_atomic_flag ma_atomic_flag_load_explicit(volatile const ma_atomic_flag* dst, ma_atomic_memory_order order) - { - #if defined(MA_X86) || defined(MA_X64) - { - ma_atomic_flag result; - if (order == ma_atomic_memory_order_relaxed) { - MA_ATOMIC_LOAD_RELAXED_GCC_X86("l", result, dst); - } else if (order <= ma_atomic_memory_order_release) { - MA_ATOMIC_LOAD_RELEASE_GCC_X86("l", result, dst); - } else { - MA_ATOMIC_LOAD_SEQ_CST_GCC_X86("l", result, dst); - } - return result; - } - #else - { - #error Unsupported architecture. - } - #endif - } -#endif -#define ma_atomic_flag_test_and_set(dst) ma_atomic_flag_test_and_set_explicit(dst, ma_atomic_memory_order_acquire) -#define ma_atomic_flag_clear(dst) ma_atomic_flag_clear_explicit(dst, ma_atomic_memory_order_release) -typedef ma_atomic_flag ma_atomic_spinlock; -static MA_INLINE void ma_atomic_spinlock_lock(volatile ma_atomic_spinlock* pSpinlock) -{ - for (;;) { - if (ma_atomic_flag_test_and_set_explicit(pSpinlock, ma_atomic_memory_order_acquire) == 0) { - break; - } - while (ma_atomic_flag_load_explicit(pSpinlock, ma_atomic_memory_order_relaxed) == 1) { - } - } -} -static MA_INLINE void ma_atomic_spinlock_unlock(volatile ma_atomic_spinlock* pSpinlock) -{ - ma_atomic_flag_clear_explicit(pSpinlock, ma_atomic_memory_order_release); -} -ma_atomic_spinlock ma_atomic_global_lock; -#if defined(MA_ATOMIC_MODERN_MSVC) || defined(MA_ATOMIC_LEGACY_MSVC) || defined(MA_ATOMIC_LEGACY_MSVC_ASM) || defined(MA_ATOMIC_LEGACY_GCC) || defined(MA_ATOMIC_LEGACY_GCC_ASM) - #if defined(MA_X64) || (defined(MA_X86) && ((defined(__GNUC__) && defined(__i486__)) || (defined(_M_IX86) && _M_IX86 >= 400))) - #if defined(MA_ATOMIC_LEGACY_MSVC) && defined(MA_X64) - #else - #define MA_ATOMIC_IS_LOCK_FREE_8 1 - #define MA_ATOMIC_IS_LOCK_FREE_16 1 - #endif - #define MA_ATOMIC_IS_LOCK_FREE_32 1 - #if defined(MA_X64) || (defined(MA_X86) && ((defined(__GNUC__) && defined(__i586__)) || (defined(_M_IX86) && _M_IX86 >= 500))) - #define MA_ATOMIC_IS_LOCK_FREE_64 1 - #else - #endif - #else - #endif - #if defined(MA_ARM32) || defined(MA_ARM64) - #define MA_ATOMIC_IS_LOCK_FREE_8 1 - #define MA_ATOMIC_IS_LOCK_FREE_16 1 - #define MA_ATOMIC_IS_LOCK_FREE_32 1 - #if defined(MA_ARM64) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) - #define MA_ATOMIC_IS_LOCK_FREE_64 1 - #endif - #endif - #if defined(MA_ATOMIC_PPC32) || defined(MA_ATOMIC_PPC64) - #if (defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 7))) && !defined(__clang__) - #else - #define MA_ATOMIC_IS_LOCK_FREE_8 1 - #define MA_ATOMIC_IS_LOCK_FREE_16 1 - #endif - #define MA_ATOMIC_IS_LOCK_FREE_32 1 - #if defined(MA_ATOMIC_PPC64) - #define MA_ATOMIC_IS_LOCK_FREE_64 1 - #endif - #endif - static MA_INLINE ma_bool32 ma_atomic_is_lock_free_8(volatile void* ptr) - { - (void)ptr; - #if defined(MA_ATOMIC_IS_LOCK_FREE_8) - return 1; - #else - return 0; - #endif - } - static MA_INLINE ma_bool32 ma_atomic_is_lock_free_16(volatile void* ptr) - { - (void)ptr; - #if defined(MA_ATOMIC_IS_LOCK_FREE_16) - return 1; - #else - return 0; - #endif - } - static MA_INLINE ma_bool32 ma_atomic_is_lock_free_32(volatile void* ptr) - { - (void)ptr; - #if defined(MA_ATOMIC_IS_LOCK_FREE_32) - return 1; - #else - return 0; - #endif - } - static MA_INLINE ma_bool32 ma_atomic_is_lock_free_64(volatile void* ptr) - { - (void)ptr; - #if defined(MA_ATOMIC_IS_LOCK_FREE_64) - return 1; - #else - return 0; - #endif - } -#endif -#define MA_ATOMIC_COMPARE_AND_SWAP_LOCK(sizeInBits, dst, expected, replacement) \ - ma_uint##sizeInBits result; \ - ma_atomic_spinlock_lock(&ma_atomic_global_lock); \ - { \ - result = *dst; \ - if (result == expected) { \ - *dst = replacement; \ - } \ - } \ - ma_atomic_spinlock_unlock(&ma_atomic_global_lock); \ - return result -#define MA_ATOMIC_LOAD_EXPLICIT_LOCK(sizeInBits, ptr, order) \ - ma_uint##sizeInBits result; \ - ma_atomic_spinlock_lock(&ma_atomic_global_lock); \ - { \ - result = *ptr; \ - (void)order; \ - } \ - ma_atomic_spinlock_unlock(&ma_atomic_global_lock); \ - return result -#define MA_ATOMIC_STORE_EXPLICIT_LOCK(sizeInBits, dst, src, order) \ - ma_atomic_spinlock_lock(&ma_atomic_global_lock); \ - { \ - *dst = src; \ - (void)order; \ - } \ - ma_atomic_spinlock_unlock(&ma_atomic_global_lock) -#define MA_ATOMIC_STORE_EXPLICIT_CAS(sizeInBits, dst, src, order) \ - ma_uint##sizeInBits oldValue; \ - do { \ - oldValue = ma_atomic_load_explicit_##sizeInBits(dst, ma_atomic_memory_order_relaxed); \ - } while (ma_atomic_compare_and_swap_##sizeInBits(dst, oldValue, src) != oldValue); \ - (void)order -#define MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(sizeInBits, dst, src, order) \ - ma_uint##sizeInBits result; \ - ma_atomic_spinlock_lock(&ma_atomic_global_lock); \ - { \ - result = *dst; \ - *dst = src; \ - (void)order; \ - } \ - ma_atomic_spinlock_unlock(&ma_atomic_global_lock); \ - return result -#define MA_ATOMIC_EXCHANGE_EXPLICIT_CAS(sizeInBits, dst, src, order) \ - ma_uint##sizeInBits oldValue; \ - do { \ - oldValue = ma_atomic_load_explicit_##sizeInBits(dst, ma_atomic_memory_order_relaxed); \ - } while (ma_atomic_compare_and_swap_##sizeInBits(dst, oldValue, src) != oldValue); \ - (void)order; \ - return oldValue -#define MA_ATOMIC_FETCH_ADD_LOCK(sizeInBits, dst, src, order) \ - ma_uint##sizeInBits result; \ - ma_atomic_spinlock_lock(&ma_atomic_global_lock); \ - { \ - result = *dst; \ - *dst += src; \ - (void)order; \ - } \ - ma_atomic_spinlock_unlock(&ma_atomic_global_lock); \ - return result -#define MA_ATOMIC_FETCH_ADD_CAS(sizeInBits, dst, src, order) \ - ma_uint##sizeInBits oldValue; \ - ma_uint##sizeInBits newValue; \ - do { \ - oldValue = ma_atomic_load_explicit_##sizeInBits(dst, ma_atomic_memory_order_relaxed); \ - newValue = oldValue + src; \ - } while (ma_atomic_compare_and_swap_##sizeInBits(dst, oldValue, newValue) != oldValue); \ - (void)order; \ - return oldValue -#define MA_ATOMIC_FETCH_AND_CAS(sizeInBits, dst, src, order) \ - ma_uint##sizeInBits oldValue; \ - ma_uint##sizeInBits newValue; \ - do { \ - oldValue = ma_atomic_load_explicit_##sizeInBits(dst, ma_atomic_memory_order_relaxed); \ - newValue = (ma_uint##sizeInBits)(oldValue & src); \ - } while (ma_atomic_compare_and_swap_##sizeInBits(dst, oldValue, newValue) != oldValue); \ - (void)order; \ - return oldValue -#define MA_ATOMIC_FETCH_OR_CAS(sizeInBits, dst, src, order) \ - ma_uint##sizeInBits oldValue; \ - ma_uint##sizeInBits newValue; \ - do { \ - oldValue = ma_atomic_load_explicit_##sizeInBits(dst, ma_atomic_memory_order_relaxed); \ - newValue = (ma_uint##sizeInBits)(oldValue | src); \ - } while (ma_atomic_compare_and_swap_##sizeInBits(dst, oldValue, newValue) != oldValue); \ - (void)order; \ - return oldValue -#define MA_ATOMIC_FETCH_XOR_CAS(sizeInBits, dst, src, order) \ - ma_uint##sizeInBits oldValue; \ - ma_uint##sizeInBits newValue; \ - do { \ - oldValue = ma_atomic_load_explicit_##sizeInBits(dst, ma_atomic_memory_order_relaxed); \ - newValue = (ma_uint##sizeInBits)(oldValue ^ src); \ - } while (ma_atomic_compare_and_swap_##sizeInBits(dst, oldValue, newValue) != oldValue); \ - (void)order; \ - return oldValue -#if defined(MA_ATOMIC_MODERN_MSVC) || defined(MA_ATOMIC_LEGACY_MSVC) - #define MA_ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, expected, replacement, order, intrin, ma_atomicType, msvcType) \ + #define MA_ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, expected, desired, order, intrin, ma_atomicType, msvcType) \ ma_atomicType result; \ switch (order) \ { \ case ma_atomic_memory_order_relaxed: \ { \ - result = (ma_atomicType)intrin##_nf((volatile msvcType*)ptr, (msvcType)expected, (msvcType)replacement); \ + result = (ma_atomicType)intrin##_nf((volatile msvcType*)ptr, (msvcType)expected, (msvcType)desired); \ } break; \ case ma_atomic_memory_order_consume: \ case ma_atomic_memory_order_acquire: \ { \ - result = (ma_atomicType)intrin##_acq((volatile msvcType*)ptr, (msvcType)expected, (msvcType)replacement); \ + result = (ma_atomicType)intrin##_acq((volatile msvcType*)ptr, (msvcType)expected, (msvcType)desired); \ } break; \ case ma_atomic_memory_order_release: \ { \ - result = (ma_atomicType)intrin##_rel((volatile msvcType*)ptr, (msvcType)expected, (msvcType)replacement); \ + result = (ma_atomicType)intrin##_rel((volatile msvcType*)ptr, (msvcType)expected, (msvcType)desired); \ } break; \ case ma_atomic_memory_order_acq_rel: \ case ma_atomic_memory_order_seq_cst: \ default: \ { \ - result = (ma_atomicType)intrin((volatile msvcType*)ptr, (msvcType)expected, (msvcType)replacement); \ + result = (ma_atomicType)intrin((volatile msvcType*)ptr, (msvcType)expected, (msvcType)desired); \ } break; \ } \ return result; - #if defined(MA_ATOMIC_IS_LOCK_FREE_8) - #define ma_atomic_compare_and_swap_8( dst, expected, replacement) (ma_uint8 )_InterlockedCompareExchange8((volatile char*)dst, (char)replacement, (char)expected) - #else - static MA_INLINE ma_uint8 __stdcall ma_atomic_compare_and_swap_8(volatile ma_uint8* dst, ma_uint8 expected, ma_uint8 replacement) - { - MA_ATOMIC_COMPARE_AND_SWAP_LOCK(8, dst, expected, replacement); - } + #define ma_atomic_memory_order_relaxed 0 + #define ma_atomic_memory_order_consume 1 + #define ma_atomic_memory_order_acquire 2 + #define ma_atomic_memory_order_release 3 + #define ma_atomic_memory_order_acq_rel 4 + #define ma_atomic_memory_order_seq_cst 5 + #if _MSC_VER < 1600 && defined(MA_X86) + #define MA_ATOMIC_MSVC_USE_INLINED_ASSEMBLY #endif - #if defined(MA_ATOMIC_IS_LOCK_FREE_16) - #define ma_atomic_compare_and_swap_16(dst, expected, replacement) (ma_uint16)_InterlockedCompareExchange16((volatile short*)dst, (short)replacement, (short)expected) - #else - static MA_INLINE ma_uint16 __stdcall ma_atomic_compare_and_swap_16(volatile ma_uint16* dst, ma_uint16 expected, ma_uint16 replacement) - { - MA_ATOMIC_COMPARE_AND_SWAP_LOCK(16, dst, expected, replacement); - } + #if _MSC_VER < 1600 + #undef MA_ATOMIC_HAS_8 + #undef MA_ATOMIC_HAS_16 #endif - #if defined(MA_ATOMIC_IS_LOCK_FREE_32) - #define ma_atomic_compare_and_swap_32(dst, expected, replacement) (ma_uint32)_InterlockedCompareExchange((volatile long*)dst, (long)replacement, (long)expected) - #else - static MA_INLINE ma_uint32 __stdcall ma_atomic_compare_and_swap_32(volatile ma_uint32* dst, ma_uint32 expected, ma_uint32 replacement) - { - MA_ATOMIC_COMPARE_AND_SWAP_LOCK(32, dst, expected, replacement); - } + #if !defined(MA_ATOMIC_MSVC_USE_INLINED_ASSEMBLY) + #include #endif - #if defined(MA_ATOMIC_IS_LOCK_FREE_32) - #define ma_atomic_compare_and_swap_64(dst, expected, replacement) (ma_uint64)_InterlockedCompareExchange64((volatile ma_int64*)dst, (ma_int64)replacement, (ma_int64)expected) + #if defined(MA_ATOMIC_MSVC_USE_INLINED_ASSEMBLY) + #if defined(MA_ATOMIC_HAS_8) + static MA_INLINE ma_uint8 __stdcall ma_atomic_compare_and_swap_8(volatile ma_uint8* dst, ma_uint8 expected, ma_uint8 desired) + { + ma_uint8 result = 0; + __asm { + mov ecx, dst + mov al, expected + mov dl, desired + lock cmpxchg [ecx], dl + mov result, al + } + return result; + } + #endif + #if defined(MA_ATOMIC_HAS_16) + static MA_INLINE ma_uint16 __stdcall ma_atomic_compare_and_swap_16(volatile ma_uint16* dst, ma_uint16 expected, ma_uint16 desired) + { + ma_uint16 result = 0; + __asm { + mov ecx, dst + mov ax, expected + mov dx, desired + lock cmpxchg [ecx], dx + mov result, ax + } + return result; + } + #endif + #if defined(MA_ATOMIC_HAS_32) + static MA_INLINE ma_uint32 __stdcall ma_atomic_compare_and_swap_32(volatile ma_uint32* dst, ma_uint32 expected, ma_uint32 desired) + { + ma_uint32 result = 0; + __asm { + mov ecx, dst + mov eax, expected + mov edx, desired + lock cmpxchg [ecx], edx + mov result, eax + } + return result; + } + #endif + #if defined(MA_ATOMIC_HAS_64) + static MA_INLINE ma_uint64 __stdcall ma_atomic_compare_and_swap_64(volatile ma_uint64* dst, ma_uint64 expected, ma_uint64 desired) + { + ma_uint32 resultEAX = 0; + ma_uint32 resultEDX = 0; + __asm { + mov esi, dst + mov eax, dword ptr expected + mov edx, dword ptr expected + 4 + mov ebx, dword ptr desired + mov ecx, dword ptr desired + 4 + lock cmpxchg8b qword ptr [esi] + mov resultEAX, eax + mov resultEDX, edx + } + return ((ma_uint64)resultEDX << 32) | resultEAX; + } + #endif #else - static MA_INLINE ma_uint64 __stdcall ma_atomic_compare_and_swap_64(volatile ma_uint64* dst, ma_uint64 expected, ma_uint64 replacement) - { - MA_ATOMIC_COMPARE_AND_SWAP_LOCK(64, dst, expected, replacement); - } + #if defined(MA_ATOMIC_HAS_8) + #define ma_atomic_compare_and_swap_8( dst, expected, desired) (ma_uint8 )_InterlockedCompareExchange8((volatile char*)dst, (char)desired, (char)expected) + #endif + #if defined(MA_ATOMIC_HAS_16) + #define ma_atomic_compare_and_swap_16(dst, expected, desired) (ma_uint16)_InterlockedCompareExchange16((volatile short*)dst, (short)desired, (short)expected) + #endif + #if defined(MA_ATOMIC_HAS_32) + #define ma_atomic_compare_and_swap_32(dst, expected, desired) (ma_uint32)_InterlockedCompareExchange((volatile long*)dst, (long)desired, (long)expected) + #endif + #if defined(MA_ATOMIC_HAS_64) + #define ma_atomic_compare_and_swap_64(dst, expected, desired) (ma_uint64)_InterlockedCompareExchange64((volatile ma_int64*)dst, (ma_int64)desired, (ma_int64)expected) + #endif #endif - static MA_INLINE ma_uint8 ma_atomic_load_explicit_8(volatile const ma_uint8* ptr, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_8) - { - #if defined(MA_ARM) - { - MA_ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, 0, 0, order, _InterlockedCompareExchange8, ma_uint8, char); - } - #else + #if defined(MA_ATOMIC_MSVC_USE_INLINED_ASSEMBLY) + #if defined(MA_ATOMIC_HAS_8) + static MA_INLINE ma_uint8 __stdcall ma_atomic_exchange_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) { + ma_uint8 result = 0; (void)order; - return ma_atomic_compare_and_swap_8((volatile ma_uint8*)ptr, 0, 0); + __asm { + mov ecx, dst + mov al, src + lock xchg [ecx], al + mov result, al + } + return result; } - #endif - } - #else - { - MA_ATOMIC_LOAD_EXPLICIT_LOCK(8, ptr, order); - } #endif - } - static MA_INLINE ma_uint16 ma_atomic_load_explicit_16(volatile const ma_uint16* ptr, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_16) - { - #if defined(MA_ARM) - { - MA_ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, 0, 0, order, _InterlockedCompareExchange16, ma_uint16, short); - } - #else + #if defined(MA_ATOMIC_HAS_16) + static MA_INLINE ma_uint16 __stdcall ma_atomic_exchange_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) { + ma_uint16 result = 0; (void)order; - return ma_atomic_compare_and_swap_16((volatile ma_uint16*)ptr, 0, 0); + __asm { + mov ecx, dst + mov ax, src + lock xchg [ecx], ax + mov result, ax + } + return result; } - #endif - } - #else - { - MA_ATOMIC_LOAD_EXPLICIT_LOCK(16, ptr, order); - } #endif - } - static MA_INLINE ma_uint32 ma_atomic_load_explicit_32(volatile const ma_uint32* ptr, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_32) - { - #if defined(MA_ARM) - { - MA_ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, 0, 0, order, _InterlockedCompareExchange, ma_uint32, long); - } - #else + #if defined(MA_ATOMIC_HAS_32) + static MA_INLINE ma_uint32 __stdcall ma_atomic_exchange_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) { + ma_uint32 result = 0; (void)order; - return ma_atomic_compare_and_swap_32((volatile ma_uint32*)ptr, 0, 0); + __asm { + mov ecx, dst + mov eax, src + lock xchg [ecx], eax + mov result, eax + } + return result; } - #endif - } - #else - { - MA_ATOMIC_LOAD_EXPLICIT_LOCK(32, ptr, order); - } #endif - } - static MA_INLINE ma_uint64 ma_atomic_load_explicit_64(volatile const ma_uint64* ptr, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_32) - { + #else + #if defined(MA_ATOMIC_HAS_8) + static MA_INLINE ma_uint8 __stdcall ma_atomic_exchange_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { #if defined(MA_ARM) - { - MA_ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, 0, 0, order, _InterlockedCompareExchange64, ma_uint64, long long); - } - #else - { - (void)order; - return ma_atomic_compare_and_swap_64((volatile ma_uint64*)ptr, 0, 0); - } - #endif - } - #else - { - MA_ATOMIC_LOAD_EXPLICIT_LOCK(64, ptr, order); - } - #endif - } - static MA_INLINE ma_uint8 __stdcall ma_atomic_exchange_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_8) - { - #if defined(MA_ARM) - { MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchange8, ma_uint8, char); - } #else - { (void)order; return (ma_uint8)_InterlockedExchange8((volatile char*)dst, (char)src); - } #endif - } - #else - { - MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(8, dst, src, order); - } - #endif - } - static MA_INLINE ma_uint16 __stdcall ma_atomic_exchange_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_16) - { - #if defined(MA_ARM) - { - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchange16, ma_uint16, short); } - #else + #endif + #if defined(MA_ATOMIC_HAS_16) + static MA_INLINE ma_uint16 __stdcall ma_atomic_exchange_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) { + #if defined(MA_ARM) + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchange16, ma_uint16, short); + #else (void)order; return (ma_uint16)_InterlockedExchange16((volatile short*)dst, (short)src); - } #endif - } - #else - { - MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(16, dst, src, order); - } - #endif - } - static MA_INLINE ma_uint32 __stdcall ma_atomic_exchange_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_32) - { - #if defined(MA_ARM) - { - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchange, ma_uint32, long); } - #else + #endif + #if defined(MA_ATOMIC_HAS_32) + static MA_INLINE ma_uint32 __stdcall ma_atomic_exchange_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) { + #if defined(MA_ARM) + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchange, ma_uint32, long); + #else (void)order; return (ma_uint32)_InterlockedExchange((volatile long*)dst, (long)src); - } #endif - } - #else - { - MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(32, dst, src, order); - } - #endif - } - static MA_INLINE ma_uint64 __stdcall ma_atomic_exchange_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_64) - { - #if defined(MA_32BIT) - { - MA_ATOMIC_EXCHANGE_EXPLICIT_CAS(64, dst, src, order); } - #else - { - #if defined(MA_ARM) - { - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchange64, ma_uint64, long long); - } - #else - { - (void)order; - return (ma_uint64)_InterlockedExchange64((volatile long long*)dst, (long long)src); - } - #endif - } - #endif - } - #else - { - MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(64, dst, src, order); - } #endif - } - static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_add_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_8) - { + #if defined(MA_ATOMIC_HAS_64) && defined(MA_64BIT) + static MA_INLINE ma_uint64 __stdcall ma_atomic_exchange_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { #if defined(MA_ARM) - { - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchangeAdd8, ma_uint8, char); - } + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchange64, ma_uint64, long long); #else - { (void)order; - return (ma_uint8)_InterlockedExchangeAdd8((volatile char*)dst, (char)src); - } + return (ma_uint64)_InterlockedExchange64((volatile long long*)dst, (long long)src); #endif - } - #else - { - MA_ATOMIC_FETCH_ADD_LOCK(8, dst, src, order); - } - #endif - } - static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_add_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_16) - { - #if defined(MA_ARM) - { - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchangeAdd16, ma_uint16, short); } - #else - { - (void)order; - return (ma_uint16)_InterlockedExchangeAdd16((volatile short*)dst, (short)src); - } - #endif - } #else - { - MA_ATOMIC_FETCH_ADD_LOCK(16, dst, src, order); - } #endif - } - static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_add_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + #endif + #if defined(MA_ATOMIC_HAS_64) && !defined(MA_64BIT) + static MA_INLINE ma_uint64 __stdcall ma_atomic_exchange_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) { - #if defined(MA_ARM) - { - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchangeAdd, ma_uint32, long); - } - #else - { - (void)order; - return (ma_uint32)_InterlockedExchangeAdd((volatile long*)dst, (long)src); - } - #endif - } - #else - { - MA_ATOMIC_FETCH_ADD_LOCK(32, dst, src, order); - } - #endif - } - static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_add_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_64) - { - #if defined(MA_32BIT) - { - MA_ATOMIC_FETCH_ADD_CAS(64, dst, src, order); - } - #else - { - #if defined(MA_ARM) - { - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchangeAdd64, ma_uint64, long long); - } - #else - { - (void)order; - return (ma_uint64)_InterlockedExchangeAdd64((volatile long long*)dst, (long long)src); - } - #endif - } - #endif - } - #else - { - MA_ATOMIC_FETCH_ADD_LOCK(64, dst, src, order); - } - #endif - } - static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_sub_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) - { - return ma_atomic_fetch_add_explicit_8(dst, (ma_uint8)(-(ma_int8)src), order); - } - static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_sub_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) - { - return ma_atomic_fetch_add_explicit_16(dst, (ma_uint16)(-(ma_int16)src), order); - } - static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_sub_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) - { - return ma_atomic_fetch_add_explicit_32(dst, (ma_uint32)(-(ma_int32)src), order); - } - static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_sub_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) - { - return ma_atomic_fetch_add_explicit_64(dst, (ma_uint64)(-(ma_int64)src), order); - } - static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_and_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) - { - #if defined(MA_ARM) - { - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedAnd8, ma_uint8, char); - } - #else - { - MA_ATOMIC_FETCH_AND_CAS(8, dst, src, order); - } - #endif - } - static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_and_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) - { - #if defined(MA_ARM) - { - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedAnd16, ma_uint16, short); - } - #else - { - MA_ATOMIC_FETCH_AND_CAS(16, dst, src, order); - } - #endif - } - static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_and_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) - { - #if defined(MA_ARM) - { - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedAnd, ma_uint32, long); - } - #else - { - MA_ATOMIC_FETCH_AND_CAS(32, dst, src, order); - } - #endif - } - static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_and_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) - { - #if defined(MA_ARM) - { - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedAnd64, ma_uint64, long long); - } - #else - { - MA_ATOMIC_FETCH_AND_CAS(64, dst, src, order); - } - #endif - } - static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_or_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) - { - #if defined(MA_ARM) - { - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedOr8, ma_uint8, char); - } - #else - { - MA_ATOMIC_FETCH_OR_CAS(8, dst, src, order); - } - #endif - } - static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_or_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) - { - #if defined(MA_ARM) - { - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedOr16, ma_uint16, short); - } - #else - { - MA_ATOMIC_FETCH_OR_CAS(16, dst, src, order); - } - #endif - } - static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_or_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) - { - #if defined(MA_ARM) - { - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedOr, ma_uint32, long); - } - #else - { - MA_ATOMIC_FETCH_OR_CAS(32, dst, src, order); - } - #endif - } - static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_or_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) - { - #if defined(MA_ARM) - { - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedOr64, ma_uint64, long long); - } - #else - { - MA_ATOMIC_FETCH_OR_CAS(64, dst, src, order); - } - #endif - } - static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_xor_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) - { - #if defined(MA_ARM) - { - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedXor8, ma_uint8, char); - } - #else - { - MA_ATOMIC_FETCH_XOR_CAS(8, dst, src, order); - } - #endif - } - static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_xor_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) - { - #if defined(MA_ARM) - { - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedXor16, ma_uint16, short); - } - #else - { - MA_ATOMIC_FETCH_XOR_CAS(16, dst, src, order); - } - #endif - } - static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_xor_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) - { - #if defined(MA_ARM) - { - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedXor, ma_uint32, long); - } - #else - { - MA_ATOMIC_FETCH_XOR_CAS(32, dst, src, order); - } - #endif - } - static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_xor_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) - { - #if defined(MA_ARM) - { - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedXor64, ma_uint64, long long); - } - #else - { - MA_ATOMIC_FETCH_XOR_CAS(64, dst, src, order); - } - #endif - } - #define ma_atomic_store_explicit_8( dst, src, order) (void)ma_atomic_exchange_explicit_8 (dst, src, order) - #define ma_atomic_store_explicit_16(dst, src, order) (void)ma_atomic_exchange_explicit_16(dst, src, order) - #define ma_atomic_store_explicit_32(dst, src, order) (void)ma_atomic_exchange_explicit_32(dst, src, order) - #define ma_atomic_store_explicit_64(dst, src, order) (void)ma_atomic_exchange_explicit_64(dst, src, order) - #if defined(MA_X64) - #define ma_atomic_thread_fence(order) __faststorefence(), (void)order - #elif defined(MA_ARM64) - #define ma_atomic_thread_fence(order) __dmb(_ARM64_BARRIER_ISH), (void)order - #else - static MA_INLINE void ma_atomic_thread_fence(ma_atomic_memory_order order) - { - volatile ma_uint32 barrier = 0; - ma_atomic_fetch_add_explicit_32(&barrier, 0, order); + ma_uint64 oldValue; + do { + oldValue = *dst; + } while (ma_atomic_compare_and_swap_64(dst, oldValue, src) != oldValue); + (void)order; + return oldValue; } #endif - #define ma_atomic_signal_fence(order) _ReadWriteBarrier(), (void)order -#endif -#if defined(MA_ATOMIC_LEGACY_MSVC_ASM) - static MA_INLINE ma_uint8 __stdcall ma_atomic_compare_and_swap_8(volatile ma_uint8* dst, ma_uint8 expected, ma_uint8 replacement) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_8) - { - ma_uint8 result = 0; - __asm { - mov ecx, dst - mov al, expected - mov dl, replacement - lock cmpxchg [ecx], dl - mov result, al - } - return result; - } - #else - { - MA_ATOMIC_COMPARE_AND_SWAP_LOCK(8, dst, expected, replacement); - } - #endif - } - static MA_INLINE ma_uint16 __stdcall ma_atomic_compare_and_swap_16(volatile ma_uint16* dst, ma_uint16 expected, ma_uint16 replacement) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_16) - { - ma_uint16 result = 0; - __asm { - mov ecx, dst - mov ax, expected - mov dx, replacement - lock cmpxchg [ecx], dx - mov result, ax - } - return result; - } - #else - { - MA_ATOMIC_COMPARE_AND_SWAP_LOCK(16, dst, expected, replacement); - } - #endif - } - static MA_INLINE ma_uint32 __stdcall ma_atomic_compare_and_swap_32(volatile ma_uint32* dst, ma_uint32 expected, ma_uint32 replacement) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_32) - { - ma_uint32 result = 0; - __asm { - mov ecx, dst - mov eax, expected - mov edx, replacement - lock cmpxchg [ecx], edx - mov result, eax - } - return result; - } - #else - { - MA_ATOMIC_COMPARE_AND_SWAP_LOCK(32, dst, expected, replacement); - } - #endif - } - static MA_INLINE ma_uint64 __stdcall ma_atomic_compare_and_swap_64(volatile ma_uint64* dst, ma_uint64 expected, ma_uint64 replacement) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_64) - { - ma_uint32 resultEAX = 0; - ma_uint32 resultEDX = 0; - __asm { - mov esi, dst - mov eax, dword ptr expected - mov edx, dword ptr expected + 4 - mov ebx, dword ptr replacement - mov ecx, dword ptr replacement + 4 - lock cmpxchg8b qword ptr [esi] - mov resultEAX, eax - mov resultEDX, edx - } - return ((ma_uint64)resultEDX << 32) | resultEAX; - } - #else - { - MA_ATOMIC_COMPARE_AND_SWAP_LOCK(64, dst, expected, replacement); - } - #endif - } - static MA_INLINE ma_uint8 ma_atomic_load_explicit_8(volatile const ma_uint8* dst, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_8) - { - ma_uint8 result = 0; - if (order == ma_atomic_memory_order_relaxed) { + #if defined(MA_ATOMIC_MSVC_USE_INLINED_ASSEMBLY) + #if defined(MA_ATOMIC_HAS_8) + static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_add_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + ma_uint8 result = 0; + (void)order; __asm { - mov esi, dst - mov al, [esi] + mov ecx, dst + mov al, src + lock xadd [ecx], al mov result, al } - } else if (order <= ma_atomic_memory_order_release) { - __asm { - mov esi, dst - mov al, [esi] - lock add dword ptr [esp], 0 - mov result, al - } - } else { - __asm { - lock add dword ptr [esp], 0 - mov esi, dst - mov al, [esi] - mov result, al - lock add dword ptr [esp], 0 - } + return result; } - return result; - } - #else - { - MA_ATOMIC_LOAD_EXPLICIT_LOCK(8, dst, order); - } #endif - } - static MA_INLINE ma_uint16 ma_atomic_load_explicit_16(volatile const ma_uint16* dst, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_16) - { - ma_uint16 result = 0; - if (order == ma_atomic_memory_order_relaxed) { + #if defined(MA_ATOMIC_HAS_16) + static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_add_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + ma_uint16 result = 0; + (void)order; __asm { - mov esi, dst - mov ax, [esi] + mov ecx, dst + mov ax, src + lock xadd [ecx], ax mov result, ax } - } else if (order <= ma_atomic_memory_order_release) { - __asm { - mov esi, dst - mov ax, [esi] - lock add dword ptr [esp], 0 - mov result, ax - } - } else { - __asm { - lock add dword ptr [esp], 0 - mov esi, dst - mov ax, [esi] - mov result, ax - lock add dword ptr [esp], 0 - } + return result; } - return result; - } - #else - { - MA_ATOMIC_LOAD_EXPLICIT_LOCK(16, dst, order); - } #endif - } - static MA_INLINE ma_uint32 ma_atomic_load_explicit_32(volatile const ma_uint32* dst, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_32) - { - ma_uint32 result = 0; - if (order == ma_atomic_memory_order_relaxed) { - __asm { - mov esi, dst - mov eax, [esi] - mov result, eax - } - } else if (order <= ma_atomic_memory_order_release) { - __asm { - mov esi, dst - mov eax, [esi] - lock add dword ptr [esp], 0 - mov result, eax - } - } else { - __asm { - lock add dword ptr [esp], 0 - mov esi, dst - mov eax, [esi] - mov result, eax - lock add dword ptr [esp], 0 - } - } - return result; - } - #else - { - MA_ATOMIC_LOAD_EXPLICIT_LOCK(32, dst, order); - } - #endif - } - static MA_INLINE ma_uint64 ma_atomic_load_explicit_64(volatile const ma_uint64* dst, ma_atomic_memory_order order) - { - (void)order; - return ma_atomic_compare_and_swap_64((volatile ma_uint64*)dst, 0, 0); - } - static MA_INLINE void __stdcall ma_atomic_store_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) - { - if (order == ma_atomic_memory_order_relaxed) { - __asm { - mov esi, dst - mov al, src - mov [esi], al - } - } else { - #if defined(MA_ATOMIC_IS_LOCK_FREE_8) + #if defined(MA_ATOMIC_HAS_32) + static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_add_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) { + ma_uint32 result = 0; + (void)order; __asm { - mov esi, dst - mov al, src - xchg [esi], al - } - } - #else - { - MA_ATOMIC_STORE_EXPLICIT_LOCK(8, dst, src, order); - } - #endif - } - } - static MA_INLINE void __stdcall ma_atomic_store_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) - { - if (order == ma_atomic_memory_order_relaxed) { - __asm { - mov esi, dst - mov ax, src - mov [esi], ax - } - } else { - #if defined(MA_ATOMIC_IS_LOCK_FREE_16) - { - __asm { - mov esi, dst - mov ax, src - xchg [esi], ax - } - } - #else - { - MA_ATOMIC_STORE_EXPLICIT_LOCK(16, dst, src, order); - } - #endif - } - } - static MA_INLINE void __stdcall ma_atomic_store_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) - { - if (order == ma_atomic_memory_order_relaxed) { - __asm { - mov esi, dst - mov eax, src - mov [esi], eax - } - } else { - #if defined(MA_ATOMIC_IS_LOCK_FREE_32) - { - __asm { - mov esi, dst + mov ecx, dst mov eax, src - xchg [esi], eax + lock xadd [ecx], eax + mov result, eax } + return result; } - #else + #endif + #else + #if defined(MA_ATOMIC_HAS_8) + static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_add_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) { - MA_ATOMIC_STORE_EXPLICIT_LOCK(32, dst, src, order); - } + #if defined(MA_ARM) + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchangeAdd8, ma_uint8, char); + #else + (void)order; + return (ma_uint8)_InterlockedExchangeAdd8((volatile char*)dst, (char)src); #endif - } - } - static MA_INLINE void __stdcall ma_atomic_store_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_64) - { - MA_ATOMIC_STORE_EXPLICIT_CAS(64, dst, src, order); - } - #else - { - MA_ATOMIC_STORE_EXPLICIT_LOCK(64, dst, src, order); - } + } #endif - } - static MA_INLINE ma_uint8 __stdcall ma_atomic_exchange_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_8) + #if defined(MA_ATOMIC_HAS_16) + static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_add_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchangeAdd16, ma_uint16, short); + #else + (void)order; + return (ma_uint16)_InterlockedExchangeAdd16((volatile short*)dst, (short)src); + #endif + } + #endif + #if defined(MA_ATOMIC_HAS_32) + static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_add_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchangeAdd, ma_uint32, long); + #else + (void)order; + return (ma_uint32)_InterlockedExchangeAdd((volatile long*)dst, (long)src); + #endif + } + #endif + #if defined(MA_ATOMIC_HAS_64) && defined(MA_64BIT) + static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_add_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchangeAdd64, ma_uint64, long long); + #else + (void)order; + return (ma_uint64)_InterlockedExchangeAdd64((volatile long long*)dst, (long long)src); + #endif + } + #else + #endif + #endif + #if defined(MA_ATOMIC_HAS_64) && !defined(MA_64BIT) + static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_add_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + ma_uint64 oldValue; + ma_uint64 newValue; + do { + oldValue = *dst; + newValue = oldValue + src; + } while (ma_atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); + (void)order; + return oldValue; + } + #endif + #if defined(MA_ATOMIC_MSVC_USE_INLINED_ASSEMBLY) + static MA_INLINE void __stdcall ma_atomic_thread_fence(ma_atomic_memory_order order) { - ma_uint8 result = 0; (void)order; __asm { - mov ecx, dst - mov al, src - lock xchg [ecx], al - mov result, al + lock add [esp], 0 } - return result; } + #else + #if defined(MA_X64) + #define ma_atomic_thread_fence(order) __faststorefence(), (void)order + #elif defined(MA_ARM64) + #define ma_atomic_thread_fence(order) __dmb(_ARM64_BARRIER_ISH), (void)order #else - { - MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(8, dst, src, order); - } + static MA_INLINE void ma_atomic_thread_fence(ma_atomic_memory_order order) + { + volatile ma_uint32 barrier = 0; + ma_atomic_fetch_add_explicit_32(&barrier, 0, order); + } #endif - } - static MA_INLINE ma_uint16 __stdcall ma_atomic_exchange_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_16) + #endif + #define ma_atomic_compiler_fence() ma_atomic_thread_fence(ma_atomic_memory_order_seq_cst) + #define ma_atomic_signal_fence(order) ma_atomic_thread_fence(order) + #if defined(MA_ATOMIC_HAS_8) + static MA_INLINE ma_uint8 ma_atomic_load_explicit_8(volatile const ma_uint8* ptr, ma_atomic_memory_order order) { - ma_uint16 result = 0; + #if defined(MA_ARM) + MA_ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, 0, 0, order, _InterlockedCompareExchange8, ma_uint8, char); + #else (void)order; - __asm { - mov ecx, dst - mov ax, src - lock xchg [ecx], ax - mov result, ax - } - return result; - } - #else - { - MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(16, dst, src, order); - } + return ma_atomic_compare_and_swap_8((volatile ma_uint8*)ptr, 0, 0); #endif - } - static MA_INLINE ma_uint32 __stdcall ma_atomic_exchange_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + } + #endif + #if defined(MA_ATOMIC_HAS_16) + static MA_INLINE ma_uint16 ma_atomic_load_explicit_16(volatile const ma_uint16* ptr, ma_atomic_memory_order order) { - ma_uint32 result = 0; + #if defined(MA_ARM) + MA_ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, 0, 0, order, _InterlockedCompareExchange16, ma_uint16, short); + #else (void)order; - __asm { - mov ecx, dst - mov eax, src - xchg [ecx], eax - mov result, eax - } - return result; - } - #else - { - MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(32, dst, src, order); - } + return ma_atomic_compare_and_swap_16((volatile ma_uint16*)ptr, 0, 0); #endif - } - static MA_INLINE ma_uint64 __stdcall ma_atomic_exchange_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_64) - { - MA_ATOMIC_EXCHANGE_EXPLICIT_CAS(64, dst, src, order); } + #endif + #if defined(MA_ATOMIC_HAS_32) + static MA_INLINE ma_uint32 ma_atomic_load_explicit_32(volatile const ma_uint32* ptr, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + MA_ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, 0, 0, order, _InterlockedCompareExchange, ma_uint32, long); #else - { - MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(64, dst, src, order); - } - #endif - } - static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_add_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_8) - { - ma_uint8 result = 0; (void)order; - __asm { - mov ecx, dst - mov al, src - lock xadd [ecx], al - mov result, al - } - return result; - } - #else - { - MA_ATOMIC_FETCH_ADD_LOCK(8, dst, src, order); - } + return ma_atomic_compare_and_swap_32((volatile ma_uint32*)ptr, 0, 0); #endif - } - static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_add_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_16) + } + #endif + #if defined(MA_ATOMIC_HAS_64) + static MA_INLINE ma_uint64 ma_atomic_load_explicit_64(volatile const ma_uint64* ptr, ma_atomic_memory_order order) { - ma_uint16 result = 0; + #if defined(MA_ARM) + MA_ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, 0, 0, order, _InterlockedCompareExchange64, ma_uint64, long long); + #else (void)order; - __asm { - mov ecx, dst - mov ax, src - lock xadd [ecx], ax - mov result, ax - } - return result; - } - #else - { - MA_ATOMIC_FETCH_ADD_LOCK(16, dst, src, order); - } + return ma_atomic_compare_and_swap_64((volatile ma_uint64*)ptr, 0, 0); #endif - } - static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_add_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + } + #endif + #if defined(MA_ATOMIC_HAS_8) + #define ma_atomic_store_explicit_8( dst, src, order) (void)ma_atomic_exchange_explicit_8 (dst, src, order) + #endif + #if defined(MA_ATOMIC_HAS_16) + #define ma_atomic_store_explicit_16(dst, src, order) (void)ma_atomic_exchange_explicit_16(dst, src, order) + #endif + #if defined(MA_ATOMIC_HAS_32) + #define ma_atomic_store_explicit_32(dst, src, order) (void)ma_atomic_exchange_explicit_32(dst, src, order) + #endif + #if defined(MA_ATOMIC_HAS_64) + #define ma_atomic_store_explicit_64(dst, src, order) (void)ma_atomic_exchange_explicit_64(dst, src, order) + #endif + #if defined(MA_ATOMIC_HAS_8) + static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_sub_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) { - ma_uint32 result = 0; + ma_uint8 oldValue; + ma_uint8 newValue; + do { + oldValue = *dst; + newValue = (ma_uint8)(oldValue - src); + } while (ma_atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); (void)order; - __asm { - mov ecx, dst - mov eax, src - lock xadd [ecx], eax - mov result, eax - } - return result; + return oldValue; } - #else + #endif + #if defined(MA_ATOMIC_HAS_16) + static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_sub_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) { - MA_ATOMIC_FETCH_ADD_LOCK(32, dst, src, order); - } - #endif - } - static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_add_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_64) - { - MA_ATOMIC_FETCH_ADD_CAS(64, dst, src, order); - } - #else - { - MA_ATOMIC_FETCH_ADD_LOCK(64, dst, src, order); - } - #endif - } - static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_sub_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_8) - { - ma_uint8 result = 0; + ma_uint16 oldValue; + ma_uint16 newValue; + do { + oldValue = *dst; + newValue = (ma_uint16)(oldValue - src); + } while (ma_atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); (void)order; - __asm { - mov ecx, dst - mov al, src - neg al - lock xadd [ecx], al - mov result, al - } - return result; + return oldValue; } - #else + #endif + #if defined(MA_ATOMIC_HAS_32) + static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_sub_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) { - MA_ATOMIC_FETCH_ADD_LOCK(8, dst, (ma_uint8)(-(ma_int8)src), order); - } - #endif - } - static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_sub_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_16) - { - ma_uint16 result = 0; + ma_uint32 oldValue; + ma_uint32 newValue; + do { + oldValue = *dst; + newValue = oldValue - src; + } while (ma_atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); (void)order; - __asm { - mov ecx, dst - mov ax, src - neg ax - lock xadd [ecx], ax - mov result, ax - } - return result; + return oldValue; } - #else + #endif + #if defined(MA_ATOMIC_HAS_64) + static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_sub_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) { - MA_ATOMIC_FETCH_ADD_LOCK(16, dst, (ma_uint16)(-(ma_int16)src), order); - } - #endif - } - static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_sub_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_32) - { - ma_uint32 result = 0; + ma_uint64 oldValue; + ma_uint64 newValue; + do { + oldValue = *dst; + newValue = oldValue - src; + } while (ma_atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); (void)order; - __asm { - mov ecx, dst - mov eax, src - neg eax - lock xadd [ecx], eax - mov result, eax - } - return result; + return oldValue; } - #else + #endif + #if defined(MA_ATOMIC_HAS_8) + static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_and_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) { - MA_ATOMIC_FETCH_ADD_LOCK(32, dst, (ma_uint32)(-(ma_int32)src), order); - } + #if defined(MA_ARM) + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedAnd8, ma_uint8, char); + #else + ma_uint8 oldValue; + ma_uint8 newValue; + do { + oldValue = *dst; + newValue = (ma_uint8)(oldValue & src); + } while (ma_atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); + (void)order; + return oldValue; #endif - } - static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_sub_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) - { - MA_ATOMIC_FETCH_ADD_CAS(64, dst, (ma_uint64)(-(ma_int64)src), order); - } - static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_and_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) - { - MA_ATOMIC_FETCH_AND_CAS(8, dst, src, order); - } - static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_and_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) - { - MA_ATOMIC_FETCH_AND_CAS(16, dst, src, order); - } - static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_and_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) - { - MA_ATOMIC_FETCH_AND_CAS(32, dst, src, order); - } - static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_and_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) - { - MA_ATOMIC_FETCH_AND_CAS(64, dst, src, order); - } - static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_or_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) - { - MA_ATOMIC_FETCH_OR_CAS(8, dst, src, order); - } - static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_or_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) - { - MA_ATOMIC_FETCH_OR_CAS(16, dst, src, order); - } - static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_or_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) - { - MA_ATOMIC_FETCH_OR_CAS(32, dst, src, order); - } - static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_or_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) - { - MA_ATOMIC_FETCH_OR_CAS(64, dst, src, order); - } - static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_xor_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) - { - MA_ATOMIC_FETCH_XOR_CAS(8, dst, src, order); - } - static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_xor_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) - { - MA_ATOMIC_FETCH_XOR_CAS(16, dst, src, order); - } - static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_xor_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) - { - MA_ATOMIC_FETCH_XOR_CAS(32, dst, src, order); - } - static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_xor_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) - { - MA_ATOMIC_FETCH_XOR_CAS(64, dst, src, order); - } - static MA_INLINE void __stdcall ma_atomic_thread_fence(ma_atomic_memory_order order) - { - (void)order; - __asm { - lock add dword ptr [esp], 0 } - } - #define ma_atomic_signal_fence(order) __asm {}; (void)order -#endif -#if defined(MA_ATOMIC_MODERN_GCC) + #endif + #if defined(MA_ATOMIC_HAS_16) + static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_and_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedAnd16, ma_uint16, short); + #else + ma_uint16 oldValue; + ma_uint16 newValue; + do { + oldValue = *dst; + newValue = (ma_uint16)(oldValue & src); + } while (ma_atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); + (void)order; + return oldValue; + #endif + } + #endif + #if defined(MA_ATOMIC_HAS_32) + static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_and_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedAnd, ma_uint32, long); + #else + ma_uint32 oldValue; + ma_uint32 newValue; + do { + oldValue = *dst; + newValue = oldValue & src; + } while (ma_atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); + (void)order; + return oldValue; + #endif + } + #endif + #if defined(MA_ATOMIC_HAS_64) + static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_and_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedAnd64, ma_uint64, long long); + #else + ma_uint64 oldValue; + ma_uint64 newValue; + do { + oldValue = *dst; + newValue = oldValue & src; + } while (ma_atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); + (void)order; + return oldValue; + #endif + } + #endif + #if defined(MA_ATOMIC_HAS_8) + static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_xor_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedXor8, ma_uint8, char); + #else + ma_uint8 oldValue; + ma_uint8 newValue; + do { + oldValue = *dst; + newValue = (ma_uint8)(oldValue ^ src); + } while (ma_atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); + (void)order; + return oldValue; + #endif + } + #endif + #if defined(MA_ATOMIC_HAS_16) + static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_xor_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedXor16, ma_uint16, short); + #else + ma_uint16 oldValue; + ma_uint16 newValue; + do { + oldValue = *dst; + newValue = (ma_uint16)(oldValue ^ src); + } while (ma_atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); + (void)order; + return oldValue; + #endif + } + #endif + #if defined(MA_ATOMIC_HAS_32) + static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_xor_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedXor, ma_uint32, long); + #else + ma_uint32 oldValue; + ma_uint32 newValue; + do { + oldValue = *dst; + newValue = oldValue ^ src; + } while (ma_atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); + (void)order; + return oldValue; + #endif + } + #endif + #if defined(MA_ATOMIC_HAS_64) + static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_xor_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedXor64, ma_uint64, long long); + #else + ma_uint64 oldValue; + ma_uint64 newValue; + do { + oldValue = *dst; + newValue = oldValue ^ src; + } while (ma_atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); + (void)order; + return oldValue; + #endif + } + #endif + #if defined(MA_ATOMIC_HAS_8) + static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_or_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedOr8, ma_uint8, char); + #else + ma_uint8 oldValue; + ma_uint8 newValue; + do { + oldValue = *dst; + newValue = (ma_uint8)(oldValue | src); + } while (ma_atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); + (void)order; + return oldValue; + #endif + } + #endif + #if defined(MA_ATOMIC_HAS_16) + static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_or_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedOr16, ma_uint16, short); + #else + ma_uint16 oldValue; + ma_uint16 newValue; + do { + oldValue = *dst; + newValue = (ma_uint16)(oldValue | src); + } while (ma_atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); + (void)order; + return oldValue; + #endif + } + #endif + #if defined(MA_ATOMIC_HAS_32) + static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_or_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedOr, ma_uint32, long); + #else + ma_uint32 oldValue; + ma_uint32 newValue; + do { + oldValue = *dst; + newValue = oldValue | src; + } while (ma_atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); + (void)order; + return oldValue; + #endif + } + #endif + #if defined(MA_ATOMIC_HAS_64) + static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_or_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedOr64, ma_uint64, long long); + #else + ma_uint64 oldValue; + ma_uint64 newValue; + do { + oldValue = *dst; + newValue = oldValue | src; + } while (ma_atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); + (void)order; + return oldValue; + #endif + } + #endif + #if defined(MA_ATOMIC_HAS_8) + #define ma_atomic_test_and_set_explicit_8( dst, order) ma_atomic_exchange_explicit_8 (dst, 1, order) + #endif + #if defined(MA_ATOMIC_HAS_16) + #define ma_atomic_test_and_set_explicit_16(dst, order) ma_atomic_exchange_explicit_16(dst, 1, order) + #endif + #if defined(MA_ATOMIC_HAS_32) + #define ma_atomic_test_and_set_explicit_32(dst, order) ma_atomic_exchange_explicit_32(dst, 1, order) + #endif + #if defined(MA_ATOMIC_HAS_64) + #define ma_atomic_test_and_set_explicit_64(dst, order) ma_atomic_exchange_explicit_64(dst, 1, order) + #endif + #if defined(MA_ATOMIC_HAS_8) + #define ma_atomic_clear_explicit_8( dst, order) ma_atomic_store_explicit_8 (dst, 0, order) + #endif + #if defined(MA_ATOMIC_HAS_16) + #define ma_atomic_clear_explicit_16(dst, order) ma_atomic_store_explicit_16(dst, 0, order) + #endif + #if defined(MA_ATOMIC_HAS_32) + #define ma_atomic_clear_explicit_32(dst, order) ma_atomic_store_explicit_32(dst, 0, order) + #endif + #if defined(MA_ATOMIC_HAS_64) + #define ma_atomic_clear_explicit_64(dst, order) ma_atomic_store_explicit_64(dst, 0, order) + #endif + #if defined(MA_ATOMIC_HAS_8) + typedef ma_uint8 ma_atomic_flag; + #define ma_atomic_flag_test_and_set_explicit(ptr, order) (ma_bool32)ma_atomic_test_and_set_explicit_8(ptr, order) + #define ma_atomic_flag_clear_explicit(ptr, order) ma_atomic_clear_explicit_8(ptr, order) + #define ma_atomic_flag_load_explicit(ptr, order) ma_atomic_load_explicit_8(ptr, order) + #else + typedef ma_uint32 ma_atomic_flag; + #define ma_atomic_flag_test_and_set_explicit(ptr, order) (ma_bool32)ma_atomic_test_and_set_explicit_32(ptr, order) + #define ma_atomic_flag_clear_explicit(ptr, order) ma_atomic_clear_explicit_32(ptr, order) + #define ma_atomic_flag_load_explicit(ptr, order) ma_atomic_load_explicit_32(ptr, order) + #endif +#elif defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))) #define MA_ATOMIC_HAS_NATIVE_COMPARE_EXCHANGE + #define MA_ATOMIC_HAS_NATIVE_IS_LOCK_FREE + #define ma_atomic_memory_order_relaxed __ATOMIC_RELAXED + #define ma_atomic_memory_order_consume __ATOMIC_CONSUME + #define ma_atomic_memory_order_acquire __ATOMIC_ACQUIRE + #define ma_atomic_memory_order_release __ATOMIC_RELEASE + #define ma_atomic_memory_order_acq_rel __ATOMIC_ACQ_REL + #define ma_atomic_memory_order_seq_cst __ATOMIC_SEQ_CST + #define ma_atomic_compiler_fence() __asm__ __volatile__("":::"memory") #define ma_atomic_thread_fence(order) __atomic_thread_fence(order) #define ma_atomic_signal_fence(order) __atomic_signal_fence(order) #define ma_atomic_is_lock_free_8(ptr) __atomic_is_lock_free(1, ptr) #define ma_atomic_is_lock_free_16(ptr) __atomic_is_lock_free(2, ptr) #define ma_atomic_is_lock_free_32(ptr) __atomic_is_lock_free(4, ptr) #define ma_atomic_is_lock_free_64(ptr) __atomic_is_lock_free(8, ptr) + #define ma_atomic_test_and_set_explicit_8( dst, order) __atomic_exchange_n(dst, 1, order) + #define ma_atomic_test_and_set_explicit_16(dst, order) __atomic_exchange_n(dst, 1, order) + #define ma_atomic_test_and_set_explicit_32(dst, order) __atomic_exchange_n(dst, 1, order) + #define ma_atomic_test_and_set_explicit_64(dst, order) __atomic_exchange_n(dst, 1, order) + #define ma_atomic_clear_explicit_8( dst, order) __atomic_store_n(dst, 0, order) + #define ma_atomic_clear_explicit_16(dst, order) __atomic_store_n(dst, 0, order) + #define ma_atomic_clear_explicit_32(dst, order) __atomic_store_n(dst, 0, order) + #define ma_atomic_clear_explicit_64(dst, order) __atomic_store_n(dst, 0, order) #define ma_atomic_store_explicit_8( dst, src, order) __atomic_store_n(dst, src, order) #define ma_atomic_store_explicit_16(dst, src, order) __atomic_store_n(dst, src, order) #define ma_atomic_store_explicit_32(dst, src, order) __atomic_store_n(dst, src, order) @@ -15773,14 +14864,14 @@ ma_atomic_spinlock ma_atomic_global_lock; #define ma_atomic_exchange_explicit_16(dst, src, order) __atomic_exchange_n(dst, src, order) #define ma_atomic_exchange_explicit_32(dst, src, order) __atomic_exchange_n(dst, src, order) #define ma_atomic_exchange_explicit_64(dst, src, order) __atomic_exchange_n(dst, src, order) - #define ma_atomic_compare_exchange_strong_explicit_8( dst, expected, replacement, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, replacement, 0, successOrder, failureOrder) - #define ma_atomic_compare_exchange_strong_explicit_16(dst, expected, replacement, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, replacement, 0, successOrder, failureOrder) - #define ma_atomic_compare_exchange_strong_explicit_32(dst, expected, replacement, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, replacement, 0, successOrder, failureOrder) - #define ma_atomic_compare_exchange_strong_explicit_64(dst, expected, replacement, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, replacement, 0, successOrder, failureOrder) - #define ma_atomic_compare_exchange_weak_explicit_8( dst, expected, replacement, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, replacement, 1, successOrder, failureOrder) - #define ma_atomic_compare_exchange_weak_explicit_16(dst, expected, replacement, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, replacement, 1, successOrder, failureOrder) - #define ma_atomic_compare_exchange_weak_explicit_32(dst, expected, replacement, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, replacement, 1, successOrder, failureOrder) - #define ma_atomic_compare_exchange_weak_explicit_64(dst, expected, replacement, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, replacement, 1, successOrder, failureOrder) + #define ma_atomic_compare_exchange_strong_explicit_8( dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 0, successOrder, failureOrder) + #define ma_atomic_compare_exchange_strong_explicit_16(dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 0, successOrder, failureOrder) + #define ma_atomic_compare_exchange_strong_explicit_32(dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 0, successOrder, failureOrder) + #define ma_atomic_compare_exchange_strong_explicit_64(dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 0, successOrder, failureOrder) + #define ma_atomic_compare_exchange_weak_explicit_8( dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 1, successOrder, failureOrder) + #define ma_atomic_compare_exchange_weak_explicit_16(dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 1, successOrder, failureOrder) + #define ma_atomic_compare_exchange_weak_explicit_32(dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 1, successOrder, failureOrder) + #define ma_atomic_compare_exchange_weak_explicit_64(dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 1, successOrder, failureOrder) #define ma_atomic_fetch_add_explicit_8( dst, src, order) __atomic_fetch_add(dst, src, order) #define ma_atomic_fetch_add_explicit_16(dst, src, order) __atomic_fetch_add(dst, src, order) #define ma_atomic_fetch_add_explicit_32(dst, src, order) __atomic_fetch_add(dst, src, order) @@ -15801,19 +14892,19 @@ ma_atomic_spinlock ma_atomic_global_lock; #define ma_atomic_fetch_and_explicit_16(dst, src, order) __atomic_fetch_and(dst, src, order) #define ma_atomic_fetch_and_explicit_32(dst, src, order) __atomic_fetch_and(dst, src, order) #define ma_atomic_fetch_and_explicit_64(dst, src, order) __atomic_fetch_and(dst, src, order) - static MA_INLINE ma_uint8 ma_atomic_compare_and_swap_8(volatile ma_uint8* dst, ma_uint8 expected, ma_uint8 replacement) + static MA_INLINE ma_uint8 ma_atomic_compare_and_swap_8(volatile ma_uint8* dst, ma_uint8 expected, ma_uint8 desired) { - __atomic_compare_exchange_n(dst, &expected, replacement, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); + __atomic_compare_exchange_n(dst, &expected, desired, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); return expected; } - static MA_INLINE ma_uint16 ma_atomic_compare_and_swap_16(volatile ma_uint16* dst, ma_uint16 expected, ma_uint16 replacement) + static MA_INLINE ma_uint16 ma_atomic_compare_and_swap_16(volatile ma_uint16* dst, ma_uint16 expected, ma_uint16 desired) { - __atomic_compare_exchange_n(dst, &expected, replacement, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); + __atomic_compare_exchange_n(dst, &expected, desired, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); return expected; } - static MA_INLINE ma_uint32 ma_atomic_compare_and_swap_32(volatile ma_uint32* dst, ma_uint32 expected, ma_uint32 replacement) + static MA_INLINE ma_uint32 ma_atomic_compare_and_swap_32(volatile ma_uint32* dst, ma_uint32 expected, ma_uint32 desired) { - __atomic_compare_exchange_n(dst, &expected, replacement, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); + __atomic_compare_exchange_n(dst, &expected, desired, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); return expected; } #if defined(__clang__) @@ -15822,1134 +14913,636 @@ ma_atomic_spinlock ma_atomic_global_lock; #pragma clang diagnostic ignored "-Watomic-alignment" #endif #endif - static MA_INLINE ma_uint64 ma_atomic_compare_and_swap_64(volatile ma_uint64* dst, ma_uint64 expected, ma_uint64 replacement) + static MA_INLINE ma_uint64 ma_atomic_compare_and_swap_64(volatile ma_uint64* dst, ma_uint64 expected, ma_uint64 desired) { - __atomic_compare_exchange_n(dst, &expected, replacement, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); + __atomic_compare_exchange_n(dst, &expected, desired, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); return expected; } #if defined(__clang__) #pragma clang diagnostic pop #endif -#endif -#if defined(MA_ATOMIC_LEGACY_GCC) || defined(MA_ATOMIC_LEGACY_GCC_ASM) - #define ma_atomic_signal_fence(order) __asm__ __volatile__("":::"memory") - #if defined(MA_ATOMIC_LEGACY_GCC) + typedef ma_uint8 ma_atomic_flag; + #define ma_atomic_flag_test_and_set_explicit(dst, order) (ma_bool32)__atomic_test_and_set(dst, order) + #define ma_atomic_flag_clear_explicit(dst, order) __atomic_clear(dst, order) + #define ma_atomic_flag_load_explicit(ptr, order) ma_atomic_load_explicit_8(ptr, order) +#else + #define ma_atomic_memory_order_relaxed 1 + #define ma_atomic_memory_order_consume 2 + #define ma_atomic_memory_order_acquire 3 + #define ma_atomic_memory_order_release 4 + #define ma_atomic_memory_order_acq_rel 5 + #define ma_atomic_memory_order_seq_cst 6 + #define ma_atomic_compiler_fence() __asm__ __volatile__("":::"memory") + #if defined(__GNUC__) #define ma_atomic_thread_fence(order) __sync_synchronize(), (void)order - static MA_INLINE ma_uint8 ma_atomic_compare_and_swap_8(volatile ma_uint8* dst, ma_uint8 expected, ma_uint8 replacement) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_8) - { - return __sync_val_compare_and_swap(dst, expected, replacement); - } - #else - { - MA_ATOMIC_COMPARE_AND_SWAP_LOCK(8, dst, expected, replacement); - } - #endif - } - static MA_INLINE ma_uint16 ma_atomic_compare_and_swap_16(volatile ma_uint16* dst, ma_uint16 expected, ma_uint16 replacement) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_16) - { - return __sync_val_compare_and_swap(dst, expected, replacement); - } - #else - { - MA_ATOMIC_COMPARE_AND_SWAP_LOCK(16, dst, expected, replacement); - } - #endif - } - static MA_INLINE ma_uint32 ma_atomic_compare_and_swap_32(volatile ma_uint32* dst, ma_uint32 expected, ma_uint32 replacement) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_32) - { - return __sync_val_compare_and_swap(dst, expected, replacement); - } - #else - { - MA_ATOMIC_COMPARE_AND_SWAP_LOCK(32, dst, expected, replacement); - } - #endif - } - static MA_INLINE ma_uint64 ma_atomic_compare_and_swap_64(volatile ma_uint64* dst, ma_uint64 expected, ma_uint64 replacement) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_64) - { - return __sync_val_compare_and_swap(dst, expected, replacement); - } - #else - { - MA_ATOMIC_COMPARE_AND_SWAP_LOCK(64, dst, expected, replacement); - } - #endif - } - static MA_INLINE ma_uint8 ma_atomic_load_explicit_8(volatile const ma_uint8* ptr, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_8) - { - (void)order; - return ma_atomic_compare_and_swap_8((ma_uint8*)ptr, 0, 0); - } - #else - { - MA_ATOMIC_LOAD_EXPLICIT_LOCK(8, ptr, order); - } - #endif - } - static MA_INLINE ma_uint16 ma_atomic_load_explicit_16(volatile const ma_uint16* ptr, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_16) - { - (void)order; - return ma_atomic_compare_and_swap_16((ma_uint16*)ptr, 0, 0); - } - #else - { - MA_ATOMIC_LOAD_EXPLICIT_LOCK(16, ptr, order); - } - #endif - } - static MA_INLINE ma_uint32 ma_atomic_load_explicit_32(volatile const ma_uint32* ptr, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_32) - { - (void)order; - return ma_atomic_compare_and_swap_32((ma_uint32*)ptr, 0, 0); - } - #else - { - MA_ATOMIC_LOAD_EXPLICIT_LOCK(32, ptr, order); - } - #endif - } - static MA_INLINE ma_uint64 ma_atomic_load_explicit_64(volatile const ma_uint64* ptr, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_64) - { - (void)order; - return ma_atomic_compare_and_swap_64((ma_uint64*)ptr, 0, 0); - } - #else - { - MA_ATOMIC_LOAD_EXPLICIT_LOCK(64, ptr, order); - } - #endif - } static MA_INLINE ma_uint8 ma_atomic_exchange_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) { - #if defined(MA_ATOMIC_IS_LOCK_FREE_8) - { - if (order > ma_atomic_memory_order_acquire) { - __sync_synchronize(); - } - return __sync_lock_test_and_set(dst, src); + if (order > ma_atomic_memory_order_acquire) { + __sync_synchronize(); } - #else - { - MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(8, dst, src, order); - } - #endif + return __sync_lock_test_and_set(dst, src); } static MA_INLINE ma_uint16 ma_atomic_exchange_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) { - #if defined(MA_ATOMIC_IS_LOCK_FREE_16) - { - if (order > ma_atomic_memory_order_acquire) { - __sync_synchronize(); - } - return __sync_lock_test_and_set(dst, src); - } - #else - { - MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(16, dst, src, order); - } - #endif + ma_uint16 oldValue; + do { + oldValue = *dst; + } while (__sync_val_compare_and_swap(dst, oldValue, src) != oldValue); + (void)order; + return oldValue; } static MA_INLINE ma_uint32 ma_atomic_exchange_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) { - #if defined(MA_ATOMIC_IS_LOCK_FREE_32) - { - if (order > ma_atomic_memory_order_acquire) { - __sync_synchronize(); - } - return __sync_lock_test_and_set(dst, src); - } - #else - { - MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(32, dst, src, order); - } - #endif + ma_uint32 oldValue; + do { + oldValue = *dst; + } while (__sync_val_compare_and_swap(dst, oldValue, src) != oldValue); + (void)order; + return oldValue; } static MA_INLINE ma_uint64 ma_atomic_exchange_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) { - #if defined(MA_ATOMIC_IS_LOCK_FREE_64) - { - if (order > ma_atomic_memory_order_acquire) { - __sync_synchronize(); - } - return __sync_lock_test_and_set(dst, src); - } - #else - { - MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(64, dst, src, order); - } - #endif - } - #define ma_atomic_store_explicit_8( dst, src, order) (void)ma_atomic_exchange_explicit_8 (dst, src, order) - #define ma_atomic_store_explicit_16(dst, src, order) (void)ma_atomic_exchange_explicit_16(dst, src, order) - #define ma_atomic_store_explicit_32(dst, src, order) (void)ma_atomic_exchange_explicit_32(dst, src, order) - #define ma_atomic_store_explicit_64(dst, src, order) (void)ma_atomic_exchange_explicit_64(dst, src, order) - static MA_INLINE ma_uint8 ma_atomic_fetch_add_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_8) - { - (void)order; - return __sync_fetch_and_add(dst, src); - } - #else - { - MA_ATOMIC_FETCH_ADD_LOCK(8, dst, src, order); - } - #endif - } - static MA_INLINE ma_uint16 ma_atomic_fetch_add_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_16) - { - (void)order; - return __sync_fetch_and_add(dst, src); - } - #else - { - MA_ATOMIC_FETCH_ADD_LOCK(16, dst, src, order); - } - #endif - } - static MA_INLINE ma_uint32 ma_atomic_fetch_add_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_32) - { - (void)order; - return __sync_fetch_and_add(dst, src); - } - #else - { - MA_ATOMIC_FETCH_ADD_LOCK(32, dst, src, order); - } - #endif - } - static MA_INLINE ma_uint64 ma_atomic_fetch_add_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_64) - { - (void)order; - return __sync_fetch_and_add(dst, src); - } - #else - { - MA_ATOMIC_FETCH_ADD_LOCK(64, dst, src, order); - } - #endif - } - static MA_INLINE ma_uint8 ma_atomic_fetch_sub_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_8) - { - (void)order; - return __sync_fetch_and_sub(dst, src); - } - #else - { - MA_ATOMIC_FETCH_ADD_LOCK(8, dst, (ma_uint8)(-(ma_int8)src), order); - } - #endif - } - static MA_INLINE ma_uint16 ma_atomic_fetch_sub_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_16) - { - (void)order; - return __sync_fetch_and_sub(dst, src); - } - #else - { - MA_ATOMIC_FETCH_ADD_LOCK(16, dst, (ma_uint16)(-(ma_int16)src), order); - } - #endif - } - static MA_INLINE ma_uint32 ma_atomic_fetch_sub_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_32) - { - (void)order; - return __sync_fetch_and_sub(dst, src); - } - #else - { - MA_ATOMIC_FETCH_ADD_LOCK(32, dst, (ma_uint32)(-(ma_int32)src), order); - } - #endif - } - static MA_INLINE ma_uint64 ma_atomic_fetch_sub_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_64) - { - (void)order; - return __sync_fetch_and_sub(dst, src); - } - #else - { - MA_ATOMIC_FETCH_ADD_LOCK(64, dst, (ma_uint64)(-(ma_int64)src), order); - } - #endif - } - static MA_INLINE ma_uint8 ma_atomic_fetch_and_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_8) - { - (void)order; - return __sync_fetch_and_and(dst, src); - } - #else - { - MA_ATOMIC_FETCH_AND_CAS(8, dst, src, order); - } - #endif - } - static MA_INLINE ma_uint16 ma_atomic_fetch_and_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_16) - { - (void)order; - return __sync_fetch_and_and(dst, src); - } - #else - { - MA_ATOMIC_FETCH_AND_CAS(16, dst, src, order); - } - #endif - } - static MA_INLINE ma_uint32 ma_atomic_fetch_and_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_32) - { - (void)order; - return __sync_fetch_and_and(dst, src); - } - #else - { - MA_ATOMIC_FETCH_AND_CAS(32, dst, src, order); - } - #endif - } - static MA_INLINE ma_uint64 ma_atomic_fetch_and_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_64) - { - (void)order; - return __sync_fetch_and_and(dst, src); - } - #else - { - MA_ATOMIC_FETCH_AND_CAS(64, dst, src, order); - } - #endif - } - static MA_INLINE ma_uint8 ma_atomic_fetch_or_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_8) - { - (void)order; - return __sync_fetch_and_or(dst, src); - } - #else - { - MA_ATOMIC_FETCH_OR_CAS(8, dst, src, order); - } - #endif - } - static MA_INLINE ma_uint16 ma_atomic_fetch_or_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_16) - { - (void)order; - return __sync_fetch_and_or(dst, src); - } - #else - { - MA_ATOMIC_FETCH_OR_CAS(16, dst, src, order); - } - #endif - } - static MA_INLINE ma_uint32 ma_atomic_fetch_or_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_32) - { - (void)order; - return __sync_fetch_and_or(dst, src); - } - #else - { - MA_ATOMIC_FETCH_OR_CAS(32, dst, src, order); - } - #endif - } - static MA_INLINE ma_uint64 ma_atomic_fetch_or_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_64) - { - (void)order; - return __sync_fetch_and_or(dst, src); - } - #else - { - MA_ATOMIC_FETCH_OR_CAS(64, dst, src, order); - } - #endif - } - static MA_INLINE ma_uint8 ma_atomic_fetch_xor_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_8) - { - (void)order; - return __sync_fetch_and_xor(dst, src); - } - #else - { - MA_ATOMIC_FETCH_XOR_CAS(8, dst, src, order); - } - #endif - } - static MA_INLINE ma_uint16 ma_atomic_fetch_xor_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_16) - { - (void)order; - return __sync_fetch_and_xor(dst, src); - } - #else - { - MA_ATOMIC_FETCH_XOR_CAS(16, dst, src, order); - } - #endif - } - static MA_INLINE ma_uint32 ma_atomic_fetch_xor_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_32) - { - (void)order; - return __sync_fetch_and_xor(dst, src); - } - #else - { - MA_ATOMIC_FETCH_XOR_CAS(32, dst, src, order); - } - #endif - } - static MA_INLINE ma_uint64 ma_atomic_fetch_xor_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_64) - { - (void)order; - return __sync_fetch_and_xor(dst, src); - } - #else - { - MA_ATOMIC_FETCH_XOR_CAS(64, dst, src, order); - } - #endif - } - #elif defined(MA_ATOMIC_LEGACY_GCC_ASM) - #define MA_ATOMIC_CMPXCHG_GCC_X86(instructionSizeSuffix, result, dst, expected, replacement) \ - __asm__ __volatile__( \ - "lock; cmpxchg"instructionSizeSuffix" %2, %1" \ - : "=a"(result), \ - "=m"(*dst) \ - : "r"(replacement), \ - "0"(expected), \ - "m"(*dst) \ - : "cc", "memory") - #define MA_ATOMIC_XADD_GCC_X86(instructionSizeSuffix, result, dst, src) \ - __asm__ __volatile__( \ - "lock; xadd"instructionSizeSuffix" %0, %1" \ - : "=a"(result), \ - "=m"(*dst) \ - : "0"(src), \ - "m"(*dst) \ - : "cc", "memory") - static MA_INLINE ma_uint8 ma_atomic_compare_and_swap_8(volatile ma_uint8* dst, ma_uint8 expected, ma_uint8 replacement) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_8) && (defined(MA_X86) || defined(MA_X64)) - { - ma_uint8 result; - #if defined(MA_X86) || defined(MA_X64) - { - MA_ATOMIC_CMPXCHG_GCC_X86("b", result, dst, expected, replacement); - } - #else - { - #error Unsupported architecture. - } - #endif - return result; - } - #else - { - MA_ATOMIC_COMPARE_AND_SWAP_LOCK(8, dst, expected, replacement); - } - #endif - } - static MA_INLINE ma_uint16 ma_atomic_compare_and_swap_16(volatile ma_uint16* dst, ma_uint16 expected, ma_uint16 replacement) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_16) && (defined(MA_X86) || defined(MA_X64)) - { - ma_uint16 result; - #if defined(MA_X86) || defined(MA_X64) - { - MA_ATOMIC_CMPXCHG_GCC_X86("w", result, dst, expected, replacement); - } - #else - { - #error Unsupported architecture. - } - #endif - return result; - } - #else - { - MA_ATOMIC_COMPARE_AND_SWAP_LOCK(16, dst, expected, replacement); - } - #endif - } - static MA_INLINE ma_uint32 ma_atomic_compare_and_swap_32(volatile ma_uint32* dst, ma_uint32 expected, ma_uint32 replacement) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_32) && (defined(MA_X86) || defined(MA_X64)) - { - ma_uint32 result; - #if defined(MA_X86) || defined(MA_X64) - { - MA_ATOMIC_CMPXCHG_GCC_X86("l", result, dst, expected, replacement); - } - #else - { - #error Unsupported architecture. - } - #endif - return result; - } - #else - { - MA_ATOMIC_COMPARE_AND_SWAP_LOCK(32, dst, expected, replacement); - } - #endif - } - static MA_INLINE ma_uint64 ma_atomic_compare_and_swap_64(volatile ma_uint64* dst, ma_uint64 expected, ma_uint64 replacement) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_64) && (defined(MA_X86) || defined(MA_X64)) - { - ma_uint64 result; - #if defined(MA_X86) - { - ma_uint32 resultEAX; - ma_uint32 resultEDX; - __asm__ __volatile__( - "pushl %%ebx\n" - "movl %4, %%ebx\n" - "lock cmpxchg8b (%%edi)\n" - "popl %%ebx\n" - : "=a"(resultEAX), - "=d"(resultEDX) - : "a"((ma_uint32)(expected & 0xFFFFFFFF)), - "d"((ma_uint32)(expected >> 32)), - "r"((ma_uint32)(replacement & 0xFFFFFFFF)), - "c"((ma_uint32)(replacement >> 32)), - "D"(dst) - : "memory", "cc"); - result = ((ma_uint64)resultEDX << 32) | resultEAX; - } - #elif defined(MA_X64) - { - MA_ATOMIC_CMPXCHG_GCC_X86("q", result, dst, expected, replacement); - } - #else - { - #error Unsupported architecture. - } - #endif - return result; - } - #else - { - MA_ATOMIC_COMPARE_AND_SWAP_LOCK(64, dst, expected, replacement); - } - #endif - } - static MA_INLINE ma_uint8 ma_atomic_load_explicit_8(volatile const ma_uint8* dst, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_8) && (defined(MA_X86) || defined(MA_X64)) - { - ma_uint8 result; - #if defined(MA_X86) || defined(MA_X64) - { - if (order == ma_atomic_memory_order_relaxed) { - MA_ATOMIC_LOAD_RELAXED_GCC_X86("b", result, dst); - } else if (order <= ma_atomic_memory_order_release) { - MA_ATOMIC_LOAD_RELEASE_GCC_X86("b", result, dst); - } else { - MA_ATOMIC_LOAD_SEQ_CST_GCC_X86("b", result, dst); - } - } - #else - { - #error Unsupported architecture. - } - #endif - return result; - } - #else - { - MA_ATOMIC_LOAD_EXPLICIT_LOCK(8, dst, order); - } - #endif - } - static MA_INLINE ma_uint16 ma_atomic_load_explicit_16(volatile const ma_uint16* dst, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_16) && (defined(MA_X86) || defined(MA_X64)) - { - ma_uint16 result; - #if defined(MA_X86) || defined(MA_X64) - { - if (order == ma_atomic_memory_order_relaxed) { - MA_ATOMIC_LOAD_RELAXED_GCC_X86("w", result, dst); - } else if (order <= ma_atomic_memory_order_release) { - MA_ATOMIC_LOAD_RELEASE_GCC_X86("w", result, dst); - } else { - MA_ATOMIC_LOAD_SEQ_CST_GCC_X86("w", result, dst); - } - } - #else - { - #error Unsupported architecture. - } - #endif - return result; - } - #else - { - MA_ATOMIC_LOAD_EXPLICIT_LOCK(16, dst, order); - } - #endif - } - static MA_INLINE ma_uint32 ma_atomic_load_explicit_32(volatile const ma_uint32* dst, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_32) && (defined(MA_X86) || defined(MA_X64)) - { - ma_uint32 result; - #if defined(MA_X86) || defined(MA_X64) - { - if (order == ma_atomic_memory_order_relaxed) { - MA_ATOMIC_LOAD_RELAXED_GCC_X86("l", result, dst); - } else if (order <= ma_atomic_memory_order_release) { - MA_ATOMIC_LOAD_RELEASE_GCC_X86("l", result, dst); - } else { - MA_ATOMIC_LOAD_SEQ_CST_GCC_X86("l", result, dst); - } - } - #else - { - #error Unsupported architecture. - } - #endif - return result; - } - #else - { - MA_ATOMIC_LOAD_EXPLICIT_LOCK(32, dst, order); - } - #endif - } - static MA_INLINE ma_uint64 ma_atomic_load_explicit_64(volatile const ma_uint64* dst, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_64) && (defined(MA_X86) || defined(MA_X64)) - { - ma_uint64 result; - #if defined(MA_X64) - { - if (order == ma_atomic_memory_order_relaxed) { - MA_ATOMIC_LOAD_RELAXED_GCC_X86("q", result, dst); - } else if (order <= ma_atomic_memory_order_release) { - MA_ATOMIC_LOAD_RELEASE_GCC_X86("q", result, dst); - } else { - MA_ATOMIC_LOAD_SEQ_CST_GCC_X86("q", result, dst); - } - } - #elif defined(MA_X86) - { - (void)order; - return ma_atomic_compare_and_swap_64((volatile ma_uint64*)dst, 0, 0); - } - #else - { - #error Unsupported architecture. - } - #endif - return result; - } - #else - { - MA_ATOMIC_LOAD_EXPLICIT_LOCK(64, dst, order); - } - #endif - } - static MA_INLINE ma_uint8 ma_atomic_exchange_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_8) && (defined(MA_X86) || defined(MA_X64)) - { - ma_uint8 result; - (void)order; - #if defined(MA_X86) || defined(MA_X64) - { - MA_ATOMIC_XCHG_GCC_X86("b", result, dst, src); - } - #else - { - #error Unsupported architecture. - } - #endif - return result; - } - #else - { - MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(8, dst, src, order); - } - #endif - } - static MA_INLINE ma_uint16 ma_atomic_exchange_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_16) && (defined(MA_X86) || defined(MA_X64)) - { - ma_uint16 result; - (void)order; - #if defined(MA_X86) || defined(MA_X64) - { - MA_ATOMIC_XCHG_GCC_X86("w", result, dst, src); - } - #else - { - #error Unsupported architecture. - } - #endif - return result; - } - #else - { - MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(16, dst, src, order); - } - #endif - } - static MA_INLINE ma_uint32 ma_atomic_exchange_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_32) && (defined(MA_X86) || defined(MA_X64)) - { - ma_uint32 result; - (void)order; - #if defined(MA_X86) || defined(MA_X64) - { - MA_ATOMIC_XCHG_GCC_X86("l", result, dst, src); - } - #else - { - #error Unsupported architecture. - } - #endif - return result; - } - #else - { - MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(32, dst, src, order); - } - #endif - } - static MA_INLINE ma_uint64 ma_atomic_exchange_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_64) && (defined(MA_X86) || defined(MA_X64)) - { - ma_uint64 result; - (void)order; - #if defined(MA_X86) - { - MA_ATOMIC_EXCHANGE_EXPLICIT_CAS(64, dst, src, order); - } - #elif defined(MA_X64) - { - MA_ATOMIC_XCHG_GCC_X86("q", result, dst, src); - } - #else - { - #error Unsupported architecture. - } - #endif - return result; - } - #else - { - MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(64, dst, src, order); - } - #endif - } - static MA_INLINE void ma_atomic_store_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_8) && (defined(MA_X86) || defined(MA_X64)) - { - #if defined(MA_X86) || defined(MA_X64) - { - if (order == ma_atomic_memory_order_relaxed) { - __asm__ __volatile__ ( - "movb %1, %0" - : "=m"(*dst) - : "r"(src) - ); - } else { - __asm__ __volatile__ ( - "xchgb %1, %0" - : "=m"(*dst) - : "r"(src) - : "memory" - ); - } - } - #else - { - #error Unsupported architecture. - } - #endif - } - #else - { - MA_ATOMIC_STORE_EXPLICIT_LOCK(8, dst, src, order); - } - #endif - } - static MA_INLINE void ma_atomic_store_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_16) && (defined(MA_X86) || defined(MA_X64)) - { - #if defined(MA_X86) || defined(MA_X64) - { - if (order == ma_atomic_memory_order_relaxed) { - __asm__ __volatile__ ( - "movw %1, %0" - : "=m"(*dst) - : "r"(src) - ); - } else { - __asm__ __volatile__ ( - "xchgw %1, %0" - : "=m"(*dst) - : "r"(src) - : "memory" - ); - } - } - #else - { - #error Unsupported architecture. - } - #endif - } - #else - { - MA_ATOMIC_STORE_EXPLICIT_LOCK(16, dst, src, order); - } - #endif - } - static MA_INLINE void ma_atomic_store_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_32) && (defined(MA_X86) || defined(MA_X64)) - { - #if defined(MA_X86) || defined(MA_X64) - { - if (order == ma_atomic_memory_order_relaxed) { - __asm__ __volatile__ ( - "movl %1, %0" - : "=m"(*dst) - : "r"(src) - ); - } else { - __asm__ __volatile__ ( - "xchgl %1, %0" - : "=m"(*dst) - : "r"(src) - : "memory" - ); - } - } - #else - { - #error Unsupported architecture. - } - #endif - } - #else - { - MA_ATOMIC_STORE_EXPLICIT_LOCK(32, dst, src, order); - } - #endif - } - static MA_INLINE void ma_atomic_store_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) - { - #if defined(MA_ATOMIC_IS_LOCK_FREE_64) && (defined(MA_X86) || defined(MA_X64)) - { - #if defined(MA_X64) - { - if (order == ma_atomic_memory_order_relaxed) { - __asm__ __volatile__ ( - "movq %1, %0" - : "=m"(*dst) - : "r"(src) - ); - } else { - __asm__ __volatile__ ( - "xchgq %1, %0" - : "=m"(*dst) - : "r"(src) - : "memory" - ); - } - } - #else - { - MA_ATOMIC_STORE_EXPLICIT_CAS(64, dst, src, order); - } - #endif - } - #else - { - MA_ATOMIC_STORE_EXPLICIT_LOCK(64, dst, src, order); - } - #endif + ma_uint64 oldValue; + do { + oldValue = *dst; + } while (__sync_val_compare_and_swap(dst, oldValue, src) != oldValue); + (void)order; + return oldValue; } static MA_INLINE ma_uint8 ma_atomic_fetch_add_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) { - #if defined(MA_ATOMIC_IS_LOCK_FREE_8) && (defined(MA_X86) || defined(MA_X64)) - { - #if defined(MA_X86) || defined(MA_X64) - { - ma_uint8 result; - (void)order; - MA_ATOMIC_XADD_GCC_X86("b", result, dst, src); - return result; - } - #else - { - #error Unsupported architecture. - } - #endif - } - #else - { - MA_ATOMIC_FETCH_ADD_LOCK(8, dst, src, order); - } - #endif + (void)order; + return __sync_fetch_and_add(dst, src); } static MA_INLINE ma_uint16 ma_atomic_fetch_add_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) { - #if defined(MA_ATOMIC_IS_LOCK_FREE_16) && (defined(MA_X86) || defined(MA_X64)) - { - #if defined(MA_X86) || defined(MA_X64) - { - ma_uint16 result; - (void)order; - MA_ATOMIC_XADD_GCC_X86("w", result, dst, src); - return result; - } - #else - { - #error Unsupported architecture. - } - #endif - } - #else - { - MA_ATOMIC_FETCH_ADD_LOCK(16, dst, src, order); - } - #endif + (void)order; + return __sync_fetch_and_add(dst, src); } static MA_INLINE ma_uint32 ma_atomic_fetch_add_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) { - #if defined(MA_ATOMIC_IS_LOCK_FREE_32) && (defined(MA_X86) || defined(MA_X64)) - { - #if defined(MA_X86) || defined(MA_X64) - { - ma_uint32 result; - (void)order; - MA_ATOMIC_XADD_GCC_X86("l", result, dst, src); - return result; - } - #else - { - #error Unsupported architecture. - } - #endif - } - #else - { - MA_ATOMIC_FETCH_ADD_LOCK(32, dst, src, order); - } - #endif + (void)order; + return __sync_fetch_and_add(dst, src); } static MA_INLINE ma_uint64 ma_atomic_fetch_add_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) { - #if defined(MA_ATOMIC_IS_LOCK_FREE_64) && (defined(MA_X86) || defined(MA_X64)) - { - #if defined(MA_X86) - { - MA_ATOMIC_FETCH_ADD_CAS(64, dst, src, order); - } - #elif defined(MA_X64) - { - ma_uint64 result; - MA_ATOMIC_XADD_GCC_X86("q", result, dst, src); - (void)order; - return result; - } - #else - { - #error Unsupported architecture. - } - #endif - } - #else - { - MA_ATOMIC_FETCH_ADD_LOCK(64, dst, src, order); - } - #endif + (void)order; + return __sync_fetch_and_add(dst, src); } static MA_INLINE ma_uint8 ma_atomic_fetch_sub_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) { - return ma_atomic_fetch_add_explicit_8(dst, (ma_uint8)(-(ma_int8)src), order); + (void)order; + return __sync_fetch_and_sub(dst, src); } static MA_INLINE ma_uint16 ma_atomic_fetch_sub_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) { - return ma_atomic_fetch_add_explicit_16(dst, (ma_uint16)(-(ma_int16)src), order); + (void)order; + return __sync_fetch_and_sub(dst, src); } static MA_INLINE ma_uint32 ma_atomic_fetch_sub_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) { - return ma_atomic_fetch_add_explicit_32(dst, (ma_uint32)(-(ma_int32)src), order); + (void)order; + return __sync_fetch_and_sub(dst, src); } static MA_INLINE ma_uint64 ma_atomic_fetch_sub_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) { - return ma_atomic_fetch_add_explicit_64(dst, (ma_uint64)(-(ma_int64)src), order); - } - static MA_INLINE ma_uint8 ma_atomic_fetch_and_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) - { - MA_ATOMIC_FETCH_AND_CAS(8, dst, src, order); - } - static MA_INLINE ma_uint16 ma_atomic_fetch_and_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) - { - MA_ATOMIC_FETCH_AND_CAS(16, dst, src, order); - } - static MA_INLINE ma_uint32 ma_atomic_fetch_and_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) - { - MA_ATOMIC_FETCH_AND_CAS(32, dst, src, order); - } - static MA_INLINE ma_uint64 ma_atomic_fetch_and_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) - { - MA_ATOMIC_FETCH_AND_CAS(64, dst, src, order); + (void)order; + return __sync_fetch_and_sub(dst, src); } static MA_INLINE ma_uint8 ma_atomic_fetch_or_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) { - MA_ATOMIC_FETCH_OR_CAS(8, dst, src, order); + (void)order; + return __sync_fetch_and_or(dst, src); } static MA_INLINE ma_uint16 ma_atomic_fetch_or_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) { - MA_ATOMIC_FETCH_OR_CAS(16, dst, src, order); + (void)order; + return __sync_fetch_and_or(dst, src); } static MA_INLINE ma_uint32 ma_atomic_fetch_or_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) { - MA_ATOMIC_FETCH_OR_CAS(32, dst, src, order); + (void)order; + return __sync_fetch_and_or(dst, src); } static MA_INLINE ma_uint64 ma_atomic_fetch_or_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) { - MA_ATOMIC_FETCH_OR_CAS(64, dst, src, order); + (void)order; + return __sync_fetch_and_or(dst, src); } static MA_INLINE ma_uint8 ma_atomic_fetch_xor_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) { - MA_ATOMIC_FETCH_XOR_CAS(8, dst, src, order); + (void)order; + return __sync_fetch_and_xor(dst, src); } static MA_INLINE ma_uint16 ma_atomic_fetch_xor_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) { - MA_ATOMIC_FETCH_XOR_CAS(16, dst, src, order); + (void)order; + return __sync_fetch_and_xor(dst, src); } static MA_INLINE ma_uint32 ma_atomic_fetch_xor_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) { - MA_ATOMIC_FETCH_XOR_CAS(32, dst, src, order); + (void)order; + return __sync_fetch_and_xor(dst, src); } static MA_INLINE ma_uint64 ma_atomic_fetch_xor_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) { - MA_ATOMIC_FETCH_XOR_CAS(64, dst, src, order); + (void)order; + return __sync_fetch_and_xor(dst, src); } + static MA_INLINE ma_uint8 ma_atomic_fetch_and_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + (void)order; + return __sync_fetch_and_and(dst, src); + } + static MA_INLINE ma_uint16 ma_atomic_fetch_and_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + (void)order; + return __sync_fetch_and_and(dst, src); + } + static MA_INLINE ma_uint32 ma_atomic_fetch_and_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + (void)order; + return __sync_fetch_and_and(dst, src); + } + static MA_INLINE ma_uint64 ma_atomic_fetch_and_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + (void)order; + return __sync_fetch_and_and(dst, src); + } + #define ma_atomic_compare_and_swap_8( dst, expected, desired) __sync_val_compare_and_swap(dst, expected, desired) + #define ma_atomic_compare_and_swap_16(dst, expected, desired) __sync_val_compare_and_swap(dst, expected, desired) + #define ma_atomic_compare_and_swap_32(dst, expected, desired) __sync_val_compare_and_swap(dst, expected, desired) + #define ma_atomic_compare_and_swap_64(dst, expected, desired) __sync_val_compare_and_swap(dst, expected, desired) #else - #error Unsupported compiler. + #if defined(MA_X86) + #define ma_atomic_thread_fence(order) __asm__ __volatile__("lock; addl $0, (%%esp)" ::: "memory", "cc") + #elif defined(MA_X64) + #define ma_atomic_thread_fence(order) __asm__ __volatile__("lock; addq $0, (%%rsp)" ::: "memory", "cc") + #else + #error Unsupported architecture. Please submit a feature request. + #endif + static MA_INLINE ma_uint8 ma_atomic_compare_and_swap_8(volatile ma_uint8* dst, ma_uint8 expected, ma_uint8 desired) + { + ma_uint8 result; + #if defined(MA_X86) || defined(MA_X64) + __asm__ __volatile__("lock; cmpxchg %3, %0" : "+m"(*dst), "=a"(result) : "a"(expected), "d"(desired) : "cc"); + #else + #error Unsupported architecture. Please submit a feature request. + #endif + return result; + } + static MA_INLINE ma_uint16 ma_atomic_compare_and_swap_16(volatile ma_uint16* dst, ma_uint16 expected, ma_uint16 desired) + { + ma_uint16 result; + #if defined(MA_X86) || defined(MA_X64) + __asm__ __volatile__("lock; cmpxchg %3, %0" : "+m"(*dst), "=a"(result) : "a"(expected), "d"(desired) : "cc"); + #else + #error Unsupported architecture. Please submit a feature request. + #endif + return result; + } + static MA_INLINE ma_uint32 ma_atomic_compare_and_swap_32(volatile ma_uint32* dst, ma_uint32 expected, ma_uint32 desired) + { + ma_uint32 result; + #if defined(MA_X86) || defined(MA_X64) + __asm__ __volatile__("lock; cmpxchg %3, %0" : "+m"(*dst), "=a"(result) : "a"(expected), "d"(desired) : "cc"); + #else + #error Unsupported architecture. Please submit a feature request. + #endif + return result; + } + static MA_INLINE ma_uint64 ma_atomic_compare_and_swap_64(volatile ma_uint64* dst, ma_uint64 expected, ma_uint64 desired) + { + volatile ma_uint64 result; + #if defined(MA_X86) + ma_uint32 resultEAX; + ma_uint32 resultEDX; + __asm__ __volatile__("push %%ebx; xchg %5, %%ebx; lock; cmpxchg8b %0; pop %%ebx" : "+m"(*dst), "=a"(resultEAX), "=d"(resultEDX) : "a"(expected & 0xFFFFFFFF), "d"(expected >> 32), "r"(desired & 0xFFFFFFFF), "c"(desired >> 32) : "cc"); + result = ((ma_uint64)resultEDX << 32) | resultEAX; + #elif defined(MA_X64) + __asm__ __volatile__("lock; cmpxchg %3, %0" : "+m"(*dst), "=a"(result) : "a"(expected), "d"(desired) : "cc"); + #else + #error Unsupported architecture. Please submit a feature request. + #endif + return result; + } + static MA_INLINE ma_uint8 ma_atomic_exchange_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + ma_uint8 result = 0; + (void)order; + #if defined(MA_X86) || defined(MA_X64) + __asm__ __volatile__("lock; xchg %1, %0" : "+m"(*dst), "=a"(result) : "a"(src)); + #else + #error Unsupported architecture. Please submit a feature request. + #endif + return result; + } + static MA_INLINE ma_uint16 ma_atomic_exchange_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + ma_uint16 result = 0; + (void)order; + #if defined(MA_X86) || defined(MA_X64) + __asm__ __volatile__("lock; xchg %1, %0" : "+m"(*dst), "=a"(result) : "a"(src)); + #else + #error Unsupported architecture. Please submit a feature request. + #endif + return result; + } + static MA_INLINE ma_uint32 ma_atomic_exchange_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + ma_uint32 result; + (void)order; + #if defined(MA_X86) || defined(MA_X64) + __asm__ __volatile__("lock; xchg %1, %0" : "+m"(*dst), "=a"(result) : "a"(src)); + #else + #error Unsupported architecture. Please submit a feature request. + #endif + return result; + } + static MA_INLINE ma_uint64 ma_atomic_exchange_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + ma_uint64 result; + (void)order; + #if defined(MA_X86) + do { + result = *dst; + } while (ma_atomic_compare_and_swap_64(dst, result, src) != result); + #elif defined(MA_X64) + __asm__ __volatile__("lock; xchg %1, %0" : "+m"(*dst), "=a"(result) : "a"(src)); + #else + #error Unsupported architecture. Please submit a feature request. + #endif + return result; + } + static MA_INLINE ma_uint8 ma_atomic_fetch_add_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + ma_uint8 result; + (void)order; + #if defined(MA_X86) || defined(MA_X64) + __asm__ __volatile__("lock; xadd %1, %0" : "+m"(*dst), "=a"(result) : "a"(src) : "cc"); + #else + #error Unsupported architecture. Please submit a feature request. + #endif + return result; + } + static MA_INLINE ma_uint16 ma_atomic_fetch_add_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + ma_uint16 result; + (void)order; + #if defined(MA_X86) || defined(MA_X64) + __asm__ __volatile__("lock; xadd %1, %0" : "+m"(*dst), "=a"(result) : "a"(src) : "cc"); + #else + #error Unsupported architecture. Please submit a feature request. + #endif + return result; + } + static MA_INLINE ma_uint32 ma_atomic_fetch_add_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + ma_uint32 result; + (void)order; + #if defined(MA_X86) || defined(MA_X64) + __asm__ __volatile__("lock; xadd %1, %0" : "+m"(*dst), "=a"(result) : "a"(src) : "cc"); + #else + #error Unsupported architecture. Please submit a feature request. + #endif + return result; + } + static MA_INLINE ma_uint64 ma_atomic_fetch_add_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + #if defined(MA_X86) + ma_uint64 oldValue; + ma_uint64 newValue; + (void)order; + do { + oldValue = *dst; + newValue = oldValue + src; + } while (ma_atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); + return oldValue; + #elif defined(MA_X64) + ma_uint64 result; + (void)order; + __asm__ __volatile__("lock; xadd %1, %0" : "+m"(*dst), "=a"(result) : "a"(src) : "cc"); + return result; + #endif + } + static MA_INLINE ma_uint8 ma_atomic_fetch_sub_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + ma_uint8 oldValue; + ma_uint8 newValue; + do { + oldValue = *dst; + newValue = (ma_uint8)(oldValue - src); + } while (ma_atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); + (void)order; + return oldValue; + } + static MA_INLINE ma_uint16 ma_atomic_fetch_sub_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + ma_uint16 oldValue; + ma_uint16 newValue; + do { + oldValue = *dst; + newValue = (ma_uint16)(oldValue - src); + } while (ma_atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); + (void)order; + return oldValue; + } + static MA_INLINE ma_uint32 ma_atomic_fetch_sub_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + ma_uint32 oldValue; + ma_uint32 newValue; + do { + oldValue = *dst; + newValue = oldValue - src; + } while (ma_atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); + (void)order; + return oldValue; + } + static MA_INLINE ma_uint64 ma_atomic_fetch_sub_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + ma_uint64 oldValue; + ma_uint64 newValue; + do { + oldValue = *dst; + newValue = oldValue - src; + } while (ma_atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); + (void)order; + return oldValue; + } + static MA_INLINE ma_uint8 ma_atomic_fetch_and_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + ma_uint8 oldValue; + ma_uint8 newValue; + do { + oldValue = *dst; + newValue = (ma_uint8)(oldValue & src); + } while (ma_atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); + (void)order; + return oldValue; + } + static MA_INLINE ma_uint16 ma_atomic_fetch_and_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + ma_uint16 oldValue; + ma_uint16 newValue; + do { + oldValue = *dst; + newValue = (ma_uint16)(oldValue & src); + } while (ma_atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); + (void)order; + return oldValue; + } + static MA_INLINE ma_uint32 ma_atomic_fetch_and_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + ma_uint32 oldValue; + ma_uint32 newValue; + do { + oldValue = *dst; + newValue = oldValue & src; + } while (ma_atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); + (void)order; + return oldValue; + } + static MA_INLINE ma_uint64 ma_atomic_fetch_and_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + ma_uint64 oldValue; + ma_uint64 newValue; + do { + oldValue = *dst; + newValue = oldValue & src; + } while (ma_atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); + (void)order; + return oldValue; + } + static MA_INLINE ma_uint8 ma_atomic_fetch_xor_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + ma_uint8 oldValue; + ma_uint8 newValue; + do { + oldValue = *dst; + newValue = (ma_uint8)(oldValue ^ src); + } while (ma_atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); + (void)order; + return oldValue; + } + static MA_INLINE ma_uint16 ma_atomic_fetch_xor_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + ma_uint16 oldValue; + ma_uint16 newValue; + do { + oldValue = *dst; + newValue = (ma_uint16)(oldValue ^ src); + } while (ma_atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); + (void)order; + return oldValue; + } + static MA_INLINE ma_uint32 ma_atomic_fetch_xor_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + ma_uint32 oldValue; + ma_uint32 newValue; + do { + oldValue = *dst; + newValue = oldValue ^ src; + } while (ma_atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); + (void)order; + return oldValue; + } + static MA_INLINE ma_uint64 ma_atomic_fetch_xor_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + ma_uint64 oldValue; + ma_uint64 newValue; + do { + oldValue = *dst; + newValue = oldValue ^ src; + } while (ma_atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); + (void)order; + return oldValue; + } + static MA_INLINE ma_uint8 ma_atomic_fetch_or_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + ma_uint8 oldValue; + ma_uint8 newValue; + do { + oldValue = *dst; + newValue = (ma_uint8)(oldValue | src); + } while (ma_atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); + (void)order; + return oldValue; + } + static MA_INLINE ma_uint16 ma_atomic_fetch_or_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + ma_uint16 oldValue; + ma_uint16 newValue; + do { + oldValue = *dst; + newValue = (ma_uint16)(oldValue | src); + } while (ma_atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); + (void)order; + return oldValue; + } + static MA_INLINE ma_uint32 ma_atomic_fetch_or_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + ma_uint32 oldValue; + ma_uint32 newValue; + do { + oldValue = *dst; + newValue = oldValue | src; + } while (ma_atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); + (void)order; + return oldValue; + } + static MA_INLINE ma_uint64 ma_atomic_fetch_or_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + ma_uint64 oldValue; + ma_uint64 newValue; + do { + oldValue = *dst; + newValue = oldValue | src; + } while (ma_atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); + (void)order; + return oldValue; + } #endif + #define ma_atomic_signal_fence(order) ma_atomic_thread_fence(order) + static MA_INLINE ma_uint8 ma_atomic_load_explicit_8(volatile const ma_uint8* ptr, ma_atomic_memory_order order) + { + (void)order; + return ma_atomic_compare_and_swap_8((ma_uint8*)ptr, 0, 0); + } + static MA_INLINE ma_uint16 ma_atomic_load_explicit_16(volatile const ma_uint16* ptr, ma_atomic_memory_order order) + { + (void)order; + return ma_atomic_compare_and_swap_16((ma_uint16*)ptr, 0, 0); + } + static MA_INLINE ma_uint32 ma_atomic_load_explicit_32(volatile const ma_uint32* ptr, ma_atomic_memory_order order) + { + (void)order; + return ma_atomic_compare_and_swap_32((ma_uint32*)ptr, 0, 0); + } + static MA_INLINE ma_uint64 ma_atomic_load_explicit_64(volatile const ma_uint64* ptr, ma_atomic_memory_order order) + { + (void)order; + return ma_atomic_compare_and_swap_64((ma_uint64*)ptr, 0, 0); + } + #define ma_atomic_store_explicit_8( dst, src, order) (void)ma_atomic_exchange_explicit_8 (dst, src, order) + #define ma_atomic_store_explicit_16(dst, src, order) (void)ma_atomic_exchange_explicit_16(dst, src, order) + #define ma_atomic_store_explicit_32(dst, src, order) (void)ma_atomic_exchange_explicit_32(dst, src, order) + #define ma_atomic_store_explicit_64(dst, src, order) (void)ma_atomic_exchange_explicit_64(dst, src, order) + #define ma_atomic_test_and_set_explicit_8( dst, order) ma_atomic_exchange_explicit_8 (dst, 1, order) + #define ma_atomic_test_and_set_explicit_16(dst, order) ma_atomic_exchange_explicit_16(dst, 1, order) + #define ma_atomic_test_and_set_explicit_32(dst, order) ma_atomic_exchange_explicit_32(dst, 1, order) + #define ma_atomic_test_and_set_explicit_64(dst, order) ma_atomic_exchange_explicit_64(dst, 1, order) + #define ma_atomic_clear_explicit_8( dst, order) ma_atomic_store_explicit_8 (dst, 0, order) + #define ma_atomic_clear_explicit_16(dst, order) ma_atomic_store_explicit_16(dst, 0, order) + #define ma_atomic_clear_explicit_32(dst, order) ma_atomic_store_explicit_32(dst, 0, order) + #define ma_atomic_clear_explicit_64(dst, order) ma_atomic_store_explicit_64(dst, 0, order) + typedef ma_uint8 ma_atomic_flag; + #define ma_atomic_flag_test_and_set_explicit(ptr, order) (ma_bool32)ma_atomic_test_and_set_explicit_8(ptr, order) + #define ma_atomic_flag_clear_explicit(ptr, order) ma_atomic_clear_explicit_8(ptr, order) + #define ma_atomic_flag_load_explicit(ptr, order) ma_atomic_load_explicit_8(ptr, order) #endif #if !defined(MA_ATOMIC_HAS_NATIVE_COMPARE_EXCHANGE) - static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_8(volatile ma_uint8* dst, ma_uint8* expected, ma_uint8 replacement, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) - { - ma_uint8 result; - (void)successOrder; - (void)failureOrder; - result = ma_atomic_compare_and_swap_8(dst, *expected, replacement); - if (result == *expected) { - return 1; - } else { - *expected = result; - return 0; + #if defined(MA_ATOMIC_HAS_8) + static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_8(volatile ma_uint8* dst, ma_uint8* expected, ma_uint8 desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) + { + ma_uint8 expectedValue; + ma_uint8 result; + (void)successOrder; + (void)failureOrder; + expectedValue = ma_atomic_load_explicit_8(expected, ma_atomic_memory_order_seq_cst); + result = ma_atomic_compare_and_swap_8(dst, expectedValue, desired); + if (result == expectedValue) { + return 1; + } else { + ma_atomic_store_explicit_8(expected, result, failureOrder); + return 0; + } } - } - static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_16(volatile ma_uint16* dst, ma_uint16* expected, ma_uint16 replacement, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) - { - ma_uint16 result; - (void)successOrder; - (void)failureOrder; - result = ma_atomic_compare_and_swap_16(dst, *expected, replacement); - if (result == *expected) { - return 1; - } else { - *expected = result; - return 0; + #endif + #if defined(MA_ATOMIC_HAS_16) + static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_16(volatile ma_uint16* dst, ma_uint16* expected, ma_uint16 desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) + { + ma_uint16 expectedValue; + ma_uint16 result; + (void)successOrder; + (void)failureOrder; + expectedValue = ma_atomic_load_explicit_16(expected, ma_atomic_memory_order_seq_cst); + result = ma_atomic_compare_and_swap_16(dst, expectedValue, desired); + if (result == expectedValue) { + return 1; + } else { + ma_atomic_store_explicit_16(expected, result, failureOrder); + return 0; + } } - } - static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_32(volatile ma_uint32* dst, ma_uint32* expected, ma_uint32 replacement, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) - { - ma_uint32 result; - (void)successOrder; - (void)failureOrder; - result = ma_atomic_compare_and_swap_32(dst, *expected, replacement); - if (result == *expected) { - return 1; - } else { - *expected = result; - return 0; + #endif + #if defined(MA_ATOMIC_HAS_32) + static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_32(volatile ma_uint32* dst, ma_uint32* expected, ma_uint32 desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) + { + ma_uint32 expectedValue; + ma_uint32 result; + (void)successOrder; + (void)failureOrder; + expectedValue = ma_atomic_load_explicit_32(expected, ma_atomic_memory_order_seq_cst); + result = ma_atomic_compare_and_swap_32(dst, expectedValue, desired); + if (result == expectedValue) { + return 1; + } else { + ma_atomic_store_explicit_32(expected, result, failureOrder); + return 0; + } } - } - static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_64(volatile ma_uint64* dst, volatile ma_uint64* expected, ma_uint64 replacement, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) - { - ma_uint64 result; - (void)successOrder; - (void)failureOrder; - result = ma_atomic_compare_and_swap_64(dst, *expected, replacement); - if (result == *expected) { - return 1; - } else { - *expected = result; - return 0; + #endif + #if defined(MA_ATOMIC_HAS_64) + static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_64(volatile ma_uint64* dst, volatile ma_uint64* expected, ma_uint64 desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) + { + ma_uint64 expectedValue; + ma_uint64 result; + (void)successOrder; + (void)failureOrder; + expectedValue = ma_atomic_load_explicit_64(expected, ma_atomic_memory_order_seq_cst); + result = ma_atomic_compare_and_swap_64(dst, expectedValue, desired); + if (result == expectedValue) { + return 1; + } else { + ma_atomic_store_explicit_64(expected, result, failureOrder); + return 0; + } } + #endif + #define ma_atomic_compare_exchange_weak_explicit_8( dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_8 (dst, expected, desired, successOrder, failureOrder) + #define ma_atomic_compare_exchange_weak_explicit_16(dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_16(dst, expected, desired, successOrder, failureOrder) + #define ma_atomic_compare_exchange_weak_explicit_32(dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_32(dst, expected, desired, successOrder, failureOrder) + #define ma_atomic_compare_exchange_weak_explicit_64(dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_64(dst, expected, desired, successOrder, failureOrder) +#endif +#if !defined(MA_ATOMIC_HAS_NATIVE_IS_LOCK_FREE) + static MA_INLINE ma_bool32 ma_atomic_is_lock_free_8(volatile void* ptr) + { + (void)ptr; + return 1; + } + static MA_INLINE ma_bool32 ma_atomic_is_lock_free_16(volatile void* ptr) + { + (void)ptr; + return 1; + } + static MA_INLINE ma_bool32 ma_atomic_is_lock_free_32(volatile void* ptr) + { + (void)ptr; + return 1; + } + static MA_INLINE ma_bool32 ma_atomic_is_lock_free_64(volatile void* ptr) + { + (void)ptr; + #if defined(MA_64BIT) + return 1; + #else + #if defined(MA_X86) || defined(MA_X64) + return 1; + #else + return 0; + #endif + #endif } - #define ma_atomic_compare_exchange_weak_explicit_8( dst, expected, replacement, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_8 (dst, expected, replacement, successOrder, failureOrder) - #define ma_atomic_compare_exchange_weak_explicit_16(dst, expected, replacement, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_16(dst, expected, replacement, successOrder, failureOrder) - #define ma_atomic_compare_exchange_weak_explicit_32(dst, expected, replacement, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_32(dst, expected, replacement, successOrder, failureOrder) - #define ma_atomic_compare_exchange_weak_explicit_64(dst, expected, replacement, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_64(dst, expected, replacement, successOrder, failureOrder) #endif #if defined(MA_64BIT) static MA_INLINE ma_bool32 ma_atomic_is_lock_free_ptr(volatile void** ptr) @@ -16968,17 +15561,17 @@ ma_atomic_spinlock ma_atomic_global_lock; { return (void*)ma_atomic_exchange_explicit_64((volatile ma_uint64*)dst, (ma_uint64)src, order); } - static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_ptr(volatile void** dst, void** expected, void* replacement, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) + static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_ptr(volatile void** dst, void** expected, void* desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) { - return ma_atomic_compare_exchange_strong_explicit_64((volatile ma_uint64*)dst, (ma_uint64*)expected, (ma_uint64)replacement, successOrder, failureOrder); + return ma_atomic_compare_exchange_strong_explicit_64((volatile ma_uint64*)dst, (ma_uint64*)expected, (ma_uint64)desired, successOrder, failureOrder); } - static MA_INLINE ma_bool32 ma_atomic_compare_exchange_weak_explicit_ptr(volatile void** dst, void** expected, void* replacement, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) + static MA_INLINE ma_bool32 ma_atomic_compare_exchange_weak_explicit_ptr(volatile void** dst, void** expected, void* desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) { - return ma_atomic_compare_exchange_weak_explicit_64((volatile ma_uint64*)dst, (ma_uint64*)expected, (ma_uint64)replacement, successOrder, failureOrder); + return ma_atomic_compare_exchange_weak_explicit_64((volatile ma_uint64*)dst, (ma_uint64*)expected, (ma_uint64)desired, successOrder, failureOrder); } - static MA_INLINE void* ma_atomic_compare_and_swap_ptr(volatile void** dst, void* expected, void* replacement) + static MA_INLINE void* ma_atomic_compare_and_swap_ptr(volatile void** dst, void* expected, void* desired) { - return (void*)ma_atomic_compare_and_swap_64((volatile ma_uint64*)dst, (ma_uint64)expected, (ma_uint64)replacement); + return (void*)ma_atomic_compare_and_swap_64((volatile ma_uint64*)dst, (ma_uint64)expected, (ma_uint64)desired); } #elif defined(MA_32BIT) static MA_INLINE ma_bool32 ma_atomic_is_lock_free_ptr(volatile void** ptr) @@ -16997,26 +15590,36 @@ ma_atomic_spinlock ma_atomic_global_lock; { return (void*)ma_atomic_exchange_explicit_32((volatile ma_uint32*)dst, (ma_uint32)src, order); } - static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_ptr(volatile void** dst, void** expected, void* replacement, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) + static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_ptr(volatile void** dst, void** expected, void* desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) { - return ma_atomic_compare_exchange_strong_explicit_32((volatile ma_uint32*)dst, (ma_uint32*)expected, (ma_uint32)replacement, successOrder, failureOrder); + return ma_atomic_compare_exchange_strong_explicit_32((volatile ma_uint32*)dst, (ma_uint32*)expected, (ma_uint32)desired, successOrder, failureOrder); } - static MA_INLINE ma_bool32 ma_atomic_compare_exchange_weak_explicit_ptr(volatile void** dst, void** expected, void* replacement, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) + static MA_INLINE ma_bool32 ma_atomic_compare_exchange_weak_explicit_ptr(volatile void** dst, void** expected, void* desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) { - return ma_atomic_compare_exchange_weak_explicit_32((volatile ma_uint32*)dst, (ma_uint32*)expected, (ma_uint32)replacement, successOrder, failureOrder); + return ma_atomic_compare_exchange_weak_explicit_32((volatile ma_uint32*)dst, (ma_uint32*)expected, (ma_uint32)desired, successOrder, failureOrder); } - static MA_INLINE void* ma_atomic_compare_and_swap_ptr(volatile void** dst, void* expected, void* replacement) + static MA_INLINE void* ma_atomic_compare_and_swap_ptr(volatile void** dst, void* expected, void* desired) { - return (void*)ma_atomic_compare_and_swap_32((volatile ma_uint32*)dst, (ma_uint32)expected, (ma_uint32)replacement); + return (void*)ma_atomic_compare_and_swap_32((volatile ma_uint32*)dst, (ma_uint32)expected, (ma_uint32)desired); } #else #error Unsupported architecture. #endif -#define ma_atomic_store_ptr(dst, src) ma_atomic_store_explicit_ptr((volatile void**)dst, (void*)src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_load_ptr(ptr) ma_atomic_load_explicit_ptr((volatile void**)ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_exchange_ptr(dst, src) ma_atomic_exchange_explicit_ptr((volatile void**)dst, (void*)src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_ptr(dst, expected, replacement) ma_atomic_compare_exchange_strong_explicit_ptr((volatile void**)dst, (void**)expected, (void*)replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_ptr(dst, expected, replacement) ma_atomic_compare_exchange_weak_explicit_ptr((volatile void**)dst, (void**)expected, (void*)replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_flag_test_and_set(ptr) ma_atomic_flag_test_and_set_explicit(ptr, ma_atomic_memory_order_seq_cst) +#define ma_atomic_flag_clear(ptr) ma_atomic_flag_clear_explicit(ptr, ma_atomic_memory_order_seq_cst) +#define ma_atomic_store_ptr(dst, src) ma_atomic_store_explicit_ptr((volatile void**)dst, (void*)src, ma_atomic_memory_order_seq_cst) +#define ma_atomic_load_ptr(ptr) ma_atomic_load_explicit_ptr((volatile void**)ptr, ma_atomic_memory_order_seq_cst) +#define ma_atomic_exchange_ptr(dst, src) ma_atomic_exchange_explicit_ptr((volatile void**)dst, (void*)src, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_strong_ptr(dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_ptr((volatile void**)dst, (void**)expected, (void*)desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_weak_ptr(dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_ptr((volatile void**)dst, (void**)expected, (void*)desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_test_and_set_8( ptr) ma_atomic_test_and_set_explicit_8( ptr, ma_atomic_memory_order_seq_cst) +#define ma_atomic_test_and_set_16(ptr) ma_atomic_test_and_set_explicit_16(ptr, ma_atomic_memory_order_seq_cst) +#define ma_atomic_test_and_set_32(ptr) ma_atomic_test_and_set_explicit_32(ptr, ma_atomic_memory_order_seq_cst) +#define ma_atomic_test_and_set_64(ptr) ma_atomic_test_and_set_explicit_64(ptr, ma_atomic_memory_order_seq_cst) +#define ma_atomic_clear_8( ptr) ma_atomic_clear_explicit_8( ptr, ma_atomic_memory_order_seq_cst) +#define ma_atomic_clear_16(ptr) ma_atomic_clear_explicit_16(ptr, ma_atomic_memory_order_seq_cst) +#define ma_atomic_clear_32(ptr) ma_atomic_clear_explicit_32(ptr, ma_atomic_memory_order_seq_cst) +#define ma_atomic_clear_64(ptr) ma_atomic_clear_explicit_64(ptr, ma_atomic_memory_order_seq_cst) #define ma_atomic_store_8( dst, src) ma_atomic_store_explicit_8( dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_store_16(dst, src) ma_atomic_store_explicit_16(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_store_32(dst, src) ma_atomic_store_explicit_32(dst, src, ma_atomic_memory_order_seq_cst) @@ -17029,14 +15632,14 @@ ma_atomic_spinlock ma_atomic_global_lock; #define ma_atomic_exchange_16(dst, src) ma_atomic_exchange_explicit_16(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_exchange_32(dst, src) ma_atomic_exchange_explicit_32(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_exchange_64(dst, src) ma_atomic_exchange_explicit_64(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_8( dst, expected, replacement) ma_atomic_compare_exchange_strong_explicit_8( dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_16(dst, expected, replacement) ma_atomic_compare_exchange_strong_explicit_16(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_32(dst, expected, replacement) ma_atomic_compare_exchange_strong_explicit_32(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_64(dst, expected, replacement) ma_atomic_compare_exchange_strong_explicit_64(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_8( dst, expected, replacement) ma_atomic_compare_exchange_weak_explicit_8( dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_16( dst, expected, replacement) ma_atomic_compare_exchange_weak_explicit_16(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_32( dst, expected, replacement) ma_atomic_compare_exchange_weak_explicit_32(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_64( dst, expected, replacement) ma_atomic_compare_exchange_weak_explicit_64(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_strong_8( dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_8( dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_strong_16(dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_16(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_strong_32(dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_32(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_strong_64(dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_64(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_weak_8( dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_8( dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_weak_16( dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_16(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_weak_32( dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_32(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_weak_64( dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_64(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) #define ma_atomic_fetch_add_8( dst, src) ma_atomic_fetch_add_explicit_8( dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_fetch_add_16(dst, src) ma_atomic_fetch_add_explicit_16(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_fetch_add_32(dst, src) ma_atomic_fetch_add_explicit_32(dst, src, ma_atomic_memory_order_seq_cst) @@ -17057,6 +15660,14 @@ ma_atomic_spinlock ma_atomic_global_lock; #define ma_atomic_fetch_and_16(dst, src) ma_atomic_fetch_and_explicit_16(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_fetch_and_32(dst, src) ma_atomic_fetch_and_explicit_32(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_fetch_and_64(dst, src) ma_atomic_fetch_and_explicit_64(dst, src, ma_atomic_memory_order_seq_cst) +#define ma_atomic_test_and_set_explicit_i8( ptr, order) (ma_int8 )ma_atomic_test_and_set_explicit_8( (ma_uint8* )ptr, order) +#define ma_atomic_test_and_set_explicit_i16(ptr, order) (ma_int16)ma_atomic_test_and_set_explicit_16((ma_uint16*)ptr, order) +#define ma_atomic_test_and_set_explicit_i32(ptr, order) (ma_int32)ma_atomic_test_and_set_explicit_32((ma_uint32*)ptr, order) +#define ma_atomic_test_and_set_explicit_i64(ptr, order) (ma_int64)ma_atomic_test_and_set_explicit_64((ma_uint64*)ptr, order) +#define ma_atomic_clear_explicit_i8( ptr, order) ma_atomic_clear_explicit_8( (ma_uint8* )ptr, order) +#define ma_atomic_clear_explicit_i16(ptr, order) ma_atomic_clear_explicit_16((ma_uint16*)ptr, order) +#define ma_atomic_clear_explicit_i32(ptr, order) ma_atomic_clear_explicit_32((ma_uint32*)ptr, order) +#define ma_atomic_clear_explicit_i64(ptr, order) ma_atomic_clear_explicit_64((ma_uint64*)ptr, order) #define ma_atomic_store_explicit_i8( dst, src, order) ma_atomic_store_explicit_8( (ma_uint8* )dst, (ma_uint8 )src, order) #define ma_atomic_store_explicit_i16(dst, src, order) ma_atomic_store_explicit_16((ma_uint16*)dst, (ma_uint16)src, order) #define ma_atomic_store_explicit_i32(dst, src, order) ma_atomic_store_explicit_32((ma_uint32*)dst, (ma_uint32)src, order) @@ -17069,14 +15680,14 @@ ma_atomic_spinlock ma_atomic_global_lock; #define ma_atomic_exchange_explicit_i16(dst, src, order) (ma_int16)ma_atomic_exchange_explicit_16((ma_uint16*)dst, (ma_uint16)src, order) #define ma_atomic_exchange_explicit_i32(dst, src, order) (ma_int32)ma_atomic_exchange_explicit_32((ma_uint32*)dst, (ma_uint32)src, order) #define ma_atomic_exchange_explicit_i64(dst, src, order) (ma_int64)ma_atomic_exchange_explicit_64((ma_uint64*)dst, (ma_uint64)src, order) -#define ma_atomic_compare_exchange_strong_explicit_i8( dst, expected, replacement, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_8( (ma_uint8* )dst, (ma_uint8* )expected, (ma_uint8 )replacement, successOrder, failureOrder) -#define ma_atomic_compare_exchange_strong_explicit_i16(dst, expected, replacement, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_16((ma_uint16*)dst, (ma_uint16*)expected, (ma_uint16)replacement, successOrder, failureOrder) -#define ma_atomic_compare_exchange_strong_explicit_i32(dst, expected, replacement, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_32((ma_uint32*)dst, (ma_uint32*)expected, (ma_uint32)replacement, successOrder, failureOrder) -#define ma_atomic_compare_exchange_strong_explicit_i64(dst, expected, replacement, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_64((ma_uint64*)dst, (ma_uint64*)expected, (ma_uint64)replacement, successOrder, failureOrder) -#define ma_atomic_compare_exchange_weak_explicit_i8( dst, expected, replacement, successOrder, failureOrder) ma_atomic_compare_exchange_weak_explicit_8( (ma_uint8* )dst, (ma_uint8* )expected, (ma_uint8 )replacement, successOrder, failureOrder) -#define ma_atomic_compare_exchange_weak_explicit_i16(dst, expected, replacement, successOrder, failureOrder) ma_atomic_compare_exchange_weak_explicit_16((ma_uint16*)dst, (ma_uint16*)expected, (ma_uint16)replacement, successOrder, failureOrder) -#define ma_atomic_compare_exchange_weak_explicit_i32(dst, expected, replacement, successOrder, failureOrder) ma_atomic_compare_exchange_weak_explicit_32((ma_uint32*)dst, (ma_uint32*)expected, (ma_uint32)replacement, successOrder, failureOrder) -#define ma_atomic_compare_exchange_weak_explicit_i64(dst, expected, replacement, successOrder, failureOrder) ma_atomic_compare_exchange_weak_explicit_64((ma_uint64*)dst, (ma_uint64*)expected, (ma_uint64)replacement, successOrder, failureOrder) +#define ma_atomic_compare_exchange_strong_explicit_i8( dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_8( (ma_uint8* )dst, (ma_uint8* )expected, (ma_uint8 )desired, successOrder, failureOrder) +#define ma_atomic_compare_exchange_strong_explicit_i16(dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_16((ma_uint16*)dst, (ma_uint16*)expected, (ma_uint16)desired, successOrder, failureOrder) +#define ma_atomic_compare_exchange_strong_explicit_i32(dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_32((ma_uint32*)dst, (ma_uint32*)expected, (ma_uint32)desired, successOrder, failureOrder) +#define ma_atomic_compare_exchange_strong_explicit_i64(dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_64((ma_uint64*)dst, (ma_uint64*)expected, (ma_uint64)desired, successOrder, failureOrder) +#define ma_atomic_compare_exchange_weak_explicit_i8( dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_weak_explicit_8( (ma_uint8* )dst, (ma_uint8* )expected, (ma_uint8 )desired, successOrder, failureOrder) +#define ma_atomic_compare_exchange_weak_explicit_i16(dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_weak_explicit_16((ma_uint16*)dst, (ma_uint16*)expected, (ma_uint16)desired, successOrder, failureOrder) +#define ma_atomic_compare_exchange_weak_explicit_i32(dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_weak_explicit_32((ma_uint32*)dst, (ma_uint32*)expected, (ma_uint32)desired, successOrder, failureOrder) +#define ma_atomic_compare_exchange_weak_explicit_i64(dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_weak_explicit_64((ma_uint64*)dst, (ma_uint64*)expected, (ma_uint64)desired, successOrder, failureOrder) #define ma_atomic_fetch_add_explicit_i8( dst, src, order) (ma_int8 )ma_atomic_fetch_add_explicit_8( (ma_uint8* )dst, (ma_uint8 )src, order) #define ma_atomic_fetch_add_explicit_i16(dst, src, order) (ma_int16)ma_atomic_fetch_add_explicit_16((ma_uint16*)dst, (ma_uint16)src, order) #define ma_atomic_fetch_add_explicit_i32(dst, src, order) (ma_int32)ma_atomic_fetch_add_explicit_32((ma_uint32*)dst, (ma_uint32)src, order) @@ -17097,6 +15708,14 @@ ma_atomic_spinlock ma_atomic_global_lock; #define ma_atomic_fetch_and_explicit_i16(dst, src, order) (ma_int16)ma_atomic_fetch_and_explicit_16((ma_uint16*)dst, (ma_uint16)src, order) #define ma_atomic_fetch_and_explicit_i32(dst, src, order) (ma_int32)ma_atomic_fetch_and_explicit_32((ma_uint32*)dst, (ma_uint32)src, order) #define ma_atomic_fetch_and_explicit_i64(dst, src, order) (ma_int64)ma_atomic_fetch_and_explicit_64((ma_uint64*)dst, (ma_uint64)src, order) +#define ma_atomic_test_and_set_i8( ptr) ma_atomic_test_and_set_explicit_i8( ptr, ma_atomic_memory_order_seq_cst) +#define ma_atomic_test_and_set_i16(ptr) ma_atomic_test_and_set_explicit_i16(ptr, ma_atomic_memory_order_seq_cst) +#define ma_atomic_test_and_set_i32(ptr) ma_atomic_test_and_set_explicit_i32(ptr, ma_atomic_memory_order_seq_cst) +#define ma_atomic_test_and_set_i64(ptr) ma_atomic_test_and_set_explicit_i64(ptr, ma_atomic_memory_order_seq_cst) +#define ma_atomic_clear_i8( ptr) ma_atomic_clear_explicit_i8( ptr, ma_atomic_memory_order_seq_cst) +#define ma_atomic_clear_i16(ptr) ma_atomic_clear_explicit_i16(ptr, ma_atomic_memory_order_seq_cst) +#define ma_atomic_clear_i32(ptr) ma_atomic_clear_explicit_i32(ptr, ma_atomic_memory_order_seq_cst) +#define ma_atomic_clear_i64(ptr) ma_atomic_clear_explicit_i64(ptr, ma_atomic_memory_order_seq_cst) #define ma_atomic_store_i8( dst, src) ma_atomic_store_explicit_i8( dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_store_i16(dst, src) ma_atomic_store_explicit_i16(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_store_i32(dst, src) ma_atomic_store_explicit_i32(dst, src, ma_atomic_memory_order_seq_cst) @@ -17109,14 +15728,14 @@ ma_atomic_spinlock ma_atomic_global_lock; #define ma_atomic_exchange_i16(dst, src) ma_atomic_exchange_explicit_i16(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_exchange_i32(dst, src) ma_atomic_exchange_explicit_i32(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_exchange_i64(dst, src) ma_atomic_exchange_explicit_i64(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_i8( dst, expected, replacement) ma_atomic_compare_exchange_strong_explicit_i8( dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_i16(dst, expected, replacement) ma_atomic_compare_exchange_strong_explicit_i16(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_i32(dst, expected, replacement) ma_atomic_compare_exchange_strong_explicit_i32(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_i64(dst, expected, replacement) ma_atomic_compare_exchange_strong_explicit_i64(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_i8( dst, expected, replacement) ma_atomic_compare_exchange_weak_explicit_i8( dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_i16(dst, expected, replacement) ma_atomic_compare_exchange_weak_explicit_i16(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_i32(dst, expected, replacement) ma_atomic_compare_exchange_weak_explicit_i32(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_i64(dst, expected, replacement) ma_atomic_compare_exchange_weak_explicit_i64(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_strong_i8( dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_i8( dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_strong_i16(dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_i16(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_strong_i32(dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_i32(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_strong_i64(dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_i64(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_weak_i8( dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_i8( dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_weak_i16(dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_i16(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_weak_i32(dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_i32(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_weak_i64(dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_i64(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) #define ma_atomic_fetch_add_i8( dst, src) ma_atomic_fetch_add_explicit_i8( dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_fetch_add_i16(dst, src) ma_atomic_fetch_add_explicit_i16(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_fetch_add_i32(dst, src) ma_atomic_fetch_add_explicit_i32(dst, src, ma_atomic_memory_order_seq_cst) @@ -17193,28 +15812,28 @@ static MA_INLINE double ma_atomic_exchange_explicit_f64(volatile double* dst, do r.i = ma_atomic_exchange_explicit_64((volatile ma_uint64*)dst, x.i, order); return r.f; } -static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_f32(volatile float* dst, float* expected, float replacement, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) +static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_f32(volatile float* dst, float* expected, float desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) { ma_atomic_if32 d; - d.f = replacement; + d.f = desired; return ma_atomic_compare_exchange_strong_explicit_32((volatile ma_uint32*)dst, (ma_uint32*)expected, d.i, successOrder, failureOrder); } -static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_f64(volatile double* dst, double* expected, double replacement, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) +static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_f64(volatile double* dst, double* expected, double desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) { ma_atomic_if64 d; - d.f = replacement; + d.f = desired; return ma_atomic_compare_exchange_strong_explicit_64((volatile ma_uint64*)dst, (ma_uint64*)expected, d.i, successOrder, failureOrder); } -static MA_INLINE ma_bool32 ma_atomic_compare_exchange_weak_explicit_f32(volatile float* dst, float* expected, float replacement, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) +static MA_INLINE ma_bool32 ma_atomic_compare_exchange_weak_explicit_f32(volatile float* dst, float* expected, float desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) { ma_atomic_if32 d; - d.f = replacement; + d.f = desired; return ma_atomic_compare_exchange_weak_explicit_32((volatile ma_uint32*)dst, (ma_uint32*)expected, d.i, successOrder, failureOrder); } -static MA_INLINE ma_bool32 ma_atomic_compare_exchange_weak_explicit_f64(volatile double* dst, double* expected, double replacement, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) +static MA_INLINE ma_bool32 ma_atomic_compare_exchange_weak_explicit_f64(volatile double* dst, double* expected, double desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) { ma_atomic_if64 d; - d.f = replacement; + d.f = desired; return ma_atomic_compare_exchange_weak_explicit_64((volatile ma_uint64*)dst, (ma_uint64*)expected, d.i, successOrder, failureOrder); } static MA_INLINE float ma_atomic_fetch_add_explicit_f32(volatile float* dst, float src, ma_atomic_memory_order order) @@ -17305,10 +15924,10 @@ static MA_INLINE double ma_atomic_fetch_and_explicit_f64(volatile double* dst, d #define ma_atomic_load_f64(ptr) (double)ma_atomic_load_explicit_f64(ptr, ma_atomic_memory_order_seq_cst) #define ma_atomic_exchange_f32(dst, src) (float )ma_atomic_exchange_explicit_f32(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_exchange_f64(dst, src) (double)ma_atomic_exchange_explicit_f64(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_f32(dst, expected, replacement) ma_atomic_compare_exchange_strong_explicit_f32(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_f64(dst, expected, replacement) ma_atomic_compare_exchange_strong_explicit_f64(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_f32(dst, expected, replacement) ma_atomic_compare_exchange_weak_explicit_f32(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_f64(dst, expected, replacement) ma_atomic_compare_exchange_weak_explicit_f64(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_strong_f32(dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_f32(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_strong_f64(dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_f64(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_weak_f32(dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_f32(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_weak_f64(dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_f64(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) #define ma_atomic_fetch_add_f32(dst, src) ma_atomic_fetch_add_explicit_f32(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_fetch_add_f64(dst, src) ma_atomic_fetch_add_explicit_f64(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_fetch_sub_f32(dst, src) ma_atomic_fetch_sub_explicit_f32(dst, src, ma_atomic_memory_order_seq_cst) @@ -17319,24 +15938,39 @@ static MA_INLINE double ma_atomic_fetch_and_explicit_f64(volatile double* dst, d #define ma_atomic_fetch_xor_f64(dst, src) ma_atomic_fetch_xor_explicit_f64(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_fetch_and_f32(dst, src) ma_atomic_fetch_and_explicit_f32(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_fetch_and_f64(dst, src) ma_atomic_fetch_and_explicit_f64(dst, src, ma_atomic_memory_order_seq_cst) -static MA_INLINE float ma_atomic_compare_and_swap_f32(volatile float* dst, float expected, float replacement) +static MA_INLINE float ma_atomic_compare_and_swap_f32(volatile float* dst, float expected, float desired) { ma_atomic_if32 r; ma_atomic_if32 e, d; e.f = expected; - d.f = replacement; + d.f = desired; r.i = ma_atomic_compare_and_swap_32((volatile ma_uint32*)dst, e.i, d.i); return r.f; } -static MA_INLINE double ma_atomic_compare_and_swap_f64(volatile double* dst, double expected, double replacement) +static MA_INLINE double ma_atomic_compare_and_swap_f64(volatile double* dst, double expected, double desired) { ma_atomic_if64 r; ma_atomic_if64 e, d; e.f = expected; - d.f = replacement; + d.f = desired; r.i = ma_atomic_compare_and_swap_64((volatile ma_uint64*)dst, e.i, d.i); return r.f; } +typedef ma_atomic_flag ma_atomic_spinlock; +static MA_INLINE void ma_atomic_spinlock_lock(volatile ma_atomic_spinlock* pSpinlock) +{ + for (;;) { + if (ma_atomic_flag_test_and_set_explicit(pSpinlock, ma_atomic_memory_order_acquire) == 0) { + break; + } + while (ma_atomic_flag_load_explicit(pSpinlock, ma_atomic_memory_order_relaxed) == 1) { + } + } +} +static MA_INLINE void ma_atomic_spinlock_unlock(volatile ma_atomic_spinlock* pSpinlock) +{ + ma_atomic_flag_clear_explicit(pSpinlock, ma_atomic_memory_order_release); +} #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) #pragma GCC diagnostic pop #endif @@ -17542,7 +16176,7 @@ static ma_result ma_thread_create__posix(ma_thread* pThread, ma_thread_priority int result; pthread_attr_t* pAttr = NULL; -#if !defined(MA_EMSCRIPTEN) && !defined(MA_3DS) && !defined(MA_SWITCH) +#if !defined(__EMSCRIPTEN__) && !defined(__3DS__) /* Try setting the thread priority. It's not critical if anything fails here. */ pthread_attr_t attr; if (pthread_attr_init(&attr) == 0) { @@ -17574,18 +16208,9 @@ static ma_result ma_thread_create__posix(ma_thread* pThread, ma_thread_priority } #endif - #if defined(_POSIX_THREAD_ATTR_STACKSIZE) && _POSIX_THREAD_ATTR_STACKSIZE >= 0 - { - if (stackSize > 0) { - pthread_attr_setstacksize(&attr, stackSize); - } + if (stackSize > 0) { + pthread_attr_setstacksize(&attr, stackSize); } - #else - { - (void)stackSize; /* Suppress unused parameter warning. */ - } - #endif - if (scheduler != -1) { int priorityMin = sched_get_priority_min(scheduler); @@ -17642,21 +16267,6 @@ static ma_result ma_thread_create__posix(ma_thread* pThread, ma_thread_priority } if (result != 0) { - /* - There have been reports that attempting to create a realtime thread can sometimes fail. In this case, - fall back to a normal priority thread. - - I'm including a compile-time option here to disable this functionality for those who have a hard - requirement on realtime threads and would rather an explicit failure. - */ - #ifndef MA_NO_PTHREAD_REALTIME_PRIORITY_FALLBACK - { - if(result == EPERM && priority == ma_thread_priority_realtime) { - return ma_thread_create__posix(pThread, ma_thread_priority_normal, stackSize, entryProc, pData); - } - } - #endif - return ma_result_from_errno(result); } @@ -17928,7 +16538,7 @@ static ma_result ma_event_signal__win32(ma_event* pEvent) static ma_result ma_semaphore_init__win32(int initialValue, ma_semaphore* pSemaphore) { - *pSemaphore = CreateSemaphore(NULL, (LONG)initialValue, LONG_MAX, NULL); + *pSemaphore = CreateSemaphoreW(NULL, (LONG)initialValue, LONG_MAX, NULL); if (*pSemaphore == NULL) { return ma_result_from_GetLastError(GetLastError()); } @@ -18822,12 +17432,10 @@ static MA_INLINE ma_uint16 ma_job_extract_slot(ma_uint64 toc) return (ma_uint16)(toc & 0x0000FFFF); } -#if 0 /* Currently unused, but might make use of this later. */ static MA_INLINE ma_uint16 ma_job_extract_code(ma_uint64 toc) { return (ma_uint16)((toc & 0xFFFF0000) >> 16); } -#endif static MA_INLINE ma_uint64 ma_job_toc_to_allocation(ma_uint64 toc) { @@ -19292,13 +17900,6 @@ MA_API ma_result ma_job_queue_next(ma_job_queue* pQueue, ma_job* pJob) Dynamic Linking *******************************************************************************/ -/* Disable run-time linking on certain backends and platforms. */ -#ifndef MA_NO_RUNTIME_LINKING - #if defined(MA_EMSCRIPTEN) || defined(MA_ORBIS) || defined(MA_PROSPERO) || defined(MA_SWITCH) || defined(MA_DOS) - #define MA_NO_RUNTIME_LINKING - #endif -#endif - #ifdef MA_POSIX /* No need for dlfcn.h if we're not using runtime linking. */ #ifndef MA_NO_RUNTIME_LINKING @@ -19308,124 +17909,104 @@ Dynamic Linking MA_API ma_handle ma_dlopen(ma_log* pLog, const char* filename) { - #ifndef MA_NO_RUNTIME_LINKING - { - ma_handle handle; +#ifndef MA_NO_RUNTIME_LINKING + ma_handle handle; - ma_log_postf(pLog, MA_LOG_LEVEL_DEBUG, "Loading library: %s\n", filename); + ma_log_postf(pLog, MA_LOG_LEVEL_DEBUG, "Loading library: %s\n", filename); - #ifdef MA_WIN32 - /* From MSDN: Desktop applications cannot use LoadPackagedLibrary; if a desktop application calls this function it fails with APPMODEL_ERROR_NO_PACKAGE.*/ - #if !defined(MA_WIN32_UWP) || !(defined(WINAPI_FAMILY) && ((defined(WINAPI_FAMILY_PHONE_APP) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP))) - handle = (ma_handle)LoadLibraryA(filename); - #else - /* *sigh* It appears there is no ANSI version of LoadPackagedLibrary()... */ - WCHAR filenameW[4096]; - if (MultiByteToWideChar(CP_UTF8, 0, filename, -1, filenameW, sizeof(filenameW)) == 0) { - handle = NULL; - } else { - handle = (ma_handle)LoadPackagedLibrary(filenameW, 0); - } - #endif + #ifdef MA_WIN32 + /* From MSDN: Desktop applications cannot use LoadPackagedLibrary; if a desktop application calls this function it fails with APPMODEL_ERROR_NO_PACKAGE.*/ + #if !defined(MA_WIN32_UWP) || !(defined(WINAPI_FAMILY) && ((defined(WINAPI_FAMILY_PHONE_APP) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP))) + handle = (ma_handle)LoadLibraryA(filename); #else - handle = (ma_handle)dlopen(filename, RTLD_NOW); + /* *sigh* It appears there is no ANSI version of LoadPackagedLibrary()... */ + WCHAR filenameW[4096]; + if (MultiByteToWideChar(CP_UTF8, 0, filename, -1, filenameW, sizeof(filenameW)) == 0) { + handle = NULL; + } else { + handle = (ma_handle)LoadPackagedLibrary(filenameW, 0); + } #endif - - /* - I'm not considering failure to load a library an error nor a warning because seamlessly falling through to a lower-priority - backend is a deliberate design choice. Instead I'm logging it as an informational message. - */ - if (handle == NULL) { - ma_log_postf(pLog, MA_LOG_LEVEL_INFO, "Failed to load library: %s\n", filename); - } - - return handle; - } #else - { - /* Runtime linking is disabled. */ - (void)pLog; - (void)filename; - return NULL; - } + handle = (ma_handle)dlopen(filename, RTLD_NOW); #endif + + /* + I'm not considering failure to load a library an error nor a warning because seamlessly falling through to a lower-priority + backend is a deliberate design choice. Instead I'm logging it as an informational message. + */ + if (handle == NULL) { + ma_log_postf(pLog, MA_LOG_LEVEL_INFO, "Failed to load library: %s\n", filename); + } + + return handle; +#else + /* Runtime linking is disabled. */ + (void)pLog; + (void)filename; + return NULL; +#endif } MA_API void ma_dlclose(ma_log* pLog, ma_handle handle) { - #ifndef MA_NO_RUNTIME_LINKING - { - #ifdef MA_WIN32 +#ifndef MA_NO_RUNTIME_LINKING + #ifdef MA_WIN32 + FreeLibrary((HMODULE)handle); + #else + /* Hack for Android bug (see https://github.com/android/ndk/issues/360). Calling dlclose() pre-API 28 may segfault. */ + #if !defined(MA_ANDROID) || (defined(__ANDROID_API__) && __ANDROID_API__ >= 28) { - FreeLibrary((HMODULE)handle); + dlclose((void*)handle); } #else { - /* Hack for Android bug (see https://github.com/android/ndk/issues/360). Calling dlclose() pre-API 28 may segfault. */ - #if !defined(MA_ANDROID) || (defined(__ANDROID_API__) && __ANDROID_API__ >= 28) - { - dlclose((void*)handle); - } - #else - { - (void)handle; - } - #endif + (void)handle; } #endif - - (void)pLog; - } - #else - { - /* Runtime linking is disabled. */ - (void)pLog; - (void)handle; - } #endif + + (void)pLog; +#else + /* Runtime linking is disabled. */ + (void)pLog; + (void)handle; +#endif } MA_API ma_proc ma_dlsym(ma_log* pLog, ma_handle handle, const char* symbol) { - #ifndef MA_NO_RUNTIME_LINKING - { - ma_proc proc; +#ifndef MA_NO_RUNTIME_LINKING + ma_proc proc; - ma_log_postf(pLog, MA_LOG_LEVEL_DEBUG, "Loading symbol: %s\n", symbol); + ma_log_postf(pLog, MA_LOG_LEVEL_DEBUG, "Loading symbol: %s\n", symbol); - #ifdef _WIN32 - { - proc = (ma_proc)GetProcAddress((HMODULE)handle, symbol); - } - #else - { - #if (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) || defined(__clang__) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wpedantic" - #endif - proc = (ma_proc)dlsym((void*)handle, symbol); - #if (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) || defined(__clang__) - #pragma GCC diagnostic pop - #endif - } - #endif +#ifdef _WIN32 + proc = (ma_proc)GetProcAddress((HMODULE)handle, symbol); +#else +#if (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) || defined(__clang__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wpedantic" +#endif + proc = (ma_proc)dlsym((void*)handle, symbol); +#if (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) || defined(__clang__) + #pragma GCC diagnostic pop +#endif +#endif - if (proc == NULL) { - ma_log_postf(pLog, MA_LOG_LEVEL_WARNING, "Failed to load symbol: %s\n", symbol); - } - - (void)pLog; /* It's possible for pContext to be unused. */ - return proc; + if (proc == NULL) { + ma_log_postf(pLog, MA_LOG_LEVEL_WARNING, "Failed to load symbol: %s\n", symbol); } - #else - { - /* Runtime linking is disabled. */ - (void)pLog; - (void)handle; - (void)symbol; - return NULL; - } - #endif + + (void)pLog; /* It's possible for pContext to be unused. */ + return proc; +#else + /* Runtime linking is disabled. */ + (void)pLog; + (void)handle; + (void)symbol; + return NULL; +#endif } @@ -19439,6 +18020,13 @@ DEVICE I/O ************************************************************************************************************************************************************* ************************************************************************************************************************************************************/ +/* Disable run-time linking on certain backends and platforms. */ +#ifndef MA_NO_RUNTIME_LINKING + #if defined(MA_EMSCRIPTEN) || defined(MA_ORBIS) || defined(MA_PROSPERO) + #define MA_NO_RUNTIME_LINKING + #endif +#endif + #ifdef MA_APPLE #include #endif @@ -19451,6 +18039,12 @@ DEVICE I/O #ifdef MA_POSIX #include + #include + + /* No need for dlfcn.h if we're not using runtime linking. */ + #ifndef MA_NO_RUNTIME_LINKING + #include + #endif #endif /* This must be set to at least 26. */ @@ -19705,7 +18299,7 @@ MA_API ma_bool32 ma_is_loopback_supported(ma_backend backend) -#if defined(MA_WIN32) && !defined(MA_XBOX) +#if defined(MA_WIN32) /* WASAPI error codes. */ #define MA_AUDCLNT_E_NOT_INITIALIZED ((HRESULT)0x88890001) #define MA_AUDCLNT_E_ALREADY_INITIALIZED ((HRESULT)0x88890002) @@ -19920,11 +18514,6 @@ typedef LONG (WINAPI * MA_PFN_RegCloseKey)(HKEY hKey); typedef LONG (WINAPI * MA_PFN_RegQueryValueExA)(HKEY hKey, const char* lpValueName, DWORD* lpReserved, DWORD* lpType, BYTE* lpData, DWORD* lpcbData); #endif /* MA_WIN32_DESKTOP */ -static GUID MA_GUID_KSDATAFORMAT_SUBTYPE_PCM = {0x00000001, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; -static GUID MA_GUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = {0x00000003, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; -/*static GUID MA_GUID_KSDATAFORMAT_SUBTYPE_ALAW = {0x00000006, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};*/ -/*static GUID MA_GUID_KSDATAFORMAT_SUBTYPE_MULAW = {0x00000007, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};*/ - MA_API size_t ma_strlen_WCHAR(const WCHAR* str) { size_t len = 0; @@ -19988,7 +18577,7 @@ Timing *******************************************************************************/ #if defined(MA_WIN32) && !defined(MA_POSIX) static LARGE_INTEGER g_ma_TimerFrequency; /* <-- Initialized to zero since it's static. */ - static MA_INLINE void ma_timer_init(ma_timer* pTimer) + static void ma_timer_init(ma_timer* pTimer) { LARGE_INTEGER counter; @@ -20000,7 +18589,7 @@ Timing pTimer->counter = counter.QuadPart; } - static MA_INLINE double ma_timer_get_time_in_seconds(ma_timer* pTimer) + static double ma_timer_get_time_in_seconds(ma_timer* pTimer) { LARGE_INTEGER counter; if (!QueryPerformanceCounter(&counter)) { @@ -20011,7 +18600,7 @@ Timing } #elif defined(MA_APPLE) && (MAC_OS_X_VERSION_MIN_REQUIRED < 101200) static ma_uint64 g_ma_TimerFrequency = 0; - static MA_INLINE void ma_timer_init(ma_timer* pTimer) + static void ma_timer_init(ma_timer* pTimer) { mach_timebase_info_data_t baseTime; mach_timebase_info(&baseTime); @@ -20020,7 +18609,7 @@ Timing pTimer->counter = mach_absolute_time(); } - static MA_INLINE double ma_timer_get_time_in_seconds(ma_timer* pTimer) + static double ma_timer_get_time_in_seconds(ma_timer* pTimer) { ma_uint64 newTimeCounter = mach_absolute_time(); ma_uint64 oldTimeCounter = pTimer->counter; @@ -20045,7 +18634,7 @@ Timing #define MA_CLOCK_ID CLOCK_REALTIME #endif - static MA_INLINE void ma_timer_init(ma_timer* pTimer) + static void ma_timer_init(ma_timer* pTimer) { struct timespec newTime; clock_gettime(MA_CLOCK_ID, &newTime); @@ -20053,7 +18642,7 @@ Timing pTimer->counter = (newTime.tv_sec * 1000000000) + newTime.tv_nsec; } - static MA_INLINE double ma_timer_get_time_in_seconds(ma_timer* pTimer) + static double ma_timer_get_time_in_seconds(ma_timer* pTimer) { ma_uint64 newTimeCounter; ma_uint64 oldTimeCounter; @@ -20067,7 +18656,7 @@ Timing return (newTimeCounter - oldTimeCounter) / 1000000000.0; } #else - static MA_INLINE void ma_timer_init(ma_timer* pTimer) + static void ma_timer_init(ma_timer* pTimer) { struct timeval newTime; gettimeofday(&newTime, NULL); @@ -20075,7 +18664,7 @@ Timing pTimer->counter = (newTime.tv_sec * 1000000) + newTime.tv_usec; } - static MA_INLINE double ma_timer_get_time_in_seconds(ma_timer* pTimer) + static double ma_timer_get_time_in_seconds(ma_timer* pTimer) { ma_uint64 newTimeCounter; ma_uint64 oldTimeCounter; @@ -20659,6 +19248,14 @@ static MA_INLINE void ma_device__set_state(ma_device* pDevice, ma_device_state n } +#if defined(MA_WIN32) + static GUID MA_GUID_KSDATAFORMAT_SUBTYPE_PCM = {0x00000001, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; + static GUID MA_GUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = {0x00000003, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; + /*static GUID MA_GUID_KSDATAFORMAT_SUBTYPE_ALAW = {0x00000006, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};*/ + /*static GUID MA_GUID_KSDATAFORMAT_SUBTYPE_MULAW = {0x00000007, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};*/ +#endif + + MA_API ma_uint32 ma_get_format_priority_index(ma_format format) /* Lower = better. */ { @@ -21370,7 +19967,7 @@ static ma_result ma_context_init__null(ma_context* pContext, const ma_context_co WIN32 COMMON *******************************************************************************/ -#if defined(MA_WIN32) && !defined(MA_XBOX) +#if defined(MA_WIN32) #if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) #define ma_CoInitializeEx(pContext, pvReserved, dwCoInit) ((pContext->win32.CoInitializeEx) ? ((MA_PFN_CoInitializeEx)pContext->win32.CoInitializeEx)(pvReserved, dwCoInit) : ((MA_PFN_CoInitialize)pContext->win32.CoInitialize)(pvReserved)) #define ma_CoUninitialize(pContext) ((MA_PFN_CoUninitialize)pContext->win32.CoUninitialize)() @@ -21385,7 +19982,7 @@ WIN32 COMMON #define ma_PropVariantClear(pContext, pvar) PropVariantClear(pvar) #endif -#if !defined(MAXULONG_PTR) && !defined(__WATCOMC__) && !defined(MA_XBOX_NXDK) +#if !defined(MAXULONG_PTR) && !defined(__WATCOMC__) typedef size_t DWORD_PTR; #endif @@ -21812,21 +20409,11 @@ typedef enum MA_AudioCategory_Other = 0 /* <-- miniaudio is only caring about Other. */ } MA_AUDIO_STREAM_CATEGORY; -typedef enum -{ - MA_AUDCLNT_STREAMOPTIONS_NONE, - MA_AUDCLNT_STREAMOPTIONS_RAW, - MA_AUDCLNT_STREAMOPTIONS_MATCH_FORMAT, - MA_AUDCLNT_STREAMOPTIONS_AMBISONICS, - MA_AUDCLNT_STREAMOPTIONS_POST_VOLUME_LOOPBACK -} MA_AUDCLNT_STREAMOPTIONS; - typedef struct { ma_uint32 cbSize; BOOL bIsOffload; MA_AUDIO_STREAM_CATEGORY eCategory; - MA_AUDCLNT_STREAMOPTIONS Options; } ma_AudioClientProperties; /* IUnknown */ @@ -23001,7 +21588,6 @@ static ma_result ma_context_get_MMDevice__wasapi(ma_context* pContext, ma_device { ma_IMMDeviceEnumerator* pDeviceEnumerator; HRESULT hr; - HRESULT CoInitializeResult; MA_ASSERT(pContext != NULL); MA_ASSERT(ppMMDevice != NULL); @@ -23015,17 +21601,12 @@ static ma_result ma_context_get_MMDevice__wasapi(ma_context* pContext, ma_device The community has reported that this seems to fix the crash. There are future plans to move all WASAPI operation over to a single thread to make everything safer, but in the meantime while we wait for that to come online I'm happy enough to use this hack instead. - - CoUninitialize should only be called if we successfully initialized. S_OK and S_FALSE both mean that we need to - call CoUninitialize since the internal ref count was increased. RPC_E_CHANGED_MODE means that CoInitializeEx was - called with a different COINIT value, and we don't call CoUninitialize in that case. Other errors are possible, - so we check for S_OK and S_FALSE specifically. */ - CoInitializeResult = ma_CoInitializeEx(pContext, NULL, MA_COINIT_VALUE); + ma_CoInitializeEx(pContext, NULL, MA_COINIT_VALUE); { hr = ma_CoCreateInstance(pContext, &MA_CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, &MA_IID_IMMDeviceEnumerator, (void**)&pDeviceEnumerator); - } - if (CoInitializeResult == S_OK || CoInitializeResult == S_FALSE) { ma_CoUninitialize(pContext); } + } + ma_CoUninitialize(pContext); if (FAILED(hr)) { /* <-- This is checking the call above to ma_CoCreateInstance(). */ ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create IMMDeviceEnumerator.\n"); @@ -23369,7 +21950,7 @@ static ma_result ma_context_get_IAudioClient__wasapi(ma_context* pContext, ma_de pActivationParams = &activationParams; /* When requesting a specific device ID we need to use a special device ID. */ - MA_COPY_MEMORY(virtualDeviceID.wasapi, MA_VIRTUAL_AUDIO_DEVICE_PROCESS_LOOPBACK, (ma_wcslen(MA_VIRTUAL_AUDIO_DEVICE_PROCESS_LOOPBACK) + 1) * sizeof(wchar_t)); /* +1 for the null terminator. */ + MA_COPY_MEMORY(virtualDeviceID.wasapi, MA_VIRTUAL_AUDIO_DEVICE_PROCESS_LOOPBACK, (wcslen(MA_VIRTUAL_AUDIO_DEVICE_PROCESS_LOOPBACK) + 1) * sizeof(wchar_t)); /* +1 for the null terminator. */ pDeviceID = &virtualDeviceID; } else { pActivationParams = NULL; /* No activation parameters required. */ @@ -28098,9 +26679,6 @@ typedef snd_pcm_channel_area_t ma_snd_pcm_channel_area_t; typedef snd_pcm_chmap_t ma_snd_pcm_chmap_t; typedef snd_pcm_state_t ma_snd_pcm_state_t; -/* snd_pcm_state_t */ -#define MA_SND_PCM_STATE_XRUN SND_PCM_STATE_XRUN - /* snd_pcm_stream_t */ #define MA_SND_PCM_STREAM_PLAYBACK SND_PCM_STREAM_PLAYBACK #define MA_SND_PCM_STREAM_CAPTURE SND_PCM_STREAM_CAPTURE @@ -28296,7 +26874,6 @@ typedef int (* ma_snd_pcm_hw_params_set_channels_minmax_proc) ( typedef int (* ma_snd_pcm_hw_params_set_rate_resample_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, unsigned int val); typedef int (* ma_snd_pcm_hw_params_set_rate_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, unsigned int val, int dir); typedef int (* ma_snd_pcm_hw_params_set_rate_near_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, unsigned int *val, int *dir); -typedef int (* ma_snd_pcm_hw_params_set_rate_minmax_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, unsigned int *min, int *mindir, unsigned int *max, int *maxdir); typedef int (* ma_snd_pcm_hw_params_set_buffer_size_near_proc)(ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, ma_snd_pcm_uframes_t *val); typedef int (* ma_snd_pcm_hw_params_set_periods_near_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, unsigned int *val, int *dir); typedef int (* ma_snd_pcm_hw_params_set_access_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, ma_snd_pcm_access_t _access); @@ -30063,9 +28640,8 @@ static ma_result ma_context_init__alsa(ma_context* pContext, const ma_context_co ma_snd_pcm_hw_params_get_format_mask_proc _snd_pcm_hw_params_get_format_mask = snd_pcm_hw_params_get_format_mask; ma_snd_pcm_hw_params_set_channels_proc _snd_pcm_hw_params_set_channels = snd_pcm_hw_params_set_channels; ma_snd_pcm_hw_params_set_channels_near_proc _snd_pcm_hw_params_set_channels_near = snd_pcm_hw_params_set_channels_near; - ma_snd_pcm_hw_params_set_channels_minmax_proc _snd_pcm_hw_params_set_channels_minmax = snd_pcm_hw_params_set_channels_minmax; ma_snd_pcm_hw_params_set_rate_resample_proc _snd_pcm_hw_params_set_rate_resample = snd_pcm_hw_params_set_rate_resample; - ma_snd_pcm_hw_params_set_rate_proc _snd_pcm_hw_params_set_rate = snd_pcm_hw_params_set_rate; + ma_snd_pcm_hw_params_set_rate_near _snd_pcm_hw_params_set_rate = snd_pcm_hw_params_set_rate; ma_snd_pcm_hw_params_set_rate_near_proc _snd_pcm_hw_params_set_rate_near = snd_pcm_hw_params_set_rate_near; ma_snd_pcm_hw_params_set_rate_minmax_proc _snd_pcm_hw_params_set_rate_minmax = snd_pcm_hw_params_set_rate_minmax; ma_snd_pcm_hw_params_set_buffer_size_near_proc _snd_pcm_hw_params_set_buffer_size_near = snd_pcm_hw_params_set_buffer_size_near; @@ -30117,9 +28693,9 @@ static ma_result ma_context_init__alsa(ma_context* pContext, const ma_context_co ma_snd_pcm_info_proc _snd_pcm_info = snd_pcm_info; ma_snd_pcm_info_sizeof_proc _snd_pcm_info_sizeof = snd_pcm_info_sizeof; ma_snd_pcm_info_get_name_proc _snd_pcm_info_get_name = snd_pcm_info_get_name; - ma_snd_pcm_poll_descriptors_proc _snd_pcm_poll_descriptors = snd_pcm_poll_descriptors; - ma_snd_pcm_poll_descriptors_count_proc _snd_pcm_poll_descriptors_count = snd_pcm_poll_descriptors_count; - ma_snd_pcm_poll_descriptors_revents_proc _snd_pcm_poll_descriptors_revents = snd_pcm_poll_descriptors_revents; + ma_snd_pcm_poll_descriptors _snd_pcm_poll_descriptors = snd_pcm_poll_descriptors; + ma_snd_pcm_poll_descriptors_count _snd_pcm_poll_descriptors_count = snd_pcm_poll_descriptors_count; + ma_snd_pcm_poll_descriptors_revents _snd_pcm_poll_descriptors_revents = snd_pcm_poll_descriptors_revents; ma_snd_config_update_free_global_proc _snd_config_update_free_global = snd_config_update_free_global; pContext->alsa.snd_pcm_open = (ma_proc)_snd_pcm_open; @@ -30135,7 +28711,6 @@ static ma_result ma_context_init__alsa(ma_context* pContext, const ma_context_co pContext->alsa.snd_pcm_hw_params_set_rate_resample = (ma_proc)_snd_pcm_hw_params_set_rate_resample; pContext->alsa.snd_pcm_hw_params_set_rate = (ma_proc)_snd_pcm_hw_params_set_rate; pContext->alsa.snd_pcm_hw_params_set_rate_near = (ma_proc)_snd_pcm_hw_params_set_rate_near; - pContext->alsa.snd_pcm_hw_params_set_rate_minmax = (ma_proc)_snd_pcm_hw_params_set_rate_minmax; pContext->alsa.snd_pcm_hw_params_set_buffer_size_near = (ma_proc)_snd_pcm_hw_params_set_buffer_size_near; pContext->alsa.snd_pcm_hw_params_set_periods_near = (ma_proc)_snd_pcm_hw_params_set_periods_near; pContext->alsa.snd_pcm_hw_params_set_access = (ma_proc)_snd_pcm_hw_params_set_access; @@ -30861,7 +29436,7 @@ typedef void (* ma_pa_threaded_mainloop_unlock_proc) ( typedef void (* ma_pa_threaded_mainloop_wait_proc) (ma_pa_threaded_mainloop* m); typedef void (* ma_pa_threaded_mainloop_signal_proc) (ma_pa_threaded_mainloop* m, int wait_for_accept); typedef void (* ma_pa_threaded_mainloop_accept_proc) (ma_pa_threaded_mainloop* m); -typedef int (* ma_pa_threaded_mainloop_get_retval_proc) (const ma_pa_threaded_mainloop* m); +typedef int (* ma_pa_threaded_mainloop_get_retval_proc) (ma_pa_threaded_mainloop* m); typedef ma_pa_mainloop_api* (* ma_pa_threaded_mainloop_get_api_proc) (ma_pa_threaded_mainloop* m); typedef int (* ma_pa_threaded_mainloop_in_thread_proc) (ma_pa_threaded_mainloop* m); typedef void (* ma_pa_threaded_mainloop_set_name_proc) (ma_pa_threaded_mainloop* m, const char* name); @@ -30870,13 +29445,13 @@ typedef void (* ma_pa_context_unref_proc) ( typedef int (* ma_pa_context_connect_proc) (ma_pa_context* c, const char* server, ma_pa_context_flags_t flags, const ma_pa_spawn_api* api); typedef void (* ma_pa_context_disconnect_proc) (ma_pa_context* c); typedef void (* ma_pa_context_set_state_callback_proc) (ma_pa_context* c, ma_pa_context_notify_cb_t cb, void* userdata); -typedef ma_pa_context_state_t (* ma_pa_context_get_state_proc) (const ma_pa_context* c); +typedef ma_pa_context_state_t (* ma_pa_context_get_state_proc) (ma_pa_context* c); typedef ma_pa_operation* (* ma_pa_context_get_sink_info_list_proc) (ma_pa_context* c, ma_pa_sink_info_cb_t cb, void* userdata); typedef ma_pa_operation* (* ma_pa_context_get_source_info_list_proc) (ma_pa_context* c, ma_pa_source_info_cb_t cb, void* userdata); typedef ma_pa_operation* (* ma_pa_context_get_sink_info_by_name_proc) (ma_pa_context* c, const char* name, ma_pa_sink_info_cb_t cb, void* userdata); typedef ma_pa_operation* (* ma_pa_context_get_source_info_by_name_proc)(ma_pa_context* c, const char* name, ma_pa_source_info_cb_t cb, void* userdata); typedef void (* ma_pa_operation_unref_proc) (ma_pa_operation* o); -typedef ma_pa_operation_state_t (* ma_pa_operation_get_state_proc) (const ma_pa_operation* o); +typedef ma_pa_operation_state_t (* ma_pa_operation_get_state_proc) (ma_pa_operation* o); typedef ma_pa_channel_map* (* ma_pa_channel_map_init_extend_proc) (ma_pa_channel_map* m, unsigned channels, ma_pa_channel_map_def_t def); typedef int (* ma_pa_channel_map_valid_proc) (const ma_pa_channel_map* m); typedef int (* ma_pa_channel_map_compatible_proc) (const ma_pa_channel_map* m, const ma_pa_sample_spec* ss); @@ -30885,12 +29460,12 @@ typedef void (* ma_pa_stream_unref_proc) ( typedef int (* ma_pa_stream_connect_playback_proc) (ma_pa_stream* s, const char* dev, const ma_pa_buffer_attr* attr, ma_pa_stream_flags_t flags, const ma_pa_cvolume* volume, ma_pa_stream* sync_stream); typedef int (* ma_pa_stream_connect_record_proc) (ma_pa_stream* s, const char* dev, const ma_pa_buffer_attr* attr, ma_pa_stream_flags_t flags); typedef int (* ma_pa_stream_disconnect_proc) (ma_pa_stream* s); -typedef ma_pa_stream_state_t (* ma_pa_stream_get_state_proc) (const ma_pa_stream* s); +typedef ma_pa_stream_state_t (* ma_pa_stream_get_state_proc) (ma_pa_stream* s); typedef const ma_pa_sample_spec* (* ma_pa_stream_get_sample_spec_proc) (ma_pa_stream* s); typedef const ma_pa_channel_map* (* ma_pa_stream_get_channel_map_proc) (ma_pa_stream* s); typedef const ma_pa_buffer_attr* (* ma_pa_stream_get_buffer_attr_proc) (ma_pa_stream* s); typedef ma_pa_operation* (* ma_pa_stream_set_buffer_attr_proc) (ma_pa_stream* s, const ma_pa_buffer_attr* attr, ma_pa_stream_success_cb_t cb, void* userdata); -typedef const char* (* ma_pa_stream_get_device_name_proc) (const ma_pa_stream* s); +typedef const char* (* ma_pa_stream_get_device_name_proc) (ma_pa_stream* s); typedef void (* ma_pa_stream_set_write_callback_proc) (ma_pa_stream* s, ma_pa_stream_request_cb_t cb, void* userdata); typedef void (* ma_pa_stream_set_read_callback_proc) (ma_pa_stream* s, ma_pa_stream_request_cb_t cb, void* userdata); typedef void (* ma_pa_stream_set_suspended_callback_proc) (ma_pa_stream* s, ma_pa_stream_notify_cb_t cb, void* userdata); @@ -30898,15 +29473,15 @@ typedef void (* ma_pa_stream_set_moved_callback_proc) ( typedef int (* ma_pa_stream_is_suspended_proc) (const ma_pa_stream* s); typedef ma_pa_operation* (* ma_pa_stream_flush_proc) (ma_pa_stream* s, ma_pa_stream_success_cb_t cb, void* userdata); typedef ma_pa_operation* (* ma_pa_stream_drain_proc) (ma_pa_stream* s, ma_pa_stream_success_cb_t cb, void* userdata); -typedef int (* ma_pa_stream_is_corked_proc) (const ma_pa_stream* s); +typedef int (* ma_pa_stream_is_corked_proc) (ma_pa_stream* s); typedef ma_pa_operation* (* ma_pa_stream_cork_proc) (ma_pa_stream* s, int b, ma_pa_stream_success_cb_t cb, void* userdata); typedef ma_pa_operation* (* ma_pa_stream_trigger_proc) (ma_pa_stream* s, ma_pa_stream_success_cb_t cb, void* userdata); typedef int (* ma_pa_stream_begin_write_proc) (ma_pa_stream* s, void** data, size_t* nbytes); typedef int (* ma_pa_stream_write_proc) (ma_pa_stream* s, const void* data, size_t nbytes, ma_pa_free_cb_t free_cb, int64_t offset, ma_pa_seek_mode_t seek); typedef int (* ma_pa_stream_peek_proc) (ma_pa_stream* s, const void** data, size_t* nbytes); typedef int (* ma_pa_stream_drop_proc) (ma_pa_stream* s); -typedef size_t (* ma_pa_stream_writable_size_proc) (const ma_pa_stream* s); -typedef size_t (* ma_pa_stream_readable_size_proc) (const ma_pa_stream* s); +typedef size_t (* ma_pa_stream_writable_size_proc) (ma_pa_stream* s); +typedef size_t (* ma_pa_stream_readable_size_proc) (ma_pa_stream* s); typedef struct { @@ -31202,7 +29777,7 @@ static ma_result ma_init_pa_mainloop_and_pa_context__pulse(ma_context* pContext, } /* Now we need to connect to the context. Everything is asynchronous so we need to wait for it to connect before returning. */ - result = ma_result_from_pulse(((ma_pa_context_connect_proc)pContext->pulse.pa_context_connect)((ma_pa_context*)pPulseContext, pServerName, (tryAutoSpawn) ? MA_PA_CONTEXT_NOFLAGS : MA_PA_CONTEXT_NOAUTOSPAWN, NULL)); + result = ma_result_from_pulse(((ma_pa_context_connect_proc)pContext->pulse.pa_context_connect)((ma_pa_context*)pPulseContext, pServerName, (tryAutoSpawn) ? 0 : MA_PA_CONTEXT_NOAUTOSPAWN, NULL)); if (result != MA_SUCCESS) { ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to connect PulseAudio context."); ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)((ma_pa_mainloop*)(pMainLoop)); @@ -31935,7 +30510,7 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi const ma_pa_buffer_attr* pActualAttr = NULL; const ma_pa_channel_map* pActualChannelMap = NULL; ma_uint32 iChannel; - int streamFlags; + ma_pa_stream_flags_t streamFlags; MA_ASSERT(pDevice != NULL); MA_ZERO_OBJECT(&pDevice->pulse); @@ -31993,13 +30568,8 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi ss.channels = pDescriptorCapture->channels; } - /* PulseAudio has a maximum channel count of 32. We'll get a crash if this is exceeded. */ - if (ss.channels > 32) { - ss.channels = 32; - } - /* Use a default channel map. */ - ((ma_pa_channel_map_init_extend_proc)pDevice->pContext->pulse.pa_channel_map_init_extend)(&cmap, ss.channels, (ma_pa_channel_map_def_t)pConfig->pulse.channelMap); + ((ma_pa_channel_map_init_extend_proc)pDevice->pContext->pulse.pa_channel_map_init_extend)(&cmap, ss.channels, pConfig->pulse.channelMap); /* Use the requested sample rate if one was specified. */ if (pDescriptorCapture->sampleRate != 0) { @@ -32056,7 +30626,7 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi streamFlags |= MA_PA_STREAM_DONT_MOVE; } - error = ((ma_pa_stream_connect_record_proc)pDevice->pContext->pulse.pa_stream_connect_record)((ma_pa_stream*)pDevice->pulse.pStreamCapture, devCapture, &attr, (ma_pa_stream_flags_t)streamFlags); + error = ((ma_pa_stream_connect_record_proc)pDevice->pContext->pulse.pa_stream_connect_record)((ma_pa_stream*)pDevice->pulse.pStreamCapture, devCapture, &attr, streamFlags); if (error != MA_PA_OK) { ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to connect PulseAudio capture stream."); result = ma_result_from_pulse(error); @@ -32150,13 +30720,8 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi ss.channels = pDescriptorPlayback->channels; } - /* PulseAudio has a maximum channel count of 32. We'll get a crash if this is exceeded. */ - if (ss.channels > 32) { - ss.channels = 32; - } - /* Use a default channel map. */ - ((ma_pa_channel_map_init_extend_proc)pDevice->pContext->pulse.pa_channel_map_init_extend)(&cmap, ss.channels, (ma_pa_channel_map_def_t)pConfig->pulse.channelMap); + ((ma_pa_channel_map_init_extend_proc)pDevice->pContext->pulse.pa_channel_map_init_extend)(&cmap, ss.channels, pConfig->pulse.channelMap); /* Use the requested sample rate if one was specified. */ @@ -32218,7 +30783,7 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi streamFlags |= MA_PA_STREAM_DONT_MOVE; } - error = ((ma_pa_stream_connect_playback_proc)pDevice->pContext->pulse.pa_stream_connect_playback)((ma_pa_stream*)pDevice->pulse.pStreamPlayback, devPlayback, &attr, (ma_pa_stream_flags_t)streamFlags, NULL, NULL); + error = ((ma_pa_stream_connect_playback_proc)pDevice->pContext->pulse.pa_stream_connect_playback)((ma_pa_stream*)pDevice->pulse.pStreamPlayback, devPlayback, &attr, streamFlags, NULL, NULL); if (error != MA_PA_OK) { ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to connect PulseAudio playback stream."); result = ma_result_from_pulse(error); @@ -32773,7 +31338,6 @@ typedef JackProcessCallback ma_JackProcessCallback; typedef JackBufferSizeCallback ma_JackBufferSizeCallback; typedef JackShutdownCallback ma_JackShutdownCallback; #define MA_JACK_DEFAULT_AUDIO_TYPE JACK_DEFAULT_AUDIO_TYPE -#define ma_JackNullOption JackNullOption #define ma_JackNoStartServer JackNoStartServer #define ma_JackPortIsInput JackPortIsInput #define ma_JackPortIsOutput JackPortIsOutput @@ -32788,7 +31352,6 @@ typedef int (* ma_JackProcessCallback) (ma_jack_nframes_t nframes, void* arg) typedef int (* ma_JackBufferSizeCallback)(ma_jack_nframes_t nframes, void* arg); typedef void (* ma_JackShutdownCallback) (void* arg); #define MA_JACK_DEFAULT_AUDIO_TYPE "32 bit float mono audio" -#define ma_JackNullOption 0 #define ma_JackNoStartServer 1 #define ma_JackPortIsInput 1 #define ma_JackPortIsOutput 2 @@ -32829,7 +31392,7 @@ static ma_result ma_context_open_client__jack(ma_context* pContext, ma_jack_clie maxClientNameSize = ((ma_jack_client_name_size_proc)pContext->jack.jack_client_name_size)(); /* Includes null terminator. */ ma_strncpy_s(clientName, ma_min(sizeof(clientName), maxClientNameSize), (pContext->jack.pClientName != NULL) ? pContext->jack.pClientName : "miniaudio", (size_t)-1); - pClient = ((ma_jack_client_open_proc)pContext->jack.jack_client_open)(clientName, (pContext->jack.tryStartServer) ? ma_JackNullOption : ma_JackNoStartServer, &status, NULL); + pClient = ((ma_jack_client_open_proc)pContext->jack.jack_client_open)(clientName, (pContext->jack.tryStartServer) ? 0 : ma_JackNoStartServer, &status, NULL); if (pClient == NULL) { return MA_FAILED_TO_OPEN_BACKEND_DEVICE; } @@ -38431,7 +36994,7 @@ OSS Backend #define MA_OSS_DEFAULT_DEVICE_NAME "/dev/dsp" -static int ma_open_temp_device__oss(void) +static int ma_open_temp_device__oss() { /* The OSS sample code uses "/dev/mixer" as the device for getting system properties so I'm going to do the same. */ int fd = open("/dev/mixer", O_RDONLY, 0); @@ -39271,30 +37834,25 @@ static void ma_stream_error_callback__aaudio(ma_AAudioStream* pStream, void* pUs (void)error; ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[AAudio] ERROR CALLBACK: error=%d, AAudioStream_getState()=%d\n", error, ((MA_PFN_AAudioStream_getState)pDevice->pContext->aaudio.AAudioStream_getState)(pStream)); - /* When we get an error, we'll assume that the stream is in an erroneous state and needs to be restarted. From the documentation, we cannot do this from the error callback. Therefore we are going to use an event thread for the AAudio backend to do this cleanly and safely. */ - if (ma_atomic_bool32_get(&pDevice->aaudio.isTearingDown)) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[AAudio] Device Disconnected. Tearing down device.\n"); + job = ma_job_init(MA_JOB_TYPE_DEVICE_AAUDIO_REROUTE); + job.data.device.aaudio.reroute.pDevice = pDevice; + + if (pStream == pDevice->aaudio.pStreamCapture) { + job.data.device.aaudio.reroute.deviceType = ma_device_type_capture; } else { - job = ma_job_init(MA_JOB_TYPE_DEVICE_AAUDIO_REROUTE); - job.data.device.aaudio.reroute.pDevice = pDevice; - - if (pStream == pDevice->aaudio.pStreamCapture) { - job.data.device.aaudio.reroute.deviceType = ma_device_type_capture; - } else { - job.data.device.aaudio.reroute.deviceType = ma_device_type_playback; - } - - result = ma_device_job_thread_post(&pDevice->pContext->aaudio.jobThread, &job); - if (result != MA_SUCCESS) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[AAudio] Device Disconnected. Failed to post job for rerouting.\n"); - return; - } + job.data.device.aaudio.reroute.deviceType = ma_device_type_playback; + } + + result = ma_device_job_thread_post(&pDevice->pContext->aaudio.jobThread, &job); + if (result != MA_SUCCESS) { + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[AAudio] Device Disconnected. Failed to post job for rerouting.\n"); + return; } } @@ -39611,7 +38169,7 @@ static ma_result ma_close_streams__aaudio(ma_device* pDevice) { MA_ASSERT(pDevice != NULL); - /* When rerouting, streams may have been closed and never re-opened. Hence the extra checks below. */ + /* When re-routing, streams may have been closed and never re-opened. Hence the extra checks below. */ if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { ma_close_stream__aaudio(pDevice->pContext, (ma_AAudioStream*)pDevice->aaudio.pStreamCapture); pDevice->aaudio.pStreamCapture = NULL; @@ -39628,12 +38186,6 @@ static ma_result ma_device_uninit__aaudio(ma_device* pDevice) { MA_ASSERT(pDevice != NULL); - /* - Note: Closing the streams may cause a timeout error, which would then trigger rerouting in our error callback. - We must not schedule a reroute when device is getting destroyed. - */ - ma_atomic_bool32_set(&pDevice->aaudio.isTearingDown, MA_TRUE); - /* Wait for any rerouting to finish before attempting to close the streams. */ ma_mutex_lock(&pDevice->aaudio.rerouteLock); { @@ -39641,7 +38193,7 @@ static ma_result ma_device_uninit__aaudio(ma_device* pDevice) } ma_mutex_unlock(&pDevice->aaudio.rerouteLock); - /* Destroy rerouting lock. */ + /* Destroy re-routing lock. */ ma_mutex_uninit(&pDevice->aaudio.rerouteLock); return MA_SUCCESS; @@ -39877,22 +38429,17 @@ static ma_result ma_device_stop__aaudio(ma_device* pDevice) static ma_result ma_device_reinit__aaudio(ma_device* pDevice, ma_device_type deviceType) { - const ma_int32 maxAttempts = 4; /* Reasonable retry limit. */ - ma_result result; - ma_int32 iAttempt; + int32_t retries = 0; MA_ASSERT(pDevice != NULL); - /* We got disconnected! Retry a few times, until we find a connected device! */ - iAttempt = 0; - while (iAttempt++ < maxAttempts) { - /* Device tearing down? No need to reroute! */ - if (ma_atomic_bool32_get(&pDevice->aaudio.isTearingDown)) { - result = MA_SUCCESS; /* Caller should continue as normal. */ - break; - } - + /* + TODO: Stop retrying if main thread is about to uninit device. + */ + ma_mutex_lock(&pDevice->aaudio.rerouteLock); + { +error_disconnected: /* The first thing to do is close the streams. */ ma_close_streams__aaudio(pDevice); @@ -39948,16 +38495,14 @@ static ma_result ma_device_reinit__aaudio(ma_device* pDevice, ma_device_type dev result = ma_device_init_streams__aaudio(pDevice, &deviceConfig, &descriptorPlayback, &descriptorCapture); if (result != MA_SUCCESS) { ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_WARNING, "[AAudio] Failed to create stream after route change."); - /* Reroute failed! */ - break; + goto done; } result = ma_device_post_init(pDevice, deviceType, &descriptorPlayback, &descriptorCapture); if (result != MA_SUCCESS) { ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_WARNING, "[AAudio] Failed to initialize device after route change."); ma_close_streams__aaudio(pDevice); - /* Reroute failed! */ - break; + goto done; } /* We'll only ever do this in response to a reroute. */ @@ -39968,23 +38513,26 @@ static ma_result ma_device_reinit__aaudio(ma_device* pDevice, ma_device_type dev if (pDevice->aaudio.noAutoStartAfterReroute == MA_FALSE) { result = ma_device_start__aaudio(pDevice); if (result != MA_SUCCESS) { - if (iAttempt < maxAttempts) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[AAudio] Failed to start stream after route change, retrying(%d)", iAttempt); - } else { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[AAudio] Failed to start stream after route change, giving up."); + /* We got disconnected! Retry a few times, until we find a connected device! */ + retries += 1; + if (retries <= 3) { + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[AAudio] Failed to start stream after route change, retrying(%d)", retries); + goto error_disconnected; } + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[AAudio] Failed to start stream after route change."); + goto done; } } else { - ma_device_stop(pDevice); /* Do a full device stop so we set internal state correctly. */ + ma_device_stop(pDevice); /* Do a full device stop so we set internal state correctly. */ } } - - if (result == MA_SUCCESS) { - /* Reroute successful! */ - break; - } + + result = MA_SUCCESS; } - +done: + /* Re-routing done */ + ma_mutex_unlock(&pDevice->aaudio.rerouteLock); + return result; } @@ -40150,7 +38698,7 @@ static ma_result ma_context_init__aaudio(ma_context* pContext, const ma_context_ static ma_result ma_job_process__device__aaudio_reroute(ma_job* pJob) { - ma_result result = MA_SUCCESS; + ma_result result; ma_device* pDevice; MA_ASSERT(pJob != NULL); @@ -40158,22 +38706,19 @@ static ma_result ma_job_process__device__aaudio_reroute(ma_job* pJob) pDevice = (ma_device*)pJob->data.device.aaudio.reroute.pDevice; MA_ASSERT(pDevice != NULL); - ma_mutex_lock(&pDevice->aaudio.rerouteLock); - { - /* Here is where we need to reroute the device. To do this we need to uninitialize the stream and reinitialize it. */ - result = ma_device_reinit__aaudio(pDevice, (ma_device_type)pJob->data.device.aaudio.reroute.deviceType); - if (result != MA_SUCCESS) { - /* - Getting here means we failed to reroute the device. The best thing I can think of here is to - just stop the device. - */ - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[AAudio] Stopping device due to reroute failure."); - ma_device_stop(pDevice); - } + /* Here is where we need to reroute the device. To do this we need to uninitialize the stream and reinitialize it. */ + result = ma_device_reinit__aaudio(pDevice, (ma_device_type)pJob->data.device.aaudio.reroute.deviceType); + if (result != MA_SUCCESS) { + /* + Getting here means we failed to reroute the device. The best thing I can think of here is to + just stop the device. + */ + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[AAudio] Stopping device due to reroute failure."); + ma_device_stop(pDevice); + return result; } - ma_mutex_unlock(&pDevice->aaudio.rerouteLock); - return result; + return MA_SUCCESS; } #else /* Getting here means there is no AAudio backend so we need a no-op job implementation. */ @@ -42691,13 +41236,13 @@ MA_API ma_result ma_device_post_init(ma_device* pDevice, ma_device_type deviceTy static ma_thread_result MA_THREADCALL ma_worker_thread(void* pData) { ma_device* pDevice = (ma_device*)pData; -#if defined(MA_WIN32) && !defined(MA_XBOX) +#ifdef MA_WIN32 HRESULT CoInitializeResult; #endif MA_ASSERT(pDevice != NULL); -#if defined(MA_WIN32) && !defined(MA_XBOX) +#ifdef MA_WIN32 CoInitializeResult = ma_CoInitializeEx(pDevice->pContext, NULL, MA_COINIT_VALUE); #endif @@ -42788,8 +41333,8 @@ static ma_thread_result MA_THREADCALL ma_worker_thread(void* pData) ma_event_signal(&pDevice->stopEvent); } -#if defined(MA_WIN32) && !defined(MA_XBOX) - if (CoInitializeResult == S_OK || CoInitializeResult == S_FALSE) { +#ifdef MA_WIN32 + if (CoInitializeResult == S_OK) { ma_CoUninitialize(pDevice->pContext); } #endif @@ -42813,92 +41358,67 @@ static ma_bool32 ma_device__is_initialized(ma_device* pDevice) static ma_result ma_context_uninit_backend_apis__win32(ma_context* pContext) { /* For some reason UWP complains when CoUninitialize() is called. I'm just not going to call it on UWP. */ - #if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) - { - /* TODO: Remove this once the new single threaded backend system is in place in 0.12. */ - #if !defined(MA_XBOX) - { - if (pContext->win32.CoInitializeResult == S_OK || pContext->win32.CoInitializeResult == S_FALSE) { - ma_CoUninitialize(pContext); /* TODO: Remove this once the new single threaded backend system is in place in 0.12. */ - } - } - #endif - - #if defined(MA_WIN32_DESKTOP) - ma_dlclose(ma_context_get_log(pContext), pContext->win32.hUser32DLL); - ma_dlclose(ma_context_get_log(pContext), pContext->win32.hAdvapi32DLL); - #endif - - ma_dlclose(ma_context_get_log(pContext), pContext->win32.hOle32DLL); - } - #else - { - (void)pContext; +#if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) + if (pContext->win32.CoInitializeResult == S_OK) { + ma_CoUninitialize(pContext); } + + #if defined(MA_WIN32_DESKTOP) + ma_dlclose(ma_context_get_log(pContext), pContext->win32.hUser32DLL); + ma_dlclose(ma_context_get_log(pContext), pContext->win32.hAdvapi32DLL); #endif + ma_dlclose(ma_context_get_log(pContext), pContext->win32.hOle32DLL); +#else + (void)pContext; +#endif + return MA_SUCCESS; } static ma_result ma_context_init_backend_apis__win32(ma_context* pContext) { - /* - TODO: Reassess all of this stuff and move everything to the relevant backends. For example, I think - GetForegroundWindow() and GetDesktopWindow() are only used by the DirectSound backend. - */ - #if (defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK)) && !defined(MA_XBOX) - { - #if defined(MA_WIN32_DESKTOP) - { - /* User32.dll */ - pContext->win32.hUser32DLL = ma_dlopen(ma_context_get_log(pContext), "user32.dll"); - if (pContext->win32.hUser32DLL == NULL) { - return MA_FAILED_TO_INIT_BACKEND; - } - - pContext->win32.GetForegroundWindow = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hUser32DLL, "GetForegroundWindow"); - pContext->win32.GetDesktopWindow = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hUser32DLL, "GetDesktopWindow"); - - - /* Advapi32.dll */ - pContext->win32.hAdvapi32DLL = ma_dlopen(ma_context_get_log(pContext), "advapi32.dll"); - if (pContext->win32.hAdvapi32DLL == NULL) { - return MA_FAILED_TO_INIT_BACKEND; - } - - pContext->win32.RegOpenKeyExA = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hAdvapi32DLL, "RegOpenKeyExA"); - pContext->win32.RegCloseKey = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hAdvapi32DLL, "RegCloseKey"); - pContext->win32.RegQueryValueExA = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hAdvapi32DLL, "RegQueryValueExA"); - } - #endif - - /* Ole32.dll */ - pContext->win32.hOle32DLL = ma_dlopen(ma_context_get_log(pContext), "ole32.dll"); - if (pContext->win32.hOle32DLL == NULL) { +#if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) + #if defined(MA_WIN32_DESKTOP) + /* User32.dll */ + pContext->win32.hUser32DLL = ma_dlopen(ma_context_get_log(pContext), "user32.dll"); + if (pContext->win32.hUser32DLL == NULL) { return MA_FAILED_TO_INIT_BACKEND; } - pContext->win32.CoInitialize = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "CoInitialize"); - pContext->win32.CoInitializeEx = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "CoInitializeEx"); - pContext->win32.CoUninitialize = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "CoUninitialize"); - pContext->win32.CoCreateInstance = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "CoCreateInstance"); - pContext->win32.CoTaskMemFree = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "CoTaskMemFree"); - pContext->win32.PropVariantClear = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "PropVariantClear"); - pContext->win32.StringFromGUID2 = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "StringFromGUID2"); - } - #else - { - (void)pContext; /* Unused. */ - } + pContext->win32.GetForegroundWindow = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hUser32DLL, "GetForegroundWindow"); + pContext->win32.GetDesktopWindow = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hUser32DLL, "GetDesktopWindow"); + + + /* Advapi32.dll */ + pContext->win32.hAdvapi32DLL = ma_dlopen(ma_context_get_log(pContext), "advapi32.dll"); + if (pContext->win32.hAdvapi32DLL == NULL) { + return MA_FAILED_TO_INIT_BACKEND; + } + + pContext->win32.RegOpenKeyExA = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hAdvapi32DLL, "RegOpenKeyExA"); + pContext->win32.RegCloseKey = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hAdvapi32DLL, "RegCloseKey"); + pContext->win32.RegQueryValueExA = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hAdvapi32DLL, "RegQueryValueExA"); #endif - /* TODO: Remove this once the new single threaded backend system is in place in 0.12. */ - #if !defined(MA_XBOX) - { - pContext->win32.CoInitializeResult = ma_CoInitializeEx(pContext, NULL, MA_COINIT_VALUE); + /* Ole32.dll */ + pContext->win32.hOle32DLL = ma_dlopen(ma_context_get_log(pContext), "ole32.dll"); + if (pContext->win32.hOle32DLL == NULL) { + return MA_FAILED_TO_INIT_BACKEND; } - #endif + pContext->win32.CoInitialize = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "CoInitialize"); + pContext->win32.CoInitializeEx = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "CoInitializeEx"); + pContext->win32.CoUninitialize = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "CoUninitialize"); + pContext->win32.CoCreateInstance = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "CoCreateInstance"); + pContext->win32.CoTaskMemFree = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "CoTaskMemFree"); + pContext->win32.PropVariantClear = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "PropVariantClear"); + pContext->win32.StringFromGUID2 = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "StringFromGUID2"); +#else + (void)pContext; /* Unused. */ +#endif + + pContext->win32.CoInitializeResult = ma_CoInitializeEx(pContext, NULL, MA_COINIT_VALUE); return MA_SUCCESS; } #else @@ -45496,7 +44016,7 @@ static MA_INLINE void ma_pcm_s16_to_s32__reference(void* dst, const void* src, m ma_uint64 i; for (i = 0; i < count; i += 1) { - dst_s32[i] = (ma_int32)src_s16[i] << 16; + dst_s32[i] = src_s16[i] << 16; } (void)ditherMode; @@ -57888,12 +56408,8 @@ MA_API size_t ma_channel_map_to_string(const ma_channel* pChannelMap, ma_uint32 } /* Null terminate. Don't increment the length here. */ - if (pBufferOut != NULL) { - if (bufferCap > len) { - pBufferOut[len] = '\0'; - } else if (bufferCap > 0) { - pBufferOut[bufferCap - 1] = '\0'; - } + if (pBufferOut != NULL && bufferCap > len + 1) { + pBufferOut[len] = '\0'; } return len; @@ -58104,7 +56620,7 @@ MA_API ma_result ma_rb_init_ex(size_t subbufferSizeInBytes, size_t subbufferCoun Here is where we allocate our own buffer. We always want to align this to MA_SIMD_ALIGNMENT for future SIMD optimization opportunity. To do this we need to make sure the stride is a multiple of MA_SIMD_ALIGNMENT. */ - pRB->subbufferStrideInBytes = ma_align(pRB->subbufferSizeInBytes, MA_SIMD_ALIGNMENT); + pRB->subbufferStrideInBytes = (pRB->subbufferSizeInBytes + (MA_SIMD_ALIGNMENT-1)) & ~MA_SIMD_ALIGNMENT; bufferSizeInBytes = (size_t)pRB->subbufferCount*pRB->subbufferStrideInBytes; pRB->pBuffer = ma_aligned_malloc(bufferSizeInBytes, MA_SIMD_ALIGNMENT, &pRB->allocationCallbacks); @@ -60999,7 +59515,7 @@ MA_API ma_result ma_vfs_info(ma_vfs* pVFS, ma_vfs_file file, ma_file_info* pInfo } -#if !defined(MA_USE_WIN32_FILEIO) && (defined(MA_WIN32) && (defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_NXDK)) && !defined(MA_NO_WIN32_FILEIO) && !defined(MA_POSIX)) +#if !defined(MA_USE_WIN32_FILEIO) && (defined(MA_WIN32) && defined(MA_WIN32_DESKTOP) && !defined(MA_NO_WIN32_FILEIO) && !defined(MA_POSIX)) #define MA_USE_WIN32_FILEIO #endif @@ -61076,34 +59592,25 @@ static ma_result ma_default_vfs_open__win32(ma_vfs* pVFS, const char* pFilePath, static ma_result ma_default_vfs_open_w__win32(ma_vfs* pVFS, const wchar_t* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile) { - #if !defined(MA_XBOX_NXDK) - { - HANDLE hFile; - DWORD dwDesiredAccess; - DWORD dwShareMode; - DWORD dwCreationDisposition; + HANDLE hFile; + DWORD dwDesiredAccess; + DWORD dwShareMode; + DWORD dwCreationDisposition; - (void)pVFS; + (void)pVFS; - /* Load some Win32 symbols dynamically so we can dynamically check for the existence of SetFilePointerEx. */ - ma_win32_fileio_init(); + /* Load some Win32 symbols dynamically so we can dynamically check for the existence of SetFilePointerEx. */ + ma_win32_fileio_init(); - ma_default_vfs__get_open_settings_win32(openMode, &dwDesiredAccess, &dwShareMode, &dwCreationDisposition); + ma_default_vfs__get_open_settings_win32(openMode, &dwDesiredAccess, &dwShareMode, &dwCreationDisposition); - hFile = CreateFileW(pFilePath, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL); - if (hFile == INVALID_HANDLE_VALUE) { - return ma_result_from_GetLastError(GetLastError()); - } - - *pFile = hFile; - return MA_SUCCESS; + hFile = CreateFileW(pFilePath, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) { + return ma_result_from_GetLastError(GetLastError()); } - #else - { - /* No CreateFileW() available. */ - return MA_NOT_IMPLEMENTED; - } - #endif + + *pFile = hFile; + return MA_SUCCESS; } static ma_result ma_default_vfs_close__win32(ma_vfs* pVFS, ma_vfs_file file) @@ -61274,28 +59781,19 @@ static ma_result ma_default_vfs_tell__win32(ma_vfs* pVFS, ma_vfs_file file, ma_i static ma_result ma_default_vfs_info__win32(ma_vfs* pVFS, ma_vfs_file file, ma_file_info* pInfo) { + BY_HANDLE_FILE_INFORMATION fi; + BOOL result; + (void)pVFS; - #if !defined(MA_XBOX_NXDK) - { - BY_HANDLE_FILE_INFORMATION fi; - BOOL result; - - result = GetFileInformationByHandle((HANDLE)file, &fi); - if (result == 0) { - return ma_result_from_GetLastError(GetLastError()); - } - - pInfo->sizeInBytes = ((ma_uint64)fi.nFileSizeHigh << 32) | ((ma_uint64)fi.nFileSizeLow); - - return MA_SUCCESS; + result = GetFileInformationByHandle((HANDLE)file, &fi); + if (result == 0) { + return ma_result_from_GetLastError(GetLastError()); } - #else - { - /* GetFileInformationByHandle() is unavailable. */ - return MA_NOT_IMPLEMENTED; - } - #endif + + pInfo->sizeInBytes = ((ma_uint64)fi.nFileSizeHigh << 32) | ((ma_uint64)fi.nFileSizeLow); + + return MA_SUCCESS; } #else static ma_result ma_default_vfs_open__stdio(ma_vfs* pVFS, const char* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile) @@ -61633,8 +60131,6 @@ static ma_result ma_default_vfs_tell(ma_vfs* pVFS, ma_vfs_file file, ma_int64* p static ma_result ma_default_vfs_info(ma_vfs* pVFS, ma_vfs_file file, ma_file_info* pInfo) { - ma_result result; - if (pInfo == NULL) { return MA_INVALID_ARGS; } @@ -61646,43 +60142,10 @@ static ma_result ma_default_vfs_info(ma_vfs* pVFS, ma_vfs_file file, ma_file_inf } #if defined(MA_USE_WIN32_FILEIO) - result = ma_default_vfs_info__win32(pVFS, file, pInfo); + return ma_default_vfs_info__win32(pVFS, file, pInfo); #else - result = ma_default_vfs_info__stdio(pVFS, file, pInfo); + return ma_default_vfs_info__stdio(pVFS, file, pInfo); #endif - - if (result == MA_NOT_IMPLEMENTED) { - /* Not implemented. Fall back to seek/tell/seek. */ - ma_result result; - ma_int64 cursor; - ma_int64 sizeInBytes; - - result = ma_default_vfs_tell(pVFS, file, &cursor); - if (result != MA_SUCCESS) { - return result; - } - - result = ma_default_vfs_seek(pVFS, file, 0, ma_seek_origin_end); - if (result != MA_SUCCESS) { - return result; - } - - result = ma_default_vfs_tell(pVFS, file, &sizeInBytes); - if (result != MA_SUCCESS) { - return result; - } - - pInfo->sizeInBytes = sizeInBytes; - - result = ma_default_vfs_seek(pVFS, file, cursor, ma_seek_origin_start); - if (result != MA_SUCCESS) { - return result; - } - - MA_ASSERT(result == MA_SUCCESS); - } - - return result; } @@ -61870,8 +60333,8 @@ extern "C" { #define MA_DR_WAV_STRINGIFY(x) #x #define MA_DR_WAV_XSTRINGIFY(x) MA_DR_WAV_STRINGIFY(x) #define MA_DR_WAV_VERSION_MAJOR 0 -#define MA_DR_WAV_VERSION_MINOR 14 -#define MA_DR_WAV_VERSION_REVISION 1 +#define MA_DR_WAV_VERSION_MINOR 13 +#define MA_DR_WAV_VERSION_REVISION 18 #define MA_DR_WAV_VERSION_STRING MA_DR_WAV_XSTRINGIFY(MA_DR_WAV_VERSION_MAJOR) "." MA_DR_WAV_XSTRINGIFY(MA_DR_WAV_VERSION_MINOR) "." MA_DR_WAV_XSTRINGIFY(MA_DR_WAV_VERSION_REVISION) #include #define MA_DR_WAVE_FORMAT_PCM 0x1 @@ -61887,9 +60350,8 @@ MA_API void ma_dr_wav_version(ma_uint32* pMajor, ma_uint32* pMinor, ma_uint32* p MA_API const char* ma_dr_wav_version_string(void); typedef enum { - MA_DR_WAV_SEEK_SET, - MA_DR_WAV_SEEK_CUR, - MA_DR_WAV_SEEK_END + ma_dr_wav_seek_origin_start, + ma_dr_wav_seek_origin_current } ma_dr_wav_seek_origin; typedef enum { @@ -61926,7 +60388,6 @@ MA_API ma_uint16 ma_dr_wav_fmt_get_format(const ma_dr_wav_fmt* pFMT); typedef size_t (* ma_dr_wav_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead); typedef size_t (* ma_dr_wav_write_proc)(void* pUserData, const void* pData, size_t bytesToWrite); typedef ma_bool32 (* ma_dr_wav_seek_proc)(void* pUserData, int offset, ma_dr_wav_seek_origin origin); -typedef ma_bool32 (* ma_dr_wav_tell_proc)(void* pUserData, ma_int64* pCursor); typedef ma_uint64 (* ma_dr_wav_chunk_proc)(void* pChunkUserData, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pReadSeekUserData, const ma_dr_wav_chunk_header* pChunkHeader, ma_dr_wav_container container, const ma_dr_wav_fmt* pFMT); typedef struct { @@ -61971,11 +60432,6 @@ typedef enum ma_dr_wav_metadata_type_list_info_genre = 1 << 15, ma_dr_wav_metadata_type_list_info_album = 1 << 16, ma_dr_wav_metadata_type_list_info_tracknumber = 1 << 17, - ma_dr_wav_metadata_type_list_info_location = 1 << 18, - ma_dr_wav_metadata_type_list_info_organization = 1 << 19, - ma_dr_wav_metadata_type_list_info_keywords = 1 << 20, - ma_dr_wav_metadata_type_list_info_medium = 1 << 21, - ma_dr_wav_metadata_type_list_info_description = 1 << 22, ma_dr_wav_metadata_type_list_all_info_strings = ma_dr_wav_metadata_type_list_info_software | ma_dr_wav_metadata_type_list_info_copyright | ma_dr_wav_metadata_type_list_info_title @@ -61984,12 +60440,7 @@ typedef enum | ma_dr_wav_metadata_type_list_info_date | ma_dr_wav_metadata_type_list_info_genre | ma_dr_wav_metadata_type_list_info_album - | ma_dr_wav_metadata_type_list_info_tracknumber - | ma_dr_wav_metadata_type_list_info_location - | ma_dr_wav_metadata_type_list_info_organization - | ma_dr_wav_metadata_type_list_info_keywords - | ma_dr_wav_metadata_type_list_info_medium - | ma_dr_wav_metadata_type_list_info_description, + | ma_dr_wav_metadata_type_list_info_tracknumber, ma_dr_wav_metadata_type_list_all_adtl = ma_dr_wav_metadata_type_list_label | ma_dr_wav_metadata_type_list_note | ma_dr_wav_metadata_type_list_labelled_cue_region, @@ -62006,8 +60457,8 @@ typedef struct { ma_uint32 cuePointId; ma_uint32 type; - ma_uint32 firstSampleOffset; - ma_uint32 lastSampleOffset; + ma_uint32 firstSampleByteOffset; + ma_uint32 lastSampleByteOffset; ma_uint32 sampleFraction; ma_uint32 playCount; } ma_dr_wav_smpl_loop; @@ -62042,7 +60493,7 @@ typedef struct ma_uint8 dataChunkId[4]; ma_uint32 chunkStart; ma_uint32 blockStart; - ma_uint32 sampleOffset; + ma_uint32 sampleByteOffset; } ma_dr_wav_cue_point; typedef struct { @@ -62144,7 +60595,6 @@ typedef struct ma_dr_wav_read_proc onRead; ma_dr_wav_write_proc onWrite; ma_dr_wav_seek_proc onSeek; - ma_dr_wav_tell_proc onTell; void* pUserData; ma_allocation_callbacks allocationCallbacks; ma_dr_wav_container container; @@ -62187,9 +60637,9 @@ typedef struct ma_bool8 isUnsigned; } aiff; } ma_dr_wav; -MA_API ma_bool32 ma_dr_wav_init(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_tell_proc onTell, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_bool32 ma_dr_wav_init_ex(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_tell_proc onTell, ma_dr_wav_chunk_proc onChunk, void* pReadSeekTellUserData, void* pChunkUserData, ma_uint32 flags, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_bool32 ma_dr_wav_init_with_metadata(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_tell_proc onTell, void* pUserData, ma_uint32 flags, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_bool32 ma_dr_wav_init(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_bool32 ma_dr_wav_init_ex(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_chunk_proc onChunk, void* pReadSeekUserData, void* pChunkUserData, ma_uint32 flags, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_bool32 ma_dr_wav_init_with_metadata(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pUserData, ma_uint32 flags, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_bool32 ma_dr_wav_init_write(ma_dr_wav* pWav, const ma_dr_wav_data_format* pFormat, ma_dr_wav_write_proc onWrite, ma_dr_wav_seek_proc onSeek, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_bool32 ma_dr_wav_init_write_sequential(ma_dr_wav* pWav, const ma_dr_wav_data_format* pFormat, ma_uint64 totalSampleCount, ma_dr_wav_write_proc onWrite, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_bool32 ma_dr_wav_init_write_sequential_pcm_frames(ma_dr_wav* pWav, const ma_dr_wav_data_format* pFormat, ma_uint64 totalPCMFrameCount, ma_dr_wav_write_proc onWrite, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); @@ -62261,9 +60711,9 @@ MA_API ma_bool32 ma_dr_wav_init_memory_write(ma_dr_wav* pWav, void** ppData, siz MA_API ma_bool32 ma_dr_wav_init_memory_write_sequential(ma_dr_wav* pWav, void** ppData, size_t* pDataSize, const ma_dr_wav_data_format* pFormat, ma_uint64 totalSampleCount, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_bool32 ma_dr_wav_init_memory_write_sequential_pcm_frames(ma_dr_wav* pWav, void** ppData, size_t* pDataSize, const ma_dr_wav_data_format* pFormat, ma_uint64 totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); #ifndef MA_DR_WAV_NO_CONVERSION_API -MA_API ma_int16* ma_dr_wav_open_and_read_pcm_frames_s16(ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API float* ma_dr_wav_open_and_read_pcm_frames_f32(ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_int32* ma_dr_wav_open_and_read_pcm_frames_s32(ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_int16* ma_dr_wav_open_and_read_pcm_frames_s16(ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API float* ma_dr_wav_open_and_read_pcm_frames_f32(ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_int32* ma_dr_wav_open_and_read_pcm_frames_s32(ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks); #ifndef MA_DR_WAV_NO_STDIO MA_API ma_int16* ma_dr_wav_open_file_and_read_pcm_frames_s16(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks); MA_API float* ma_dr_wav_open_file_and_read_pcm_frames_f32(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks); @@ -62303,8 +60753,8 @@ extern "C" { #define MA_DR_FLAC_STRINGIFY(x) #x #define MA_DR_FLAC_XSTRINGIFY(x) MA_DR_FLAC_STRINGIFY(x) #define MA_DR_FLAC_VERSION_MAJOR 0 -#define MA_DR_FLAC_VERSION_MINOR 13 -#define MA_DR_FLAC_VERSION_REVISION 1 +#define MA_DR_FLAC_VERSION_MINOR 12 +#define MA_DR_FLAC_VERSION_REVISION 43 #define MA_DR_FLAC_VERSION_STRING MA_DR_FLAC_XSTRINGIFY(MA_DR_FLAC_VERSION_MAJOR) "." MA_DR_FLAC_XSTRINGIFY(MA_DR_FLAC_VERSION_MINOR) "." MA_DR_FLAC_XSTRINGIFY(MA_DR_FLAC_VERSION_REVISION) #include #if defined(_MSC_VER) && _MSC_VER >= 1700 @@ -62367,9 +60817,8 @@ typedef enum } ma_dr_flac_container; typedef enum { - MA_DR_FLAC_SEEK_SET, - MA_DR_FLAC_SEEK_CUR, - MA_DR_FLAC_SEEK_END + ma_dr_flac_seek_origin_start, + ma_dr_flac_seek_origin_current } ma_dr_flac_seek_origin; typedef struct { @@ -62445,7 +60894,6 @@ typedef struct } ma_dr_flac_metadata; typedef size_t (* ma_dr_flac_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead); typedef ma_bool32 (* ma_dr_flac_seek_proc)(void* pUserData, int offset, ma_dr_flac_seek_origin origin); -typedef ma_bool32 (* ma_dr_flac_tell_proc)(void* pUserData, ma_int64* pCursor); typedef void (* ma_dr_flac_meta_proc)(void* pUserData, ma_dr_flac_metadata* pMetadata); typedef struct { @@ -62457,7 +60905,6 @@ typedef struct { ma_dr_flac_read_proc onRead; ma_dr_flac_seek_proc onSeek; - ma_dr_flac_tell_proc onTell; void* pUserData; size_t unalignedByteCount; ma_dr_flac_cache_t unalignedCache; @@ -62517,10 +60964,10 @@ typedef struct ma_dr_flac_bs bs; ma_uint8 pExtraData[1]; } ma_dr_flac; -MA_API ma_dr_flac* ma_dr_flac_open(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_dr_flac* ma_dr_flac_open_relaxed(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, ma_dr_flac_container container, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_dr_flac* ma_dr_flac_open_with_metadata(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, ma_dr_flac_meta_proc onMeta, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_dr_flac* ma_dr_flac_open_with_metadata_relaxed(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, ma_dr_flac_meta_proc onMeta, ma_dr_flac_container container, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_dr_flac* ma_dr_flac_open(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_dr_flac* ma_dr_flac_open_relaxed(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_container container, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_dr_flac* ma_dr_flac_open_with_metadata(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_meta_proc onMeta, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_dr_flac* ma_dr_flac_open_with_metadata_relaxed(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_meta_proc onMeta, ma_dr_flac_container container, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); MA_API void ma_dr_flac_close(ma_dr_flac* pFlac); MA_API ma_uint64 ma_dr_flac_read_pcm_frames_s32(ma_dr_flac* pFlac, ma_uint64 framesToRead, ma_int32* pBufferOut); MA_API ma_uint64 ma_dr_flac_read_pcm_frames_s16(ma_dr_flac* pFlac, ma_uint64 framesToRead, ma_int16* pBufferOut); @@ -62534,9 +60981,9 @@ MA_API ma_dr_flac* ma_dr_flac_open_file_with_metadata_w(const wchar_t* pFileName #endif MA_API ma_dr_flac* ma_dr_flac_open_memory(const void* pData, size_t dataSize, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_dr_flac* ma_dr_flac_open_memory_with_metadata(const void* pData, size_t dataSize, ma_dr_flac_meta_proc onMeta, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_int32* ma_dr_flac_open_and_read_pcm_frames_s32(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, void* pUserData, unsigned int* channels, unsigned int* sampleRate, ma_uint64* totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_int16* ma_dr_flac_open_and_read_pcm_frames_s16(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, void* pUserData, unsigned int* channels, unsigned int* sampleRate, ma_uint64* totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API float* ma_dr_flac_open_and_read_pcm_frames_f32(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, void* pUserData, unsigned int* channels, unsigned int* sampleRate, ma_uint64* totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_int32* ma_dr_flac_open_and_read_pcm_frames_s32(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, ma_uint64* totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_int16* ma_dr_flac_open_and_read_pcm_frames_s16(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, ma_uint64* totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API float* ma_dr_flac_open_and_read_pcm_frames_f32(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, ma_uint64* totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); #ifndef MA_DR_FLAC_NO_STDIO MA_API ma_int32* ma_dr_flac_open_file_and_read_pcm_frames_s32(const char* filename, unsigned int* channels, unsigned int* sampleRate, ma_uint64* totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_int16* ma_dr_flac_open_file_and_read_pcm_frames_s16(const char* filename, unsigned int* channels, unsigned int* sampleRate, ma_uint64* totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); @@ -62584,12 +61031,6 @@ MA_API ma_bool32 ma_dr_flac_next_cuesheet_track(ma_dr_flac_cuesheet_track_iterat #endif /* MA_NO_FLAC */ #if !defined(MA_NO_MP3) && !defined(MA_NO_DECODING) -#ifndef MA_DR_MP3_NO_SIMD - #if (defined(MA_NO_NEON) && defined(MA_ARM)) || (defined(MA_NO_SSE2) && (defined(MA_X86) || defined(MA_X64))) - #define MA_DR_MP3_NO_SIMD - #endif -#endif - /* dr_mp3_h begin */ #ifndef ma_dr_mp3_h #define ma_dr_mp3_h @@ -62599,8 +61040,8 @@ extern "C" { #define MA_DR_MP3_STRINGIFY(x) #x #define MA_DR_MP3_XSTRINGIFY(x) MA_DR_MP3_STRINGIFY(x) #define MA_DR_MP3_VERSION_MAJOR 0 -#define MA_DR_MP3_VERSION_MINOR 7 -#define MA_DR_MP3_VERSION_REVISION 1 +#define MA_DR_MP3_VERSION_MINOR 6 +#define MA_DR_MP3_VERSION_REVISION 40 #define MA_DR_MP3_VERSION_STRING MA_DR_MP3_XSTRINGIFY(MA_DR_MP3_VERSION_MAJOR) "." MA_DR_MP3_XSTRINGIFY(MA_DR_MP3_VERSION_MINOR) "." MA_DR_MP3_XSTRINGIFY(MA_DR_MP3_VERSION_REVISION) #include #define MA_DR_MP3_MAX_PCM_FRAMES_PER_MP3_FRAME 1152 @@ -62609,7 +61050,7 @@ MA_API void ma_dr_mp3_version(ma_uint32* pMajor, ma_uint32* pMinor, ma_uint32* p MA_API const char* ma_dr_mp3_version_string(void); typedef struct { - int frame_bytes, channels, sample_rate, layer, bitrate_kbps; + int frame_bytes, channels, hz, layer, bitrate_kbps; } ma_dr_mp3dec_frame_info; typedef struct { @@ -62622,9 +61063,8 @@ MA_API int ma_dr_mp3dec_decode_frame(ma_dr_mp3dec *dec, const ma_uint8 *mp3, int MA_API void ma_dr_mp3dec_f32_to_s16(const float *in, ma_int16 *out, size_t num_samples); typedef enum { - MA_DR_MP3_SEEK_SET, - MA_DR_MP3_SEEK_CUR, - MA_DR_MP3_SEEK_END + ma_dr_mp3_seek_origin_start, + ma_dr_mp3_seek_origin_current } ma_dr_mp3_seek_origin; typedef struct { @@ -62633,24 +61073,8 @@ typedef struct ma_uint16 mp3FramesToDiscard; ma_uint16 pcmFramesToDiscard; } ma_dr_mp3_seek_point; -typedef enum -{ - MA_DR_MP3_METADATA_TYPE_ID3V1, - MA_DR_MP3_METADATA_TYPE_ID3V2, - MA_DR_MP3_METADATA_TYPE_APE, - MA_DR_MP3_METADATA_TYPE_XING, - MA_DR_MP3_METADATA_TYPE_VBRI -} ma_dr_mp3_metadata_type; -typedef struct -{ - ma_dr_mp3_metadata_type type; - const void* pRawData; - size_t rawDataSize; -} ma_dr_mp3_metadata; typedef size_t (* ma_dr_mp3_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead); typedef ma_bool32 (* ma_dr_mp3_seek_proc)(void* pUserData, int offset, ma_dr_mp3_seek_origin origin); -typedef ma_bool32 (* ma_dr_mp3_tell_proc)(void* pUserData, ma_int64* pCursor); -typedef void (* ma_dr_mp3_meta_proc)(void* pUserData, const ma_dr_mp3_metadata* pMetadata); typedef struct { ma_uint32 channels; @@ -62663,9 +61087,7 @@ typedef struct ma_uint32 sampleRate; ma_dr_mp3_read_proc onRead; ma_dr_mp3_seek_proc onSeek; - ma_dr_mp3_meta_proc onMeta; void* pUserData; - void* pUserDataMeta; ma_allocation_callbacks allocationCallbacks; ma_uint32 mp3FrameChannels; ma_uint32 mp3FrameSampleRate; @@ -62674,20 +61096,13 @@ typedef struct ma_uint8 pcmFrames[sizeof(float)*MA_DR_MP3_MAX_SAMPLES_PER_FRAME]; ma_uint64 currentPCMFrame; ma_uint64 streamCursor; - ma_uint64 streamLength; - ma_uint64 streamStartOffset; ma_dr_mp3_seek_point* pSeekPoints; ma_uint32 seekPointCount; - ma_uint32 delayInPCMFrames; - ma_uint32 paddingInPCMFrames; - ma_uint64 totalPCMFrameCount; - ma_bool32 isVBR; - ma_bool32 isCBR; size_t dataSize; size_t dataCapacity; size_t dataConsumed; ma_uint8* pData; - ma_bool32 atEnd; + ma_bool32 atEnd : 1; struct { const ma_uint8* pData; @@ -62695,12 +61110,9 @@ typedef struct size_t currentReadPos; } memory; } ma_dr_mp3; -MA_API ma_bool32 ma_dr_mp3_init(ma_dr_mp3* pMP3, ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, ma_dr_mp3_tell_proc onTell, ma_dr_mp3_meta_proc onMeta, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_bool32 ma_dr_mp3_init_memory_with_metadata(ma_dr_mp3* pMP3, const void* pData, size_t dataSize, ma_dr_mp3_meta_proc onMeta, void* pUserDataMeta, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_bool32 ma_dr_mp3_init(ma_dr_mp3* pMP3, ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_bool32 ma_dr_mp3_init_memory(ma_dr_mp3* pMP3, const void* pData, size_t dataSize, const ma_allocation_callbacks* pAllocationCallbacks); #ifndef MA_DR_MP3_NO_STDIO -MA_API ma_bool32 ma_dr_mp3_init_file_with_metadata(ma_dr_mp3* pMP3, const char* pFilePath, ma_dr_mp3_meta_proc onMeta, void* pUserDataMeta, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_bool32 ma_dr_mp3_init_file_with_metadata_w(ma_dr_mp3* pMP3, const wchar_t* pFilePath, ma_dr_mp3_meta_proc onMeta, void* pUserDataMeta, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_bool32 ma_dr_mp3_init_file(ma_dr_mp3* pMP3, const char* pFilePath, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_bool32 ma_dr_mp3_init_file_w(ma_dr_mp3* pMP3, const wchar_t* pFilePath, const ma_allocation_callbacks* pAllocationCallbacks); #endif @@ -62713,8 +61125,8 @@ MA_API ma_uint64 ma_dr_mp3_get_mp3_frame_count(ma_dr_mp3* pMP3); MA_API ma_bool32 ma_dr_mp3_get_mp3_and_pcm_frame_count(ma_dr_mp3* pMP3, ma_uint64* pMP3FrameCount, ma_uint64* pPCMFrameCount); MA_API ma_bool32 ma_dr_mp3_calculate_seek_points(ma_dr_mp3* pMP3, ma_uint32* pSeekPointCount, ma_dr_mp3_seek_point* pSeekPoints); MA_API ma_bool32 ma_dr_mp3_bind_seek_table(ma_dr_mp3* pMP3, ma_uint32 seekPointCount, ma_dr_mp3_seek_point* pSeekPoints); -MA_API float* ma_dr_mp3_open_and_read_pcm_frames_f32(ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, ma_dr_mp3_tell_proc onTell, void* pUserData, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_int16* ma_dr_mp3_open_and_read_pcm_frames_s16(ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, ma_dr_mp3_tell_proc onTell, void* pUserData, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API float* ma_dr_mp3_open_and_read_pcm_frames_f32(ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, void* pUserData, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_int16* ma_dr_mp3_open_and_read_pcm_frames_s16(ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, void* pUserData, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); MA_API float* ma_dr_mp3_open_memory_and_read_pcm_frames_f32(const void* pData, size_t dataSize, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_int16* ma_dr_mp3_open_memory_and_read_pcm_frames_s16(const void* pData, size_t dataSize, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); #ifndef MA_DR_MP3_NO_STDIO @@ -63267,10 +61679,8 @@ static ma_bool32 ma_wav_dr_callback__seek(void* pUserData, int offset, ma_dr_wav MA_ASSERT(pWav != NULL); maSeekOrigin = ma_seek_origin_start; - if (origin == MA_DR_WAV_SEEK_CUR) { - maSeekOrigin = ma_seek_origin_current; - } else if (origin == MA_DR_WAV_SEEK_END) { - maSeekOrigin = ma_seek_origin_end; + if (origin == ma_dr_wav_seek_origin_current) { + maSeekOrigin = ma_seek_origin_current; } result = pWav->onSeek(pWav->pReadSeekTellUserData, offset, maSeekOrigin); @@ -63280,26 +61690,6 @@ static ma_bool32 ma_wav_dr_callback__seek(void* pUserData, int offset, ma_dr_wav return MA_TRUE; } - -static ma_bool32 ma_wav_dr_callback__tell(void* pUserData, ma_int64* pCursor) -{ - ma_wav* pWav = (ma_wav*)pUserData; - ma_result result; - - MA_ASSERT(pWav != NULL); - MA_ASSERT(pCursor != NULL); - - if (pWav->onTell == NULL) { - return MA_FALSE; /* Not implemented. */ - } - - result = pWav->onTell(pWav->pReadSeekTellUserData, pCursor); - if (result != MA_SUCCESS) { - return MA_FALSE; /* Failed to tell. */ - } - - return MA_TRUE; -} #endif static ma_result ma_wav_init_internal(const ma_decoding_backend_config* pConfig, ma_wav* pWav) @@ -63394,7 +61784,7 @@ MA_API ma_result ma_wav_init(ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_p { ma_bool32 wavResult; - wavResult = ma_dr_wav_init(&pWav->dr, ma_wav_dr_callback__read, ma_wav_dr_callback__seek, ma_wav_dr_callback__tell, pWav, pAllocationCallbacks); + wavResult = ma_dr_wav_init(&pWav->dr, ma_wav_dr_callback__read, ma_wav_dr_callback__seek, pWav, pAllocationCallbacks); if (wavResult != MA_TRUE) { return MA_INVALID_FILE; } @@ -63973,10 +62363,8 @@ static ma_bool32 ma_flac_dr_callback__seek(void* pUserData, int offset, ma_dr_fl MA_ASSERT(pFlac != NULL); maSeekOrigin = ma_seek_origin_start; - if (origin == MA_DR_FLAC_SEEK_CUR) { - maSeekOrigin = ma_seek_origin_current; - } else if (origin == MA_DR_FLAC_SEEK_END) { - maSeekOrigin = ma_seek_origin_end; + if (origin == ma_dr_flac_seek_origin_current) { + maSeekOrigin = ma_seek_origin_current; } result = pFlac->onSeek(pFlac->pReadSeekTellUserData, offset, maSeekOrigin); @@ -63986,26 +62374,6 @@ static ma_bool32 ma_flac_dr_callback__seek(void* pUserData, int offset, ma_dr_fl return MA_TRUE; } - -static ma_bool32 ma_flac_dr_callback__tell(void* pUserData, ma_int64* pCursor) -{ - ma_flac* pFlac = (ma_flac*)pUserData; - ma_result result; - - MA_ASSERT(pFlac != NULL); - MA_ASSERT(pCursor != NULL); - - if (pFlac->onTell == NULL) { - return MA_FALSE; /* Not implemented. */ - } - - result = pFlac->onTell(pFlac->pReadSeekTellUserData, pCursor); - if (result != MA_SUCCESS) { - return MA_FALSE; /* Failed to tell. */ - } - - return MA_TRUE; -} #endif static ma_result ma_flac_init_internal(const ma_decoding_backend_config* pConfig, ma_flac* pFlac) @@ -64057,7 +62425,7 @@ MA_API ma_result ma_flac_init(ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_ #if !defined(MA_NO_FLAC) { - pFlac->dr = ma_dr_flac_open(ma_flac_dr_callback__read, ma_flac_dr_callback__seek, ma_flac_dr_callback__tell, pFlac, pAllocationCallbacks); + pFlac->dr = ma_dr_flac_open(ma_flac_dr_callback__read, ma_flac_dr_callback__seek, pFlac, pAllocationCallbacks); if (pFlac->dr == NULL) { return MA_INVALID_FILE; } @@ -64618,12 +62986,9 @@ static ma_bool32 ma_mp3_dr_callback__seek(void* pUserData, int offset, ma_dr_mp3 MA_ASSERT(pMP3 != NULL); - if (origin == MA_DR_MP3_SEEK_SET) { - maSeekOrigin = ma_seek_origin_start; - } else if (origin == MA_DR_MP3_SEEK_END) { - maSeekOrigin = ma_seek_origin_end; - } else { - maSeekOrigin = ma_seek_origin_current; + maSeekOrigin = ma_seek_origin_start; + if (origin == ma_dr_mp3_seek_origin_current) { + maSeekOrigin = ma_seek_origin_current; } result = pMP3->onSeek(pMP3->pReadSeekTellUserData, offset, maSeekOrigin); @@ -64633,21 +62998,6 @@ static ma_bool32 ma_mp3_dr_callback__seek(void* pUserData, int offset, ma_dr_mp3 return MA_TRUE; } - -static ma_bool32 ma_mp3_dr_callback__tell(void* pUserData, ma_int64* pCursor) -{ - ma_mp3* pMP3 = (ma_mp3*)pUserData; - ma_result result; - - MA_ASSERT(pMP3 != NULL); - - result = pMP3->onTell(pMP3->pReadSeekTellUserData, pCursor); - if (result != MA_SUCCESS) { - return MA_FALSE; - } - - return MA_TRUE; -} #endif static ma_result ma_mp3_init_internal(const ma_decoding_backend_config* pConfig, ma_mp3* pMP3) @@ -64748,7 +63098,7 @@ MA_API ma_result ma_mp3_init(ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_p { ma_bool32 mp3Result; - mp3Result = ma_dr_mp3_init(&pMP3->dr, ma_mp3_dr_callback__read, ma_mp3_dr_callback__seek, ma_mp3_dr_callback__tell, NULL, pMP3, pAllocationCallbacks); + mp3Result = ma_dr_mp3_init(&pMP3->dr, ma_mp3_dr_callback__read, ma_mp3_dr_callback__seek, pMP3, pAllocationCallbacks); if (mp3Result != MA_TRUE) { return MA_INVALID_FILE; } @@ -66647,16 +64997,14 @@ static ma_bool32 ma_path_extension_equal_w(const wchar_t* path, const wchar_t* e ext1 = extension; ext2 = ma_path_extension_w(path); - #if (defined(_MSC_VER) || defined(__WATCOMC__) || defined(__DMC__)) && !defined(MA_XBOX_NXDK) +#if defined(_MSC_VER) || defined(__WATCOMC__) || defined(__DMC__) + return _wcsicmp(ext1, ext2) == 0; +#else + /* + I'm not aware of a wide character version of strcasecmp(). I'm therefore converting the extensions to multibyte strings and comparing those. This + isn't the most efficient way to do it, but it should work OK. + */ { - return _wcsicmp(ext1, ext2) == 0; - } - #elif !defined(MA_XBOX_NXDK) && !defined(MA_DOS) - { - /* - I'm not aware of a wide character version of strcasecmp(). I'm therefore converting the extensions to multibyte strings and comparing those. This - isn't the most efficient way to do it, but it should work OK. - */ char ext1MB[4096]; char ext2MB[4096]; const wchar_t* pext1 = ext1; @@ -66676,13 +65024,7 @@ static ma_bool32 ma_path_extension_equal_w(const wchar_t* path, const wchar_t* e return strcasecmp(ext1MB, ext2MB) == 0; } - #else - { - /* Getting here means we don't have a way to do a case-sensitive comparison for wide strings. Fall back to a simple case-sensitive comparison. */ - /* TODO: Implement our own wchar_t-to-char conversion routine and then use the char* version for comparing. */ - return ma_wcscmp(ext1, ext2) == 0; - } - #endif +#endif } #endif /* MA_HAS_PATH_API */ @@ -67777,18 +66119,10 @@ static ma_bool32 ma_encoder__internal_on_seek_wav(void* pUserData, int offset, m { ma_encoder* pEncoder = (ma_encoder*)pUserData; ma_result result; - ma_seek_origin maSeekOrigin; MA_ASSERT(pEncoder != NULL); - maSeekOrigin = ma_seek_origin_start; - if (origin == MA_DR_WAV_SEEK_CUR) { - maSeekOrigin = ma_seek_origin_current; - } else if (origin == MA_DR_WAV_SEEK_END) { - maSeekOrigin = ma_seek_origin_end; - } - - result = pEncoder->onSeek(pEncoder, offset, maSeekOrigin); + result = pEncoder->onSeek(pEncoder, offset, (origin == ma_dr_wav_seek_origin_start) ? ma_seek_origin_start : ma_seek_origin_current); if (result != MA_SUCCESS) { return MA_FALSE; } else { @@ -69310,7 +67644,7 @@ static MA_INLINE ma_uint32 ma_hash_getblock(const ma_uint32* blocks, int i) ma_uint32 block; /* Try silencing a sanitization warning about unaligned access by doing a memcpy() instead of assignment. */ - MA_COPY_MEMORY(&block, ma_offset_ptr(blocks, i * (int) sizeof(block)), sizeof(block)); + MA_COPY_MEMORY(&block, ma_offset_ptr(blocks, i * sizeof(block)), sizeof(block)); if (ma_is_little_endian()) { return block; @@ -69386,7 +67720,7 @@ static ma_uint32 ma_hash_string_32(const char* str) static ma_uint32 ma_hash_string_w_32(const wchar_t* str) { - return ma_hash_32(str, (int)ma_wcslen(str) * sizeof(*str), MA_DEFAULT_HASH_SEED); + return ma_hash_32(str, (int)wcslen(str) * sizeof(*str), MA_DEFAULT_HASH_SEED); } @@ -69546,7 +67880,6 @@ static MA_INLINE ma_resource_manager_data_buffer_node* ma_resource_manager_data_ return ma_resource_manager_data_buffer_node_find_min(pDataBufferNode->pChildHi); } -#if 0 /* Currently unused, but might make use of this later. */ static MA_INLINE ma_resource_manager_data_buffer_node* ma_resource_manager_data_buffer_node_find_inorder_predecessor(ma_resource_manager_data_buffer_node* pDataBufferNode) { MA_ASSERT(pDataBufferNode != NULL); @@ -69554,7 +67887,6 @@ static MA_INLINE ma_resource_manager_data_buffer_node* ma_resource_manager_data_ return ma_resource_manager_data_buffer_node_find_max(pDataBufferNode->pChildLo); } -#endif static ma_result ma_resource_manager_data_buffer_node_remove(ma_resource_manager* pResourceManager, ma_resource_manager_data_buffer_node* pDataBufferNode) { @@ -70677,19 +69009,16 @@ static ma_result ma_resource_manager_data_buffer_node_acquire_critical_section(m /* Failed to post job. Probably ran out of memory. */ ma_log_postf(ma_resource_manager_get_log(pResourceManager), MA_LOG_LEVEL_ERROR, "Failed to post MA_JOB_TYPE_RESOURCE_MANAGER_LOAD_DATA_BUFFER_NODE job. %s.\n", ma_result_description(result)); + /* + Fences were acquired before posting the job, but since the job was not able to + be posted, we need to make sure we release them so nothing gets stuck waiting. + */ + if (pInitFence != NULL) { ma_fence_release(pInitFence); } + if (pDoneFence != NULL) { ma_fence_release(pDoneFence); } + if ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT) != 0) { ma_resource_manager_inline_notification_uninit(pInitNotification); } else { - /* - Fences were acquired before posting the job, but since the job was not able to - be posted, we need to make sure we release them so nothing gets stuck waiting. - - In the WAIT_INIT case, these will have already been released in ma_job_process() - so we should only release fences in this branch. - */ - if (pInitFence != NULL) { ma_fence_release(pInitFence); } - if (pDoneFence != NULL) { ma_fence_release(pDoneFence); } - /* These will have been freed by the job thread, but with WAIT_INIT they will already have happened since the job has already been handled. */ ma_free(pFilePathCopy, &pResourceManager->config.allocationCallbacks); ma_free(pFilePathWCopy, &pResourceManager->config.allocationCallbacks); @@ -78345,7 +76674,7 @@ static ma_result ma_sound_init_from_data_source_internal(ma_engine* pEngine, con } if (pConfig->loopPointBegInPCMFrames != 0 || pConfig->loopPointEndInPCMFrames != ~((ma_uint64)0)) { - ma_data_source_set_loop_point_in_pcm_frames(ma_sound_get_data_source(pSound), pConfig->loopPointBegInPCMFrames, pConfig->loopPointEndInPCMFrames); + ma_data_source_set_range_in_pcm_frames(ma_sound_get_data_source(pSound), pConfig->loopPointBegInPCMFrames, pConfig->loopPointEndInPCMFrames); } ma_sound_set_looping(pSound, pConfig->isLooping || ((pConfig->flags & MA_SOUND_FLAG_LOOPING) != 0)); @@ -78407,7 +76736,6 @@ MA_API ma_result ma_sound_init_from_file_internal(ma_engine* pEngine, const ma_s result = ma_resource_manager_data_source_init_ex(pEngine->pResourceManager, &resourceManagerDataSourceConfig, pSound->pResourceManagerDataSource); if (result != MA_SUCCESS) { - ma_free(pSound->pResourceManagerDataSource, &pEngine->allocationCallbacks); goto done; } @@ -79213,12 +77541,7 @@ MA_API ma_uint64 ma_sound_get_time_in_pcm_frames(const ma_sound* pSound) MA_API ma_uint64 ma_sound_get_time_in_milliseconds(const ma_sound* pSound) { - ma_uint32 sampleRate = ma_engine_get_sample_rate(ma_sound_get_engine(pSound)); - if (sampleRate == 0) { - return 0; /* Prevent a division by zero. */ - } - - return ma_sound_get_time_in_pcm_frames(pSound) * 1000 / sampleRate; + return ma_sound_get_time_in_pcm_frames(pSound) * 1000 / ma_engine_get_sample_rate(ma_sound_get_engine(pSound)); } MA_API void ma_sound_set_looping(ma_sound* pSound, ma_bool32 isLooping) @@ -79302,7 +77625,7 @@ MA_API ma_result ma_sound_seek_to_second(ma_sound* pSound, float seekPointInSeco return ma_sound_seek_to_pcm_frame(pSound, frameIndex); } -MA_API ma_result ma_sound_get_data_format(const ma_sound* pSound, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) +MA_API ma_result ma_sound_get_data_format(ma_sound* pSound, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) { if (pSound == NULL) { return MA_INVALID_ARGS; @@ -79335,7 +77658,7 @@ MA_API ma_result ma_sound_get_data_format(const ma_sound* pSound, ma_format* pFo } } -MA_API ma_result ma_sound_get_cursor_in_pcm_frames(const ma_sound* pSound, ma_uint64* pCursor) +MA_API ma_result ma_sound_get_cursor_in_pcm_frames(ma_sound* pSound, ma_uint64* pCursor) { ma_uint64 seekTarget; @@ -79357,7 +77680,7 @@ MA_API ma_result ma_sound_get_cursor_in_pcm_frames(const ma_sound* pSound, ma_ui } } -MA_API ma_result ma_sound_get_length_in_pcm_frames(const ma_sound* pSound, ma_uint64* pLength) +MA_API ma_result ma_sound_get_length_in_pcm_frames(ma_sound* pSound, ma_uint64* pLength) { if (pSound == NULL) { return MA_INVALID_ARGS; @@ -79371,7 +77694,7 @@ MA_API ma_result ma_sound_get_length_in_pcm_frames(const ma_sound* pSound, ma_ui return ma_data_source_get_length_in_pcm_frames(pSound->pDataSource, pLength); } -MA_API ma_result ma_sound_get_cursor_in_seconds(const ma_sound* pSound, float* pCursor) +MA_API ma_result ma_sound_get_cursor_in_seconds(ma_sound* pSound, float* pCursor) { ma_result result; ma_uint64 cursorInPCMFrames; @@ -79397,7 +77720,7 @@ MA_API ma_result ma_sound_get_cursor_in_seconds(const ma_sound* pSound, float* p return MA_SUCCESS; } -MA_API ma_result ma_sound_get_length_in_seconds(const ma_sound* pSound, float* pLength) +MA_API ma_result ma_sound_get_length_in_seconds(ma_sound* pSound, float* pLength) { if (pSound == NULL) { return MA_INVALID_ARGS; @@ -80216,12 +78539,12 @@ MA_PRIVATE ma_bool32 ma_dr_wav__seek_forward(ma_dr_wav_seek_proc onSeek, ma_uint ma_uint64 bytesRemainingToSeek = offset; while (bytesRemainingToSeek > 0) { if (bytesRemainingToSeek > 0x7FFFFFFF) { - if (!onSeek(pUserData, 0x7FFFFFFF, MA_DR_WAV_SEEK_CUR)) { + if (!onSeek(pUserData, 0x7FFFFFFF, ma_dr_wav_seek_origin_current)) { return MA_FALSE; } bytesRemainingToSeek -= 0x7FFFFFFF; } else { - if (!onSeek(pUserData, (int)bytesRemainingToSeek, MA_DR_WAV_SEEK_CUR)) { + if (!onSeek(pUserData, (int)bytesRemainingToSeek, ma_dr_wav_seek_origin_current)) { return MA_FALSE; } bytesRemainingToSeek = 0; @@ -80232,17 +78555,17 @@ MA_PRIVATE ma_bool32 ma_dr_wav__seek_forward(ma_dr_wav_seek_proc onSeek, ma_uint MA_PRIVATE ma_bool32 ma_dr_wav__seek_from_start(ma_dr_wav_seek_proc onSeek, ma_uint64 offset, void* pUserData) { if (offset <= 0x7FFFFFFF) { - return onSeek(pUserData, (int)offset, MA_DR_WAV_SEEK_SET); + return onSeek(pUserData, (int)offset, ma_dr_wav_seek_origin_start); } - if (!onSeek(pUserData, 0x7FFFFFFF, MA_DR_WAV_SEEK_SET)) { + if (!onSeek(pUserData, 0x7FFFFFFF, ma_dr_wav_seek_origin_start)) { return MA_FALSE; } offset -= 0x7FFFFFFF; for (;;) { if (offset <= 0x7FFFFFFF) { - return onSeek(pUserData, (int)offset, MA_DR_WAV_SEEK_CUR); + return onSeek(pUserData, (int)offset, ma_dr_wav_seek_origin_current); } - if (!onSeek(pUserData, 0x7FFFFFFF, MA_DR_WAV_SEEK_CUR)) { + if (!onSeek(pUserData, 0x7FFFFFFF, ma_dr_wav_seek_origin_current)) { return MA_FALSE; } offset -= 0x7FFFFFFF; @@ -80265,7 +78588,7 @@ MA_PRIVATE ma_bool32 ma_dr_wav__on_seek(ma_dr_wav_seek_proc onSeek, void* pUserD if (!onSeek(pUserData, offset, origin)) { return MA_FALSE; } - if (origin == MA_DR_WAV_SEEK_SET) { + if (origin == ma_dr_wav_seek_origin_start) { *pCursor = offset; } else { *pCursor += offset; @@ -80384,12 +78707,12 @@ MA_PRIVATE ma_uint64 ma_dr_wav__read_smpl_to_metadata_obj(ma_dr_wav__metadata_pa ma_uint8 smplLoopData[MA_DR_WAV_SMPL_LOOP_BYTES]; bytesJustRead = ma_dr_wav__metadata_parser_read(pParser, smplLoopData, sizeof(smplLoopData), &totalBytesRead); if (bytesJustRead == sizeof(smplLoopData)) { - pMetadata->data.smpl.pLoops[iSampleLoop].cuePointId = ma_dr_wav_bytes_to_u32(smplLoopData + 0); - pMetadata->data.smpl.pLoops[iSampleLoop].type = ma_dr_wav_bytes_to_u32(smplLoopData + 4); - pMetadata->data.smpl.pLoops[iSampleLoop].firstSampleOffset = ma_dr_wav_bytes_to_u32(smplLoopData + 8); - pMetadata->data.smpl.pLoops[iSampleLoop].lastSampleOffset = ma_dr_wav_bytes_to_u32(smplLoopData + 12); - pMetadata->data.smpl.pLoops[iSampleLoop].sampleFraction = ma_dr_wav_bytes_to_u32(smplLoopData + 16); - pMetadata->data.smpl.pLoops[iSampleLoop].playCount = ma_dr_wav_bytes_to_u32(smplLoopData + 20); + pMetadata->data.smpl.pLoops[iSampleLoop].cuePointId = ma_dr_wav_bytes_to_u32(smplLoopData + 0); + pMetadata->data.smpl.pLoops[iSampleLoop].type = ma_dr_wav_bytes_to_u32(smplLoopData + 4); + pMetadata->data.smpl.pLoops[iSampleLoop].firstSampleByteOffset = ma_dr_wav_bytes_to_u32(smplLoopData + 8); + pMetadata->data.smpl.pLoops[iSampleLoop].lastSampleByteOffset = ma_dr_wav_bytes_to_u32(smplLoopData + 12); + pMetadata->data.smpl.pLoops[iSampleLoop].sampleFraction = ma_dr_wav_bytes_to_u32(smplLoopData + 16); + pMetadata->data.smpl.pLoops[iSampleLoop].playCount = ma_dr_wav_bytes_to_u32(smplLoopData + 20); } else { break; } @@ -80433,7 +78756,7 @@ MA_PRIVATE ma_uint64 ma_dr_wav__read_cue_to_metadata_obj(ma_dr_wav__metadata_par pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[3] = cuePointData[11]; pMetadata->data.cue.pCuePoints[iCuePoint].chunkStart = ma_dr_wav_bytes_to_u32(cuePointData + 12); pMetadata->data.cue.pCuePoints[iCuePoint].blockStart = ma_dr_wav_bytes_to_u32(cuePointData + 16); - pMetadata->data.cue.pCuePoints[iCuePoint].sampleOffset = ma_dr_wav_bytes_to_u32(cuePointData + 20); + pMetadata->data.cue.pCuePoints[iCuePoint].sampleByteOffset = ma_dr_wav_bytes_to_u32(cuePointData + 20); } else { break; } @@ -80773,7 +79096,7 @@ MA_PRIVATE ma_uint64 ma_dr_wav__metadata_process_chunk(ma_dr_wav__metadata_parse if (pParser->stage == ma_dr_wav__metadata_parser_stage_count) { ma_uint8 buffer[4]; size_t bytesJustRead; - if (!pParser->onSeek(pParser->pReadSeekUserData, 28, MA_DR_WAV_SEEK_CUR)) { + if (!pParser->onSeek(pParser->pReadSeekUserData, 28, ma_dr_wav_seek_origin_current)) { return bytesRead; } bytesRead += 28; @@ -80868,7 +79191,7 @@ MA_PRIVATE ma_uint64 ma_dr_wav__metadata_process_chunk(ma_dr_wav__metadata_parse return bytesRead; } allocSizeNeeded += ma_dr_wav__strlen(buffer) + 1; - allocSizeNeeded += (size_t)pChunkHeader->sizeInBytes - MA_DR_WAV_BEXT_BYTES + 1; + allocSizeNeeded += (size_t)pChunkHeader->sizeInBytes - MA_DR_WAV_BEXT_BYTES; ma_dr_wav__metadata_request_extra_memory_for_stage_2(pParser, allocSizeNeeded, 1); pParser->metadataCount += 1; } else { @@ -80951,16 +79274,6 @@ MA_PRIVATE ma_uint64 ma_dr_wav__metadata_process_chunk(ma_dr_wav__metadata_parse subchunkBytesRead = ma_dr_wav__metadata_process_info_text_chunk(pParser, subchunkDataSize, ma_dr_wav_metadata_type_list_info_album); } else if (ma_dr_wav__chunk_matches(allowedMetadataTypes, subchunkId, ma_dr_wav_metadata_type_list_info_tracknumber, "ITRK")) { subchunkBytesRead = ma_dr_wav__metadata_process_info_text_chunk(pParser, subchunkDataSize, ma_dr_wav_metadata_type_list_info_tracknumber); - } else if (ma_dr_wav__chunk_matches(allowedMetadataTypes, subchunkId, ma_dr_wav_metadata_type_list_info_location, "IARL")) { - subchunkBytesRead = ma_dr_wav__metadata_process_info_text_chunk(pParser, subchunkDataSize, ma_dr_wav_metadata_type_list_info_location); - } else if (ma_dr_wav__chunk_matches(allowedMetadataTypes, subchunkId, ma_dr_wav_metadata_type_list_info_organization, "ICMS")) { - subchunkBytesRead = ma_dr_wav__metadata_process_info_text_chunk(pParser, subchunkDataSize, ma_dr_wav_metadata_type_list_info_organization); - } else if (ma_dr_wav__chunk_matches(allowedMetadataTypes, subchunkId, ma_dr_wav_metadata_type_list_info_keywords, "IKEY")) { - subchunkBytesRead = ma_dr_wav__metadata_process_info_text_chunk(pParser, subchunkDataSize, ma_dr_wav_metadata_type_list_info_keywords); - } else if (ma_dr_wav__chunk_matches(allowedMetadataTypes, subchunkId, ma_dr_wav_metadata_type_list_info_medium, "IMED")) { - subchunkBytesRead = ma_dr_wav__metadata_process_info_text_chunk(pParser, subchunkDataSize, ma_dr_wav_metadata_type_list_info_medium); - } else if (ma_dr_wav__chunk_matches(allowedMetadataTypes, subchunkId, ma_dr_wav_metadata_type_list_info_description, "ISBJ")) { - subchunkBytesRead = ma_dr_wav__metadata_process_info_text_chunk(pParser, subchunkDataSize, ma_dr_wav_metadata_type_list_info_description); } else if ((allowedMetadataTypes & ma_dr_wav_metadata_type_unknown) != 0) { subchunkBytesRead = ma_dr_wav__metadata_process_unknown_chunk(pParser, subchunkId, subchunkDataSize, listType); } @@ -80968,13 +79281,13 @@ MA_PRIVATE ma_uint64 ma_dr_wav__metadata_process_chunk(ma_dr_wav__metadata_parse MA_DR_WAV_ASSERT(subchunkBytesRead <= subchunkDataSize); if (subchunkBytesRead < subchunkDataSize) { ma_uint64 bytesToSeek = subchunkDataSize - subchunkBytesRead; - if (!pParser->onSeek(pParser->pReadSeekUserData, (int)bytesToSeek, MA_DR_WAV_SEEK_CUR)) { + if (!pParser->onSeek(pParser->pReadSeekUserData, (int)bytesToSeek, ma_dr_wav_seek_origin_current)) { break; } bytesRead += bytesToSeek; } if ((subchunkDataSize % 2) == 1) { - if (!pParser->onSeek(pParser->pReadSeekUserData, 1, MA_DR_WAV_SEEK_CUR)) { + if (!pParser->onSeek(pParser->pReadSeekUserData, 1, ma_dr_wav_seek_origin_current)) { break; } bytesRead += 1; @@ -81011,7 +79324,7 @@ MA_API ma_uint16 ma_dr_wav_fmt_get_format(const ma_dr_wav_fmt* pFMT) return ma_dr_wav_bytes_to_u16(pFMT->subFormat); } } -MA_PRIVATE ma_bool32 ma_dr_wav_preinit(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_tell_proc onTell, void* pReadSeekTellUserData, const ma_allocation_callbacks* pAllocationCallbacks) +MA_PRIVATE ma_bool32 ma_dr_wav_preinit(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pReadSeekUserData, const ma_allocation_callbacks* pAllocationCallbacks) { if (pWav == NULL || onRead == NULL || onSeek == NULL) { return MA_FALSE; @@ -81019,8 +79332,7 @@ MA_PRIVATE ma_bool32 ma_dr_wav_preinit(ma_dr_wav* pWav, ma_dr_wav_read_proc onRe MA_DR_WAV_ZERO_MEMORY(pWav, sizeof(*pWav)); pWav->onRead = onRead; pWav->onSeek = onSeek; - pWav->onTell = onTell; - pWav->pUserData = pReadSeekTellUserData; + pWav->pUserData = pReadSeekUserData; pWav->allocationCallbacks = ma_dr_wav_copy_allocation_callbacks_or_defaults(pAllocationCallbacks); if (pWav->allocationCallbacks.onFree == NULL || (pWav->allocationCallbacks.onMalloc == NULL && pWav->allocationCallbacks.onRealloc == NULL)) { return MA_FALSE; @@ -81234,14 +79546,14 @@ MA_PRIVATE ma_bool32 ma_dr_wav_init__internal(ma_dr_wav* pWav, ma_dr_wav_chunk_p fmt.channelMask = ma_dr_wav_bytes_to_u32_ex(fmtext + 2, pWav->container); ma_dr_wav_bytes_to_guid(fmtext + 6, fmt.subFormat); } else { - if (pWav->onSeek(pWav->pUserData, fmt.extendedSize, MA_DR_WAV_SEEK_CUR) == MA_FALSE) { + if (pWav->onSeek(pWav->pUserData, fmt.extendedSize, ma_dr_wav_seek_origin_current) == MA_FALSE) { return MA_FALSE; } } cursor += fmt.extendedSize; bytesReadSoFar += fmt.extendedSize; } - if (pWav->onSeek(pWav->pUserData, (int)(header.sizeInBytes - bytesReadSoFar), MA_DR_WAV_SEEK_CUR) == MA_FALSE) { + if (pWav->onSeek(pWav->pUserData, (int)(header.sizeInBytes - bytesReadSoFar), ma_dr_wav_seek_origin_current) == MA_FALSE) { return MA_FALSE; } cursor += (header.sizeInBytes - bytesReadSoFar); @@ -81392,26 +79704,15 @@ MA_PRIVATE ma_bool32 ma_dr_wav_init__internal(ma_dr_wav* pWav, ma_dr_wav_chunk_p return MA_FALSE; } offset = ma_dr_wav_bytes_to_u32_ex(offsetAndBlockSizeData + 0, pWav->container); - pWav->dataChunkDataPos = cursor + offset; - dataChunkSize = chunkSize; - if (dataChunkSize > offset) { - dataChunkSize -= offset; - } else { - dataChunkSize = 0; + if (ma_dr_wav__seek_forward(pWav->onSeek, offset, pWav->pUserData) == MA_FALSE) { + return MA_FALSE; } - if (sequential) { - if (foundChunk_fmt) { - if (ma_dr_wav__seek_forward(pWav->onSeek, offset, pWav->pUserData) == MA_FALSE) { - return MA_FALSE; - } - cursor += offset; - break; - } else { - return MA_FALSE; - } + cursor += offset; + pWav->dataChunkDataPos = cursor; + dataChunkSize = chunkSize; + if (sequential || !isProcessingMetadata) { + break; } else { - chunkSize += header.paddingSize; - chunkSize -= sizeof(offsetAndBlockSizeData); if (ma_dr_wav__seek_forward(pWav->onSeek, chunkSize, pWav->pUserData) == MA_FALSE) { break; } @@ -81475,17 +79776,6 @@ MA_PRIVATE ma_bool32 ma_dr_wav_init__internal(ma_dr_wav* pWav, ma_dr_wav_chunk_p pWav->pMetadata = metadataParser.pMetadata; pWav->metadataCount = metadataParser.metadataCount; } - if (pWav->onTell != NULL && pWav->onSeek != NULL) { - if (pWav->onSeek(pWav->pUserData, 0, MA_DR_WAV_SEEK_END) == MA_TRUE) { - ma_int64 fileSize; - if (pWav->onTell(pWav->pUserData, &fileSize)) { - if (dataChunkSize + pWav->dataChunkDataPos > (ma_uint64)fileSize) { - dataChunkSize = (ma_uint64)fileSize - pWav->dataChunkDataPos; - } - } - } else { - } - } if (dataChunkSize == 0xFFFFFFFF && (pWav->container == ma_dr_wav_container_riff || pWav->container == ma_dr_wav_container_rifx) && pWav->isSequentialWrite == MA_FALSE) { dataChunkSize = 0; for (;;) { @@ -81505,14 +79795,8 @@ MA_PRIVATE ma_bool32 ma_dr_wav_init__internal(ma_dr_wav* pWav, ma_dr_wav_chunk_p pWav->sampleRate = fmt.sampleRate; pWav->channels = fmt.channels; pWav->bitsPerSample = fmt.bitsPerSample; - pWav->translatedFormatTag = translatedFormatTag; - if (!ma_dr_wav__is_compressed_format_tag(translatedFormatTag)) { - ma_uint32 bytesPerFrame = ma_dr_wav_get_bytes_per_pcm_frame(pWav); - if (bytesPerFrame > 0) { - dataChunkSize -= (dataChunkSize % bytesPerFrame); - } - } pWav->bytesRemaining = dataChunkSize; + pWav->translatedFormatTag = translatedFormatTag; pWav->dataChunkDataSize = dataChunkSize; if (sampleCountFromFactChunk != 0) { pWav->totalPCMFrameCount = sampleCountFromFactChunk; @@ -81567,20 +79851,20 @@ MA_PRIVATE ma_bool32 ma_dr_wav_init__internal(ma_dr_wav* pWav, ma_dr_wav_chunk_p #endif return MA_TRUE; } -MA_API ma_bool32 ma_dr_wav_init(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_tell_proc onTell, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_bool32 ma_dr_wav_init(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) { - return ma_dr_wav_init_ex(pWav, onRead, onSeek, onTell, NULL, pUserData, NULL, 0, pAllocationCallbacks); + return ma_dr_wav_init_ex(pWav, onRead, onSeek, NULL, pUserData, NULL, 0, pAllocationCallbacks); } -MA_API ma_bool32 ma_dr_wav_init_ex(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_tell_proc onTell, ma_dr_wav_chunk_proc onChunk, void* pReadSeekTellUserData, void* pChunkUserData, ma_uint32 flags, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_bool32 ma_dr_wav_init_ex(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_chunk_proc onChunk, void* pReadSeekUserData, void* pChunkUserData, ma_uint32 flags, const ma_allocation_callbacks* pAllocationCallbacks) { - if (!ma_dr_wav_preinit(pWav, onRead, onSeek, onTell, pReadSeekTellUserData, pAllocationCallbacks)) { + if (!ma_dr_wav_preinit(pWav, onRead, onSeek, pReadSeekUserData, pAllocationCallbacks)) { return MA_FALSE; } return ma_dr_wav_init__internal(pWav, onChunk, pChunkUserData, flags); } -MA_API ma_bool32 ma_dr_wav_init_with_metadata(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_tell_proc onTell, void* pUserData, ma_uint32 flags, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_bool32 ma_dr_wav_init_with_metadata(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pUserData, ma_uint32 flags, const ma_allocation_callbacks* pAllocationCallbacks) { - if (!ma_dr_wav_preinit(pWav, onRead, onSeek, onTell, pUserData, pAllocationCallbacks)) { + if (!ma_dr_wav_preinit(pWav, onRead, onSeek, pUserData, pAllocationCallbacks)) { return MA_FALSE; } return ma_dr_wav_init__internal(pWav, NULL, NULL, flags | MA_DR_WAV_WITH_METADATA); @@ -81742,8 +80026,8 @@ MA_PRIVATE size_t ma_dr_wav__write_or_count_metadata(ma_dr_wav* pWav, ma_dr_wav_ for (iLoop = 0; iLoop < pMetadata->data.smpl.sampleLoopCount; ++iLoop) { bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].cuePointId); bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].type); - bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].firstSampleOffset); - bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].lastSampleOffset); + bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].firstSampleByteOffset); + bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].lastSampleByteOffset); bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].sampleFraction); bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].playCount); } @@ -81777,7 +80061,7 @@ MA_PRIVATE size_t ma_dr_wav__write_or_count_metadata(ma_dr_wav* pWav, ma_dr_wav_ bytesWritten += ma_dr_wav__write_or_count(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId, 4); bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].chunkStart); bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].blockStart); - bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].sampleOffset); + bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].sampleByteOffset); } } break; case ma_dr_wav_metadata_type_acid: @@ -81863,20 +80147,15 @@ MA_PRIVATE size_t ma_dr_wav__write_or_count_metadata(ma_dr_wav* pWav, ma_dr_wav_ if (pMetadata->type & ma_dr_wav_metadata_type_list_all_info_strings) { const char* pID = NULL; switch (pMetadata->type) { - case ma_dr_wav_metadata_type_list_info_software: pID = "ISFT"; break; - case ma_dr_wav_metadata_type_list_info_copyright: pID = "ICOP"; break; - case ma_dr_wav_metadata_type_list_info_title: pID = "INAM"; break; - case ma_dr_wav_metadata_type_list_info_artist: pID = "IART"; break; - case ma_dr_wav_metadata_type_list_info_comment: pID = "ICMT"; break; - case ma_dr_wav_metadata_type_list_info_date: pID = "ICRD"; break; - case ma_dr_wav_metadata_type_list_info_genre: pID = "IGNR"; break; - case ma_dr_wav_metadata_type_list_info_album: pID = "IPRD"; break; - case ma_dr_wav_metadata_type_list_info_tracknumber: pID = "ITRK"; break; - case ma_dr_wav_metadata_type_list_info_location: pID = "IARL"; break; - case ma_dr_wav_metadata_type_list_info_organization: pID = "ICMS"; break; - case ma_dr_wav_metadata_type_list_info_keywords: pID = "IKEY"; break; - case ma_dr_wav_metadata_type_list_info_medium: pID = "IMED"; break; - case ma_dr_wav_metadata_type_list_info_description: pID = "ISBJ"; break; + case ma_dr_wav_metadata_type_list_info_software: pID = "ISFT"; break; + case ma_dr_wav_metadata_type_list_info_copyright: pID = "ICOP"; break; + case ma_dr_wav_metadata_type_list_info_title: pID = "INAM"; break; + case ma_dr_wav_metadata_type_list_info_artist: pID = "IART"; break; + case ma_dr_wav_metadata_type_list_info_comment: pID = "ICMT"; break; + case ma_dr_wav_metadata_type_list_info_date: pID = "ICRD"; break; + case ma_dr_wav_metadata_type_list_info_genre: pID = "IGNR"; break; + case ma_dr_wav_metadata_type_list_info_album: pID = "IPRD"; break; + case ma_dr_wav_metadata_type_list_info_tracknumber: pID = "ITRK"; break; default: break; } MA_DR_WAV_ASSERT(pID != NULL); @@ -82091,7 +80370,7 @@ MA_PRIVATE ma_bool32 ma_dr_wav_init_write__internal(ma_dr_wav* pWav, const ma_dr } pWav->dataChunkDataSizeTargetWrite = initialDataChunkSize; if (pFormat->container == ma_dr_wav_container_riff) { - ma_uint32 chunkSizeRIFF = 36 + (ma_uint32)initialDataChunkSize; + ma_uint32 chunkSizeRIFF = 28 + (ma_uint32)initialDataChunkSize; runningPos += ma_dr_wav__write(pWav, "RIFF", 4); runningPos += ma_dr_wav__write_u32ne_to_le(pWav, chunkSizeRIFF); runningPos += ma_dr_wav__write(pWav, "WAVE", 4); @@ -82214,31 +80493,7 @@ MA_PRIVATE size_t ma_dr_wav__on_write_stdio(void* pUserData, const void* pData, } MA_PRIVATE ma_bool32 ma_dr_wav__on_seek_stdio(void* pUserData, int offset, ma_dr_wav_seek_origin origin) { - int whence = SEEK_SET; - if (origin == MA_DR_WAV_SEEK_CUR) { - whence = SEEK_CUR; - } else if (origin == MA_DR_WAV_SEEK_END) { - whence = SEEK_END; - } - return fseek((FILE*)pUserData, offset, whence) == 0; -} -MA_PRIVATE ma_bool32 ma_dr_wav__on_tell_stdio(void* pUserData, ma_int64* pCursor) -{ - FILE* pFileStdio = (FILE*)pUserData; - ma_int64 result; - MA_DR_WAV_ASSERT(pFileStdio != NULL); - MA_DR_WAV_ASSERT(pCursor != NULL); -#if defined(_WIN32) && !defined(NXDK) - #if defined(_MSC_VER) && _MSC_VER > 1200 - result = _ftelli64(pFileStdio); - #else - result = ftell(pFileStdio); - #endif -#else - result = ftell(pFileStdio); -#endif - *pCursor = result; - return MA_TRUE; + return fseek((FILE*)pUserData, offset, (origin == ma_dr_wav_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0; } MA_API ma_bool32 ma_dr_wav_init_file(ma_dr_wav* pWav, const char* filename, const ma_allocation_callbacks* pAllocationCallbacks) { @@ -82247,7 +80502,7 @@ MA_API ma_bool32 ma_dr_wav_init_file(ma_dr_wav* pWav, const char* filename, cons MA_PRIVATE ma_bool32 ma_dr_wav_init_file__internal_FILE(ma_dr_wav* pWav, FILE* pFile, ma_dr_wav_chunk_proc onChunk, void* pChunkUserData, ma_uint32 flags, const ma_allocation_callbacks* pAllocationCallbacks) { ma_bool32 result; - result = ma_dr_wav_preinit(pWav, ma_dr_wav__on_read_stdio, ma_dr_wav__on_seek_stdio, ma_dr_wav__on_tell_stdio, (void*)pFile, pAllocationCallbacks); + result = ma_dr_wav_preinit(pWav, ma_dr_wav__on_read_stdio, ma_dr_wav__on_seek_stdio, (void*)pFile, pAllocationCallbacks); if (result != MA_TRUE) { fclose(pFile); return result; @@ -82384,27 +80639,25 @@ MA_PRIVATE size_t ma_dr_wav__on_read_memory(void* pUserData, void* pBufferOut, s MA_PRIVATE ma_bool32 ma_dr_wav__on_seek_memory(void* pUserData, int offset, ma_dr_wav_seek_origin origin) { ma_dr_wav* pWav = (ma_dr_wav*)pUserData; - ma_int64 newCursor; MA_DR_WAV_ASSERT(pWav != NULL); - newCursor = pWav->memoryStream.currentReadPos; - if (origin == MA_DR_WAV_SEEK_SET) { - newCursor = 0; - } else if (origin == MA_DR_WAV_SEEK_CUR) { - newCursor = (ma_int64)pWav->memoryStream.currentReadPos; - } else if (origin == MA_DR_WAV_SEEK_END) { - newCursor = (ma_int64)pWav->memoryStream.dataSize; + if (origin == ma_dr_wav_seek_origin_current) { + if (offset > 0) { + if (pWav->memoryStream.currentReadPos + offset > pWav->memoryStream.dataSize) { + return MA_FALSE; + } + } else { + if (pWav->memoryStream.currentReadPos < (size_t)-offset) { + return MA_FALSE; + } + } + pWav->memoryStream.currentReadPos += offset; } else { - MA_DR_WAV_ASSERT(!"Invalid seek origin"); - return MA_FALSE; + if ((ma_uint32)offset <= pWav->memoryStream.dataSize) { + pWav->memoryStream.currentReadPos = offset; + } else { + return MA_FALSE; + } } - newCursor += offset; - if (newCursor < 0) { - return MA_FALSE; - } - if ((size_t)newCursor > pWav->memoryStream.dataSize) { - return MA_FALSE; - } - pWav->memoryStream.currentReadPos = (size_t)newCursor; return MA_TRUE; } MA_PRIVATE size_t ma_dr_wav__on_write_memory(void* pUserData, const void* pDataIn, size_t bytesToWrite) @@ -82438,35 +80691,25 @@ MA_PRIVATE size_t ma_dr_wav__on_write_memory(void* pUserData, const void* pDataI MA_PRIVATE ma_bool32 ma_dr_wav__on_seek_memory_write(void* pUserData, int offset, ma_dr_wav_seek_origin origin) { ma_dr_wav* pWav = (ma_dr_wav*)pUserData; - ma_int64 newCursor; MA_DR_WAV_ASSERT(pWav != NULL); - newCursor = pWav->memoryStreamWrite.currentWritePos; - if (origin == MA_DR_WAV_SEEK_SET) { - newCursor = 0; - } else if (origin == MA_DR_WAV_SEEK_CUR) { - newCursor = (ma_int64)pWav->memoryStreamWrite.currentWritePos; - } else if (origin == MA_DR_WAV_SEEK_END) { - newCursor = (ma_int64)pWav->memoryStreamWrite.dataSize; + if (origin == ma_dr_wav_seek_origin_current) { + if (offset > 0) { + if (pWav->memoryStreamWrite.currentWritePos + offset > pWav->memoryStreamWrite.dataSize) { + offset = (int)(pWav->memoryStreamWrite.dataSize - pWav->memoryStreamWrite.currentWritePos); + } + } else { + if (pWav->memoryStreamWrite.currentWritePos < (size_t)-offset) { + offset = -(int)pWav->memoryStreamWrite.currentWritePos; + } + } + pWav->memoryStreamWrite.currentWritePos += offset; } else { - MA_DR_WAV_ASSERT(!"Invalid seek origin"); - return MA_INVALID_ARGS; + if ((ma_uint32)offset <= pWav->memoryStreamWrite.dataSize) { + pWav->memoryStreamWrite.currentWritePos = offset; + } else { + pWav->memoryStreamWrite.currentWritePos = pWav->memoryStreamWrite.dataSize; + } } - newCursor += offset; - if (newCursor < 0) { - return MA_FALSE; - } - if ((size_t)newCursor > pWav->memoryStreamWrite.dataSize) { - return MA_FALSE; - } - pWav->memoryStreamWrite.currentWritePos = (size_t)newCursor; - return MA_TRUE; -} -MA_PRIVATE ma_bool32 ma_dr_wav__on_tell_memory(void* pUserData, ma_int64* pCursor) -{ - ma_dr_wav* pWav = (ma_dr_wav*)pUserData; - MA_DR_WAV_ASSERT(pWav != NULL); - MA_DR_WAV_ASSERT(pCursor != NULL); - *pCursor = (ma_int64)pWav->memoryStream.currentReadPos; return MA_TRUE; } MA_API ma_bool32 ma_dr_wav_init_memory(ma_dr_wav* pWav, const void* data, size_t dataSize, const ma_allocation_callbacks* pAllocationCallbacks) @@ -82478,7 +80721,7 @@ MA_API ma_bool32 ma_dr_wav_init_memory_ex(ma_dr_wav* pWav, const void* data, siz if (data == NULL || dataSize == 0) { return MA_FALSE; } - if (!ma_dr_wav_preinit(pWav, ma_dr_wav__on_read_memory, ma_dr_wav__on_seek_memory, ma_dr_wav__on_tell_memory, pWav, pAllocationCallbacks)) { + if (!ma_dr_wav_preinit(pWav, ma_dr_wav__on_read_memory, ma_dr_wav__on_seek_memory, pWav, pAllocationCallbacks)) { return MA_FALSE; } pWav->memoryStream.data = (const ma_uint8*)data; @@ -82491,7 +80734,7 @@ MA_API ma_bool32 ma_dr_wav_init_memory_with_metadata(ma_dr_wav* pWav, const void if (data == NULL || dataSize == 0) { return MA_FALSE; } - if (!ma_dr_wav_preinit(pWav, ma_dr_wav__on_read_memory, ma_dr_wav__on_seek_memory, ma_dr_wav__on_tell_memory, pWav, pAllocationCallbacks)) { + if (!ma_dr_wav_preinit(pWav, ma_dr_wav__on_read_memory, ma_dr_wav__on_seek_memory, pWav, pAllocationCallbacks)) { return MA_FALSE; } pWav->memoryStream.data = (const ma_uint8*)data; @@ -82550,30 +80793,30 @@ MA_API ma_result ma_dr_wav_uninit(ma_dr_wav* pWav) } if (pWav->onSeek && !pWav->isSequentialWrite) { if (pWav->container == ma_dr_wav_container_riff) { - if (pWav->onSeek(pWav->pUserData, 4, MA_DR_WAV_SEEK_SET)) { + if (pWav->onSeek(pWav->pUserData, 4, ma_dr_wav_seek_origin_start)) { ma_uint32 riffChunkSize = ma_dr_wav__riff_chunk_size_riff(pWav->dataChunkDataSize, pWav->pMetadata, pWav->metadataCount); ma_dr_wav__write_u32ne_to_le(pWav, riffChunkSize); } - if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos - 4, MA_DR_WAV_SEEK_SET)) { + if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos - 4, ma_dr_wav_seek_origin_start)) { ma_uint32 dataChunkSize = ma_dr_wav__data_chunk_size_riff(pWav->dataChunkDataSize); ma_dr_wav__write_u32ne_to_le(pWav, dataChunkSize); } } else if (pWav->container == ma_dr_wav_container_w64) { - if (pWav->onSeek(pWav->pUserData, 16, MA_DR_WAV_SEEK_SET)) { + if (pWav->onSeek(pWav->pUserData, 16, ma_dr_wav_seek_origin_start)) { ma_uint64 riffChunkSize = ma_dr_wav__riff_chunk_size_w64(pWav->dataChunkDataSize); ma_dr_wav__write_u64ne_to_le(pWav, riffChunkSize); } - if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos - 8, MA_DR_WAV_SEEK_SET)) { + if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos - 8, ma_dr_wav_seek_origin_start)) { ma_uint64 dataChunkSize = ma_dr_wav__data_chunk_size_w64(pWav->dataChunkDataSize); ma_dr_wav__write_u64ne_to_le(pWav, dataChunkSize); } } else if (pWav->container == ma_dr_wav_container_rf64) { int ds64BodyPos = 12 + 8; - if (pWav->onSeek(pWav->pUserData, ds64BodyPos + 0, MA_DR_WAV_SEEK_SET)) { + if (pWav->onSeek(pWav->pUserData, ds64BodyPos + 0, ma_dr_wav_seek_origin_start)) { ma_uint64 riffChunkSize = ma_dr_wav__riff_chunk_size_rf64(pWav->dataChunkDataSize, pWav->pMetadata, pWav->metadataCount); ma_dr_wav__write_u64ne_to_le(pWav, riffChunkSize); } - if (pWav->onSeek(pWav->pUserData, ds64BodyPos + 8, MA_DR_WAV_SEEK_SET)) { + if (pWav->onSeek(pWav->pUserData, ds64BodyPos + 8, ma_dr_wav_seek_origin_start)) { ma_uint64 dataChunkSize = ma_dr_wav__data_chunk_size_rf64(pWav->dataChunkDataSize); ma_dr_wav__write_u64ne_to_le(pWav, dataChunkSize); } @@ -82620,7 +80863,7 @@ MA_API size_t ma_dr_wav_read_raw(ma_dr_wav* pWav, size_t bytesToRead, void* pBuf if (bytesToSeek > 0x7FFFFFFF) { bytesToSeek = 0x7FFFFFFF; } - if (pWav->onSeek(pWav->pUserData, (int)bytesToSeek, MA_DR_WAV_SEEK_CUR) == MA_FALSE) { + if (pWav->onSeek(pWav->pUserData, (int)bytesToSeek, ma_dr_wav_seek_origin_current) == MA_FALSE) { break; } bytesRead += bytesToSeek; @@ -82719,7 +80962,7 @@ MA_PRIVATE ma_bool32 ma_dr_wav_seek_to_first_pcm_frame(ma_dr_wav* pWav) if (pWav->onWrite != NULL) { return MA_FALSE; } - if (!pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos, MA_DR_WAV_SEEK_SET)) { + if (!pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos, ma_dr_wav_seek_origin_start)) { return MA_FALSE; } if (ma_dr_wav__is_compressed_format_tag(pWav->translatedFormatTag)) { @@ -82800,7 +81043,7 @@ MA_API ma_bool32 ma_dr_wav_seek_to_pcm_frame(ma_dr_wav* pWav, ma_uint64 targetFr } while (offset > 0) { int offset32 = ((offset > INT_MAX) ? INT_MAX : (int)offset); - if (!pWav->onSeek(pWav->pUserData, offset32, MA_DR_WAV_SEEK_CUR)) { + if (!pWav->onSeek(pWav->pUserData, offset32, ma_dr_wav_seek_origin_current)) { return MA_FALSE; } pWav->readCursorInPCMFrames += offset32 / bytesPerFrame; @@ -82926,12 +81169,12 @@ MA_API ma_uint64 ma_dr_wav_write_pcm_frames(ma_dr_wav* pWav, ma_uint64 framesToW MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_s16__msadpcm(ma_dr_wav* pWav, ma_uint64 framesToRead, ma_int16* pBufferOut) { ma_uint64 totalFramesRead = 0; - static const ma_int32 adaptationTable[] = { + static ma_int32 adaptationTable[] = { 230, 230, 230, 230, 307, 409, 512, 614, 768, 614, 512, 409, 307, 230, 230, 230 }; - static const ma_int32 coeff1Table[] = { 256, 512, 0, 192, 240, 460, 392 }; - static const ma_int32 coeff2Table[] = { 0, -256, 0, 64, 0, -208, -232 }; + static ma_int32 coeff1Table[] = { 256, 512, 0, 192, 240, 460, 392 }; + static ma_int32 coeff2Table[] = { 0, -256, 0, 64, 0, -208, -232 }; MA_DR_WAV_ASSERT(pWav != NULL); MA_DR_WAV_ASSERT(framesToRead > 0); while (pWav->readCursorInPCMFrames < pWav->totalPCMFrameCount) { @@ -83064,11 +81307,11 @@ MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_s16__ima(ma_dr_wav* pWav, ma_uint { ma_uint64 totalFramesRead = 0; ma_uint32 iChannel; - static const ma_int32 indexTable[16] = { + static ma_int32 indexTable[16] = { -1, -1, -1, -1, 2, 4, 6, 8, -1, -1, -1, -1, 2, 4, 6, 8 }; - static const ma_int32 stepTable[89] = { + static ma_int32 stepTable[89] = { 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, @@ -83091,7 +81334,7 @@ MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_s16__ima(ma_dr_wav* pWav, ma_uint } pWav->ima.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header); if (header[2] >= ma_dr_wav_countof(stepTable)) { - pWav->onSeek(pWav->pUserData, pWav->ima.bytesRemainingInBlock, MA_DR_WAV_SEEK_CUR); + pWav->onSeek(pWav->pUserData, pWav->ima.bytesRemainingInBlock, ma_dr_wav_seek_origin_current); pWav->ima.bytesRemainingInBlock = 0; return totalFramesRead; } @@ -83106,7 +81349,7 @@ MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_s16__ima(ma_dr_wav* pWav, ma_uint } pWav->ima.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header); if (header[2] >= ma_dr_wav_countof(stepTable) || header[6] >= ma_dr_wav_countof(stepTable)) { - pWav->onSeek(pWav->pUserData, pWav->ima.bytesRemainingInBlock, MA_DR_WAV_SEEK_CUR); + pWav->onSeek(pWav->pUserData, pWav->ima.bytesRemainingInBlock, ma_dr_wav_seek_origin_current); pWav->ima.bytesRemainingInBlock = 0; return totalFramesRead; } @@ -83181,7 +81424,7 @@ MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_s16__ima(ma_dr_wav* pWav, ma_uint return totalFramesRead; } #ifndef MA_DR_WAV_NO_CONVERSION_API -static const unsigned short ma_dr_wav_gAlawTable[256] = { +static unsigned short g_ma_dr_wavAlawTable[256] = { 0xEA80, 0xEB80, 0xE880, 0xE980, 0xEE80, 0xEF80, 0xEC80, 0xED80, 0xE280, 0xE380, 0xE080, 0xE180, 0xE680, 0xE780, 0xE480, 0xE580, 0xF540, 0xF5C0, 0xF440, 0xF4C0, 0xF740, 0xF7C0, 0xF640, 0xF6C0, 0xF140, 0xF1C0, 0xF040, 0xF0C0, 0xF340, 0xF3C0, 0xF240, 0xF2C0, 0xAA00, 0xAE00, 0xA200, 0xA600, 0xBA00, 0xBE00, 0xB200, 0xB600, 0x8A00, 0x8E00, 0x8200, 0x8600, 0x9A00, 0x9E00, 0x9200, 0x9600, @@ -83199,7 +81442,7 @@ static const unsigned short ma_dr_wav_gAlawTable[256] = { 0x0560, 0x0520, 0x05E0, 0x05A0, 0x0460, 0x0420, 0x04E0, 0x04A0, 0x0760, 0x0720, 0x07E0, 0x07A0, 0x0660, 0x0620, 0x06E0, 0x06A0, 0x02B0, 0x0290, 0x02F0, 0x02D0, 0x0230, 0x0210, 0x0270, 0x0250, 0x03B0, 0x0390, 0x03F0, 0x03D0, 0x0330, 0x0310, 0x0370, 0x0350 }; -static const unsigned short ma_dr_wav_gMulawTable[256] = { +static unsigned short g_ma_dr_wavMulawTable[256] = { 0x8284, 0x8684, 0x8A84, 0x8E84, 0x9284, 0x9684, 0x9A84, 0x9E84, 0xA284, 0xA684, 0xAA84, 0xAE84, 0xB284, 0xB684, 0xBA84, 0xBE84, 0xC184, 0xC384, 0xC584, 0xC784, 0xC984, 0xCB84, 0xCD84, 0xCF84, 0xD184, 0xD384, 0xD584, 0xD784, 0xD984, 0xDB84, 0xDD84, 0xDF84, 0xE104, 0xE204, 0xE304, 0xE404, 0xE504, 0xE604, 0xE704, 0xE804, 0xE904, 0xEA04, 0xEB04, 0xEC04, 0xED04, 0xEE04, 0xEF04, 0xF004, @@ -83219,11 +81462,11 @@ static const unsigned short ma_dr_wav_gMulawTable[256] = { }; static MA_INLINE ma_int16 ma_dr_wav__alaw_to_s16(ma_uint8 sampleIn) { - return (short)ma_dr_wav_gAlawTable[sampleIn]; + return (short)g_ma_dr_wavAlawTable[sampleIn]; } static MA_INLINE ma_int16 ma_dr_wav__mulaw_to_s16(ma_uint8 sampleIn) { - return (short)ma_dr_wav_gMulawTable[sampleIn]; + return (short)g_ma_dr_wavMulawTable[sampleIn]; } MA_PRIVATE void ma_dr_wav__pcm_to_s16(ma_int16* pOut, const ma_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample) { @@ -84382,7 +82625,7 @@ MA_PRIVATE ma_int32* ma_dr_wav__read_pcm_frames_and_close_s32(ma_dr_wav* pWav, u } return pSampleData; } -MA_API ma_int16* ma_dr_wav_open_and_read_pcm_frames_s16(ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_int16* ma_dr_wav_open_and_read_pcm_frames_s16(ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) { ma_dr_wav wav; if (channelsOut) { @@ -84394,12 +82637,12 @@ MA_API ma_int16* ma_dr_wav_open_and_read_pcm_frames_s16(ma_dr_wav_read_proc onRe if (totalFrameCountOut) { *totalFrameCountOut = 0; } - if (!ma_dr_wav_init(&wav, onRead, onSeek, onTell, pUserData, pAllocationCallbacks)) { + if (!ma_dr_wav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) { return NULL; } return ma_dr_wav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut); } -MA_API float* ma_dr_wav_open_and_read_pcm_frames_f32(ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API float* ma_dr_wav_open_and_read_pcm_frames_f32(ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) { ma_dr_wav wav; if (channelsOut) { @@ -84411,12 +82654,12 @@ MA_API float* ma_dr_wav_open_and_read_pcm_frames_f32(ma_dr_wav_read_proc onRead, if (totalFrameCountOut) { *totalFrameCountOut = 0; } - if (!ma_dr_wav_init(&wav, onRead, onSeek, onTell, pUserData, pAllocationCallbacks)) { + if (!ma_dr_wav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) { return NULL; } return ma_dr_wav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); } -MA_API ma_int32* ma_dr_wav_open_and_read_pcm_frames_s32(ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_int32* ma_dr_wav_open_and_read_pcm_frames_s32(ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) { ma_dr_wav wav; if (channelsOut) { @@ -84428,7 +82671,7 @@ MA_API ma_int32* ma_dr_wav_open_and_read_pcm_frames_s32(ma_dr_wav_read_proc onRe if (totalFrameCountOut) { *totalFrameCountOut = 0; } - if (!ma_dr_wav_init(&wav, onRead, onSeek, onTell, pUserData, pAllocationCallbacks)) { + if (!ma_dr_wav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) { return NULL; } return ma_dr_wav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); @@ -85863,23 +84106,23 @@ static ma_bool32 ma_dr_flac__seek_to_byte(ma_dr_flac_bs* bs, ma_uint64 offsetFro MA_DR_FLAC_ASSERT(offsetFromStart > 0); if (offsetFromStart > 0x7FFFFFFF) { ma_uint64 bytesRemaining = offsetFromStart; - if (!bs->onSeek(bs->pUserData, 0x7FFFFFFF, MA_DR_FLAC_SEEK_SET)) { + if (!bs->onSeek(bs->pUserData, 0x7FFFFFFF, ma_dr_flac_seek_origin_start)) { return MA_FALSE; } bytesRemaining -= 0x7FFFFFFF; while (bytesRemaining > 0x7FFFFFFF) { - if (!bs->onSeek(bs->pUserData, 0x7FFFFFFF, MA_DR_FLAC_SEEK_CUR)) { + if (!bs->onSeek(bs->pUserData, 0x7FFFFFFF, ma_dr_flac_seek_origin_current)) { return MA_FALSE; } bytesRemaining -= 0x7FFFFFFF; } if (bytesRemaining > 0) { - if (!bs->onSeek(bs->pUserData, (int)bytesRemaining, MA_DR_FLAC_SEEK_CUR)) { + if (!bs->onSeek(bs->pUserData, (int)bytesRemaining, ma_dr_flac_seek_origin_current)) { return MA_FALSE; } } } else { - if (!bs->onSeek(bs->pUserData, (int)offsetFromStart, MA_DR_FLAC_SEEK_SET)) { + if (!bs->onSeek(bs->pUserData, (int)offsetFromStart, ma_dr_flac_seek_origin_start)) { return MA_FALSE; } } @@ -88357,7 +86600,6 @@ typedef struct { ma_dr_flac_read_proc onRead; ma_dr_flac_seek_proc onSeek; - ma_dr_flac_tell_proc onTell; ma_dr_flac_meta_proc onMeta; ma_dr_flac_container container; void* pUserData; @@ -88486,12 +86728,11 @@ static void ma_dr_flac__free_from_callbacks(void* p, const ma_allocation_callbac pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData); } } -static ma_bool32 ma_dr_flac__read_and_decode_metadata(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, ma_dr_flac_meta_proc onMeta, void* pUserData, void* pUserDataMD, ma_uint64* pFirstFramePos, ma_uint64* pSeektablePos, ma_uint32* pSeekpointCount, ma_allocation_callbacks* pAllocationCallbacks) +static ma_bool32 ma_dr_flac__read_and_decode_metadata(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_meta_proc onMeta, void* pUserData, void* pUserDataMD, ma_uint64* pFirstFramePos, ma_uint64* pSeektablePos, ma_uint32* pSeekpointCount, ma_allocation_callbacks* pAllocationCallbacks) { ma_uint64 runningFilePos = 42; ma_uint64 seektablePos = 0; ma_uint32 seektableSize = 0; - (void)onTell; for (;;) { ma_dr_flac_metadata metadata; ma_uint8 isLastBlock = 0; @@ -88749,7 +86990,7 @@ static ma_bool32 ma_dr_flac__read_and_decode_metadata(ma_dr_flac_read_proc onRea { if (onMeta) { metadata.data.padding.unused = 0; - if (!onSeek(pUserData, blockSize, MA_DR_FLAC_SEEK_CUR)) { + if (!onSeek(pUserData, blockSize, ma_dr_flac_seek_origin_current)) { isLastBlock = MA_TRUE; } else { onMeta(pUserDataMD, &metadata); @@ -88759,7 +87000,7 @@ static ma_bool32 ma_dr_flac__read_and_decode_metadata(ma_dr_flac_read_proc onRea case MA_DR_FLAC_METADATA_BLOCK_TYPE_INVALID: { if (onMeta) { - if (!onSeek(pUserData, blockSize, MA_DR_FLAC_SEEK_CUR)) { + if (!onSeek(pUserData, blockSize, ma_dr_flac_seek_origin_current)) { isLastBlock = MA_TRUE; } } @@ -88783,7 +87024,7 @@ static ma_bool32 ma_dr_flac__read_and_decode_metadata(ma_dr_flac_read_proc onRea } break; } if (onMeta == NULL && blockSize > 0) { - if (!onSeek(pUserData, blockSize, MA_DR_FLAC_SEEK_CUR)) { + if (!onSeek(pUserData, blockSize, ma_dr_flac_seek_origin_current)) { isLastBlock = MA_TRUE; } } @@ -89047,7 +87288,6 @@ typedef struct { ma_dr_flac_read_proc onRead; ma_dr_flac_seek_proc onSeek; - ma_dr_flac_tell_proc onTell; void* pUserData; ma_uint64 currentBytePos; ma_uint64 firstBytePos; @@ -89066,29 +87306,29 @@ static size_t ma_dr_flac_oggbs__read_physical(ma_dr_flac_oggbs* oggbs, void* buf } static ma_bool32 ma_dr_flac_oggbs__seek_physical(ma_dr_flac_oggbs* oggbs, ma_uint64 offset, ma_dr_flac_seek_origin origin) { - if (origin == MA_DR_FLAC_SEEK_SET) { + if (origin == ma_dr_flac_seek_origin_start) { if (offset <= 0x7FFFFFFF) { - if (!oggbs->onSeek(oggbs->pUserData, (int)offset, MA_DR_FLAC_SEEK_SET)) { + if (!oggbs->onSeek(oggbs->pUserData, (int)offset, ma_dr_flac_seek_origin_start)) { return MA_FALSE; } oggbs->currentBytePos = offset; return MA_TRUE; } else { - if (!oggbs->onSeek(oggbs->pUserData, 0x7FFFFFFF, MA_DR_FLAC_SEEK_SET)) { + if (!oggbs->onSeek(oggbs->pUserData, 0x7FFFFFFF, ma_dr_flac_seek_origin_start)) { return MA_FALSE; } oggbs->currentBytePos = offset; - return ma_dr_flac_oggbs__seek_physical(oggbs, offset - 0x7FFFFFFF, MA_DR_FLAC_SEEK_CUR); + return ma_dr_flac_oggbs__seek_physical(oggbs, offset - 0x7FFFFFFF, ma_dr_flac_seek_origin_current); } } else { while (offset > 0x7FFFFFFF) { - if (!oggbs->onSeek(oggbs->pUserData, 0x7FFFFFFF, MA_DR_FLAC_SEEK_CUR)) { + if (!oggbs->onSeek(oggbs->pUserData, 0x7FFFFFFF, ma_dr_flac_seek_origin_current)) { return MA_FALSE; } oggbs->currentBytePos += 0x7FFFFFFF; offset -= 0x7FFFFFFF; } - if (!oggbs->onSeek(oggbs->pUserData, (int)offset, MA_DR_FLAC_SEEK_CUR)) { + if (!oggbs->onSeek(oggbs->pUserData, (int)offset, ma_dr_flac_seek_origin_current)) { return MA_FALSE; } oggbs->currentBytePos += offset; @@ -89114,7 +87354,7 @@ static ma_bool32 ma_dr_flac_oggbs__goto_next_page(ma_dr_flac_oggbs* oggbs, ma_dr continue; } if (header.serialNumber != oggbs->serialNumber) { - if (pageBodySize > 0 && !ma_dr_flac_oggbs__seek_physical(oggbs, pageBodySize, MA_DR_FLAC_SEEK_CUR)) { + if (pageBodySize > 0 && !ma_dr_flac_oggbs__seek_physical(oggbs, pageBodySize, ma_dr_flac_seek_origin_current)) { return MA_FALSE; } continue; @@ -89176,7 +87416,7 @@ static ma_bool32 ma_dr_flac_oggbs__seek_to_next_packet(ma_dr_flac_oggbs* oggbs) } bytesToEndOfPacketOrPage += segmentSize; } - ma_dr_flac_oggbs__seek_physical(oggbs, bytesToEndOfPacketOrPage, MA_DR_FLAC_SEEK_CUR); + ma_dr_flac_oggbs__seek_physical(oggbs, bytesToEndOfPacketOrPage, ma_dr_flac_seek_origin_current); oggbs->bytesRemainingInPage -= bytesToEndOfPacketOrPage; if (atEndOfPage) { if (!ma_dr_flac_oggbs__goto_next_page(oggbs)) { @@ -89229,44 +87469,36 @@ static ma_bool32 ma_dr_flac__on_seek_ogg(void* pUserData, int offset, ma_dr_flac int bytesSeeked = 0; MA_DR_FLAC_ASSERT(oggbs != NULL); MA_DR_FLAC_ASSERT(offset >= 0); - if (origin == MA_DR_FLAC_SEEK_SET) { - if (!ma_dr_flac_oggbs__seek_physical(oggbs, (int)oggbs->firstBytePos, MA_DR_FLAC_SEEK_SET)) { + if (origin == ma_dr_flac_seek_origin_start) { + if (!ma_dr_flac_oggbs__seek_physical(oggbs, (int)oggbs->firstBytePos, ma_dr_flac_seek_origin_start)) { return MA_FALSE; } if (!ma_dr_flac_oggbs__goto_next_page(oggbs, ma_dr_flac_ogg_fail_on_crc_mismatch)) { return MA_FALSE; } - return ma_dr_flac__on_seek_ogg(pUserData, offset, MA_DR_FLAC_SEEK_CUR); - } else if (origin == MA_DR_FLAC_SEEK_CUR) { - while (bytesSeeked < offset) { - int bytesRemainingToSeek = offset - bytesSeeked; - MA_DR_FLAC_ASSERT(bytesRemainingToSeek >= 0); - if (oggbs->bytesRemainingInPage >= (size_t)bytesRemainingToSeek) { - bytesSeeked += bytesRemainingToSeek; - (void)bytesSeeked; - oggbs->bytesRemainingInPage -= bytesRemainingToSeek; - break; - } - if (oggbs->bytesRemainingInPage > 0) { - bytesSeeked += (int)oggbs->bytesRemainingInPage; - oggbs->bytesRemainingInPage = 0; - } - MA_DR_FLAC_ASSERT(bytesRemainingToSeek > 0); - if (!ma_dr_flac_oggbs__goto_next_page(oggbs, ma_dr_flac_ogg_fail_on_crc_mismatch)) { - return MA_FALSE; - } + return ma_dr_flac__on_seek_ogg(pUserData, offset, ma_dr_flac_seek_origin_current); + } + MA_DR_FLAC_ASSERT(origin == ma_dr_flac_seek_origin_current); + while (bytesSeeked < offset) { + int bytesRemainingToSeek = offset - bytesSeeked; + MA_DR_FLAC_ASSERT(bytesRemainingToSeek >= 0); + if (oggbs->bytesRemainingInPage >= (size_t)bytesRemainingToSeek) { + bytesSeeked += bytesRemainingToSeek; + (void)bytesSeeked; + oggbs->bytesRemainingInPage -= bytesRemainingToSeek; + break; + } + if (oggbs->bytesRemainingInPage > 0) { + bytesSeeked += (int)oggbs->bytesRemainingInPage; + oggbs->bytesRemainingInPage = 0; + } + MA_DR_FLAC_ASSERT(bytesRemainingToSeek > 0); + if (!ma_dr_flac_oggbs__goto_next_page(oggbs, ma_dr_flac_ogg_fail_on_crc_mismatch)) { + return MA_FALSE; } - } else if (origin == MA_DR_FLAC_SEEK_END) { - return MA_FALSE; } return MA_TRUE; } -static ma_bool32 ma_dr_flac__on_tell_ogg(void* pUserData, ma_int64* pCursor) -{ - (void)pUserData; - (void)pCursor; - return MA_FALSE; -} static ma_bool32 ma_dr_flac_ogg__seek_to_pcm_frame(ma_dr_flac* pFlac, ma_uint64 pcmFrameIndex) { ma_dr_flac_oggbs* oggbs = (ma_dr_flac_oggbs*)pFlac->_oggbs; @@ -89283,7 +87515,7 @@ static ma_bool32 ma_dr_flac_ogg__seek_to_pcm_frame(ma_dr_flac* pFlac, ma_uint64 runningGranulePosition = 0; for (;;) { if (!ma_dr_flac_oggbs__goto_next_page(oggbs, ma_dr_flac_ogg_recover_on_crc_mismatch)) { - ma_dr_flac_oggbs__seek_physical(oggbs, originalBytePos, MA_DR_FLAC_SEEK_SET); + ma_dr_flac_oggbs__seek_physical(oggbs, originalBytePos, ma_dr_flac_seek_origin_start); return MA_FALSE; } runningFrameBytePos = oggbs->currentBytePos - ma_dr_flac_ogg__get_page_header_size(&oggbs->currentPageHeader) - oggbs->pageDataSize; @@ -89302,7 +87534,7 @@ static ma_bool32 ma_dr_flac_ogg__seek_to_pcm_frame(ma_dr_flac* pFlac, ma_uint64 } } } - if (!ma_dr_flac_oggbs__seek_physical(oggbs, runningFrameBytePos, MA_DR_FLAC_SEEK_SET)) { + if (!ma_dr_flac_oggbs__seek_physical(oggbs, runningFrameBytePos, ma_dr_flac_seek_origin_start)) { return MA_FALSE; } if (!ma_dr_flac_oggbs__goto_next_page(oggbs, ma_dr_flac_ogg_recover_on_crc_mismatch)) { @@ -89397,7 +87629,7 @@ static ma_bool32 ma_dr_flac__init_private__ogg(ma_dr_flac_init_info* pInit, ma_d if (mappingVersion[0] != 1) { return MA_FALSE; } - if (!onSeek(pUserData, 2, MA_DR_FLAC_SEEK_CUR)) { + if (!onSeek(pUserData, 2, ma_dr_flac_seek_origin_current)) { return MA_FALSE; } if (onRead(pUserData, sig, 4) != 4) { @@ -89442,17 +87674,17 @@ static ma_bool32 ma_dr_flac__init_private__ogg(ma_dr_flac_init_info* pInit, ma_d return MA_FALSE; } } else { - if (!onSeek(pUserData, bytesRemainingInPage, MA_DR_FLAC_SEEK_CUR)) { + if (!onSeek(pUserData, bytesRemainingInPage, ma_dr_flac_seek_origin_current)) { return MA_FALSE; } } } else { - if (!onSeek(pUserData, bytesRemainingInPage, MA_DR_FLAC_SEEK_CUR)) { + if (!onSeek(pUserData, bytesRemainingInPage, ma_dr_flac_seek_origin_current)) { return MA_FALSE; } } } else { - if (!onSeek(pUserData, pageBodySize, MA_DR_FLAC_SEEK_CUR)) { + if (!onSeek(pUserData, pageBodySize, ma_dr_flac_seek_origin_current)) { return MA_FALSE; } } @@ -89466,7 +87698,7 @@ static ma_bool32 ma_dr_flac__init_private__ogg(ma_dr_flac_init_info* pInit, ma_d return MA_TRUE; } #endif -static ma_bool32 ma_dr_flac__init_private(ma_dr_flac_init_info* pInit, ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, ma_dr_flac_meta_proc onMeta, ma_dr_flac_container container, void* pUserData, void* pUserDataMD) +static ma_bool32 ma_dr_flac__init_private(ma_dr_flac_init_info* pInit, ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_meta_proc onMeta, ma_dr_flac_container container, void* pUserData, void* pUserDataMD) { ma_bool32 relaxed; ma_uint8 id[4]; @@ -89476,14 +87708,12 @@ static ma_bool32 ma_dr_flac__init_private(ma_dr_flac_init_info* pInit, ma_dr_fla MA_DR_FLAC_ZERO_MEMORY(pInit, sizeof(*pInit)); pInit->onRead = onRead; pInit->onSeek = onSeek; - pInit->onTell = onTell; pInit->onMeta = onMeta; pInit->container = container; pInit->pUserData = pUserData; pInit->pUserDataMD = pUserDataMD; pInit->bs.onRead = onRead; pInit->bs.onSeek = onSeek; - pInit->bs.onTell = onTell; pInit->bs.pUserData = pUserData; ma_dr_flac__reset_cache(&pInit->bs); relaxed = container != ma_dr_flac_container_unknown; @@ -89506,7 +87736,7 @@ static ma_bool32 ma_dr_flac__init_private(ma_dr_flac_init_info* pInit, ma_dr_fla if (flags & 0x10) { headerSize += 10; } - if (!onSeek(pUserData, headerSize, MA_DR_FLAC_SEEK_CUR)) { + if (!onSeek(pUserData, headerSize, ma_dr_flac_seek_origin_current)) { return MA_FALSE; } pInit->runningFilePos += headerSize; @@ -89549,7 +87779,7 @@ static void ma_dr_flac__init_from_info(ma_dr_flac* pFlac, const ma_dr_flac_init_ pFlac->totalPCMFrameCount = pInit->totalPCMFrameCount; pFlac->container = pInit->container; } -static ma_dr_flac* ma_dr_flac_open_with_metadata_private(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, ma_dr_flac_meta_proc onMeta, ma_dr_flac_container container, void* pUserData, void* pUserDataMD, const ma_allocation_callbacks* pAllocationCallbacks) +static ma_dr_flac* ma_dr_flac_open_with_metadata_private(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_meta_proc onMeta, ma_dr_flac_container container, void* pUserData, void* pUserDataMD, const ma_allocation_callbacks* pAllocationCallbacks) { ma_dr_flac_init_info init; ma_uint32 allocationSize; @@ -89564,7 +87794,7 @@ static ma_dr_flac* ma_dr_flac_open_with_metadata_private(ma_dr_flac_read_proc on ma_allocation_callbacks allocationCallbacks; ma_dr_flac* pFlac; ma_dr_flac__init_cpu_caps(); - if (!ma_dr_flac__init_private(&init, onRead, onSeek, onTell, onMeta, container, pUserData, pUserDataMD)) { + if (!ma_dr_flac__init_private(&init, onRead, onSeek, onMeta, container, pUserData, pUserDataMD)) { return NULL; } if (pAllocationCallbacks != NULL) { @@ -89597,7 +87827,6 @@ static ma_dr_flac* ma_dr_flac_open_with_metadata_private(ma_dr_flac_read_proc on MA_DR_FLAC_ZERO_MEMORY(pOggbs, sizeof(*pOggbs)); pOggbs->onRead = onRead; pOggbs->onSeek = onSeek; - pOggbs->onTell = onTell; pOggbs->pUserData = pUserData; pOggbs->currentBytePos = init.oggFirstBytePos; pOggbs->firstBytePos = init.oggFirstBytePos; @@ -89612,17 +87841,15 @@ static ma_dr_flac* ma_dr_flac_open_with_metadata_private(ma_dr_flac_read_proc on if (init.hasMetadataBlocks) { ma_dr_flac_read_proc onReadOverride = onRead; ma_dr_flac_seek_proc onSeekOverride = onSeek; - ma_dr_flac_tell_proc onTellOverride = onTell; void* pUserDataOverride = pUserData; #ifndef MA_DR_FLAC_NO_OGG if (init.container == ma_dr_flac_container_ogg) { onReadOverride = ma_dr_flac__on_read_ogg; onSeekOverride = ma_dr_flac__on_seek_ogg; - onTellOverride = ma_dr_flac__on_tell_ogg; pUserDataOverride = (void*)pOggbs; } #endif - if (!ma_dr_flac__read_and_decode_metadata(onReadOverride, onSeekOverride, onTellOverride, onMeta, pUserDataOverride, pUserDataMD, &firstFramePos, &seektablePos, &seekpointCount, &allocationCallbacks)) { + if (!ma_dr_flac__read_and_decode_metadata(onReadOverride, onSeekOverride, onMeta, pUserDataOverride, pUserDataMD, &firstFramePos, &seektablePos, &seekpointCount, &allocationCallbacks)) { #ifndef MA_DR_FLAC_NO_OGG ma_dr_flac__free_from_callbacks(pOggbs, &allocationCallbacks); #endif @@ -89648,7 +87875,6 @@ static ma_dr_flac* ma_dr_flac_open_with_metadata_private(ma_dr_flac_read_proc on pOggbs = NULL; pFlac->bs.onRead = ma_dr_flac__on_read_ogg; pFlac->bs.onSeek = ma_dr_flac__on_seek_ogg; - pFlac->bs.onTell = ma_dr_flac__on_tell_ogg; pFlac->bs.pUserData = (void*)pInternalOggbs; pFlac->_oggbs = (void*)pInternalOggbs; } @@ -89668,7 +87894,7 @@ static ma_dr_flac* ma_dr_flac_open_with_metadata_private(ma_dr_flac_read_proc on pFlac->pSeekpoints = (ma_dr_flac_seekpoint*)((ma_uint8*)pFlac->pDecodedSamples + decodedSamplesAllocationSize); MA_DR_FLAC_ASSERT(pFlac->bs.onSeek != NULL); MA_DR_FLAC_ASSERT(pFlac->bs.onRead != NULL); - if (pFlac->bs.onSeek(pFlac->bs.pUserData, (int)seektablePos, MA_DR_FLAC_SEEK_SET)) { + if (pFlac->bs.onSeek(pFlac->bs.pUserData, (int)seektablePos, ma_dr_flac_seek_origin_start)) { ma_uint32 iSeekpoint; for (iSeekpoint = 0; iSeekpoint < seekpointCount; iSeekpoint += 1) { if (pFlac->bs.onRead(pFlac->bs.pUserData, pFlac->pSeekpoints + iSeekpoint, MA_DR_FLAC_SEEKPOINT_SIZE_IN_BYTES) == MA_DR_FLAC_SEEKPOINT_SIZE_IN_BYTES) { @@ -89681,7 +87907,7 @@ static ma_dr_flac* ma_dr_flac_open_with_metadata_private(ma_dr_flac_read_proc on break; } } - if (!pFlac->bs.onSeek(pFlac->bs.pUserData, (int)pFlac->firstFLACFramePosInBytes, MA_DR_FLAC_SEEK_SET)) { + if (!pFlac->bs.onSeek(pFlac->bs.pUserData, (int)pFlac->firstFLACFramePosInBytes, ma_dr_flac_seek_origin_start)) { ma_dr_flac__free_from_callbacks(pFlac, &allocationCallbacks); return NULL; } @@ -89724,31 +87950,8 @@ static size_t ma_dr_flac__on_read_stdio(void* pUserData, void* bufferOut, size_t } static ma_bool32 ma_dr_flac__on_seek_stdio(void* pUserData, int offset, ma_dr_flac_seek_origin origin) { - int whence = SEEK_SET; - if (origin == MA_DR_FLAC_SEEK_CUR) { - whence = SEEK_CUR; - } else if (origin == MA_DR_FLAC_SEEK_END) { - whence = SEEK_END; - } - return fseek((FILE*)pUserData, offset, whence) == 0; -} -static ma_bool32 ma_dr_flac__on_tell_stdio(void* pUserData, ma_int64* pCursor) -{ - FILE* pFileStdio = (FILE*)pUserData; - ma_int64 result; - MA_DR_FLAC_ASSERT(pFileStdio != NULL); - MA_DR_FLAC_ASSERT(pCursor != NULL); -#if defined(_WIN32) && !defined(NXDK) - #if defined(_MSC_VER) && _MSC_VER > 1200 - result = _ftelli64(pFileStdio); - #else - result = ftell(pFileStdio); - #endif -#else - result = ftell(pFileStdio); -#endif - *pCursor = result; - return MA_TRUE; + MA_DR_FLAC_ASSERT(offset >= 0); + return fseek((FILE*)pUserData, offset, (origin == ma_dr_flac_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0; } MA_API ma_dr_flac* ma_dr_flac_open_file(const char* pFileName, const ma_allocation_callbacks* pAllocationCallbacks) { @@ -89757,7 +87960,7 @@ MA_API ma_dr_flac* ma_dr_flac_open_file(const char* pFileName, const ma_allocati if (ma_fopen(&pFile, pFileName, "rb") != MA_SUCCESS) { return NULL; } - pFlac = ma_dr_flac_open(ma_dr_flac__on_read_stdio, ma_dr_flac__on_seek_stdio, ma_dr_flac__on_tell_stdio, (void*)pFile, pAllocationCallbacks); + pFlac = ma_dr_flac_open(ma_dr_flac__on_read_stdio, ma_dr_flac__on_seek_stdio, (void*)pFile, pAllocationCallbacks); if (pFlac == NULL) { fclose(pFile); return NULL; @@ -89772,7 +87975,7 @@ MA_API ma_dr_flac* ma_dr_flac_open_file_w(const wchar_t* pFileName, const ma_all if (ma_wfopen(&pFile, pFileName, L"rb", pAllocationCallbacks) != MA_SUCCESS) { return NULL; } - pFlac = ma_dr_flac_open(ma_dr_flac__on_read_stdio, ma_dr_flac__on_seek_stdio, ma_dr_flac__on_tell_stdio, (void*)pFile, pAllocationCallbacks); + pFlac = ma_dr_flac_open(ma_dr_flac__on_read_stdio, ma_dr_flac__on_seek_stdio, (void*)pFile, pAllocationCallbacks); if (pFlac == NULL) { fclose(pFile); return NULL; @@ -89787,7 +87990,7 @@ MA_API ma_dr_flac* ma_dr_flac_open_file_with_metadata(const char* pFileName, ma_ if (ma_fopen(&pFile, pFileName, "rb") != MA_SUCCESS) { return NULL; } - pFlac = ma_dr_flac_open_with_metadata_private(ma_dr_flac__on_read_stdio, ma_dr_flac__on_seek_stdio, ma_dr_flac__on_tell_stdio, onMeta, ma_dr_flac_container_unknown, (void*)pFile, pUserData, pAllocationCallbacks); + pFlac = ma_dr_flac_open_with_metadata_private(ma_dr_flac__on_read_stdio, ma_dr_flac__on_seek_stdio, onMeta, ma_dr_flac_container_unknown, (void*)pFile, pUserData, pAllocationCallbacks); if (pFlac == NULL) { fclose(pFile); return pFlac; @@ -89802,7 +88005,7 @@ MA_API ma_dr_flac* ma_dr_flac_open_file_with_metadata_w(const wchar_t* pFileName if (ma_wfopen(&pFile, pFileName, L"rb", pAllocationCallbacks) != MA_SUCCESS) { return NULL; } - pFlac = ma_dr_flac_open_with_metadata_private(ma_dr_flac__on_read_stdio, ma_dr_flac__on_seek_stdio, ma_dr_flac__on_tell_stdio, onMeta, ma_dr_flac_container_unknown, (void*)pFile, pUserData, pAllocationCallbacks); + pFlac = ma_dr_flac_open_with_metadata_private(ma_dr_flac__on_read_stdio, ma_dr_flac__on_seek_stdio, onMeta, ma_dr_flac_container_unknown, (void*)pFile, pUserData, pAllocationCallbacks); if (pFlac == NULL) { fclose(pFile); return pFlac; @@ -89830,35 +88033,24 @@ static size_t ma_dr_flac__on_read_memory(void* pUserData, void* bufferOut, size_ static ma_bool32 ma_dr_flac__on_seek_memory(void* pUserData, int offset, ma_dr_flac_seek_origin origin) { ma_dr_flac__memory_stream* memoryStream = (ma_dr_flac__memory_stream*)pUserData; - ma_int64 newCursor; MA_DR_FLAC_ASSERT(memoryStream != NULL); - newCursor = memoryStream->currentReadPos; - if (origin == MA_DR_FLAC_SEEK_SET) { - newCursor = 0; - } else if (origin == MA_DR_FLAC_SEEK_CUR) { - newCursor = (ma_int64)memoryStream->currentReadPos; - } else if (origin == MA_DR_FLAC_SEEK_END) { - newCursor = (ma_int64)memoryStream->dataSize; + MA_DR_FLAC_ASSERT(offset >= 0); + if (offset > (ma_int64)memoryStream->dataSize) { + return MA_FALSE; + } + if (origin == ma_dr_flac_seek_origin_current) { + if (memoryStream->currentReadPos + offset <= memoryStream->dataSize) { + memoryStream->currentReadPos += offset; + } else { + return MA_FALSE; + } } else { - MA_DR_FLAC_ASSERT(!"Invalid seek origin"); - return MA_FALSE; + if ((ma_uint32)offset <= memoryStream->dataSize) { + memoryStream->currentReadPos = offset; + } else { + return MA_FALSE; + } } - newCursor += offset; - if (newCursor < 0) { - return MA_FALSE; - } - if ((size_t)newCursor > memoryStream->dataSize) { - return MA_FALSE; - } - memoryStream->currentReadPos = (size_t)newCursor; - return MA_TRUE; -} -static ma_bool32 ma_dr_flac__on_tell_memory(void* pUserData, ma_int64* pCursor) -{ - ma_dr_flac__memory_stream* memoryStream = (ma_dr_flac__memory_stream*)pUserData; - MA_DR_FLAC_ASSERT(memoryStream != NULL); - MA_DR_FLAC_ASSERT(pCursor != NULL); - *pCursor = (ma_int64)memoryStream->currentReadPos; return MA_TRUE; } MA_API ma_dr_flac* ma_dr_flac_open_memory(const void* pData, size_t dataSize, const ma_allocation_callbacks* pAllocationCallbacks) @@ -89868,7 +88060,7 @@ MA_API ma_dr_flac* ma_dr_flac_open_memory(const void* pData, size_t dataSize, co memoryStream.data = (const ma_uint8*)pData; memoryStream.dataSize = dataSize; memoryStream.currentReadPos = 0; - pFlac = ma_dr_flac_open(ma_dr_flac__on_read_memory, ma_dr_flac__on_seek_memory, ma_dr_flac__on_tell_memory, &memoryStream, pAllocationCallbacks); + pFlac = ma_dr_flac_open(ma_dr_flac__on_read_memory, ma_dr_flac__on_seek_memory, &memoryStream, pAllocationCallbacks); if (pFlac == NULL) { return NULL; } @@ -89893,7 +88085,7 @@ MA_API ma_dr_flac* ma_dr_flac_open_memory_with_metadata(const void* pData, size_ memoryStream.data = (const ma_uint8*)pData; memoryStream.dataSize = dataSize; memoryStream.currentReadPos = 0; - pFlac = ma_dr_flac_open_with_metadata_private(ma_dr_flac__on_read_memory, ma_dr_flac__on_seek_memory, ma_dr_flac__on_tell_memory, onMeta, ma_dr_flac_container_unknown, &memoryStream, pUserData, pAllocationCallbacks); + pFlac = ma_dr_flac_open_with_metadata_private(ma_dr_flac__on_read_memory, ma_dr_flac__on_seek_memory, onMeta, ma_dr_flac_container_unknown, &memoryStream, pUserData, pAllocationCallbacks); if (pFlac == NULL) { return NULL; } @@ -89911,21 +88103,21 @@ MA_API ma_dr_flac* ma_dr_flac_open_memory_with_metadata(const void* pData, size_ } return pFlac; } -MA_API ma_dr_flac* ma_dr_flac_open(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_dr_flac* ma_dr_flac_open(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) { - return ma_dr_flac_open_with_metadata_private(onRead, onSeek, onTell, NULL, ma_dr_flac_container_unknown, pUserData, pUserData, pAllocationCallbacks); + return ma_dr_flac_open_with_metadata_private(onRead, onSeek, NULL, ma_dr_flac_container_unknown, pUserData, pUserData, pAllocationCallbacks); } -MA_API ma_dr_flac* ma_dr_flac_open_relaxed(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, ma_dr_flac_container container, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_dr_flac* ma_dr_flac_open_relaxed(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_container container, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) { - return ma_dr_flac_open_with_metadata_private(onRead, onSeek, onTell, NULL, container, pUserData, pUserData, pAllocationCallbacks); + return ma_dr_flac_open_with_metadata_private(onRead, onSeek, NULL, container, pUserData, pUserData, pAllocationCallbacks); } -MA_API ma_dr_flac* ma_dr_flac_open_with_metadata(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, ma_dr_flac_meta_proc onMeta, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_dr_flac* ma_dr_flac_open_with_metadata(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_meta_proc onMeta, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) { - return ma_dr_flac_open_with_metadata_private(onRead, onSeek, onTell, onMeta, ma_dr_flac_container_unknown, pUserData, pUserData, pAllocationCallbacks); + return ma_dr_flac_open_with_metadata_private(onRead, onSeek, onMeta, ma_dr_flac_container_unknown, pUserData, pUserData, pAllocationCallbacks); } -MA_API ma_dr_flac* ma_dr_flac_open_with_metadata_relaxed(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, ma_dr_flac_meta_proc onMeta, ma_dr_flac_container container, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_dr_flac* ma_dr_flac_open_with_metadata_relaxed(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_meta_proc onMeta, ma_dr_flac_container container, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) { - return ma_dr_flac_open_with_metadata_private(onRead, onSeek, onTell, onMeta, container, pUserData, pUserData, pAllocationCallbacks); + return ma_dr_flac_open_with_metadata_private(onRead, onSeek, onMeta, container, pUserData, pUserData, pAllocationCallbacks); } MA_API void ma_dr_flac_close(ma_dr_flac* pFlac) { @@ -92218,7 +90410,7 @@ on_error: MA_DR_FLAC_DEFINE_FULL_READ_AND_CLOSE(s32, ma_int32) MA_DR_FLAC_DEFINE_FULL_READ_AND_CLOSE(s16, ma_int16) MA_DR_FLAC_DEFINE_FULL_READ_AND_CLOSE(f32, float) -MA_API ma_int32* ma_dr_flac_open_and_read_pcm_frames_s32(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalPCMFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_int32* ma_dr_flac_open_and_read_pcm_frames_s32(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalPCMFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) { ma_dr_flac* pFlac; if (channelsOut) { @@ -92230,13 +90422,13 @@ MA_API ma_int32* ma_dr_flac_open_and_read_pcm_frames_s32(ma_dr_flac_read_proc on if (totalPCMFrameCountOut) { *totalPCMFrameCountOut = 0; } - pFlac = ma_dr_flac_open(onRead, onSeek, onTell, pUserData, pAllocationCallbacks); + pFlac = ma_dr_flac_open(onRead, onSeek, pUserData, pAllocationCallbacks); if (pFlac == NULL) { return NULL; } return ma_dr_flac__full_read_and_close_s32(pFlac, channelsOut, sampleRateOut, totalPCMFrameCountOut); } -MA_API ma_int16* ma_dr_flac_open_and_read_pcm_frames_s16(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalPCMFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_int16* ma_dr_flac_open_and_read_pcm_frames_s16(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalPCMFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) { ma_dr_flac* pFlac; if (channelsOut) { @@ -92248,13 +90440,13 @@ MA_API ma_int16* ma_dr_flac_open_and_read_pcm_frames_s16(ma_dr_flac_read_proc on if (totalPCMFrameCountOut) { *totalPCMFrameCountOut = 0; } - pFlac = ma_dr_flac_open(onRead, onSeek, onTell, pUserData, pAllocationCallbacks); + pFlac = ma_dr_flac_open(onRead, onSeek, pUserData, pAllocationCallbacks); if (pFlac == NULL) { return NULL; } return ma_dr_flac__full_read_and_close_s16(pFlac, channelsOut, sampleRateOut, totalPCMFrameCountOut); } -MA_API float* ma_dr_flac_open_and_read_pcm_frames_f32(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalPCMFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API float* ma_dr_flac_open_and_read_pcm_frames_f32(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalPCMFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) { ma_dr_flac* pFlac; if (channelsOut) { @@ -92266,7 +90458,7 @@ MA_API float* ma_dr_flac_open_and_read_pcm_frames_f32(ma_dr_flac_read_proc onRea if (totalPCMFrameCountOut) { *totalPCMFrameCountOut = 0; } - pFlac = ma_dr_flac_open(onRead, onSeek, onTell, pUserData, pAllocationCallbacks); + pFlac = ma_dr_flac_open(onRead, onSeek, pUserData, pAllocationCallbacks); if (pFlac == NULL) { return NULL; } @@ -93070,10 +91262,6 @@ static float ma_dr_mp3_L3_ldexp_q2(float y, int exp_q2) } while ((exp_q2 -= e) > 0); return y; } -#if (defined(__GNUC__) && (__GNUC__ >= 14)) && !defined(__clang__) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wstringop-overflow" -#endif static void ma_dr_mp3_L3_decode_scalefactors(const ma_uint8 *hdr, ma_uint8 *ist_pos, ma_dr_mp3_bs *bs, const ma_dr_mp3_L3_gr_info *gr, float *scf, int ch) { static const ma_uint8 g_scf_partitions[3][28] = { @@ -93132,10 +91320,7 @@ static void ma_dr_mp3_L3_decode_scalefactors(const ma_uint8 *hdr, ma_uint8 *ist_ scf[i] = ma_dr_mp3_L3_ldexp_q2(gain, iscf[i] << scf_shift); } } -#if (defined(__GNUC__) && (__GNUC__ >= 14)) && !defined(__clang__) - #pragma GCC diagnostic pop -#endif -static const float ma_dr_mp3_g_pow43[129 + 16] = { +static const float g_ma_dr_mp3_pow43[129 + 16] = { 0,-1,-2.519842f,-4.326749f,-6.349604f,-8.549880f,-10.902724f,-13.390518f,-16.000000f,-18.720754f,-21.544347f,-24.463781f,-27.473142f,-30.567351f,-33.741992f,-36.993181f, 0,1,2.519842f,4.326749f,6.349604f,8.549880f,10.902724f,13.390518f,16.000000f,18.720754f,21.544347f,24.463781f,27.473142f,30.567351f,33.741992f,36.993181f,40.317474f,43.711787f,47.173345f,50.699631f,54.288352f,57.937408f,61.644865f,65.408941f,69.227979f,73.100443f,77.024898f,81.000000f,85.024491f,89.097188f,93.216975f,97.382800f,101.593667f,105.848633f,110.146801f,114.487321f,118.869381f,123.292209f,127.755065f,132.257246f,136.798076f,141.376907f,145.993119f,150.646117f,155.335327f,160.060199f,164.820202f,169.614826f,174.443577f,179.305980f,184.201575f,189.129918f,194.090580f,199.083145f,204.107210f,209.162385f,214.248292f,219.364564f,224.510845f,229.686789f,234.892058f,240.126328f,245.389280f,250.680604f,256.000000f,261.347174f,266.721841f,272.123723f,277.552547f,283.008049f,288.489971f,293.998060f,299.532071f,305.091761f,310.676898f,316.287249f,321.922592f,327.582707f,333.267377f,338.976394f,344.709550f,350.466646f,356.247482f,362.051866f,367.879608f,373.730522f,379.604427f,385.501143f,391.420496f,397.362314f,403.326427f,409.312672f,415.320884f,421.350905f,427.402579f,433.475750f,439.570269f,445.685987f,451.822757f,457.980436f,464.158883f,470.357960f,476.577530f,482.817459f,489.077615f,495.357868f,501.658090f,507.978156f,514.317941f,520.677324f,527.056184f,533.454404f,539.871867f,546.308458f,552.764065f,559.238575f,565.731879f,572.243870f,578.774440f,585.323483f,591.890898f,598.476581f,605.080431f,611.702349f,618.342238f,625.000000f,631.675540f,638.368763f,645.079578f }; @@ -93145,7 +91330,7 @@ static float ma_dr_mp3_L3_pow_43(int x) int sign, mult = 256; if (x < 129) { - return ma_dr_mp3_g_pow43[16 + x]; + return g_ma_dr_mp3_pow43[16 + x]; } if (x < 1024) { @@ -93154,7 +91339,7 @@ static float ma_dr_mp3_L3_pow_43(int x) } sign = 2*x & 64; frac = (float)((x & 63) - sign) / ((x & ~63) + sign); - return ma_dr_mp3_g_pow43[16 + ((x + sign) >> 6)]*(1.f + frac*((4.f/3) + frac*(2.f/9)))*mult; + return g_ma_dr_mp3_pow43[16 + ((x + sign) >> 6)]*(1.f + frac*((4.f/3) + frac*(2.f/9)))*mult; } static void ma_dr_mp3_L3_huffman(float *dst, ma_dr_mp3_bs *bs, const ma_dr_mp3_L3_gr_info *gr_info, const float *scf, int layer3gr_limit) { @@ -93224,7 +91409,7 @@ static void ma_dr_mp3_L3_huffman(float *dst, ma_dr_mp3_bs *bs, const ma_dr_mp3_L *dst = one*ma_dr_mp3_L3_pow_43(lsb)*((ma_int32)bs_cache < 0 ? -1: 1); } else { - *dst = ma_dr_mp3_g_pow43[16 + lsb - 16*(bs_cache >> 31)]*one; + *dst = g_ma_dr_mp3_pow43[16 + lsb - 16*(bs_cache >> 31)]*one; } MA_DR_MP3_FLUSH_BITS(lsb ? 1 : 0); } @@ -93252,7 +91437,7 @@ static void ma_dr_mp3_L3_huffman(float *dst, ma_dr_mp3_bs *bs, const ma_dr_mp3_L for (j = 0; j < 2; j++, dst++, leaf >>= 4) { int lsb = leaf & 0x0F; - *dst = ma_dr_mp3_g_pow43[16 + lsb - 16*(bs_cache >> 31)]*one; + *dst = g_ma_dr_mp3_pow43[16 + lsb - 16*(bs_cache >> 31)]*one; MA_DR_MP3_FLUSH_BITS(lsb ? 1 : 0); } MA_DR_MP3_CHECK_BITS; @@ -94083,7 +92268,7 @@ MA_API int ma_dr_mp3dec_decode_frame(ma_dr_mp3dec *dec, const ma_uint8 *mp3, int MA_DR_MP3_COPY_MEMORY(dec->header, hdr, MA_DR_MP3_HDR_SIZE); info->frame_bytes = i + frame_size; info->channels = MA_DR_MP3_HDR_IS_MONO(hdr) ? 1 : 2; - info->sample_rate = ma_dr_mp3_hdr_sample_rate_hz(hdr); + info->hz = ma_dr_mp3_hdr_sample_rate_hz(hdr); info->layer = 4 - MA_DR_MP3_HDR_GET_LAYER(hdr); info->bitrate_kbps = ma_dr_mp3_hdr_bitrate_kbps(hdr); ma_dr_mp3_bs_init(bs_frame, hdr + MA_DR_MP3_HDR_SIZE, frame_size - MA_DR_MP3_HDR_SIZE); @@ -94306,41 +92491,19 @@ static ma_allocation_callbacks ma_dr_mp3_copy_allocation_callbacks_or_defaults(c } static size_t ma_dr_mp3__on_read(ma_dr_mp3* pMP3, void* pBufferOut, size_t bytesToRead) { - size_t bytesRead; - MA_DR_MP3_ASSERT(pMP3 != NULL); - MA_DR_MP3_ASSERT(pMP3->onRead != NULL); - if (bytesToRead == 0) { - return 0; - } - bytesRead = pMP3->onRead(pMP3->pUserData, pBufferOut, bytesToRead); + size_t bytesRead = pMP3->onRead(pMP3->pUserData, pBufferOut, bytesToRead); pMP3->streamCursor += bytesRead; return bytesRead; } -static size_t ma_dr_mp3__on_read_clamped(ma_dr_mp3* pMP3, void* pBufferOut, size_t bytesToRead) -{ - MA_DR_MP3_ASSERT(pMP3 != NULL); - MA_DR_MP3_ASSERT(pMP3->onRead != NULL); - if (pMP3->streamLength == MA_UINT64_MAX) { - return ma_dr_mp3__on_read(pMP3, pBufferOut, bytesToRead); - } else { - ma_uint64 bytesRemaining; - bytesRemaining = (pMP3->streamLength - pMP3->streamCursor); - if (bytesToRead > bytesRemaining) { - bytesToRead = (size_t)bytesRemaining; - } - return ma_dr_mp3__on_read(pMP3, pBufferOut, bytesToRead); - } -} static ma_bool32 ma_dr_mp3__on_seek(ma_dr_mp3* pMP3, int offset, ma_dr_mp3_seek_origin origin) { MA_DR_MP3_ASSERT(offset >= 0); - MA_DR_MP3_ASSERT(origin == MA_DR_MP3_SEEK_SET || origin == MA_DR_MP3_SEEK_CUR); if (!pMP3->onSeek(pMP3->pUserData, offset, origin)) { return MA_FALSE; } - if (origin == MA_DR_MP3_SEEK_SET) { + if (origin == ma_dr_mp3_seek_origin_start) { pMP3->streamCursor = (ma_uint64)offset; - } else{ + } else { pMP3->streamCursor += offset; } return MA_TRUE; @@ -94350,18 +92513,18 @@ static ma_bool32 ma_dr_mp3__on_seek_64(ma_dr_mp3* pMP3, ma_uint64 offset, ma_dr_ if (offset <= 0x7FFFFFFF) { return ma_dr_mp3__on_seek(pMP3, (int)offset, origin); } - if (!ma_dr_mp3__on_seek(pMP3, 0x7FFFFFFF, MA_DR_MP3_SEEK_SET)) { + if (!ma_dr_mp3__on_seek(pMP3, 0x7FFFFFFF, ma_dr_mp3_seek_origin_start)) { return MA_FALSE; } offset -= 0x7FFFFFFF; while (offset > 0) { if (offset <= 0x7FFFFFFF) { - if (!ma_dr_mp3__on_seek(pMP3, (int)offset, MA_DR_MP3_SEEK_CUR)) { + if (!ma_dr_mp3__on_seek(pMP3, (int)offset, ma_dr_mp3_seek_origin_current)) { return MA_FALSE; } offset = 0; } else { - if (!ma_dr_mp3__on_seek(pMP3, 0x7FFFFFFF, MA_DR_MP3_SEEK_CUR)) { + if (!ma_dr_mp3__on_seek(pMP3, 0x7FFFFFFF, ma_dr_mp3_seek_origin_current)) { return MA_FALSE; } offset -= 0x7FFFFFFF; @@ -94369,18 +92532,7 @@ static ma_bool32 ma_dr_mp3__on_seek_64(ma_dr_mp3* pMP3, ma_uint64 offset, ma_dr_ } return MA_TRUE; } -static void ma_dr_mp3__on_meta(ma_dr_mp3* pMP3, ma_dr_mp3_metadata_type type, const void* pRawData, size_t rawDataSize) -{ - if (pMP3->onMeta) { - ma_dr_mp3_metadata metadata; - MA_DR_MP3_ZERO_OBJECT(&metadata); - metadata.type = type; - metadata.pRawData = pRawData; - metadata.rawDataSize = rawDataSize; - pMP3->onMeta(pMP3->pUserDataMeta, &metadata); - } -} -static ma_uint32 ma_dr_mp3_decode_next_frame_ex__callbacks(ma_dr_mp3* pMP3, ma_dr_mp3d_sample_t* pPCMFrames, ma_dr_mp3dec_frame_info* pMP3FrameInfo, const ma_uint8** ppMP3FrameData) +static ma_uint32 ma_dr_mp3_decode_next_frame_ex__callbacks(ma_dr_mp3* pMP3, ma_dr_mp3d_sample_t* pPCMFrames) { ma_uint32 pcmFramesRead = 0; MA_DR_MP3_ASSERT(pMP3 != NULL); @@ -94407,7 +92559,7 @@ static ma_uint32 ma_dr_mp3_decode_next_frame_ex__callbacks(ma_dr_mp3* pMP3, ma_d pMP3->pData = pNewData; pMP3->dataCapacity = newDataCap; } - bytesRead = ma_dr_mp3__on_read_clamped(pMP3, pMP3->pData + pMP3->dataSize, (pMP3->dataCapacity - pMP3->dataSize)); + bytesRead = ma_dr_mp3__on_read(pMP3, pMP3->pData + pMP3->dataSize, (pMP3->dataCapacity - pMP3->dataSize)); if (bytesRead == 0) { if (pMP3->dataSize == 0) { pMP3->atEnd = MA_TRUE; @@ -94426,20 +92578,16 @@ static ma_uint32 ma_dr_mp3_decode_next_frame_ex__callbacks(ma_dr_mp3* pMP3, ma_d return 0; } pcmFramesRead = ma_dr_mp3dec_decode_frame(&pMP3->decoder, pMP3->pData + pMP3->dataConsumed, (int)pMP3->dataSize, pPCMFrames, &info); - pMP3->dataConsumed += (size_t)info.frame_bytes; - pMP3->dataSize -= (size_t)info.frame_bytes; + if (info.frame_bytes > 0) { + pMP3->dataConsumed += (size_t)info.frame_bytes; + pMP3->dataSize -= (size_t)info.frame_bytes; + } if (pcmFramesRead > 0) { pcmFramesRead = ma_dr_mp3_hdr_frame_samples(pMP3->decoder.header); pMP3->pcmFramesConsumedInMP3Frame = 0; pMP3->pcmFramesRemainingInMP3Frame = pcmFramesRead; pMP3->mp3FrameChannels = info.channels; - pMP3->mp3FrameSampleRate = info.sample_rate; - if (pMP3FrameInfo != NULL) { - *pMP3FrameInfo = info; - } - if (ppMP3FrameData != NULL) { - *ppMP3FrameData = pMP3->pData + pMP3->dataConsumed - (size_t)info.frame_bytes; - } + pMP3->mp3FrameSampleRate = info.hz; break; } else if (info.frame_bytes == 0) { size_t bytesRead; @@ -94456,7 +92604,7 @@ static ma_uint32 ma_dr_mp3_decode_next_frame_ex__callbacks(ma_dr_mp3* pMP3, ma_d pMP3->pData = pNewData; pMP3->dataCapacity = newDataCap; } - bytesRead = ma_dr_mp3__on_read_clamped(pMP3, pMP3->pData + pMP3->dataSize, (pMP3->dataCapacity - pMP3->dataSize)); + bytesRead = ma_dr_mp3__on_read(pMP3, pMP3->pData + pMP3->dataSize, (pMP3->dataCapacity - pMP3->dataSize)); if (bytesRead == 0) { pMP3->atEnd = MA_TRUE; return 0; @@ -94466,7 +92614,7 @@ static ma_uint32 ma_dr_mp3_decode_next_frame_ex__callbacks(ma_dr_mp3* pMP3, ma_d }; return pcmFramesRead; } -static ma_uint32 ma_dr_mp3_decode_next_frame_ex__memory(ma_dr_mp3* pMP3, ma_dr_mp3d_sample_t* pPCMFrames, ma_dr_mp3dec_frame_info* pMP3FrameInfo, const ma_uint8** ppMP3FrameData) +static ma_uint32 ma_dr_mp3_decode_next_frame_ex__memory(ma_dr_mp3* pMP3, ma_dr_mp3d_sample_t* pPCMFrames) { ma_uint32 pcmFramesRead = 0; ma_dr_mp3dec_frame_info info; @@ -94482,44 +92630,36 @@ static ma_uint32 ma_dr_mp3_decode_next_frame_ex__memory(ma_dr_mp3* pMP3, ma_dr_m pMP3->pcmFramesConsumedInMP3Frame = 0; pMP3->pcmFramesRemainingInMP3Frame = pcmFramesRead; pMP3->mp3FrameChannels = info.channels; - pMP3->mp3FrameSampleRate = info.sample_rate; - if (pMP3FrameInfo != NULL) { - *pMP3FrameInfo = info; - } - if (ppMP3FrameData != NULL) { - *ppMP3FrameData = pMP3->memory.pData + pMP3->memory.currentReadPos; - } + pMP3->mp3FrameSampleRate = info.hz; break; } else if (info.frame_bytes > 0) { pMP3->memory.currentReadPos += (size_t)info.frame_bytes; - pMP3->streamCursor += (size_t)info.frame_bytes; } else { break; } } pMP3->memory.currentReadPos += (size_t)info.frame_bytes; - pMP3->streamCursor += (size_t)info.frame_bytes; return pcmFramesRead; } -static ma_uint32 ma_dr_mp3_decode_next_frame_ex(ma_dr_mp3* pMP3, ma_dr_mp3d_sample_t* pPCMFrames, ma_dr_mp3dec_frame_info* pMP3FrameInfo, const ma_uint8** ppMP3FrameData) +static ma_uint32 ma_dr_mp3_decode_next_frame_ex(ma_dr_mp3* pMP3, ma_dr_mp3d_sample_t* pPCMFrames) { if (pMP3->memory.pData != NULL && pMP3->memory.dataSize > 0) { - return ma_dr_mp3_decode_next_frame_ex__memory(pMP3, pPCMFrames, pMP3FrameInfo, ppMP3FrameData); + return ma_dr_mp3_decode_next_frame_ex__memory(pMP3, pPCMFrames); } else { - return ma_dr_mp3_decode_next_frame_ex__callbacks(pMP3, pPCMFrames, pMP3FrameInfo, ppMP3FrameData); + return ma_dr_mp3_decode_next_frame_ex__callbacks(pMP3, pPCMFrames); } } static ma_uint32 ma_dr_mp3_decode_next_frame(ma_dr_mp3* pMP3) { MA_DR_MP3_ASSERT(pMP3 != NULL); - return ma_dr_mp3_decode_next_frame_ex(pMP3, (ma_dr_mp3d_sample_t*)pMP3->pcmFrames, NULL, NULL); + return ma_dr_mp3_decode_next_frame_ex(pMP3, (ma_dr_mp3d_sample_t*)pMP3->pcmFrames); } #if 0 static ma_uint32 ma_dr_mp3_seek_next_frame(ma_dr_mp3* pMP3) { ma_uint32 pcmFrameCount; MA_DR_MP3_ASSERT(pMP3 != NULL); - pcmFrameCount = ma_dr_mp3_decode_next_frame_ex(pMP3, NULL, NULL, NULL); + pcmFrameCount = ma_dr_mp3_decode_next_frame_ex(pMP3, NULL); if (pcmFrameCount == 0) { return 0; } @@ -94529,249 +92669,33 @@ static ma_uint32 ma_dr_mp3_seek_next_frame(ma_dr_mp3* pMP3) return pcmFrameCount; } #endif -static ma_bool32 ma_dr_mp3_init_internal(ma_dr_mp3* pMP3, ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, ma_dr_mp3_tell_proc onTell, ma_dr_mp3_meta_proc onMeta, void* pUserData, void* pUserDataMeta, const ma_allocation_callbacks* pAllocationCallbacks) +static ma_bool32 ma_dr_mp3_init_internal(ma_dr_mp3* pMP3, ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) { - ma_dr_mp3dec_frame_info firstFrameInfo; - const ma_uint8* pFirstFrameData; - ma_uint32 firstFramePCMFrameCount; - ma_uint32 detectedMP3FrameCount = 0xFFFFFFFF; MA_DR_MP3_ASSERT(pMP3 != NULL); MA_DR_MP3_ASSERT(onRead != NULL); ma_dr_mp3dec_init(&pMP3->decoder); pMP3->onRead = onRead; pMP3->onSeek = onSeek; - pMP3->onMeta = onMeta; pMP3->pUserData = pUserData; - pMP3->pUserDataMeta = pUserDataMeta; pMP3->allocationCallbacks = ma_dr_mp3_copy_allocation_callbacks_or_defaults(pAllocationCallbacks); if (pMP3->allocationCallbacks.onFree == NULL || (pMP3->allocationCallbacks.onMalloc == NULL && pMP3->allocationCallbacks.onRealloc == NULL)) { return MA_FALSE; } - pMP3->streamCursor = 0; - pMP3->streamLength = MA_UINT64_MAX; - pMP3->streamStartOffset = 0; - pMP3->delayInPCMFrames = 0; - pMP3->paddingInPCMFrames = 0; - pMP3->totalPCMFrameCount = MA_UINT64_MAX; - #if 1 - if (onSeek != NULL && onTell != NULL) { - if (onSeek(pUserData, 0, MA_DR_MP3_SEEK_END)) { - ma_int64 streamLen; - int streamEndOffset = 0; - if (onTell(pUserData, &streamLen)) { - if (streamLen > 128) { - char id3[3]; - if (onSeek(pUserData, streamEndOffset - 128, MA_DR_MP3_SEEK_END)) { - if (onRead(pUserData, id3, 3) == 3 && id3[0] == 'T' && id3[1] == 'A' && id3[2] == 'G') { - streamEndOffset -= 128; - streamLen -= 128; - if (onMeta != NULL) { - ma_uint8 tag[128]; - tag[0] = 'T'; tag[1] = 'A'; tag[2] = 'G'; - if (onRead(pUserData, tag + 3, 125) == 125) { - ma_dr_mp3__on_meta(pMP3, MA_DR_MP3_METADATA_TYPE_ID3V1, tag, 128); - } - } - } else { - } - } else { - } - } else { - } - if (streamLen > 32) { - char ape[32]; - if (onSeek(pUserData, streamEndOffset - 32, MA_DR_MP3_SEEK_END)) { - if (onRead(pUserData, ape, 32) == 32 && ape[0] == 'A' && ape[1] == 'P' && ape[2] == 'E' && ape[3] == 'T' && ape[4] == 'A' && ape[5] == 'G' && ape[6] == 'E' && ape[7] == 'X') { - ma_uint32 tagSize = - ((ma_uint32)ape[24] << 0) | - ((ma_uint32)ape[25] << 8) | - ((ma_uint32)ape[26] << 16) | - ((ma_uint32)ape[27] << 24); - streamEndOffset -= 32 + tagSize; - streamLen -= 32 + tagSize; - if (onMeta != NULL) { - if (onSeek(pUserData, streamEndOffset, MA_DR_MP3_SEEK_END)) { - size_t apeTagSize = (size_t)tagSize + 32; - ma_uint8* pTagData = (ma_uint8*)ma_dr_mp3_malloc(apeTagSize, pAllocationCallbacks); - if (pTagData != NULL) { - if (onRead(pUserData, pTagData, apeTagSize) == apeTagSize) { - ma_dr_mp3__on_meta(pMP3, MA_DR_MP3_METADATA_TYPE_APE, pTagData, apeTagSize); - } - ma_dr_mp3_free(pTagData, pAllocationCallbacks); - } - } - } - } - } - } else { - } - if (!onSeek(pUserData, 0, MA_DR_MP3_SEEK_SET)) { - return MA_FALSE; - } - pMP3->streamLength = (ma_uint64)streamLen; - if (pMP3->memory.pData != NULL) { - pMP3->memory.dataSize = (size_t)pMP3->streamLength; - } - } else { - if (!onSeek(pUserData, 0, MA_DR_MP3_SEEK_SET)) { - return MA_FALSE; - } - } - } else { - } - } else { - } - #endif - #if 1 - { - char header[10]; - if (onRead(pUserData, header, 10) == 10) { - if (header[0] == 'I' && header[1] == 'D' && header[2] == '3') { - ma_uint32 tagSize = - (((ma_uint32)header[6] & 0x7F) << 21) | - (((ma_uint32)header[7] & 0x7F) << 14) | - (((ma_uint32)header[8] & 0x7F) << 7) | - (((ma_uint32)header[9] & 0x7F) << 0); - if (header[5] & 0x10) { - tagSize += 10; - } - if (onMeta != NULL) { - size_t tagSizeWithHeader = 10 + tagSize; - ma_uint8* pTagData = (ma_uint8*)ma_dr_mp3_malloc(tagSizeWithHeader, pAllocationCallbacks); - if (pTagData != NULL) { - MA_DR_MP3_COPY_MEMORY(pTagData, header, 10); - if (onRead(pUserData, pTagData + 10, tagSize) == tagSize) { - ma_dr_mp3__on_meta(pMP3, MA_DR_MP3_METADATA_TYPE_ID3V2, pTagData, tagSizeWithHeader); - } - ma_dr_mp3_free(pTagData, pAllocationCallbacks); - } - } else { - if (onSeek != NULL) { - if (!onSeek(pUserData, tagSize, MA_DR_MP3_SEEK_CUR)) { - return MA_FALSE; - } - } else { - char discard[1024]; - while (tagSize > 0) { - size_t bytesToRead = tagSize; - if (bytesToRead > sizeof(discard)) { - bytesToRead = sizeof(discard); - } - if (onRead(pUserData, discard, bytesToRead) != bytesToRead) { - return MA_FALSE; - } - tagSize -= (ma_uint32)bytesToRead; - } - } - } - pMP3->streamStartOffset += 10 + tagSize; - pMP3->streamCursor = pMP3->streamStartOffset; - } else { - if (onSeek != NULL) { - if (!onSeek(pUserData, 0, MA_DR_MP3_SEEK_SET)) { - return MA_FALSE; - } - } else { - } - } - } else { - return MA_FALSE; - } - } - #endif - firstFramePCMFrameCount = ma_dr_mp3_decode_next_frame_ex(pMP3, (ma_dr_mp3d_sample_t*)pMP3->pcmFrames, &firstFrameInfo, &pFirstFrameData); - if (firstFramePCMFrameCount > 0) { - MA_DR_MP3_ASSERT(pFirstFrameData != NULL); - #if 1 - MA_DR_MP3_ASSERT(firstFrameInfo.frame_bytes > 0); - { - ma_dr_mp3_bs bs; - ma_dr_mp3_L3_gr_info grInfo[4]; - const ma_uint8* pTagData = pFirstFrameData; - ma_dr_mp3_bs_init(&bs, pFirstFrameData + MA_DR_MP3_HDR_SIZE, firstFrameInfo.frame_bytes - MA_DR_MP3_HDR_SIZE); - if (MA_DR_MP3_HDR_IS_CRC(pFirstFrameData)) { - ma_dr_mp3_bs_get_bits(&bs, 16); - } - if (ma_dr_mp3_L3_read_side_info(&bs, grInfo, pFirstFrameData) >= 0) { - ma_bool32 isXing = MA_FALSE; - ma_bool32 isInfo = MA_FALSE; - const ma_uint8* pTagDataBeg; - pTagDataBeg = pFirstFrameData + MA_DR_MP3_HDR_SIZE + (bs.pos/8); - pTagData = pTagDataBeg; - isXing = (pTagData[0] == 'X' && pTagData[1] == 'i' && pTagData[2] == 'n' && pTagData[3] == 'g'); - isInfo = (pTagData[0] == 'I' && pTagData[1] == 'n' && pTagData[2] == 'f' && pTagData[3] == 'o'); - if (isXing || isInfo) { - ma_uint32 bytes = 0; - ma_uint32 flags = pTagData[7]; - pTagData += 8; - if (flags & 0x01) { - detectedMP3FrameCount = (ma_uint32)pTagData[0] << 24 | (ma_uint32)pTagData[1] << 16 | (ma_uint32)pTagData[2] << 8 | (ma_uint32)pTagData[3]; - pTagData += 4; - } - if (flags & 0x02) { - bytes = (ma_uint32)pTagData[0] << 24 | (ma_uint32)pTagData[1] << 16 | (ma_uint32)pTagData[2] << 8 | (ma_uint32)pTagData[3]; - (void)bytes; - pTagData += 4; - } - if (flags & 0x04) { - pTagData += 100; - } - if (flags & 0x08) { - pTagData += 4; - } - if (pTagData[0]) { - pTagData += 21; - if (pTagData - pFirstFrameData + 14 < firstFrameInfo.frame_bytes) { - int delayInPCMFrames; - int paddingInPCMFrames; - delayInPCMFrames = (( (ma_uint32)pTagData[0] << 4) | ((ma_uint32)pTagData[1] >> 4)) + (528 + 1); - paddingInPCMFrames = ((((ma_uint32)pTagData[1] & 0xF) << 8) | ((ma_uint32)pTagData[2] )) - (528 + 1); - if (paddingInPCMFrames < 0) { - paddingInPCMFrames = 0; - } - pMP3->delayInPCMFrames = (ma_uint32)delayInPCMFrames; - pMP3->paddingInPCMFrames = (ma_uint32)paddingInPCMFrames; - } - } - if (isXing) { - pMP3->isVBR = MA_TRUE; - } else if (isInfo) { - pMP3->isCBR = MA_TRUE; - } - if (onMeta != NULL) { - ma_dr_mp3_metadata_type metadataType = isXing ? MA_DR_MP3_METADATA_TYPE_XING : MA_DR_MP3_METADATA_TYPE_VBRI; - size_t tagDataSize; - tagDataSize = (size_t)firstFrameInfo.frame_bytes; - tagDataSize -= (size_t)(pTagDataBeg - pFirstFrameData); - ma_dr_mp3__on_meta(pMP3, metadataType, pTagDataBeg, tagDataSize); - } - pMP3->pcmFramesRemainingInMP3Frame = 0; - pMP3->streamStartOffset += (ma_uint32)(firstFrameInfo.frame_bytes); - pMP3->streamCursor = pMP3->streamStartOffset; - ma_dr_mp3dec_init(&pMP3->decoder); - } - } else { - } - } - #endif - } else { + if (ma_dr_mp3_decode_next_frame(pMP3) == 0) { ma_dr_mp3__free_from_callbacks(pMP3->pData, &pMP3->allocationCallbacks); return MA_FALSE; } - if (detectedMP3FrameCount != 0xFFFFFFFF) { - pMP3->totalPCMFrameCount = detectedMP3FrameCount * firstFramePCMFrameCount; - } pMP3->channels = pMP3->mp3FrameChannels; pMP3->sampleRate = pMP3->mp3FrameSampleRate; return MA_TRUE; } -MA_API ma_bool32 ma_dr_mp3_init(ma_dr_mp3* pMP3, ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, ma_dr_mp3_tell_proc onTell, ma_dr_mp3_meta_proc onMeta, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_bool32 ma_dr_mp3_init(ma_dr_mp3* pMP3, ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) { if (pMP3 == NULL || onRead == NULL) { return MA_FALSE; } MA_DR_MP3_ZERO_OBJECT(pMP3); - return ma_dr_mp3_init_internal(pMP3, onRead, onSeek, onTell, onMeta, pUserData, pUserData, pAllocationCallbacks); + return ma_dr_mp3_init_internal(pMP3, onRead, onSeek, pUserData, pAllocationCallbacks); } static size_t ma_dr_mp3__on_read_memory(void* pUserData, void* pBufferOut, size_t bytesToRead) { @@ -94792,40 +92716,29 @@ static size_t ma_dr_mp3__on_read_memory(void* pUserData, void* pBufferOut, size_ static ma_bool32 ma_dr_mp3__on_seek_memory(void* pUserData, int byteOffset, ma_dr_mp3_seek_origin origin) { ma_dr_mp3* pMP3 = (ma_dr_mp3*)pUserData; - ma_int64 newCursor; MA_DR_MP3_ASSERT(pMP3 != NULL); - newCursor = pMP3->memory.currentReadPos; - if (origin == MA_DR_MP3_SEEK_SET) { - newCursor = 0; - } else if (origin == MA_DR_MP3_SEEK_CUR) { - newCursor = (ma_int64)pMP3->memory.currentReadPos; - } else if (origin == MA_DR_MP3_SEEK_END) { - newCursor = (ma_int64)pMP3->memory.dataSize; + if (origin == ma_dr_mp3_seek_origin_current) { + if (byteOffset > 0) { + if (pMP3->memory.currentReadPos + byteOffset > pMP3->memory.dataSize) { + byteOffset = (int)(pMP3->memory.dataSize - pMP3->memory.currentReadPos); + } + } else { + if (pMP3->memory.currentReadPos < (size_t)-byteOffset) { + byteOffset = -(int)pMP3->memory.currentReadPos; + } + } + pMP3->memory.currentReadPos += byteOffset; } else { - MA_DR_MP3_ASSERT(!"Invalid seek origin"); - return MA_FALSE; + if ((ma_uint32)byteOffset <= pMP3->memory.dataSize) { + pMP3->memory.currentReadPos = byteOffset; + } else { + pMP3->memory.currentReadPos = pMP3->memory.dataSize; + } } - newCursor += byteOffset; - if (newCursor < 0) { - return MA_FALSE; - } - if ((size_t)newCursor > pMP3->memory.dataSize) { - return MA_FALSE; - } - pMP3->memory.currentReadPos = (size_t)newCursor; return MA_TRUE; } -static ma_bool32 ma_dr_mp3__on_tell_memory(void* pUserData, ma_int64* pCursor) +MA_API ma_bool32 ma_dr_mp3_init_memory(ma_dr_mp3* pMP3, const void* pData, size_t dataSize, const ma_allocation_callbacks* pAllocationCallbacks) { - ma_dr_mp3* pMP3 = (ma_dr_mp3*)pUserData; - MA_DR_MP3_ASSERT(pMP3 != NULL); - MA_DR_MP3_ASSERT(pCursor != NULL); - *pCursor = (ma_int64)pMP3->memory.currentReadPos; - return MA_TRUE; -} -MA_API ma_bool32 ma_dr_mp3_init_memory_with_metadata(ma_dr_mp3* pMP3, const void* pData, size_t dataSize, ma_dr_mp3_meta_proc onMeta, void* pUserDataMeta, const ma_allocation_callbacks* pAllocationCallbacks) -{ - ma_bool32 result; if (pMP3 == NULL) { return MA_FALSE; } @@ -94836,21 +92749,7 @@ MA_API ma_bool32 ma_dr_mp3_init_memory_with_metadata(ma_dr_mp3* pMP3, const void pMP3->memory.pData = (const ma_uint8*)pData; pMP3->memory.dataSize = dataSize; pMP3->memory.currentReadPos = 0; - result = ma_dr_mp3_init_internal(pMP3, ma_dr_mp3__on_read_memory, ma_dr_mp3__on_seek_memory, ma_dr_mp3__on_tell_memory, onMeta, pMP3, pUserDataMeta, pAllocationCallbacks); - if (result == MA_FALSE) { - return MA_FALSE; - } - if (pMP3->streamLength <= (ma_uint64)MA_SIZE_MAX) { - pMP3->memory.dataSize = (size_t)pMP3->streamLength; - } - if (pMP3->streamStartOffset > (ma_uint64)MA_SIZE_MAX) { - return MA_FALSE; - } - return MA_TRUE; -} -MA_API ma_bool32 ma_dr_mp3_init_memory(ma_dr_mp3* pMP3, const void* pData, size_t dataSize, const ma_allocation_callbacks* pAllocationCallbacks) -{ - return ma_dr_mp3_init_memory_with_metadata(pMP3, pData, dataSize, NULL, NULL, pAllocationCallbacks); + return ma_dr_mp3_init_internal(pMP3, ma_dr_mp3__on_read_memory, ma_dr_mp3__on_seek_memory, pMP3, pAllocationCallbacks); } #ifndef MA_DR_MP3_NO_STDIO #include @@ -94861,75 +92760,35 @@ static size_t ma_dr_mp3__on_read_stdio(void* pUserData, void* pBufferOut, size_t } static ma_bool32 ma_dr_mp3__on_seek_stdio(void* pUserData, int offset, ma_dr_mp3_seek_origin origin) { - int whence = SEEK_SET; - if (origin == MA_DR_MP3_SEEK_CUR) { - whence = SEEK_CUR; - } else if (origin == MA_DR_MP3_SEEK_END) { - whence = SEEK_END; - } - return fseek((FILE*)pUserData, offset, whence) == 0; -} -static ma_bool32 ma_dr_mp3__on_tell_stdio(void* pUserData, ma_int64* pCursor) -{ - FILE* pFileStdio = (FILE*)pUserData; - ma_int64 result; - MA_DR_MP3_ASSERT(pFileStdio != NULL); - MA_DR_MP3_ASSERT(pCursor != NULL); -#if defined(_WIN32) && !defined(NXDK) - #if defined(_MSC_VER) && _MSC_VER > 1200 - result = _ftelli64(pFileStdio); - #else - result = ftell(pFileStdio); - #endif -#else - result = ftell(pFileStdio); -#endif - *pCursor = result; - return MA_TRUE; -} -MA_API ma_bool32 ma_dr_mp3_init_file_with_metadata(ma_dr_mp3* pMP3, const char* pFilePath, ma_dr_mp3_meta_proc onMeta, void* pUserDataMeta, const ma_allocation_callbacks* pAllocationCallbacks) -{ - ma_bool32 result; - FILE* pFile; - if (pMP3 == NULL) { - return MA_FALSE; - } - MA_DR_MP3_ZERO_OBJECT(pMP3); - if (ma_fopen(&pFile, pFilePath, "rb") != MA_SUCCESS) { - return MA_FALSE; - } - result = ma_dr_mp3_init_internal(pMP3, ma_dr_mp3__on_read_stdio, ma_dr_mp3__on_seek_stdio, ma_dr_mp3__on_tell_stdio, onMeta, (void*)pFile, pUserDataMeta, pAllocationCallbacks); - if (result != MA_TRUE) { - fclose(pFile); - return result; - } - return MA_TRUE; -} -MA_API ma_bool32 ma_dr_mp3_init_file_with_metadata_w(ma_dr_mp3* pMP3, const wchar_t* pFilePath, ma_dr_mp3_meta_proc onMeta, void* pUserDataMeta, const ma_allocation_callbacks* pAllocationCallbacks) -{ - ma_bool32 result; - FILE* pFile; - if (pMP3 == NULL) { - return MA_FALSE; - } - MA_DR_MP3_ZERO_OBJECT(pMP3); - if (ma_wfopen(&pFile, pFilePath, L"rb", pAllocationCallbacks) != MA_SUCCESS) { - return MA_FALSE; - } - result = ma_dr_mp3_init_internal(pMP3, ma_dr_mp3__on_read_stdio, ma_dr_mp3__on_seek_stdio, ma_dr_mp3__on_tell_stdio, onMeta, (void*)pFile, pUserDataMeta, pAllocationCallbacks); - if (result != MA_TRUE) { - fclose(pFile); - return result; - } - return MA_TRUE; + return fseek((FILE*)pUserData, offset, (origin == ma_dr_mp3_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0; } MA_API ma_bool32 ma_dr_mp3_init_file(ma_dr_mp3* pMP3, const char* pFilePath, const ma_allocation_callbacks* pAllocationCallbacks) { - return ma_dr_mp3_init_file_with_metadata(pMP3, pFilePath, NULL, NULL, pAllocationCallbacks); + ma_bool32 result; + FILE* pFile; + if (ma_fopen(&pFile, pFilePath, "rb") != MA_SUCCESS) { + return MA_FALSE; + } + result = ma_dr_mp3_init(pMP3, ma_dr_mp3__on_read_stdio, ma_dr_mp3__on_seek_stdio, (void*)pFile, pAllocationCallbacks); + if (result != MA_TRUE) { + fclose(pFile); + return result; + } + return MA_TRUE; } MA_API ma_bool32 ma_dr_mp3_init_file_w(ma_dr_mp3* pMP3, const wchar_t* pFilePath, const ma_allocation_callbacks* pAllocationCallbacks) { - return ma_dr_mp3_init_file_with_metadata_w(pMP3, pFilePath, NULL, NULL, pAllocationCallbacks); + ma_bool32 result; + FILE* pFile; + if (ma_wfopen(&pFile, pFilePath, L"rb", pAllocationCallbacks) != MA_SUCCESS) { + return MA_FALSE; + } + result = ma_dr_mp3_init(pMP3, ma_dr_mp3__on_read_stdio, ma_dr_mp3__on_seek_stdio, (void*)pFile, pAllocationCallbacks); + if (result != MA_TRUE) { + fclose(pFile); + return result; + } + return MA_TRUE; } #endif MA_API void ma_dr_mp3_uninit(ma_dr_mp3* pMP3) @@ -95000,38 +92859,17 @@ static ma_uint64 ma_dr_mp3_read_pcm_frames_raw(ma_dr_mp3* pMP3, ma_uint64 frames MA_DR_MP3_ASSERT(pMP3 != NULL); MA_DR_MP3_ASSERT(pMP3->onRead != NULL); while (framesToRead > 0) { - ma_uint32 framesToConsume; - if (pMP3->currentPCMFrame < pMP3->delayInPCMFrames) { - ma_uint32 framesToSkip = (ma_uint32)MA_DR_MP3_MIN(pMP3->pcmFramesRemainingInMP3Frame, pMP3->delayInPCMFrames - pMP3->currentPCMFrame); - pMP3->currentPCMFrame += framesToSkip; - pMP3->pcmFramesConsumedInMP3Frame += framesToSkip; - pMP3->pcmFramesRemainingInMP3Frame -= framesToSkip; - } - framesToConsume = (ma_uint32)MA_DR_MP3_MIN(pMP3->pcmFramesRemainingInMP3Frame, framesToRead); - if (pMP3->totalPCMFrameCount != MA_UINT64_MAX && pMP3->totalPCMFrameCount > pMP3->paddingInPCMFrames) { - if (pMP3->currentPCMFrame < (pMP3->totalPCMFrameCount - pMP3->paddingInPCMFrames)) { - ma_uint64 framesRemainigToPadding = (pMP3->totalPCMFrameCount - pMP3->paddingInPCMFrames) - pMP3->currentPCMFrame; - if (framesToConsume > framesRemainigToPadding) { - framesToConsume = (ma_uint32)framesRemainigToPadding; - } - } else { - break; - } - } + ma_uint32 framesToConsume = (ma_uint32)MA_DR_MP3_MIN(pMP3->pcmFramesRemainingInMP3Frame, framesToRead); if (pBufferOut != NULL) { - #if defined(MA_DR_MP3_FLOAT_OUTPUT) - { - float* pFramesOutF32 = (float*)MA_DR_MP3_OFFSET_PTR(pBufferOut, sizeof(float) * totalFramesRead * pMP3->channels); - float* pFramesInF32 = (float*)MA_DR_MP3_OFFSET_PTR(&pMP3->pcmFrames[0], sizeof(float) * pMP3->pcmFramesConsumedInMP3Frame * pMP3->mp3FrameChannels); - MA_DR_MP3_COPY_MEMORY(pFramesOutF32, pFramesInF32, sizeof(float) * framesToConsume * pMP3->channels); - } - #else - { - ma_int16* pFramesOutS16 = (ma_int16*)MA_DR_MP3_OFFSET_PTR(pBufferOut, sizeof(ma_int16) * totalFramesRead * pMP3->channels); - ma_int16* pFramesInS16 = (ma_int16*)MA_DR_MP3_OFFSET_PTR(&pMP3->pcmFrames[0], sizeof(ma_int16) * pMP3->pcmFramesConsumedInMP3Frame * pMP3->mp3FrameChannels); - MA_DR_MP3_COPY_MEMORY(pFramesOutS16, pFramesInS16, sizeof(ma_int16) * framesToConsume * pMP3->channels); - } - #endif + #if defined(MA_DR_MP3_FLOAT_OUTPUT) + float* pFramesOutF32 = (float*)MA_DR_MP3_OFFSET_PTR(pBufferOut, sizeof(float) * totalFramesRead * pMP3->channels); + float* pFramesInF32 = (float*)MA_DR_MP3_OFFSET_PTR(&pMP3->pcmFrames[0], sizeof(float) * pMP3->pcmFramesConsumedInMP3Frame * pMP3->mp3FrameChannels); + MA_DR_MP3_COPY_MEMORY(pFramesOutF32, pFramesInF32, sizeof(float) * framesToConsume * pMP3->channels); + #else + ma_int16* pFramesOutS16 = (ma_int16*)MA_DR_MP3_OFFSET_PTR(pBufferOut, sizeof(ma_int16) * totalFramesRead * pMP3->channels); + ma_int16* pFramesInS16 = (ma_int16*)MA_DR_MP3_OFFSET_PTR(&pMP3->pcmFrames[0], sizeof(ma_int16) * pMP3->pcmFramesConsumedInMP3Frame * pMP3->mp3FrameChannels); + MA_DR_MP3_COPY_MEMORY(pFramesOutS16, pFramesInS16, sizeof(ma_int16) * framesToConsume * pMP3->channels); + #endif } pMP3->currentPCMFrame += framesToConsume; pMP3->pcmFramesConsumedInMP3Frame += framesToConsume; @@ -95041,9 +92879,6 @@ static ma_uint64 ma_dr_mp3_read_pcm_frames_raw(ma_dr_mp3* pMP3, ma_uint64 frames if (framesToRead == 0) { break; } - if (pMP3->totalPCMFrameCount != MA_UINT64_MAX && pMP3->totalPCMFrameCount > pMP3->paddingInPCMFrames && pMP3->currentPCMFrame >= (pMP3->totalPCMFrameCount - pMP3->paddingInPCMFrames)) { - break; - } MA_DR_MP3_ASSERT(pMP3->pcmFramesRemainingInMP3Frame == 0); if (ma_dr_mp3_decode_next_frame(pMP3) == 0) { break; @@ -95123,7 +92958,7 @@ static ma_bool32 ma_dr_mp3_seek_to_start_of_stream(ma_dr_mp3* pMP3) { MA_DR_MP3_ASSERT(pMP3 != NULL); MA_DR_MP3_ASSERT(pMP3->onSeek != NULL); - if (!ma_dr_mp3__on_seek_64(pMP3, pMP3->streamStartOffset, MA_DR_MP3_SEEK_SET)) { + if (!ma_dr_mp3__on_seek(pMP3, 0, ma_dr_mp3_seek_origin_start)) { return MA_FALSE; } ma_dr_mp3_reset(pMP3); @@ -95189,7 +93024,7 @@ static ma_bool32 ma_dr_mp3_seek_to_pcm_frame__seek_table(ma_dr_mp3* pMP3, ma_uin seekPoint.mp3FramesToDiscard = 0; seekPoint.pcmFramesToDiscard = 0; } - if (!ma_dr_mp3__on_seek_64(pMP3, seekPoint.seekPosInBytes, MA_DR_MP3_SEEK_SET)) { + if (!ma_dr_mp3__on_seek_64(pMP3, seekPoint.seekPosInBytes, ma_dr_mp3_seek_origin_start)) { return MA_FALSE; } ma_dr_mp3_reset(pMP3); @@ -95200,7 +93035,7 @@ static ma_bool32 ma_dr_mp3_seek_to_pcm_frame__seek_table(ma_dr_mp3* pMP3, ma_uin if (iMP3Frame == seekPoint.mp3FramesToDiscard-1) { pPCMFrames = (ma_dr_mp3d_sample_t*)pMP3->pcmFrames; } - pcmFramesRead = ma_dr_mp3_decode_next_frame_ex(pMP3, pPCMFrames, NULL, NULL); + pcmFramesRead = ma_dr_mp3_decode_next_frame_ex(pMP3, pPCMFrames); if (pcmFramesRead == 0) { return MA_FALSE; } @@ -95242,7 +93077,7 @@ MA_API ma_bool32 ma_dr_mp3_get_mp3_and_pcm_frame_count(ma_dr_mp3* pMP3, ma_uint6 totalMP3FrameCount = 0; for (;;) { ma_uint32 pcmFramesInCurrentMP3Frame; - pcmFramesInCurrentMP3Frame = ma_dr_mp3_decode_next_frame_ex(pMP3, NULL, NULL, NULL); + pcmFramesInCurrentMP3Frame = ma_dr_mp3_decode_next_frame_ex(pMP3, NULL); if (pcmFramesInCurrentMP3Frame == 0) { break; } @@ -95266,26 +93101,10 @@ MA_API ma_bool32 ma_dr_mp3_get_mp3_and_pcm_frame_count(ma_dr_mp3* pMP3, ma_uint6 MA_API ma_uint64 ma_dr_mp3_get_pcm_frame_count(ma_dr_mp3* pMP3) { ma_uint64 totalPCMFrameCount; - if (pMP3 == NULL) { + if (!ma_dr_mp3_get_mp3_and_pcm_frame_count(pMP3, NULL, &totalPCMFrameCount)) { return 0; } - if (pMP3->totalPCMFrameCount != MA_UINT64_MAX) { - totalPCMFrameCount = pMP3->totalPCMFrameCount; - if (totalPCMFrameCount >= pMP3->delayInPCMFrames) { - totalPCMFrameCount -= pMP3->delayInPCMFrames; - } else { - } - if (totalPCMFrameCount >= pMP3->paddingInPCMFrames) { - totalPCMFrameCount -= pMP3->paddingInPCMFrames; - } else { - } - return totalPCMFrameCount; - } else { - if (!ma_dr_mp3_get_mp3_and_pcm_frame_count(pMP3, NULL, &totalPCMFrameCount)) { - return 0; - } - return totalPCMFrameCount; - } + return totalPCMFrameCount; } MA_API ma_uint64 ma_dr_mp3_get_mp3_frame_count(ma_dr_mp3* pMP3) { @@ -95355,7 +93174,7 @@ MA_API ma_bool32 ma_dr_mp3_calculate_seek_points(ma_dr_mp3* pMP3, ma_uint32* pSe MA_DR_MP3_ASSERT(pMP3->streamCursor >= pMP3->dataSize); mp3FrameInfo[iMP3Frame].bytePos = pMP3->streamCursor - pMP3->dataSize; mp3FrameInfo[iMP3Frame].pcmFrameIndex = runningPCMFrameCount; - pcmFramesInCurrentMP3FrameIn = ma_dr_mp3_decode_next_frame_ex(pMP3, NULL, NULL, NULL); + pcmFramesInCurrentMP3FrameIn = ma_dr_mp3_decode_next_frame_ex(pMP3, NULL); if (pcmFramesInCurrentMP3FrameIn == 0) { return MA_FALSE; } @@ -95379,7 +93198,7 @@ MA_API ma_bool32 ma_dr_mp3_calculate_seek_points(ma_dr_mp3* pMP3, ma_uint32* pSe } mp3FrameInfo[MA_DR_MP3_COUNTOF(mp3FrameInfo)-1].bytePos = pMP3->streamCursor - pMP3->dataSize; mp3FrameInfo[MA_DR_MP3_COUNTOF(mp3FrameInfo)-1].pcmFrameIndex = runningPCMFrameCount; - pcmFramesInCurrentMP3FrameIn = ma_dr_mp3_decode_next_frame_ex(pMP3, NULL, NULL, NULL); + pcmFramesInCurrentMP3FrameIn = ma_dr_mp3_decode_next_frame_ex(pMP3, NULL); if (pcmFramesInCurrentMP3FrameIn == 0) { pSeekPoints[iSeekPoint].seekPosInBytes = mp3FrameInfo[0].bytePos; pSeekPoints[iSeekPoint].pcmFrameIndex = nextTargetPCMFrame; @@ -95517,18 +93336,18 @@ static ma_int16* ma_dr_mp3__full_read_and_close_s16(ma_dr_mp3* pMP3, ma_dr_mp3_c } return pFrames; } -MA_API float* ma_dr_mp3_open_and_read_pcm_frames_f32(ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, ma_dr_mp3_tell_proc onTell, void* pUserData, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API float* ma_dr_mp3_open_and_read_pcm_frames_f32(ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, void* pUserData, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount, const ma_allocation_callbacks* pAllocationCallbacks) { ma_dr_mp3 mp3; - if (!ma_dr_mp3_init(&mp3, onRead, onSeek, onTell, NULL, pUserData, pAllocationCallbacks)) { + if (!ma_dr_mp3_init(&mp3, onRead, onSeek, pUserData, pAllocationCallbacks)) { return NULL; } return ma_dr_mp3__full_read_and_close_f32(&mp3, pConfig, pTotalFrameCount); } -MA_API ma_int16* ma_dr_mp3_open_and_read_pcm_frames_s16(ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, ma_dr_mp3_tell_proc onTell, void* pUserData, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_int16* ma_dr_mp3_open_and_read_pcm_frames_s16(ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, void* pUserData, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount, const ma_allocation_callbacks* pAllocationCallbacks) { ma_dr_mp3 mp3; - if (!ma_dr_mp3_init(&mp3, onRead, onSeek, onTell, NULL, pUserData, pAllocationCallbacks)) { + if (!ma_dr_mp3_init(&mp3, onRead, onSeek, pUserData, pAllocationCallbacks)) { return NULL; } return ma_dr_mp3__full_read_and_close_s16(&mp3, pConfig, pTotalFrameCount); From 0e57a572b447e45ac5afcc8bc83795dd4158c5c4 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 29 Sep 2025 18:05:07 +0200 Subject: [PATCH 051/167] REVIEWED: `rlsw` module and related files --- src/external/rlsw.h | 3512 +++++++++++++---------------- src/platforms/rcore_desktop_sdl.c | 2 +- src/platforms/rcore_drm.c | 46 +- src/rlgl.h | 24 +- 4 files changed, 1640 insertions(+), 1944 deletions(-) diff --git a/src/external/rlsw.h b/src/external/rlsw.h index 2177467ec..49050f848 100644 --- a/src/external/rlsw.h +++ b/src/external/rlsw.h @@ -1,26 +1,81 @@ -/** - * MIT License - * - * Copyright (c) 2025 Le Juez Victor - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +/********************************************************************************************** +* +* rlsw v1.0 - An OpenGL 1.1-style software renderer implementation +* +* DESCRIPTION: +* 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. +* +* FEATURES: +* - Rendering to custom internal framebuffer with multiple color modes supported: +* - Color buffer: RGB - 8-bit (3:3:2) | RGB - 16-bit (5:6:5) | RGB - 24-bit (8:8:8) +* - Depth buffer: D - 8-bit (unorm) | D - 16-bit (unorm) | D - 24-bit (unorm) +* - Rendering modes supported: POINT, LINES, TRIANGLE, QUADS +* - Additional features: Polygon modes, Point width, Line width +* - Clipping support for all rendering modes +* - Texture features supported: +* - All uncompressed texture formats supported by raylib +* - Texture Minification/Magnification checks +* - Point and Bilinear filtering +* - Texture Wrap Modes with separate checks for S/T coordinates +* - Vertex Arrays support with direct primitive drawing mode +* - Matrix Stack support (Matrix Push/Pop) +* - Other GL misc features: +* - GL-style getter functions +* - Framebuffer resizing +* - Perspective correction +* - Scissor clipping +* - Depth testing +* - Blend modes +* - Face culling +* +* ADDITIONAL NOTES: +* Check PR for more info: https://github.com/raysan5/raylib/pull/4832 +* +* CONFIGURATION: +* #define RLSW_IMPLEMENTATION +* Generates the implementation of the library into the included file +* If not defined, the library is in header only mode and can be included in other headers +* or source files without problems. But only ONE file should hold the implementation +* +* rlsw capabilities could be customized just defining some internal +* values before library inclusion (default values listed): +* +* #define SW_GL_FRAMEBUFFER_COPY_BGRA true +* #define SW_GL_BINDING_COPY_TEXTURE true +* #define SW_COLOR_BUFFER_BITS 24 +* #define SW_DEPTH_BUFFER_BITS 16 +* #define SW_MAX_PROJECTION_STACK_SIZE 2 +* #define SW_MAX_MODELVIEW_STACK_SIZE 8 +* #define SW_MAX_TEXTURE_STACK_SIZE 2 +* #define SW_MAX_TEXTURES 128 +* +* +* LICENSE: MIT +* +* Copyright (c) 2025-2026 Le Juez Victor (@Bigfoot71), reviewed by Ramon Santamaria (@raysan5) +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +**********************************************************************************************/ #ifndef RLSW_H #define RLSW_H @@ -28,94 +83,102 @@ #include #include -/* === RLSW Definition And Macros === */ +//---------------------------------------------------------------------------------- +// Defines and Macros +//---------------------------------------------------------------------------------- +// Function specifiers definition +#ifndef SWAPI + #define SWAPI // Functions defined as 'extern' by default (implicit specifiers) +#endif #ifndef SW_MALLOC -# define SW_MALLOC(sz) malloc(sz) + #define SW_MALLOC(sz) malloc(sz) #endif #ifndef SW_REALLOC -# define SW_REALLOC(ptr, newSz) realloc(ptr, newSz) + #define SW_REALLOC(ptr, newSz) realloc(ptr, newSz) #endif #ifndef SW_FREE -# define SW_FREE(ptr) free(ptr) + #define SW_FREE(ptr) free(ptr) #endif #ifndef SW_RESTRICT -# ifdef _MSC_VER -# define SW_RESTRICT __restrict -# else -# define SW_RESTRICT restrict -# endif + #ifdef _MSC_VER + #define SW_RESTRICT __restrict + #else + #define SW_RESTRICT restrict + #endif #endif #ifndef SW_GL_FRAMEBUFFER_COPY_BGRA -# define SW_GL_FRAMEBUFFER_COPY_BGRA true + #define SW_GL_FRAMEBUFFER_COPY_BGRA true #endif #ifndef SW_GL_BINDING_COPY_TEXTURE -# define SW_GL_BINDING_COPY_TEXTURE true + #define SW_GL_BINDING_COPY_TEXTURE true #endif #ifndef SW_COLOR_BUFFER_BITS -# define SW_COLOR_BUFFER_BITS 24 + #define SW_COLOR_BUFFER_BITS 24 #endif #ifndef SW_DEPTH_BUFFER_BITS -# define SW_DEPTH_BUFFER_BITS 16 + #define SW_DEPTH_BUFFER_BITS 16 #endif #ifndef SW_MAX_PROJECTION_STACK_SIZE -# define SW_MAX_PROJECTION_STACK_SIZE 2 + #define SW_MAX_PROJECTION_STACK_SIZE 2 #endif #ifndef SW_MAX_MODELVIEW_STACK_SIZE -# define SW_MAX_MODELVIEW_STACK_SIZE 8 + #define SW_MAX_MODELVIEW_STACK_SIZE 8 #endif #ifndef SW_MAX_TEXTURE_STACK_SIZE -# define SW_MAX_TEXTURE_STACK_SIZE 2 + #define SW_MAX_TEXTURE_STACK_SIZE 2 #endif #ifndef SW_MAX_TEXTURES -# define SW_MAX_TEXTURES 128 + #define SW_MAX_TEXTURES 128 #endif -#ifndef SW_MAX_CLIPPED_POLYGON_VERTICES // Under normal circumstances, clipping a polygon can add at most one vertex per clipping plane. // Considering the largest polygon involved is a quadrilateral (4 vertices), -// and that clipping occurs against both the frustum (6 planes) -// and the scissors (4 planes), +// and that clipping occurs against both the frustum (6 planes) and the scissors (4 planes), // the maximum number of vertices after clipping is: // 4 (original vertices) + 6 (frustum planes) + 4 (scissors planes) = 14 -# define SW_MAX_CLIPPED_POLYGON_VERTICES 14 +#ifndef SW_MAX_CLIPPED_POLYGON_VERTICES + #define SW_MAX_CLIPPED_POLYGON_VERTICES 14 #endif #ifndef SW_CLIP_EPSILON -# define SW_CLIP_EPSILON 1e-4f + #define SW_CLIP_EPSILON 1e-4f #endif -/* === OpenGL Compatibility Types === */ - -typedef unsigned int GLenum; -typedef unsigned char GLboolean; -typedef unsigned int GLbitfield; -typedef void GLvoid; -typedef signed char GLbyte; -typedef short GLshort; -typedef int GLint; -typedef unsigned char GLubyte; -typedef unsigned short GLushort; -typedef unsigned int GLuint; -typedef int GLsizei; -typedef float GLfloat; -typedef float GLclampf; -typedef double GLdouble; -typedef double GLclampd; - -/* === OpenGL Definitions === */ +//---------------------------------------------------------------------------------- +// OpenGL Compatibility Types +//---------------------------------------------------------------------------------- +typedef unsigned int GLenum; +typedef unsigned char GLboolean; +typedef unsigned int GLbitfield; +typedef void GLvoid; +typedef signed char GLbyte; +typedef short GLshort; +typedef int GLint; +typedef unsigned char GLubyte; +typedef unsigned short GLushort; +typedef unsigned int GLuint; +typedef int GLsizei; +typedef float GLfloat; +typedef float GLclampf; +typedef double GLdouble; +typedef double GLclampd; +//---------------------------------------------------------------------------------- +// OpenGL Definitions +// NOTE: Not used/supported definitions are commented +//---------------------------------------------------------------------------------- #define GL_FALSE 0 #define GL_TRUE 1 @@ -168,7 +231,7 @@ typedef double GLclampd; #define GL_TEXTURE 0x1702 #define GL_VERTEX_ARRAY 0x8074 -#define GL_NORMAL_ARRAY 0x8075 //< WARNING: Not implemented (defined for RLGL) +#define GL_NORMAL_ARRAY 0x8075 // WARNING: Not implemented (defined for RLGL) #define GL_COLOR_ARRAY 0x8076 //#define GL_INDEX_ARRAY 0x8077 #define GL_TEXTURE_COORD_ARRAY 0x8078 @@ -237,8 +300,7 @@ typedef double GLclampd; #define GL_UNSIGNED_INT 0x1405 #define GL_FLOAT 0x1406 -/* === Not Used Definitions === */ - +// OpenGL Definitions NOT USED #define GL_PERSPECTIVE_CORRECTION_HINT 0x0C50 #define GL_PACK_ALIGNMENT 0x0D05 #define GL_UNPACK_ALIGNMENT 0x0CF5 @@ -256,8 +318,9 @@ typedef double GLclampd; #define GL_GEQUAL 0x0206 #define GL_ALWAYS 0x0207 -/* === OpenGL Binding === */ - +//---------------------------------------------------------------------------------- +// OpenGL Bindings to rlsw +//---------------------------------------------------------------------------------- #define glReadPixels(x, y, w, h, f, t, p) swCopyFramebuffer((x), (y), (w), (h), (f), (t), (p)) #define glEnable(state) swEnable((state)) #define glDisable(state) swDisable((state)) @@ -317,8 +380,7 @@ typedef double GLclampd; #define glTexParameteri(tr, pname, param) swTexParameteri((pname), (param)) #define glBindTexture(tr, id) swBindTexture((id)) -/* === Not Implemented === */ - +// OpenGL functions NOT IMPLEMENTED by rlsw #define glClearDepth(X) ((void)(X)) #define glDepthMask(X) ((void)(X)) #define glColorMask(X,Y,Z,W) ((void)(X),(void)(Y),(void)(Z),(void)(W)) @@ -334,8 +396,9 @@ typedef double GLclampd; #define glNormal3fv(X) ((void)(X)) #define glNormalPointer(X,Y,Z) ((void)(X),(void)(Y),(void)(Z)) -/* === RLSW Enums === */ - +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- typedef enum { SW_SCISSOR_TEST = GL_SCISSOR_TEST, SW_TEXTURE_2D = GL_TEXTURE_2D, @@ -455,102 +518,108 @@ typedef enum { SW_INVALID_OPERATION = GL_INVALID_OPERATION, } SWerrcode; -/* === Public API === */ +//------------------------------------------------------------------------------------ +// Functions Declaration - Public API +//------------------------------------------------------------------------------------ +SWAPI bool swInit(int w, int h); +SWAPI void swClose(void); -bool swInit(int w, int h); -void swClose(void); +SWAPI bool swResizeFramebuffer(int w, int h); +SWAPI void swCopyFramebuffer(int x, int y, int w, int h, SWformat format, SWtype type, void *pixels); +SWAPI void swBlitFramebuffer(int xDst, int yDst, int wDst, int hDst, int xSrc, int ySrc, int wSrc, int hSrc, SWformat format, SWtype type, void *pixels); +SWAPI void *swGetColorBuffer(int *w, int *h); -bool swResizeFramebuffer(int w, int h); -void swCopyFramebuffer(int x, int y, int w, int h, SWformat format, SWtype type, void* pixels); -void swBlitFramebuffer(int xDst, int yDst, int wDst, int hDst, int xSrc, int ySrc, int wSrc, int hSrc, SWformat format, SWtype type, void* pixels); -void* swGetColorBuffer(int* w, int* h); +SWAPI void swEnable(SWstate state); +SWAPI void swDisable(SWstate state); -void swEnable(SWstate state); -void swDisable(SWstate state); +SWAPI void swGetFloatv(SWget name, float *v); +SWAPI const char *swGetString(SWget name); +SWAPI SWerrcode swGetError(void); -void swGetFloatv(SWget name, float* v); -const char* swGetString(SWget name); -SWerrcode swGetError(void); +SWAPI void swViewport(int x, int y, int width, int height); +SWAPI void swScissor(int x, int y, int width, int height); -void swViewport(int x, int y, int width, int height); -void swScissor(int x, int y, int width, int height); +SWAPI void swClearColor(float r, float g, float b, float a); +SWAPI void swClear(uint32_t bitmask); -void swClearColor(float r, float g, float b, float a); -void swClear(uint32_t bitmask); +SWAPI void swBlendFunc(SWfactor sfactor, SWfactor dfactor); +SWAPI void swPolygonMode(SWpoly mode); +SWAPI void swCullFace(SWface face); -void swBlendFunc(SWfactor sfactor, SWfactor dfactor); -void swPolygonMode(SWpoly mode); -void swCullFace(SWface face); +SWAPI void swPointSize(float size); +SWAPI void swLineWidth(float width); -void swPointSize(float size); -void swLineWidth(float width); +SWAPI void swMatrixMode(SWmatrix mode); +SWAPI void swPushMatrix(void); +SWAPI void swPopMatrix(void); +SWAPI void swLoadIdentity(void); +SWAPI void swTranslatef(float x, float y, float z); +SWAPI void swRotatef(float angle, float x, float y, float z); +SWAPI void swScalef(float x, float y, float z); +SWAPI void swMultMatrixf(const float *mat); +SWAPI void swFrustum(double left, double right, double bottom, double top, double znear, double zfar); +SWAPI void swOrtho(double left, double right, double bottom, double top, double znear, double zfar); -void swMatrixMode(SWmatrix mode); -void swPushMatrix(void); -void swPopMatrix(void); -void swLoadIdentity(void); -void swTranslatef(float x, float y, float z); -void swRotatef(float angle, float x, float y, float z); -void swScalef(float x, float y, float z); -void swMultMatrixf(const float* mat); -void swFrustum(double left, double right, double bottom, double top, double znear, double zfar); -void swOrtho(double left, double right, double bottom, double top, double znear, double zfar); +SWAPI void swBegin(SWdraw mode); +SWAPI void swEnd(void); -void swBegin(SWdraw mode); -void swEnd(void); +SWAPI void swVertex2i(int x, int y); +SWAPI void swVertex2f(float x, float y); +SWAPI void swVertex2fv(const float *v); +SWAPI void swVertex3i(int x, int y, int z); +SWAPI void swVertex3f(float x, float y, float z); +SWAPI void swVertex3fv(const float *v); +SWAPI void swVertex4i(int x, int y, int z, int w); +SWAPI void swVertex4f(float x, float y, float z, float w); +SWAPI void swVertex4fv(const float *v); -void swVertex2i(int x, int y); -void swVertex2f(float x, float y); -void swVertex2fv(const float* v); -void swVertex3i(int x, int y, int z); -void swVertex3f(float x, float y, float z); -void swVertex3fv(const float* v); -void swVertex4i(int x, int y, int z, int w); -void swVertex4f(float x, float y, float z, float w); -void swVertex4fv(const float* v); +SWAPI void swColor3ub(uint8_t r, uint8_t g, uint8_t b); +SWAPI void swColor3ubv(const uint8_t *v); +SWAPI void swColor3f(float r, float g, float b); +SWAPI void swColor3fv(const float *v); +SWAPI void swColor4ub(uint8_t r, uint8_t g, uint8_t b, uint8_t a); +SWAPI void swColor4ubv(const uint8_t *v); +SWAPI void swColor4f(float r, float g, float b, float a); +SWAPI void swColor4fv(const float *v); -void swColor3ub(uint8_t r, uint8_t g, uint8_t b); -void swColor3ubv(const uint8_t* v); -void swColor3f(float r, float g, float b); -void swColor3fv(const float* v); -void swColor4ub(uint8_t r, uint8_t g, uint8_t b, uint8_t a); -void swColor4ubv(const uint8_t* v); -void swColor4f(float r, float g, float b, float a); -void swColor4fv(const float* v); +SWAPI void swTexCoord2f(float u, float v); +SWAPI void swTexCoord2fv(const float *v); -void swTexCoord2f(float u, float v); -void swTexCoord2fv(const float* v); +SWAPI void swBindArray(SWarray type, void *buffer); +SWAPI void swDrawArrays(SWdraw mode, int offset, int count); -void swBindArray(SWarray type, void *buffer); -void swDrawArrays(SWdraw mode, int offset, int count); +SWAPI void swGenTextures(int count, uint32_t *textures); +SWAPI void swDeleteTextures(int count, uint32_t *textures); -void swGenTextures(int count, uint32_t* textures); -void swDeleteTextures(int count, uint32_t* textures); - -void swTexImage2D(int width, int height, SWformat format, SWtype type, bool copy, const void* data); -void swTexParameteri(int param, int value); -void swBindTexture(uint32_t id); +SWAPI void swTexImage2D(int width, int height, SWformat format, SWtype type, bool copy, const void *data); +SWAPI void swTexParameteri(int param, int value); +SWAPI void swBindTexture(uint32_t id); #endif // RLSW_H -/* === RLSW Implementation === */ - -#ifdef RLSW_IMPL +/*********************************************************************************** +* +* RLSW IMPLEMENTATION +* +************************************************************************************/ +#define RLSW_IMPLEMENTATION +#if defined(RLSW_IMPLEMENTATION) #include #include -#include +#include // Required for: floorf(), fabsf() -/* === Defines and Macros === */ +//---------------------------------------------------------------------------------- +// Defines and Macros +//---------------------------------------------------------------------------------- +#define SW_PI 3.14159265358979323846f +#define SW_DEG2RAD (SW_PI/180.0f) +#define SW_RAD2DEG (180.0f/SW_PI) -#define SW_PI 3.14159265358979323846f -#define SW_DEG2RAD (SW_PI/180.0f) -#define SW_RAD2DEG (180.0f/SW_PI) +#define SW_COLOR_PIXEL_SIZE (SW_COLOR_BUFFER_BITS/8) +#define SW_DEPTH_PIXEL_SIZE (SW_DEPTH_BUFFER_BITS/8) -#define SW_COLOR_PIXEL_SIZE (SW_COLOR_BUFFER_BITS / 8) -#define SW_DEPTH_PIXEL_SIZE (SW_DEPTH_BUFFER_BITS / 8) - -#define SW_STATE_CHECK(flags) ((RLSW.stateFlags & (flags)) == (flags)) +#define SW_STATE_CHECK(flags) ((RLSW.stateFlags & (flags)) == (flags)) #define SW_STATE_SCISSOR_TEST (1 << 0) #define SW_STATE_TEXTURE_2D (1 << 1) @@ -558,8 +627,11 @@ void swBindTexture(uint32_t id); #define SW_STATE_CULL_FACE (1 << 3) #define SW_STATE_BLEND (1 << 4) -/* === Internal Structs === */ - +//---------------------------------------------------------------------------------- +// Module Types and Structures Definition +//---------------------------------------------------------------------------------- +// Pixel data format type +// NOTE: Enum aligned with raylib PixelFormat typedef enum { SW_PIXELFORMAT_UNKNOWN = 0, SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE, // 8 bit per pixel (no alpha) @@ -578,49 +650,45 @@ typedef enum { } sw_pixelformat_t; typedef void (*sw_factor_f)( - float* SW_RESTRICT factor, - const float* SW_RESTRICT src, - const float* SW_RESTRICT dst + float *SW_RESTRICT factor, + const float *SW_RESTRICT src, + const float *SW_RESTRICT dst ); typedef float sw_matrix_t[4*4]; typedef uint16_t sw_half_t; typedef struct { + float position[4]; // Position coordinates + float texcoord[2]; // Texture coordinates + float color[4]; // Color value (RGBA) - float position[4]; // Position coordinates - float texcoord[2]; // Texture coordinates - float color[4]; // Color - - float homogeneous[4]; // Homogeneous coordinates - float screen[2]; // Screen coordinates - + float homogeneous[4]; // Homogeneous coordinates + float screen[2]; // Screen coordinates } sw_vertex_t; typedef struct { - // Dirty hack for copied data - // TODO: Rework copied image handling - + // TODO: Rework copied image handling union { - const void* cptr; //< NOTE: Is used for all data reads - void* ptr; //< WARNING: Should only be used to allocate and free data + const void *cptr; // NOTE: Is used for all data reads + void *ptr; // WARNING: Should only be used to allocate and free data } pixels; - int width, height; //< Dimensions of the texture - int wMinus1, hMinus1; //< Dimensions minus one - sw_pixelformat_t format; //< Pixel format (internal representation) + int width, height; // Dimensions of the texture + int wMinus1, hMinus1; // Dimensions minus one + sw_pixelformat_t format; // Pixel format (internal representation) - SWfilter minFilter; //< Minification filter - SWfilter magFilter; //< Magnification filter + SWfilter minFilter; // Minification filter + SWfilter magFilter; // Magnification filter - SWwrap sWrap; //< texcoord.x wrap mode - SWwrap tWrap; //< texcoord.y wrap mode + SWwrap sWrap; // texcoord.x wrap mode + SWwrap tWrap; // texcoord.y wrap mode - float tx; //< Texel width - float ty; //< Texel height + float tx; // Texel width + float ty; // Texel height - bool copy; //< Flag indicating whether memory has been allocated + bool copy; // Flag indicating whether memory has been allocated } sw_texture_t; @@ -633,28 +701,27 @@ typedef struct { } sw_framebuffer_t; typedef struct { - - sw_framebuffer_t framebuffer; + sw_framebuffer_t framebuffer; // Main framebuffer float clearColor[4]; // Color used to clear the screen float clearDepth; // Depth value used to clear the screen - int vpCenter[2]; // Represents the center of the viewport - int vpHalfSize[2]; // Represents the half dimensions of the viewport - int vpSize[2]; // Represents the dimensions of the viewport (minus one) - int vpMin[2]; // Represents the minimum renderable point of the viewport (top-left) - int vpMax[2]; // Represents the maximum renderable point of the viewport (bottom-right) + int vpCenter[2]; // Viewport center + int vpHalfSize[2]; // Viewport half dimensions + int vpSize[2]; // Viewport dimensions (minus one) + int vpMin[2]; // Viewport minimum renderable point (top-left) + int vpMax[2]; // Viewport maximum renderable point (bottom-right) - int scMin[2]; // Represents the minimum renderable point of the scissor rect (top-left) - int scMax[2]; // Represents the maximum renderable point of the scissor rect (bottom-right) - float scClipMin[2]; // Represents the minimum renderable point of the scissor rect in clip space - float scClipMax[2]; // Represents the maximum renderable point of the scissor rect in clip space + int scMin[2]; // Scissor rectangle minimum renderable point (top-left) + int scMax[2]; // Scissor rectangle maximum renderable point (bottom-right) + float scClipMin[2]; // Scissor rectangle minimum renderable point in clip space + float scClipMax[2]; // Scissor rectangle maximum renderable point in clip space - uint32_t currentTexture; + uint32_t currentTexture; // Current active texture id struct { - float* positions; - float* texcoords; - uint8_t* colors; + float *positions; + float *texcoords; + uint8_t *colors; } array; struct { @@ -678,7 +745,7 @@ typedef struct { uint32_t stackModelviewCounter; // Counter for matrix stack operations uint32_t stackTextureCounter; // Counter for matrix stack operations SWmatrix currentMatrixMode; // Current matrix mode (e.g., sw_MODELVIEW, sw_PROJECTION) - sw_matrix_t* currentMatrix; // Pointer to the currently used matrix according to the mode + sw_matrix_t *currentMatrix; // Pointer to the currently used matrix according to the mode sw_matrix_t matMVP; // Model view projection matrix, calculated and used internally bool isDirtyMVP; // Indicates if the MVP matrix should be rebuilt @@ -691,22 +758,24 @@ typedef struct { SWface cullFace; // Faces to cull SWerrcode errCode; // Last error code - sw_texture_t* loadedTextures; + sw_texture_t *loadedTextures; int loadedTextureCount; - uint32_t* freeTextureIds; + uint32_t *freeTextureIds; int freeTextureIdCount; uint32_t stateFlags; } sw_context_t; -/* === Global Data === */ - +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- static sw_context_t RLSW = { 0 }; -/* === Helper Functions === */ - +//---------------------------------------------------------------------------------- +// Module Functions Declaration +//---------------------------------------------------------------------------------- static inline void sw_matrix_id(sw_matrix_t dst) { dst[0] = 1, dst[1] = 0, dst[2] = 0, dst[3] = 0; @@ -715,32 +784,32 @@ static inline void sw_matrix_id(sw_matrix_t dst) dst[12] = 0, dst[13] = 0, dst[14] = 0, dst[15] = 1; } -static inline void sw_matrix_mul_rst(float* SW_RESTRICT dst, const float* SW_RESTRICT left, const float* SW_RESTRICT right) +static inline void sw_matrix_mul_rst(float *SW_RESTRICT dst, const float *SW_RESTRICT left, const float *SW_RESTRICT right) { - float l00 = left[0], l01 = left[1], l02 = left[2], l03 = left[3]; + float l00 = left[0], l01 = left[1], l02 = left[2], l03 = left[3]; float l10 = left[4], l11 = left[5], l12 = left[6], l13 = left[7]; float l20 = left[8], l21 = left[9], l22 = left[10], l23 = left[11]; float l30 = left[12], l31 = left[13], l32 = left[14], l33 = left[15]; - dst[0] = l00 * right[0] + l01 * right[4] + l02 * right[8] + l03 * right[12]; - dst[4] = l10 * right[0] + l11 * right[4] + l12 * right[8] + l13 * right[12]; - dst[8] = l20 * right[0] + l21 * right[4] + l22 * right[8] + l23 * right[12]; - dst[12] = l30 * right[0] + l31 * right[4] + l32 * right[8] + l33 * right[12]; + dst[0] = l00*right[0] + l01*right[4] + l02*right[8] + l03*right[12]; + dst[4] = l10*right[0] + l11*right[4] + l12*right[8] + l13*right[12]; + dst[8] = l20*right[0] + l21*right[4] + l22*right[8] + l23*right[12]; + dst[12] = l30*right[0] + l31*right[4] + l32*right[8] + l33*right[12]; - dst[1] = l00 * right[1] + l01 * right[5] + l02 * right[9] + l03 * right[13]; - dst[5] = l10 * right[1] + l11 * right[5] + l12 * right[9] + l13 * right[13]; - dst[9] = l20 * right[1] + l21 * right[5] + l22 * right[9] + l23 * right[13]; - dst[13] = l30 * right[1] + l31 * right[5] + l32 * right[9] + l33 * right[13]; + dst[1] = l00*right[1] + l01*right[5] + l02*right[9] + l03*right[13]; + dst[5] = l10*right[1] + l11*right[5] + l12*right[9] + l13*right[13]; + dst[9] = l20*right[1] + l21*right[5] + l22*right[9] + l23*right[13]; + dst[13] = l30*right[1] + l31*right[5] + l32*right[9] + l33*right[13]; - dst[2] = l00 * right[2] + l01 * right[6] + l02 * right[10] + l03 * right[14]; - dst[6] = l10 * right[2] + l11 * right[6] + l12 * right[10] + l13 * right[14]; - dst[10] = l20 * right[2] + l21 * right[6] + l22 * right[10] + l23 * right[14]; - dst[14] = l30 * right[2] + l31 * right[6] + l32 * right[10] + l33 * right[14]; + dst[2] = l00*right[2] + l01*right[6] + l02*right[10] + l03*right[14]; + dst[6] = l10*right[2] + l11*right[6] + l12*right[10] + l13*right[14]; + dst[10] = l20*right[2] + l21*right[6] + l22*right[10] + l23*right[14]; + dst[14] = l30*right[2] + l31*right[6] + l32*right[10] + l33*right[14]; - dst[3] = l00 * right[3] + l01 * right[7] + l02 * right[11] + l03 * right[15]; - dst[7] = l10 * right[3] + l11 * right[7] + l12 * right[11] + l13 * right[15]; - dst[11] = l20 * right[3] + l21 * right[7] + l22 * right[11] + l23 * right[15]; - dst[15] = l30 * right[3] + l31 * right[7] + l32 * right[11] + l33 * right[15]; + dst[3] = l00*right[3] + l01*right[7] + l02*right[11] + l03*right[15]; + dst[7] = l10*right[3] + l11*right[7] + l12*right[11] + l13*right[15]; + dst[11] = l20*right[3] + l21*right[7] + l22*right[11] + l23*right[15]; + dst[15] = l30*right[3] + l31*right[7] + l32*right[11] + l33*right[15]; } static inline void sw_matrix_mul(sw_matrix_t dst, const sw_matrix_t left, const sw_matrix_t right) @@ -749,9 +818,7 @@ static inline void sw_matrix_mul(sw_matrix_t dst, const sw_matrix_t left, const sw_matrix_mul_rst(result, left, right); - for (int i = 0; i < 16; i++) { - dst[i] = result[i]; - } + for (int i = 0; i < 16; i++) dst[i] = result[i]; } static inline float sw_saturate(float x) @@ -761,15 +828,11 @@ static inline float sw_saturate(float x) // Check if x < 0.0f // If sign bit is set (MSB), x is negative - if ((fb.u & 0x80000000) != 0) { - return 0.0f; - } + if ((fb.u & 0x80000000) != 0) return 0.0f; // Check if x > 1.0f // Works for positive floats: IEEE 754 ordering matches integer ordering - if (fb.u > 0x3F800000) { - return 1.0f; - } + if (fb.u > 0x3F800000) return 1.0f; // x is in [0.0f, 1.0f] return x; @@ -777,7 +840,7 @@ static inline float sw_saturate(float x) static inline float sw_fract(float x) { - return x - floorf(x); + return (x - floorf(x)); } static inline int sw_clampi(int v, int min, int max) @@ -788,68 +851,68 @@ static inline int sw_clampi(int v, int min, int max) } static inline void sw_lerp_vertex_PTCH( - sw_vertex_t* SW_RESTRICT out, - const sw_vertex_t* SW_RESTRICT a, - const sw_vertex_t* SW_RESTRICT b, + sw_vertex_t *SW_RESTRICT out, + const sw_vertex_t *SW_RESTRICT a, + const sw_vertex_t *SW_RESTRICT b, float t) { const float tInv = 1.0f - t; // Position interpolation (4 components) - out->position[0] = a->position[0] * tInv + b->position[0] * t; - out->position[1] = a->position[1] * tInv + b->position[1] * t; - out->position[2] = a->position[2] * tInv + b->position[2] * t; - out->position[3] = a->position[3] * tInv + b->position[3] * t; + out->position[0] = a->position[0]*tInv + b->position[0]*t; + out->position[1] = a->position[1]*tInv + b->position[1]*t; + out->position[2] = a->position[2]*tInv + b->position[2]*t; + out->position[3] = a->position[3]*tInv + b->position[3]*t; // Texture coordinate interpolation (2 components) - out->texcoord[0] = a->texcoord[0] * tInv + b->texcoord[0] * t; - out->texcoord[1] = a->texcoord[1] * tInv + b->texcoord[1] * t; + out->texcoord[0] = a->texcoord[0]*tInv + b->texcoord[0]*t; + out->texcoord[1] = a->texcoord[1]*tInv + b->texcoord[1]*t; // Color interpolation (4 components) - out->color[0] = a->color[0] * tInv + b->color[0] * t; - out->color[1] = a->color[1] * tInv + b->color[1] * t; - out->color[2] = a->color[2] * tInv + b->color[2] * t; - out->color[3] = a->color[3] * tInv + b->color[3] * t; + out->color[0] = a->color[0]*tInv + b->color[0]*t; + out->color[1] = a->color[1]*tInv + b->color[1]*t; + out->color[2] = a->color[2]*tInv + b->color[2]*t; + out->color[3] = a->color[3]*tInv + b->color[3]*t; // Homogeneous coordinate interpolation (4 components) - out->homogeneous[0] = a->homogeneous[0] * tInv + b->homogeneous[0] * t; - out->homogeneous[1] = a->homogeneous[1] * tInv + b->homogeneous[1] * t; - out->homogeneous[2] = a->homogeneous[2] * tInv + b->homogeneous[2] * t; - out->homogeneous[3] = a->homogeneous[3] * tInv + b->homogeneous[3] * t; + out->homogeneous[0] = a->homogeneous[0]*tInv + b->homogeneous[0]*t; + out->homogeneous[1] = a->homogeneous[1]*tInv + b->homogeneous[1]*t; + out->homogeneous[2] = a->homogeneous[2]*tInv + b->homogeneous[2]*t; + out->homogeneous[3] = a->homogeneous[3]*tInv + b->homogeneous[3]*t; } static inline void sw_get_vertex_grad_PTCH( - sw_vertex_t* SW_RESTRICT out, - const sw_vertex_t* SW_RESTRICT a, - const sw_vertex_t* SW_RESTRICT b, + sw_vertex_t *SW_RESTRICT out, + const sw_vertex_t *SW_RESTRICT a, + const sw_vertex_t *SW_RESTRICT b, float scale) { // Calculate gradients for Position - out->position[0] = (b->position[0] - a->position[0]) * scale; - out->position[1] = (b->position[1] - a->position[1]) * scale; - out->position[2] = (b->position[2] - a->position[2]) * scale; - out->position[3] = (b->position[3] - a->position[3]) * scale; + out->position[0] = (b->position[0] - a->position[0])*scale; + out->position[1] = (b->position[1] - a->position[1])*scale; + out->position[2] = (b->position[2] - a->position[2])*scale; + out->position[3] = (b->position[3] - a->position[3])*scale; // Calculate gradients for Texture coordinates - out->texcoord[0] = (b->texcoord[0] - a->texcoord[0]) * scale; - out->texcoord[1] = (b->texcoord[1] - a->texcoord[1]) * scale; + out->texcoord[0] = (b->texcoord[0] - a->texcoord[0])*scale; + out->texcoord[1] = (b->texcoord[1] - a->texcoord[1])*scale; // Calculate gradients for Color - out->color[0] = (b->color[0] - a->color[0]) * scale; - out->color[1] = (b->color[1] - a->color[1]) * scale; - out->color[2] = (b->color[2] - a->color[2]) * scale; - out->color[3] = (b->color[3] - a->color[3]) * scale; + out->color[0] = (b->color[0] - a->color[0])*scale; + out->color[1] = (b->color[1] - a->color[1])*scale; + out->color[2] = (b->color[2] - a->color[2])*scale; + out->color[3] = (b->color[3] - a->color[3])*scale; // Calculate gradients for Homogeneous coordinates - out->homogeneous[0] = (b->homogeneous[0] - a->homogeneous[0]) * scale; - out->homogeneous[1] = (b->homogeneous[1] - a->homogeneous[1]) * scale; - out->homogeneous[2] = (b->homogeneous[2] - a->homogeneous[2]) * scale; - out->homogeneous[3] = (b->homogeneous[3] - a->homogeneous[3]) * scale; + out->homogeneous[0] = (b->homogeneous[0] - a->homogeneous[0])*scale; + out->homogeneous[1] = (b->homogeneous[1] - a->homogeneous[1])*scale; + out->homogeneous[2] = (b->homogeneous[2] - a->homogeneous[2])*scale; + out->homogeneous[3] = (b->homogeneous[3] - a->homogeneous[3])*scale; } static inline void sw_add_vertex_grad_PTCH( - sw_vertex_t* SW_RESTRICT out, - const sw_vertex_t* SW_RESTRICT gradients) + sw_vertex_t *SW_RESTRICT out, + const sw_vertex_t *SW_RESTRICT gradients) { // Add gradients to Position out->position[0] += gradients->position[0]; @@ -874,8 +937,7 @@ static inline void sw_add_vertex_grad_PTCH( out->homogeneous[3] += gradients->homogeneous[3]; } -/* === Half Floating Point === */ - +// Half floating point management functions static inline uint32_t sw_f16_to_f32_ui(uint16_t h) { uint32_t s = (uint32_t)(h & 0x8000) << 16; @@ -885,20 +947,19 @@ static inline uint32_t sw_f16_to_f32_ui(uint16_t h) int32_t r = (em + (112 << 10)) << 13; // denormal: flush to zero - r = (em < (1 << 10)) ? 0 : r; + r = (em < (1 << 10))? 0 : r; // infinity/NaN; note that we preserve NaN payload as a byproduct of unifying inf/nan cases // 112 is an exponent bias fixup; since we already applied it once, applying it twice converts 31 to 255 - r += (em >= (31 << 10)) ? (112 << 23) : 0; + r += (em >= (31 << 10))? (112 << 23) : 0; return s | r; } static inline float sw_f16_to_f32(sw_half_t y) { - union { float f; uint32_t i; } v = { - .i = sw_f16_to_f32_ui(y) - }; + union { float f; uint32_t i; } v = { .i = sw_f16_to_f32_ui(y) }; + return v.f; } @@ -907,17 +968,17 @@ static inline uint16_t sw_f16_from_f32_ui(uint32_t ui) int32_t s = (ui >> 16) & 0x8000; int32_t em = ui & 0x7fffffff; - // bias exponent and round to nearest; 112 is relative exponent bias (127-15) + // Bias exponent and round to nearest; 112 is relative exponent bias (127-15) int32_t h = (em - (112 << 23) + (1 << 12)) >> 13; - // underflow: flush to zero; 113 encodes exponent -14 - h = (em < (113 << 23)) ? 0 : h; + // Underflow: flush to zero; 113 encodes exponent -14 + h = (em < (113 << 23))? 0 : h; - // overflow: infinity; 143 encodes exponent 16 - h = (em >= (143 << 23)) ? 0x7c00 : h; + // Overflow: infinity; 143 encodes exponent 16 + h = (em >= (143 << 23))? 0x7c00 : h; // NaN; note that we convert all types of NaN to qNaN - h = (em > (255 << 23)) ? 0x7e00 : h; + h = (em > (255 << 23))? 0x7e00 : h; return (uint16_t)(s | h); } @@ -929,39 +990,39 @@ static inline sw_half_t sw_f16_from_f32(float i) return sw_f16_from_f32_ui(v.i); } -/* === Framebuffer Part === */ - +// Framebuffer management functions static inline bool sw_framebuffer_load(int w, int h) { - int size = w * h; + int size = w*h; - RLSW.framebuffer.color = SW_MALLOC(SW_COLOR_PIXEL_SIZE * size); + RLSW.framebuffer.color = SW_MALLOC(SW_COLOR_PIXEL_SIZE*size); if (RLSW.framebuffer.color == NULL) return false; - RLSW.framebuffer.depth = SW_MALLOC(SW_DEPTH_PIXEL_SIZE * size); + RLSW.framebuffer.depth = SW_MALLOC(SW_DEPTH_PIXEL_SIZE*size); if (RLSW.framebuffer.depth == NULL) return false; RLSW.framebuffer.width = w; RLSW.framebuffer.height = h; - RLSW.framebuffer.allocSz = w * h; + RLSW.framebuffer.allocSz = size; return true; } static inline bool sw_framebuffer_resize(int w, int h) { - int newSize = w * h; + int newSize = w*h; - if (newSize <= RLSW.framebuffer.allocSz) { + if (newSize <= RLSW.framebuffer.allocSz) + { RLSW.framebuffer.width = w; RLSW.framebuffer.height = h; return true; } - void* newColor = SW_REALLOC(RLSW.framebuffer.color, newSize); + void *newColor = SW_REALLOC(RLSW.framebuffer.color, newSize); if (newColor == NULL) return false; - void* newDepth = SW_REALLOC(RLSW.framebuffer.depth, newSize); + void *newDepth = SW_REALLOC(RLSW.framebuffer.depth, newSize); if (newDepth == NULL) return false; RLSW.framebuffer.color = newColor; @@ -974,199 +1035,201 @@ static inline bool sw_framebuffer_resize(int w, int h) return true; } -static inline void* sw_framebuffer_get_color_addr(const void* ptr, uint32_t offset) +static inline void *sw_framebuffer_get_color_addr(const void *ptr, uint32_t offset) { - return (uint8_t*)ptr + offset * SW_COLOR_PIXEL_SIZE; + return (uint8_t *)ptr + offset*SW_COLOR_PIXEL_SIZE; } -static inline void sw_framebuffer_inc_color_addr(void** ptr) +static inline void sw_framebuffer_inc_color_addr(void **ptr) { - *ptr = (void*)(((uint8_t*)*ptr) + SW_COLOR_PIXEL_SIZE); + *ptr = (void *)(((uint8_t *)*ptr) + SW_COLOR_PIXEL_SIZE); } -static inline void sw_framebuffer_inc_const_color_addr(const void** ptr) +static inline void sw_framebuffer_inc_const_color_addr(const void **ptr) { - *ptr = (const void*)(((const uint8_t*)*ptr) + SW_COLOR_PIXEL_SIZE); + *ptr = (const void *)(((const uint8_t *)*ptr) + SW_COLOR_PIXEL_SIZE); } -static inline void* sw_framebuffer_get_depth_addr(const void* ptr, uint32_t offset) +static inline void *sw_framebuffer_get_depth_addr(const void *ptr, uint32_t offset) { - return (uint8_t*)ptr + offset * SW_DEPTH_PIXEL_SIZE; + return (uint8_t *)ptr + offset*SW_DEPTH_PIXEL_SIZE; } -static inline void sw_framebuffer_inc_depth_addr(void** ptr) +static inline void sw_framebuffer_inc_depth_addr(void* *ptr) { - *ptr = (void*)(((uint8_t*)*ptr) + SW_DEPTH_PIXEL_SIZE); + *ptr = (void*)(((uint8_t *)*ptr) + SW_DEPTH_PIXEL_SIZE); } -#if (SW_COLOR_BUFFER_BITS == 8) // RGB - 332 - -static inline void sw_framebuffer_read_color(float dst[4], const void* src) +#if (SW_COLOR_BUFFER_BITS == 8) // RGB - (3:3:2) +static inline void sw_framebuffer_read_color(float dst[4], const void *src) { - uint8_t pixel = ((uint8_t*)src)[0]; + uint8_t pixel = ((uint8_t *)src)[0]; - dst[0] = ((pixel >> 5) & 0x07) * (1.0f / 7.0f); - dst[1] = ((pixel >> 2) & 0x07) * (1.0f / 7.0f); - dst[2] = (pixel & 0x03) * (1.0f / 3.0f); + dst[0] = ((pixel >> 5) & 0x07)*(1.0f/7.0f); + dst[1] = ((pixel >> 2) & 0x07)*(1.0f/7.0f); + dst[2] = (pixel & 0x03)*(1.0f/3.0f); dst[3] = 1.0f; } -static inline void sw_framebuffer_read_color8(uint8_t dst[4], const void* src) +static inline void sw_framebuffer_read_color8(uint8_t dst[4], const void *src) { - uint8_t pixel = ((const uint8_t*)src)[0]; + uint8_t pixel = ((const uint8_t *)src)[0]; uint8_t r = (pixel >> 5) & 0x07; uint8_t g = (pixel >> 2) & 0x07; uint8_t b = pixel & 0x03; - dst[0] = (r * 255 + 3) / 7; - dst[1] = (g * 255 + 3) / 7; - dst[2] = (b * 255 + 1) / 3; + dst[0] = (r*255 + 3)/7; + dst[1] = (g*255 + 3)/7; + dst[2] = (b*255 + 1)/3; dst[3] = 255; } -static inline void sw_framebuffer_write_color(void* dst, const float color[3]) +static inline void sw_framebuffer_write_color(void *dst, const float color[3]) { - uint8_t r = ((uint8_t)(color[0] * UINT8_MAX) >> 5) & 0x07; - uint8_t g = ((uint8_t)(color[1] * UINT8_MAX) >> 5) & 0x07; - uint8_t b = ((uint8_t)(color[2] * UINT8_MAX) >> 6) & 0x03; + uint8_t r = ((uint8_t)(color[0]*UINT8_MAX) >> 5) & 0x07; + uint8_t g = ((uint8_t)(color[1]*UINT8_MAX) >> 5) & 0x07; + uint8_t b = ((uint8_t)(color[2]*UINT8_MAX) >> 6) & 0x03; - ((uint8_t*)dst)[0] = (r << 5) | (g << 2) | b; + ((uint8_t *)dst)[0] = (r << 5) | (g << 2) | b; } -static inline void sw_framebuffer_fill_color(void* ptr, int size, const float color[3]) +static inline void sw_framebuffer_fill_color(void *ptr, int size, const float color[3]) { - uint8_t r8 = (uint8_t)(color[0] * 7.0f + 0.5f); - uint8_t g8 = (uint8_t)(color[1] * 7.0f + 0.5f); - uint8_t b8 = (uint8_t)(color[2] * 3.0f + 0.5f); + uint8_t r8 = (uint8_t)(color[0]*7.0f + 0.5f); + uint8_t g8 = (uint8_t)(color[1]*7.0f + 0.5f); + uint8_t b8 = (uint8_t)(color[2]*3.0f + 0.5f); uint8_t packedColor = ((r8 & 0x07) << 5) | ((g8 & 0x07) << 2) | (b8 & 0x03); - uint8_t* p = (uint8_t*)ptr; + uint8_t *p = (uint8_t *)ptr; - if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST) { + if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST) + { int wScissor = RLSW.scMax[0] - RLSW.scMin[0] + 1; - for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++) { - uint8_t* curPtr = p + y * RLSW.framebuffer.width + RLSW.scMin[0]; - for (int xCount = 0; xCount < wScissor; xCount++) { - *curPtr++ = packedColor; - } + for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++) + { + uint8_t *curPtr = p + y*RLSW.framebuffer.width + RLSW.scMin[0]; + for (int xCount = 0; xCount < wScissor; xCount++) *curPtr++ = packedColor; } } - else { - for (int i = 0; i < size; i++) { - *p++ = packedColor; - } + else + { + for (int i = 0; i < size; i++) *p++ = packedColor; } } -#elif (SW_COLOR_BUFFER_BITS == 16) // RGB - 565 +#elif (SW_COLOR_BUFFER_BITS == 16) // RGB - (5:6:5) -static inline void sw_framebuffer_read_color(float dst[4], const void* src) +static inline void sw_framebuffer_read_color(float dst[4], const void *src) { - uint16_t pixel = ((uint16_t*)src)[0]; + uint16_t pixel = ((uint16_t *)src)[0]; - dst[0] = ((pixel >> 11) & 0x1F) * (1.0f / 31.0f); - dst[1] = ((pixel >> 5) & 0x3F) * (1.0f / 63.0f); - dst[2] = (pixel & 0x1F) * (1.0f / 31.0f); + dst[0] = ((pixel >> 11) & 0x1F)*(1.0f/31.0f); + dst[1] = ((pixel >> 5) & 0x3F)*(1.0f/63.0f); + dst[2] = (pixel & 0x1F)*(1.0f/31.0f); dst[3] = 1.0f; } -static inline void sw_framebuffer_read_color8(uint8_t dst[4], const void* src) +static inline void sw_framebuffer_read_color8(uint8_t dst[4], const void *src) { - uint16_t pixel = ((const uint16_t*)src)[0]; + uint16_t pixel = ((const uint16_t *)src)[0]; uint8_t r = (pixel >> 11) & 0x1F; uint8_t g = (pixel >> 5) & 0x3F; uint8_t b = pixel & 0x1F; - dst[0] = (r * 255 + 15) / 31; - dst[1] = (g * 255 + 31) / 63; - dst[2] = (b * 255 + 15) / 31; + dst[0] = (r*255 + 15)/31; + dst[1] = (g*255 + 31)/63; + dst[2] = (b*255 + 15)/31; dst[3] = 255; } -static inline void sw_framebuffer_write_color(void* dst, const float color[3]) +static inline void sw_framebuffer_write_color(void *dst, const float color[3]) { - uint8_t r = (uint8_t)(color[0] * 31.0f + 0.5f) & 0x1F; - uint8_t g = (uint8_t)(color[1] * 63.0f + 0.5f) & 0x3F; - uint8_t b = (uint8_t)(color[2] * 31.0f + 0.5f) & 0x1F; + uint8_t r = (uint8_t)(color[0]*31.0f + 0.5f) & 0x1F; + uint8_t g = (uint8_t)(color[1]*63.0f + 0.5f) & 0x3F; + uint8_t b = (uint8_t)(color[2]*31.0f + 0.5f) & 0x1F; - ((uint16_t*)dst)[0] = (r << 11) | (g << 5) | b; + ((uint16_t *)dst)[0] = (r << 11) | (g << 5) | b; } -static inline void sw_framebuffer_fill_color(void* ptr, int size, const float color[3]) +static inline void sw_framebuffer_fill_color(void *ptr, int size, const float color[3]) { - uint16_t r16 = (uint16_t)(color[0] * 31.0f + 0.5f); - uint16_t g_16 = (uint16_t)(color[1] * 63.0f + 0.5f); - uint16_t b_16 = (uint16_t)(color[2] * 31.0f + 0.5f); + uint16_t r16 = (uint16_t)(color[0]*31.0f + 0.5f); + uint16_t g_16 = (uint16_t)(color[1]*63.0f + 0.5f); + uint16_t b_16 = (uint16_t)(color[2]*31.0f + 0.5f); uint16_t packedColor = ((r16 & 0x1F) << 11) | ((g_16 & 0x3F) << 5) | (b_16 & 0x1F); - uint16_t* p = (uint16_t*)ptr; + uint16_t *p = (uint16_t *)ptr; - if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST) { + if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST) + { int wScissor = RLSW.scMax[0] - RLSW.scMin[0] + 1; - for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++) { - uint16_t* curPtr = p + y * RLSW.framebuffer.width + RLSW.scMin[0]; - for (int xCount = 0; xCount < wScissor; xCount++) { - *curPtr++ = packedColor; - } + for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++) + { + uint16_t *curPtr = p + y*RLSW.framebuffer.width + RLSW.scMin[0]; + for (int xCount = 0; xCount < wScissor; xCount++) *curPtr++ = packedColor; } } - else { - for (int i = 0; i < size; i++) { - *p++ = packedColor; - } + else + { + for (int i = 0; i < size; i++) *p++ = packedColor; } } -#elif (SW_COLOR_BUFFER_BITS == 24) // RGB - 888 +#elif (SW_COLOR_BUFFER_BITS == 24) // RGB - (8:8:8) -static inline void sw_framebuffer_read_color(float dst[4], const void* src) +static inline void sw_framebuffer_read_color(float dst[4], const void *src) { - dst[0] = ((uint8_t*)src)[0] * (1.0f / 255.0f); - dst[1] = ((uint8_t*)src)[1] * (1.0f / 255.0f); - dst[2] = ((uint8_t*)src)[2] * (1.0f / 255.0f); + dst[0] = ((uint8_t *)src)[0]*(1.0f/255.0f); + dst[1] = ((uint8_t *)src)[1]*(1.0f/255.0f); + dst[2] = ((uint8_t *)src)[2]*(1.0f/255.0f); dst[3] = 1.0f; } -static inline void sw_framebuffer_read_color8(uint8_t dst[4], const void* src) +static inline void sw_framebuffer_read_color8(uint8_t dst[4], const void *src) { - dst[0] = ((uint8_t*)src)[0]; - dst[1] = ((uint8_t*)src)[1]; - dst[2] = ((uint8_t*)src)[2]; + dst[0] = ((uint8_t *)src)[0]; + dst[1] = ((uint8_t *)src)[1]; + dst[2] = ((uint8_t *)src)[2]; dst[3] = 255; } -static inline void sw_framebuffer_write_color(void* dst, const float color[3]) +static inline void sw_framebuffer_write_color(void *dst, const float color[3]) { - ((uint8_t*)dst)[0] = (uint8_t)(color[0] * UINT8_MAX); - ((uint8_t*)dst)[1] = (uint8_t)(color[1] * UINT8_MAX); - ((uint8_t*)dst)[2] = (uint8_t)(color[2] * UINT8_MAX); + ((uint8_t *)dst)[0] = (uint8_t)(color[0]*UINT8_MAX); + ((uint8_t *)dst)[1] = (uint8_t)(color[1]*UINT8_MAX); + ((uint8_t *)dst)[2] = (uint8_t)(color[2]*UINT8_MAX); } -static inline void sw_framebuffer_fill_color(void* ptr, int size, const float color[3]) +static inline void sw_framebuffer_fill_color(void *ptr, int size, const float color[3]) { - uint8_t r = (uint8_t)(color[0] * 255.0f); - uint8_t g = (uint8_t)(color[1] * 255.0f); - uint8_t b = (uint8_t)(color[2] * 255.0f); + uint8_t r = (uint8_t)(color[0]*255.0f); + uint8_t g = (uint8_t)(color[1]*255.0f); + uint8_t b = (uint8_t)(color[2]*255.0f); - uint8_t* p = (uint8_t*)ptr; + uint8_t *p = (uint8_t *)ptr; - if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST) { + if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST) + { int wScissor = RLSW.scMax[0] - RLSW.scMin[0] + 1; - for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++) { - uint8_t* curPtr = p + 3 * (y * RLSW.framebuffer.width + RLSW.scMin[0]); - for (int xCount = 0; xCount < wScissor; xCount++) { + for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++) + { + uint8_t *curPtr = p + 3*(y*RLSW.framebuffer.width + RLSW.scMin[0]); + for (int xCount = 0; xCount < wScissor; xCount++) + { *curPtr++ = r; *curPtr++ = g; *curPtr++ = b; } } } - else { - for (int i = 0; i < size; i++) { + else + { + for (int i = 0; i < size; i++) + { *p++ = r; *p++ = g; *p++ = b; @@ -1178,112 +1241,115 @@ static inline void sw_framebuffer_fill_color(void* ptr, int size, const float co #if (SW_DEPTH_BUFFER_BITS == 8) -static inline float sw_framebuffer_read_depth(const void* src) +static inline float sw_framebuffer_read_depth(const void *src) { - return (float)((uint8_t*)src)[0] * (1.0f / UINT8_MAX); + return (float)((uint8_t *)src)[0]*(1.0f/UINT8_MAX); } -static inline void sw_framebuffer_write_depth(void* dst, float depth) +static inline void sw_framebuffer_write_depth(void *dst, float depth) { - ((uint8_t*)dst)[0] = (uint8_t)(depth * UINT8_MAX); + ((uint8_t *)dst)[0] = (uint8_t)(depth*UINT8_MAX); } -static inline void sw_framebuffer_fill_depth(void* ptr, int size, float value) +static inline void sw_framebuffer_fill_depth(void *ptr, int size, float value) { - uint8_t d8 = (uint8_t)(value * UINT8_MAX); - uint8_t* p = (uint8_t*)ptr; + uint8_t d8 = (uint8_t)(value*UINT8_MAX); + uint8_t *p = (uint8_t *)ptr; - if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST) { + if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST) + { int wScissor = RLSW.scMax[0] - RLSW.scMin[0] + 1; - for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++) { - uint8_t* curPtr = p + y * RLSW.framebuffer.width + RLSW.scMin[0]; - for (int xCount = 0; xCount < wScissor; xCount++) { - *curPtr++ = d8; - } + for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++) + { + uint8_t *curPtr = p + y*RLSW.framebuffer.width + RLSW.scMin[0]; + for (int xCount = 0; xCount < wScissor; xCount++) *curPtr++ = d8; } } - else { - for (int i = 0; i < size; i++) { - *p++ = d8; - } + else + { + for (int i = 0; i < size; i++) *p++ = d8; } } #elif (SW_DEPTH_BUFFER_BITS == 16) -static inline float sw_framebuffer_read_depth(const void* src) +static inline float sw_framebuffer_read_depth(const void *src) { - return (float)((uint16_t*)src)[0] * (1.0f / UINT16_MAX); + return (float)((uint16_t *)src)[0]*(1.0f/UINT16_MAX); } -static inline void sw_framebuffer_write_depth(void* dst, float depth) +static inline void sw_framebuffer_write_depth(void *dst, float depth) { - ((uint16_t*)dst)[0] = (uint16_t)(depth * UINT16_MAX); + ((uint16_t *)dst)[0] = (uint16_t)(depth*UINT16_MAX); } -static inline void sw_framebuffer_fill_depth(void* ptr, int size, float value) +static inline void sw_framebuffer_fill_depth(void *ptr, int size, float value) { - uint16_t d16 = (uint16_t)(value * UINT16_MAX); - uint16_t* p = (uint16_t*)ptr; + uint16_t d16 = (uint16_t)(value*UINT16_MAX); + uint16_t *p = (uint16_t *)ptr; - if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST) { + if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST) + { int wScissor = RLSW.scMax[0] - RLSW.scMin[0] + 1; - for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++) { - uint16_t* curPtr = p + y * RLSW.framebuffer.width + RLSW.scMin[0]; - for (int xCount = 0; xCount < wScissor; xCount++) { - *curPtr++ = d16; - } + for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++) + { + uint16_t *curPtr = p + y*RLSW.framebuffer.width + RLSW.scMin[0]; + for (int xCount = 0; xCount < wScissor; xCount++) *curPtr++ = d16; } } - else { - for (int i = 0; i < size; i++) { - *p++ = d16; - } + else + { + for (int i = 0; i < size; i++) *p++ = d16; } } #elif (SW_DEPTH_BUFFER_BITS == 24) -static inline float sw_framebuffer_read_depth(const void* src) +static inline float sw_framebuffer_read_depth(const void *src) { - uint32_t depth24 = (((uint8_t*)src)[0] << 16) | - (((uint8_t*)src)[1] << 8) | - ((uint8_t*)src)[2]; + uint32_t depth24 = (((uint8_t *)src)[0] << 16) | + (((uint8_t *)src)[1] << 8) | + ((uint8_t *)src)[2]; - return depth24 / (float)0xFFFFFF; + return depth24/(float)0xFFFFFF; } -static inline void sw_framebuffer_write_depth(void* dst, float depth) +static inline void sw_framebuffer_write_depth(void *dst, float depth) { - uint32_t depth24 = (uint32_t)(depth * 0xFFFFFF); + uint32_t depth24 = (uint32_t)(depth*0xFFFFFF); - ((uint8_t*)dst)[0] = (depth24 >> 16) & 0xFF; - ((uint8_t*)dst)[1] = (depth24 >> 8) & 0xFF; - ((uint8_t*)dst)[2] = depth24 & 0xFF; + ((uint8_t *)dst)[0] = (depth24 >> 16) & 0xFF; + ((uint8_t *)dst)[1] = (depth24 >> 8) & 0xFF; + ((uint8_t *)dst)[2] = depth24 & 0xFF; } -static inline void sw_framebuffer_fill_depth(void* ptr, int size, float value) +static inline void sw_framebuffer_fill_depth(void *ptr, int size, float value) { - uint32_t d32 = (uint32_t)(value * UINT32_MAX); + uint32_t d32 = (uint32_t)(value*UINT32_MAX); uint8_t d_byte0 = (uint8_t)((d32 >> 16) & 0xFF); uint8_t d_byte1 = (uint8_t)((d32 >> 8) & 0xFF); uint8_t d_byte2 = (uint8_t)(d32 & 0xFF); - uint8_t* p = (uint8_t*)ptr; + uint8_t *p = (uint8_t *)ptr; - if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST) { + if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST) + { int wScissor = RLSW.scMax[0] - RLSW.scMin[0] + 1; - for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++) { - uint8_t* curPtr = p + 3 * (y * RLSW.framebuffer.width + RLSW.scMin[0]); - for (int xCount = 0; xCount < wScissor; xCount++) { + for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++) + { + uint8_t *curPtr = p + 3*(y*RLSW.framebuffer.width + RLSW.scMin[0]); + for (int xCount = 0; xCount < wScissor; xCount++) + { *curPtr++ = d_byte0; *curPtr++ = d_byte1; *curPtr++ = d_byte2; } } } - else { - for (int i = 0; i < size; i++) { + else + { + for (int i = 0; i < size; i++) + { *p++ = d_byte0; *p++ = d_byte1; *p++ = d_byte2; @@ -1293,97 +1359,99 @@ static inline void sw_framebuffer_fill_depth(void* ptr, int size, float value) #endif // SW_DEPTH_BUFFER_BITS -static inline void sw_framebuffer_fill(void* colorPtr, void* depthPtr, int size, float color[4], float depth_value) +static inline void sw_framebuffer_fill(void *colorPtr, void *depthPtr, int size, float color[4], float depth_value) { #if (SW_COLOR_BUFFER_BITS == 8) // Calculate and pack 3:3:2 color // Scale color components to the max value for each bit depth and round - uint8_t r8 = (uint8_t)(color[0] * 7.0f + 0.5f); - uint8_t g8 = (uint8_t)(color[1] * 7.0f + 0.5f); - uint8_t b8 = (uint8_t)(color[2] * 3.0f + 0.5f); + uint8_t r8 = (uint8_t)(color[0]*7.0f + 0.5f); + uint8_t g8 = (uint8_t)(color[1]*7.0f + 0.5f); + uint8_t b8 = (uint8_t)(color[2]*3.0f + 0.5f); // Pack the components into a single byte uint8_t packedColor = ((r8 & 0x07) << 5) | ((g8 & 0x07) << 2) | (b8 & 0x03); - uint8_t* cptr = (uint8_t*)colorPtr; + uint8_t *cptr = (uint8_t *)colorPtr; #elif (SW_COLOR_BUFFER_BITS == 16) // Calculate and pack 5:6:5 color // Scale color components to the max value for each bit depth and round - uint16_t r16 = (uint16_t)(color[0] * 31.0f + 0.5f); - uint16_t g16 = (uint16_t)(color[1] * 63.0f + 0.5f); - uint16_t b16 = (uint16_t)(color[2] * 31.0f + 0.5f); + uint16_t r16 = (uint16_t)(color[0]*31.0f + 0.5f); + uint16_t g16 = (uint16_t)(color[1]*63.0f + 0.5f); + uint16_t b16 = (uint16_t)(color[2]*31.0f + 0.5f); // Pack the components into a 16-bit value uint16_t packedColor = ((r16 & 0x1F) << 11) | ((g16 & 0x3F) << 5) | (b16 & 0x1F); - uint16_t* cptr = (uint16_t*)colorPtr; + uint16_t *cptr = (uint16_t *)colorPtr; #elif (SW_COLOR_BUFFER_BITS == 24) // Calculate 8:8:8 color components - uint8_t r24 = (uint8_t)(color[0] * 255.0f); - uint8_t g24 = (uint8_t)(color[1] * 255.0f); - uint8_t b24 = (uint8_t)(color[2] * 255.0f); - uint8_t* cptr = (uint8_t*)colorPtr; + uint8_t r24 = (uint8_t)(color[0]*255.0f); + uint8_t g24 = (uint8_t)(color[1]*255.0f); + uint8_t b24 = (uint8_t)(color[2]*255.0f); + uint8_t *cptr = (uint8_t *)colorPtr; #endif #if (SW_DEPTH_BUFFER_BITS == 8) // Calculate 8-bit depth - uint8_t d8 = (uint8_t)(depth_value * UINT8_MAX); - uint8_t* dptr = (uint8_t*)depthPtr; + uint8_t d8 = (uint8_t)(depth_value*UINT8_MAX); + uint8_t *dptr = (uint8_t *)depthPtr; #elif (SW_DEPTH_BUFFER_BITS == 16) // Calculate 16-bit depth - uint16_t d16 = (uint16_t)(depth_value * UINT16_MAX); - uint16_t* dptr = (uint16_t*)depthPtr; + uint16_t d16 = (uint16_t)(depth_value*UINT16_MAX); + uint16_t *dptr = (uint16_t *)depthPtr; #elif (SW_DEPTH_BUFFER_BITS == 24) // Calculate 24-bit depth and pre-calculate bytes - uint32_t d32 = (uint32_t)(depth_value * UINT32_MAX); + uint32_t d32 = (uint32_t)(depth_value*UINT32_MAX); uint8_t dByte0 = (uint8_t)((d32 >> 16) & 0xFF); uint8_t dByte1 = (uint8_t)((d32 >> 8) & 0xFF); uint8_t dByte2 = (uint8_t)(d32 & 0xFF); - uint8_t* dptr = (uint8_t*)depthPtr; + uint8_t *dptr = (uint8_t *)depthPtr; #endif - if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST) { + if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST) + { int wScissor = RLSW.scMax[0] - RLSW.scMin[0] + 1; - for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++) { - int rowStartIdx = y * RLSW.framebuffer.width + RLSW.scMin[0]; + for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++) + { + int rowStartIdx = y*RLSW.framebuffer.width + RLSW.scMin[0]; // Calculate starting pointers for the current row within the scissor rectangle -# if (SW_COLOR_BUFFER_BITS == 8) - uint8_t* curCPtr = cptr + rowStartIdx; -# elif (SW_COLOR_BUFFER_BITS == 16) - uint16_t* curCPtr = cptr + rowStartIdx; -# elif (SW_COLOR_BUFFER_BITS == 24) - uint8_t* curCPtr = cptr + 3 * rowStartIdx; -# endif + #if (SW_COLOR_BUFFER_BITS == 8) + uint8_t *curCPtr = cptr + rowStartIdx; + #elif (SW_COLOR_BUFFER_BITS == 16) + uint16_t *curCPtr = cptr + rowStartIdx; + #elif (SW_COLOR_BUFFER_BITS == 24) + uint8_t *curCPtr = cptr + 3*rowStartIdx; + #endif -# if (SW_DEPTH_BUFFER_BITS == 8) - uint8_t* curDPtr = dptr + rowStartIdx; -# elif (SW_DEPTH_BUFFER_BITS == 16) - uint16_t* curDPtr = dptr + rowStartIdx; -# elif (SW_DEPTH_BUFFER_BITS == 24) - uint8_t* curDPtr = dptr + 3 * rowStartIdx; -# endif + #if (SW_DEPTH_BUFFER_BITS == 8) + uint8_t *curDPtr = dptr + rowStartIdx; + #elif (SW_DEPTH_BUFFER_BITS == 16) + uint16_t *curDPtr = dptr + rowStartIdx; + #elif (SW_DEPTH_BUFFER_BITS == 24) + uint8_t *curDPtr = dptr + 3*rowStartIdx; + #endif // Fill the current row within the scissor rectangle for (int xCount = 0; xCount < wScissor; xCount++) { // Write color -# if (SW_COLOR_BUFFER_BITS == 8) + #if (SW_COLOR_BUFFER_BITS == 8) *curCPtr++ = packedColor; -# elif (SW_COLOR_BUFFER_BITS == 16) + #elif (SW_COLOR_BUFFER_BITS == 16) *curCPtr++ = packedColor; -# elif (SW_COLOR_BUFFER_BITS == 24) + #elif (SW_COLOR_BUFFER_BITS == 24) *curCPtr++ = r24; *curCPtr++ = g24; *curCPtr++ = b24; -# endif + #endif // Write depth -# if (SW_DEPTH_BUFFER_BITS == 8) + #if (SW_DEPTH_BUFFER_BITS == 8) *curDPtr++ = d8; -# elif (SW_DEPTH_BUFFER_BITS == 16) + #elif (SW_DEPTH_BUFFER_BITS == 16) *curDPtr++ = d16; -# elif (SW_DEPTH_BUFFER_BITS == 24) + #elif (SW_DEPTH_BUFFER_BITS == 24) *curDPtr++ = dByte0; *curDPtr++ = dByte1; *curDPtr++ = dByte2; -# endif + #endif } } return; @@ -1392,33 +1460,33 @@ static inline void sw_framebuffer_fill(void* colorPtr, void* depthPtr, int size, for (int i = 0; i < size; i++) { // Write color -# if (SW_COLOR_BUFFER_BITS == 8) + #if (SW_COLOR_BUFFER_BITS == 8) *cptr++ = packedColor; -# elif (SW_COLOR_BUFFER_BITS == 16) + #elif (SW_COLOR_BUFFER_BITS == 16) *cptr++ = packedColor; -# elif (SW_COLOR_BUFFER_BITS == 24) + #elif (SW_COLOR_BUFFER_BITS == 24) *cptr++ = r24; *cptr++ = g24; *cptr++ = b24; -# endif + #endif // Write depth -# if (SW_DEPTH_BUFFER_BITS == 8) + #if (SW_DEPTH_BUFFER_BITS == 8) *dptr++ = d8; -# elif (SW_DEPTH_BUFFER_BITS == 16) + #elif (SW_DEPTH_BUFFER_BITS == 16) *dptr++ = d16; -# elif (SW_DEPTH_BUFFER_BITS == 24) + #elif (SW_DEPTH_BUFFER_BITS == 24) *dptr++ = dByte0; *dptr++ = dByte1; *dptr++ = dByte2; -# endif + #endif } } #define DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(name, DST_PTR_T) \ -static inline void sw_framebuffer_copy_to_##name(int x, int y, int w, int h, DST_PTR_T* dst) \ +static inline void sw_framebuffer_copy_to_##name(int x, int y, int w, int h, DST_PTR_T *dst) \ { \ - const void* src = RLSW.framebuffer.color; \ + const void *src = RLSW.framebuffer.color; \ \ for (int iy = y; iy < h; iy++) { \ for (int ix = x; ix < w; ix++) { \ @@ -1426,9 +1494,9 @@ static inline void sw_framebuffer_copy_to_##name(int x, int y, int w, int h, DST sw_framebuffer_read_color8(color, src); \ #define DEFINE_FRAMEBUFFER_COPY_F32_BEGIN(name, DST_PTR_T) \ -static inline void sw_framebuffer_copy_to_##name(int x, int y, int w, int h, DST_PTR_T* dst) \ +static inline void sw_framebuffer_copy_to_##name(int x, int y, int w, int h, DST_PTR_T *dst) \ { \ - const void* src = RLSW.framebuffer.color; \ + const void *src = RLSW.framebuffer.color; \ \ for (int iy = y; iy < h; iy++) { \ for (int ix = x; ix < w; ix++) { \ @@ -1444,7 +1512,7 @@ static inline void sw_framebuffer_copy_to_##name(int x, int y, int w, int h, DST DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(GRAYSCALE, uint8_t) { // NTSC grayscale conversion: Y = 0.299R + 0.587G + 0.114B - uint8_t gray = (uint8_t)((color[0] * 299 + color[1] * 587 + color[2] * 114 + 500) / 1000); + uint8_t gray = (uint8_t)((color[0]*299 + color[1]*587 + color[2]*114 + 500)/1000); *dst++ = gray; } DEFINE_FRAMEBUFFER_COPY_END() @@ -1452,7 +1520,7 @@ DEFINE_FRAMEBUFFER_COPY_END() DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(GRAYALPHA, uint8_t) { // Convert RGB to grayscale using NTSC formula - uint8_t gray = (uint8_t)((color[0] * 299 + color[1] * 587 + color[2] * 114 + 500) / 1000); + uint8_t gray = (uint8_t)((color[0]*299 + color[1]*587 + color[2]*114 + 500)/1000); dst[0] = gray; dst[1] = color[3]; // alpha @@ -1464,9 +1532,9 @@ DEFINE_FRAMEBUFFER_COPY_END() DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(R5G6B5, uint16_t) { // Convert 8-bit RGB to 5:6:5 format - uint8_t r5 = (color[0] * 31 + 127) / 255; - uint8_t g6 = (color[1] * 63 + 127) / 255; - uint8_t b5 = (color[2] * 31 + 127) / 255; + uint8_t r5 = (color[0]*31 + 127)/255; + uint8_t g6 = (color[1]*63 + 127)/255; + uint8_t b5 = (color[2]*31 + 127)/255; #if SW_GL_FRAMEBUFFER_COPY_BGRA uint16_t rgb565 = (b5 << 11) | (g6 << 5) | r5; @@ -1496,9 +1564,9 @@ DEFINE_FRAMEBUFFER_COPY_END() DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(R5G5B5A1, uint16_t) { - uint8_t r5 = (color[0] * 31 + 127) / 255; - uint8_t g5 = (color[1] * 31 + 127) / 255; - uint8_t b5 = (color[2] * 31 + 127) / 255; + uint8_t r5 = (color[0]*31 + 127)/255; + uint8_t g5 = (color[1]*31 + 127)/255; + uint8_t b5 = (color[2]*31 + 127)/255; uint8_t a1 = color[3] >= 128 ? 1 : 0; #if SW_GL_FRAMEBUFFER_COPY_BGRA @@ -1513,10 +1581,10 @@ DEFINE_FRAMEBUFFER_COPY_END() DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(R4G4B4A4, uint16_t) { - uint8_t r4 = (color[0] * 15 + 127) / 255; - uint8_t g4 = (color[1] * 15 + 127) / 255; - uint8_t b4 = (color[2] * 15 + 127) / 255; - uint8_t a4 = (color[3] * 15 + 127) / 255; + uint8_t r4 = (color[0]*15 + 127)/255; + uint8_t g4 = (color[1]*15 + 127)/255; + uint8_t b4 = (color[2]*15 + 127)/255; + uint8_t a4 = (color[3]*15 + 127)/255; #if SW_GL_FRAMEBUFFER_COPY_BGRA uint16_t pixel = (b4 << 12) | (g4 << 8) | (r4 << 4) | a4; @@ -1629,22 +1697,22 @@ DEFINE_FRAMEBUFFER_COPY_END() static inline void sw_framebuffer_blit_to_##name( \ int xDst, int yDst, int wDst, int hDst, \ int xSrc, int ySrc, int wSrc, int hSrc, \ - DST_PTR_T* dst) \ + DST_PTR_T *dst) \ { \ - const uint8_t* srcBase = RLSW.framebuffer.color; \ + const uint8_t *srcBase = RLSW.framebuffer.color; \ int fbWidth = RLSW.framebuffer.width; \ \ - uint32_t xScale = ((uint32_t)wSrc << 16) / (uint32_t)wDst; \ - uint32_t yScale = ((uint32_t)hSrc << 16) / (uint32_t)hDst; \ + uint32_t xScale = ((uint32_t)wSrc << 16)/(uint32_t)wDst; \ + uint32_t yScale = ((uint32_t)hSrc << 16)/(uint32_t)hDst; \ \ for (int dy = 0; dy < hDst; dy++) { \ - uint32_t yFix = ((uint32_t)ySrc << 16) + dy * yScale; \ + uint32_t yFix = ((uint32_t)ySrc << 16) + dy*yScale; \ int sy = yFix >> 16; \ \ for (int dx = 0; dx < wDst; dx++) { \ - uint32_t xFix = dx * xScale; \ + uint32_t xFix = dx*xScale; \ int sx = xFix >> 16; \ - const void* srcPtr = sw_framebuffer_get_color_addr(srcBase, sy * fbWidth + sx); \ + const void *srcPtr = sw_framebuffer_get_color_addr(srcBase, sy*fbWidth + sx); \ uint8_t color[4]; \ sw_framebuffer_read_color8(color, srcPtr); \ @@ -1652,22 +1720,22 @@ static inline void sw_framebuffer_blit_to_##name( static inline void sw_framebuffer_blit_to_##name( \ int xDst, int yDst, int wDst, int hDst, \ int xSrc, int ySrc, int wSrc, int hSrc, \ - DST_PTR_T* dst) \ + DST_PTR_T *dst) \ { \ - const uint8_t* srcBase = RLSW.framebuffer.color; \ + const uint8_t *srcBase = RLSW.framebuffer.color; \ int fbWidth = RLSW.framebuffer.width; \ \ - uint32_t xScale = ((uint32_t)wSrc << 16) / (uint32_t)wDst; \ - uint32_t yScale = ((uint32_t)hSrc << 16) / (uint32_t)hDst; \ + uint32_t xScale = ((uint32_t)wSrc << 16)/(uint32_t)wDst; \ + uint32_t yScale = ((uint32_t)hSrc << 16)/(uint32_t)hDst; \ \ for (int dy = 0; dy < hDst; dy++) { \ - uint32_t yFix = ((uint32_t)ySrc << 16) + dy * yScale; \ + uint32_t yFix = ((uint32_t)ySrc << 16) + dy*yScale; \ int sy = yFix >> 16; \ \ for (int dx = 0; dx < wDst; dx++) { \ - uint32_t xFix = dx * xScale; \ + uint32_t xFix = dx*xScale; \ int sx = xFix >> 16; \ - const void* srcPtr = sw_framebuffer_get_color_addr(srcBase, sy * fbWidth + sx); \ + const void *srcPtr = sw_framebuffer_get_color_addr(srcBase, sy*fbWidth + sx); \ float color[4]; \ sw_framebuffer_read_color(color, srcPtr); \ @@ -1678,14 +1746,14 @@ static inline void sw_framebuffer_blit_to_##name( DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(GRAYSCALE, uint8_t) { - uint8_t gray = (uint8_t)((color[0] * 299 + color[1] * 587 + color[2] * 114 + 500) / 1000); + uint8_t gray = (uint8_t)((color[0]*299 + color[1]*587 + color[2]*114 + 500)/1000); *dst++ = gray; } DEFINE_FRAMEBUFFER_BLIT_END() DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(GRAYALPHA, uint8_t) { - uint8_t gray = (uint8_t)((color[0] * 299 + color[1] * 587 + color[2] * 114 + 500) / 1000); + uint8_t gray = (uint8_t)((color[0]*299 + color[1]*587 + color[2]*114 + 500)/1000); dst[0] = gray; dst[1] = color[3]; // alpha @@ -1696,9 +1764,9 @@ DEFINE_FRAMEBUFFER_BLIT_END() DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(R5G6B5, uint16_t) { - uint8_t r5 = (color[0] * 31 + 127) / 255; - uint8_t g6 = (color[1] * 63 + 127) / 255; - uint8_t b5 = (color[2] * 31 + 127) / 255; + uint8_t r5 = (color[0]*31 + 127)/255; + uint8_t g6 = (color[1]*63 + 127)/255; + uint8_t b5 = (color[2]*31 + 127)/255; #if SW_GL_FRAMEBUFFER_COPY_BGRA uint16_t rgb565 = (b5 << 11) | (g6 << 5) | r5; @@ -1728,9 +1796,9 @@ DEFINE_FRAMEBUFFER_BLIT_END() DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(R5G5B5A1, uint16_t) { - uint8_t r5 = (color[0] * 31 + 127) / 255; - uint8_t g5 = (color[1] * 31 + 127) / 255; - uint8_t b5 = (color[2] * 31 + 127) / 255; + uint8_t r5 = (color[0]*31 + 127)/255; + uint8_t g5 = (color[1]*31 + 127)/255; + uint8_t b5 = (color[2]*31 + 127)/255; uint8_t a1 = color[3] >= 128 ? 1 : 0; #if SW_GL_FRAMEBUFFER_COPY_BGRA @@ -1745,10 +1813,10 @@ DEFINE_FRAMEBUFFER_BLIT_END() DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(R4G4B4A4, uint16_t) { - uint8_t r4 = (color[0] * 15 + 127) / 255; - uint8_t g4 = (color[1] * 15 + 127) / 255; - uint8_t b4 = (color[2] * 15 + 127) / 255; - uint8_t a4 = (color[3] * 15 + 127) / 255; + uint8_t r4 = (color[0]*15 + 127)/255; + uint8_t g4 = (color[1]*15 + 127)/255; + uint8_t b4 = (color[2]*15 + 127)/255; + uint8_t a4 = (color[3]*15 + 127)/255; #if SW_GL_FRAMEBUFFER_COPY_BGRA uint16_t pixel = (b4 << 12) | (g4 << 8) | (r4 << 4) | a4; @@ -1857,49 +1925,52 @@ DEFINE_FRAMEBUFFER_BLIT_F32_BEGIN(R16G16B16A16, sw_half_t) } DEFINE_FRAMEBUFFER_BLIT_END() -/* === Pixel Format Part === */ +// Pixel format management functions static inline int sw_get_pixel_format(SWformat format, SWtype type) { int channels = 0; int bitsPerChannel = 8; // Default: 8 bits per channel - + // Determine the number of channels (format) - switch (format) { - case SW_LUMINANCE: channels = 1; break; - case SW_LUMINANCE_ALPHA: channels = 2; break; - case SW_RGB: channels = 3; break; - case SW_RGBA: channels = 4; break; - default: - return SW_PIXELFORMAT_UNKNOWN; + switch (format) + { + case SW_LUMINANCE: channels = 1; break; + case SW_LUMINANCE_ALPHA: channels = 2; break; + case SW_RGB: channels = 3; break; + case SW_RGBA: channels = 4; break; + default: return SW_PIXELFORMAT_UNKNOWN; } // Determine the depth of each channel (type) - switch (type) { - case SW_UNSIGNED_BYTE: bitsPerChannel = 8; break; - case SW_BYTE: bitsPerChannel = 8; break; - case SW_UNSIGNED_SHORT: bitsPerChannel = 16; break; - case SW_SHORT: bitsPerChannel = 16; break; - case SW_UNSIGNED_INT: bitsPerChannel = 32; break; - case SW_INT: bitsPerChannel = 32; break; - case SW_FLOAT: bitsPerChannel = 32; break; - default: - return SW_PIXELFORMAT_UNKNOWN; + switch (type) + { + case SW_UNSIGNED_BYTE: bitsPerChannel = 8; break; + case SW_BYTE: bitsPerChannel = 8; break; + case SW_UNSIGNED_SHORT: bitsPerChannel = 16; break; + case SW_SHORT: bitsPerChannel = 16; break; + case SW_UNSIGNED_INT: bitsPerChannel = 32; break; + case SW_INT: bitsPerChannel = 32; break; + case SW_FLOAT: bitsPerChannel = 32; break; + default: return SW_PIXELFORMAT_UNKNOWN; } // Map the format and type to the correct internal format - if (bitsPerChannel == 8) { + if (bitsPerChannel == 8) + { if (channels == 1) return SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE; if (channels == 2) return SW_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA; if (channels == 3) return SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8; if (channels == 4) return SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; } - else if (bitsPerChannel == 16) { + else if (bitsPerChannel == 16) + { if (channels == 1) return SW_PIXELFORMAT_UNCOMPRESSED_R16; if (channels == 3) return SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16; if (channels == 4) return SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16; } - else if (bitsPerChannel == 32) { + else if (bitsPerChannel == 32) + { if (channels == 1) return SW_PIXELFORMAT_UNCOMPRESSED_R32; if (channels == 3) return SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32; if (channels == 4) return SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32; @@ -1912,29 +1983,30 @@ int sw_get_pixel_bytes(sw_pixelformat_t format) { int bpp = 0; - switch (format) { - case SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: bpp = 1; break; - case SW_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: - case SW_PIXELFORMAT_UNCOMPRESSED_R5G6B5: - case SW_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: - case SW_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: bpp = 2; break; - case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: bpp = 4; break; - case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8: bpp = 3; break; - case SW_PIXELFORMAT_UNCOMPRESSED_R32: bpp = 4; break; - case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32: bpp = 4*3; break; - case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: bpp = 4*4; break; - case SW_PIXELFORMAT_UNCOMPRESSED_R16: bpp = 2; break; - case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16: bpp = 2*3; break; - case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: bpp = 2*4; break; - default: break; + switch (format) + { + case SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: bpp = 1; break; + case SW_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: + case SW_PIXELFORMAT_UNCOMPRESSED_R5G6B5: + case SW_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: + case SW_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: bpp = 2; break; + case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: bpp = 4; break; + case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8: bpp = 3; break; + case SW_PIXELFORMAT_UNCOMPRESSED_R32: bpp = 4; break; + case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32: bpp = 4*3; break; + case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: bpp = 4*4; break; + case SW_PIXELFORMAT_UNCOMPRESSED_R16: bpp = 2; break; + case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16: bpp = 2*3; break; + case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: bpp = 2*4; break; + default: break; } return bpp; } -static inline void sw_get_pixel_grayscale(float* color, const void* pixels, uint32_t offset) +static inline void sw_get_pixel_grayscale(float *color, const void *pixels, uint32_t offset) { - float gray = (float)((uint8_t*)pixels)[offset] * (1.0f / 255); + float gray = (float)((uint8_t *)pixels)[offset]*(1.0f/255); color[0] = gray; color[1] = gray; @@ -1942,9 +2014,9 @@ static inline void sw_get_pixel_grayscale(float* color, const void* pixels, uint color[3] = 1.0f; } -static inline void sw_get_pixel_red_16(float* color, const void* pixels, uint32_t offset) +static inline void sw_get_pixel_red_16(float *color, const void *pixels, uint32_t offset) { - float value = sw_f16_to_f32(((sw_half_t*)pixels)[offset]); + float value = sw_f16_to_f32(((sw_half_t *)pixels)[offset]); color[0] = value; color[1] = value; @@ -1952,9 +2024,9 @@ static inline void sw_get_pixel_red_16(float* color, const void* pixels, uint32_ color[3] = 1.0f; } -static inline void sw_get_pixel_red_32(float* color, const void* pixels, uint32_t offset) +static inline void sw_get_pixel_red_32(float *color, const void *pixels, uint32_t offset) { - float value = ((float*)pixels)[offset]; + float value = ((float *)pixels)[offset]; color[0] = value; color[1] = value; @@ -1962,37 +2034,37 @@ static inline void sw_get_pixel_red_32(float* color, const void* pixels, uint32_ color[3] = 1.0f; } -static inline void sw_get_pixel_grayscale_alpha(float* color, const void* pixels, uint32_t offset) +static inline void sw_get_pixel_grayscale_alpha(float *color, const void *pixels, uint32_t offset) { - const uint8_t* pixelData = (const uint8_t*)pixels + 2 * offset; + const uint8_t *pixelData = (const uint8_t *)pixels + 2*offset; - color[0] = color[1] = color[2] = (float)pixelData[0] * (1.0f / 255); - color[3] = (float)pixelData[1] * (1.0f / 255); + color[0] = color[1] = color[2] = (float)pixelData[0]*(1.0f/255); + color[3] = (float)pixelData[1]*(1.0f/255); } -static inline void sw_get_pixel_rgb_565(float* color, const void* pixels, uint32_t offset) +static inline void sw_get_pixel_rgb_565(float *color, const void *pixels, uint32_t offset) { - uint16_t pixel = ((uint16_t*)pixels)[offset]; + uint16_t pixel = ((uint16_t *)pixels)[offset]; - color[0] = (float)((pixel & 0xF800) >> 11) / 31; - color[1] = (float)((pixel & 0x7E0) >> 5) / 63; - color[2] = (float)(pixel & 0x1F) / 31; + color[0] = (float)((pixel & 0xF800) >> 11)/31; + color[1] = (float)((pixel & 0x7E0) >> 5)/63; + color[2] = (float)(pixel & 0x1F)/31; color[3] = 1.0f; } -static inline void sw_get_pixel_rgb_888(float* color, const void* pixels, uint32_t offset) +static inline void sw_get_pixel_rgb_888(float *color, const void *pixels, uint32_t offset) { - const uint8_t* pixel = (const uint8_t*)pixels + 3 * offset; + const uint8_t *pixel = (const uint8_t *)pixels + 3*offset; - color[0] = (float)pixel[0] * (1.0f / 255); - color[1] = (float)pixel[1] * (1.0f / 255); - color[2] = (float)pixel[2] * (1.0f / 255); + color[0] = (float)pixel[0]*(1.0f/255); + color[1] = (float)pixel[1]*(1.0f/255); + color[2] = (float)pixel[2]*(1.0f/255); color[3] = 1.0f; } -static inline void sw_get_pixel_rgb_161616(float* color, const void* pixels, uint32_t offset) +static inline void sw_get_pixel_rgb_161616(float *color, const void *pixels, uint32_t offset) { - const sw_half_t *pixel = (sw_half_t*)pixels + 3 * offset; + const sw_half_t *pixel = (sw_half_t *)pixels + 3*offset; color[0] = sw_f16_to_f32(pixel[0]); color[1] = sw_f16_to_f32(pixel[1]); @@ -2000,9 +2072,9 @@ static inline void sw_get_pixel_rgb_161616(float* color, const void* pixels, uin color[3] = 1.0f; } -static inline void sw_get_pixel_rgb_323232(float* color, const void* pixels, uint32_t offset) +static inline void sw_get_pixel_rgb_323232(float *color, const void *pixels, uint32_t offset) { - const float *pixel = (float*)pixels + 3 * offset; + const float *pixel = (float *)pixels + 3*offset; color[0] = pixel[0]; color[1] = pixel[1]; @@ -2010,39 +2082,39 @@ static inline void sw_get_pixel_rgb_323232(float* color, const void* pixels, uin color[3] = 1.0f; } -static inline void sw_get_pixel_rgba_5551(float* color, const void* pixels, uint32_t offset) +static inline void sw_get_pixel_rgba_5551(float *color, const void *pixels, uint32_t offset) { - uint16_t pixel = ((uint16_t*)pixels)[offset]; + uint16_t pixel = ((uint16_t *)pixels)[offset]; - color[0] = (float)((pixel & 0xF800) >> 11) / 31; - color[1] = (float)((pixel & 0x7C0) >> 6) / 31; - color[2] = (float)((pixel & 0x3E) >> 1) / 31; + color[0] = (float)((pixel & 0xF800) >> 11)/31; + color[1] = (float)((pixel & 0x7C0) >> 6)/31; + color[2] = (float)((pixel & 0x3E) >> 1)/31; color[3] = (float)(pixel & 0x1); } -static inline void sw_get_pixel_rgba_4444(float* color, const void* pixels, uint32_t offset) +static inline void sw_get_pixel_rgba_4444(float *color, const void *pixels, uint32_t offset) { - uint16_t pixel = ((uint16_t*)pixels)[offset]; + uint16_t pixel = ((uint16_t *)pixels)[offset]; - color[0] = (float)((pixel & 0xF000) >> 12) / 15; - color[1] = (float)((pixel & 0xF00) >> 8) / 15; - color[2] = (float)((pixel & 0xF0) >> 4) / 15; - color[3] = (float)(pixel & 0xF) / 15; + color[0] = (float)((pixel & 0xF000) >> 12)/15; + color[1] = (float)((pixel & 0xF00) >> 8)/15; + color[2] = (float)((pixel & 0xF0) >> 4)/15; + color[3] = (float)(pixel & 0xF)/15; } -static inline void sw_get_pixel_rgba_8888(float* color, const void* pixels, uint32_t offset) +static inline void sw_get_pixel_rgba_8888(float *color, const void *pixels, uint32_t offset) { - const uint8_t *pixel = (uint8_t*)pixels + 4 * offset; + const uint8_t *pixel = (uint8_t *)pixels + 4*offset; - color[0] = (float)pixel[0] * (1.0f / 255); - color[1] = (float)pixel[1] * (1.0f / 255); - color[2] = (float)pixel[2] * (1.0f / 255); - color[3] = (float)pixel[3] * (1.0f / 255); + color[0] = (float)pixel[0]*(1.0f/255); + color[1] = (float)pixel[1]*(1.0f/255); + color[2] = (float)pixel[2]*(1.0f/255); + color[3] = (float)pixel[3]*(1.0f/255); } -static inline void sw_get_pixel_rgba_16161616(float* color, const void* pixels, uint32_t offset) +static inline void sw_get_pixel_rgba_16161616(float *color, const void *pixels, uint32_t offset) { - const sw_half_t *pixel = (sw_half_t*)pixels + 4 * offset; + const sw_half_t *pixel = (sw_half_t *)pixels + 4*offset; color[0] = sw_f16_to_f32(pixel[0]); color[1] = sw_f16_to_f32(pixel[1]); @@ -2050,9 +2122,9 @@ static inline void sw_get_pixel_rgba_16161616(float* color, const void* pixels, color[3] = sw_f16_to_f32(pixel[3]); } -static inline void sw_get_pixel_rgba_32323232(float* color, const void* pixels, uint32_t offset) +static inline void sw_get_pixel_rgba_32323232(float *color, const void *pixels, uint32_t offset) { - const float *pixel = (float*)pixels + 4 * offset; + const float *pixel = (float *)pixels + 4*offset; color[0] = pixel[0]; color[1] = pixel[1]; @@ -2060,72 +2132,47 @@ static inline void sw_get_pixel_rgba_32323232(float* color, const void* pixels, color[3] = pixel[3]; } -static inline void sw_get_pixel(float* color, const void* pixels, uint32_t offset, sw_pixelformat_t format) +static inline void sw_get_pixel(float *color, const void *pixels, uint32_t offset, sw_pixelformat_t format) { - switch (format) { - case SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: - sw_get_pixel_grayscale(color, pixels, offset); - break; - case SW_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: - sw_get_pixel_grayscale_alpha(color, pixels, offset); - break; - case SW_PIXELFORMAT_UNCOMPRESSED_R5G6B5: - sw_get_pixel_rgb_565(color, pixels, offset); - break; - case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8: - sw_get_pixel_rgb_888(color, pixels, offset); - break; - case SW_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: - sw_get_pixel_rgba_5551(color, pixels, offset); - break; - case SW_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: - sw_get_pixel_rgba_4444(color, pixels, offset); - break; - case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: - sw_get_pixel_rgba_8888(color, pixels, offset); - break; - case SW_PIXELFORMAT_UNCOMPRESSED_R32: - sw_get_pixel_red_32(color, pixels, offset); - break; - case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32: - sw_get_pixel_rgb_323232(color, pixels, offset); - break; - case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: - sw_get_pixel_rgba_32323232(color, pixels, offset); - break; - case SW_PIXELFORMAT_UNCOMPRESSED_R16: - sw_get_pixel_red_16(color, pixels, offset); - break; - case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16: - sw_get_pixel_rgb_161616(color, pixels, offset); - break; - case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: - sw_get_pixel_rgba_16161616(color, pixels, offset); - break; - case SW_PIXELFORMAT_UNKNOWN: - break; + switch (format) + { + case SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: sw_get_pixel_grayscale(color, pixels, offset); break; + case SW_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: sw_get_pixel_grayscale_alpha(color, pixels, offset); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R5G6B5: sw_get_pixel_rgb_565(color, pixels, offset); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8: sw_get_pixel_rgb_888(color, pixels, offset); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: sw_get_pixel_rgba_5551(color, pixels, offset); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: sw_get_pixel_rgba_4444(color, pixels, offset); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: sw_get_pixel_rgba_8888(color, pixels, offset); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R32: sw_get_pixel_red_32(color, pixels, offset); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32: sw_get_pixel_rgb_323232(color, pixels, offset); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: sw_get_pixel_rgba_32323232(color, pixels, offset); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R16: sw_get_pixel_red_16(color, pixels, offset); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16: sw_get_pixel_rgb_161616(color, pixels, offset); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: sw_get_pixel_rgba_16161616(color, pixels, offset); break; + case SW_PIXELFORMAT_UNKNOWN: break; + default: break; } } -/* === Texture Sampling Part === */ +// Texture sampling functionality -static inline void sw_texture_sample_nearest(float* color, const sw_texture_t* tex, float u, float v) +static inline void sw_texture_sample_nearest(float *color, const sw_texture_t *tex, float u, float v) { - u = (tex->sWrap == SW_REPEAT) ? sw_fract(u) : sw_saturate(u); - v = (tex->tWrap == SW_REPEAT) ? sw_fract(v) : sw_saturate(v); + u = (tex->sWrap == SW_REPEAT)? sw_fract(u) : sw_saturate(u); + v = (tex->tWrap == SW_REPEAT)? sw_fract(v) : sw_saturate(v); - int x = u * tex->width, y = v * tex->height; + int x = u*tex->width, y = v*tex->height; - sw_get_pixel(color, tex->pixels.cptr, y * tex->width + x, tex->format); + sw_get_pixel(color, tex->pixels.cptr, y*tex->width + x, tex->format); } -static inline void sw_texture_sample_linear(float* color, const sw_texture_t* tex, float u, float v) +static inline void sw_texture_sample_linear(float *color, const sw_texture_t *tex, float u, float v) { - // REVIEW: With a bit more cleverness we could clearly reduce the - // number of operations here, but for now it works fine. + // TODO: REVIEW: With a bit more cleverness we could clearly reduce the + // number of operations here, but for now it works fine. - float xf = u * tex->width - 0.5f; - float yf = v * tex->height - 0.5f; + float xf = u*tex->width - 0.5f; + float yf = v*tex->height - 0.5f; int x0 = (int)floorf(xf); int y0 = (int)floorf(yf); @@ -2136,148 +2183,149 @@ static inline void sw_texture_sample_linear(float* color, const sw_texture_t* te int x1 = x0 + 1; int y1 = y0 + 1; - if (tex->sWrap == SW_CLAMP) { - x0 = x0 > tex->wMinus1 ? tex->wMinus1 : x0; - x1 = x1 > tex->wMinus1 ? tex->wMinus1 : x1; + if (tex->sWrap == SW_CLAMP) + { + x0 = (x0 > tex->wMinus1)? tex->wMinus1 : x0; + x1 = (x1 > tex->wMinus1)? tex->wMinus1 : x1; } - else { - x0 = (x0 % tex->width + tex->width) % tex->width; - x1 = (x1 % tex->width + tex->width) % tex->width; + else + { + x0 = (x0%tex->width + tex->width)%tex->width; + x1 = (x1%tex->width + tex->width)%tex->width; } - if (tex->tWrap == SW_CLAMP) { - y0 = y0 > tex->hMinus1 ? tex->hMinus1 : y0; - y1 = y1 > tex->hMinus1 ? tex->hMinus1 : y1; + if (tex->tWrap == SW_CLAMP) + { + y0 = (y0 > tex->hMinus1)? tex->hMinus1 : y0; + y1 = (y1 > tex->hMinus1)? tex->hMinus1 : y1; } - else { - y0 = (y0 % tex->height + tex->height) % tex->height; - y1 = (y1 % tex->height + tex->height) % tex->height; + else + { + y0 = (y0%tex->height + tex->height)%tex->height; + y1 = (y1%tex->height + tex->height)%tex->height; } float c00[4], c10[4], c01[4], c11[4]; - sw_get_pixel(c00, tex->pixels.cptr, y0 * tex->width + x0, tex->format); - sw_get_pixel(c10, tex->pixels.cptr, y0 * tex->width + x1, tex->format); - sw_get_pixel(c01, tex->pixels.cptr, y1 * tex->width + x0, tex->format); - sw_get_pixel(c11, tex->pixels.cptr, y1 * tex->width + x1, tex->format); + sw_get_pixel(c00, tex->pixels.cptr, y0*tex->width + x0, tex->format); + sw_get_pixel(c10, tex->pixels.cptr, y0*tex->width + x1, tex->format); + sw_get_pixel(c01, tex->pixels.cptr, y1*tex->width + x0, tex->format); + sw_get_pixel(c11, tex->pixels.cptr, y1*tex->width + x1, tex->format); - for (int i = 0; i < 4; i++) { - float t = c00[i] + fx * (c10[i] - c00[i]); - float b = c01[i] + fx * (c11[i] - c01[i]); - color[i] = t + fy * (b - t); + for (int i = 0; i < 4; i++) + { + float t = c00[i] + fx*(c10[i] - c00[i]); + float b = c01[i] + fx*(c11[i] - c01[i]); + color[i] = t + fy*(b - t); } } -static inline void sw_texture_sample(float* color, const sw_texture_t* tex, float u, float v, - float duDx, float duDy, float dvDx, float dvDy) +static inline void sw_texture_sample(float *color, const sw_texture_t *tex, float u, float v, float duDx, float duDy, float dvDx, float dvDy) { // Previous method: There is no need to compute the square root - // because using the squared value, the comparison remains `L2 > 1.0f * 1.0f` - //float du = sqrtf(duDx * duDx + duDy * duDy); - //float dv = sqrtf(dvDx * dvDx + dvDy * dvDy); - //float L = (du > dv) ? du : dv; + // because using the squared value, the comparison remains `L2 > 1.0f*1.0f` + //float du = sqrtf(duDx*duDx + duDy*duDy); + //float dv = sqrtf(dvDx*dvDx + dvDy*dvDy); + //float L = (du > dv)? du : dv; // Calculate the derivatives for each axis - float du2 = duDx * duDx + duDy * duDy; - float dv2 = dvDx * dvDx + dvDy * dvDy; - float L2 = (du2 > dv2) ? du2 : dv2; + float du2 = duDx*duDx + duDy*duDy; + float dv2 = dvDx*dvDx + dvDy*dvDy; + float L2 = (du2 > dv2)? du2 : dv2; - SWfilter filter = (L2 > 1.0f) - ? tex->minFilter : tex->magFilter; + SWfilter filter = (L2 > 1.0f)? tex->minFilter : tex->magFilter; - switch (filter) { - case SW_NEAREST: - sw_texture_sample_nearest(color, tex, u, v); - break; - case SW_LINEAR: - sw_texture_sample_linear(color, tex, u, v); - break; + switch (filter) + { + case SW_NEAREST: sw_texture_sample_nearest(color, tex, u, v); break; + case SW_LINEAR: sw_texture_sample_linear(color, tex, u, v); break; + default: break; } } -/* === Color Blending Functions === */ +// Color Blending functionality -static inline void sw_factor_zero(float* SW_RESTRICT factor, const float* SW_RESTRICT src, const float* SW_RESTRICT dst) +static inline void sw_factor_zero(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst) { factor[0] = factor[1] = factor[2] = factor[3] = 0.0f; } -static inline void sw_factor_one(float* SW_RESTRICT factor, const float* SW_RESTRICT src, const float* SW_RESTRICT dst) +static inline void sw_factor_one(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst) { factor[0] = factor[1] = factor[2] = factor[3] = 1.0f; } -static inline void sw_factor_src_color(float* SW_RESTRICT factor, const float* SW_RESTRICT src, const float* SW_RESTRICT dst) +static inline void sw_factor_src_color(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst) { factor[0] = src[0]; factor[1] = src[1]; factor[2] = src[2]; factor[3] = src[3]; } -static inline void sw_factor_one_minus_src_color(float* SW_RESTRICT factor, const float* SW_RESTRICT src, const float* SW_RESTRICT dst) +static inline void sw_factor_one_minus_src_color(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst) { - factor[0] = 1.0f - src[0]; factor[1] = 1.0f - src[1]; + factor[0] = 1.0f - src[0]; factor[1] = 1.0f - src[1]; factor[2] = 1.0f - src[2]; factor[3] = 1.0f - src[3]; } -static inline void sw_factor_src_alpha(float* SW_RESTRICT factor, const float* SW_RESTRICT src, const float* SW_RESTRICT dst) +static inline void sw_factor_src_alpha(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst) { factor[0] = factor[1] = factor[2] = factor[3] = src[3]; } -static inline void sw_factor_one_minus_src_alpha(float* SW_RESTRICT factor, const float* SW_RESTRICT src, const float* SW_RESTRICT dst) +static inline void sw_factor_one_minus_src_alpha(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst) { - float inv_alpha = 1.0f - src[3]; - factor[0] = factor[1] = factor[2] = factor[3] = inv_alpha; + float invAlpha = 1.0f - src[3]; + factor[0] = factor[1] = factor[2] = factor[3] = invAlpha; } -static inline void sw_factor_dst_alpha(float* SW_RESTRICT factor, const float* SW_RESTRICT src, const float* SW_RESTRICT dst) +static inline void sw_factor_dst_alpha(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst) { factor[0] = factor[1] = factor[2] = factor[3] = dst[3]; } -static inline void sw_factor_one_minus_dst_alpha(float* SW_RESTRICT factor, const float* SW_RESTRICT src, const float* SW_RESTRICT dst) +static inline void sw_factor_one_minus_dst_alpha(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst) { - float inv_alpha = 1.0f - dst[3]; - factor[0] = factor[1] = factor[2] = factor[3] = inv_alpha; + float invAlpha = 1.0f - dst[3]; + factor[0] = factor[1] = factor[2] = factor[3] = invAlpha; } -static inline void sw_factor_dst_color(float* SW_RESTRICT factor, const float* SW_RESTRICT src, const float* SW_RESTRICT dst) +static inline void sw_factor_dst_color(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst) { factor[0] = dst[0]; factor[1] = dst[1]; factor[2] = dst[2]; factor[3] = dst[3]; } -static inline void sw_factor_one_minus_dst_color(float* SW_RESTRICT factor, const float* SW_RESTRICT src, const float* SW_RESTRICT dst) +static inline void sw_factor_one_minus_dst_color(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst) { - factor[0] = 1.0f - dst[0]; factor[1] = 1.0f - dst[1]; + factor[0] = 1.0f - dst[0]; factor[1] = 1.0f - dst[1]; factor[2] = 1.0f - dst[2]; factor[3] = 1.0f - dst[3]; } -static inline void sw_factor_src_alpha_saturate(float* SW_RESTRICT factor, const float* SW_RESTRICT src, const float* SW_RESTRICT dst) +static inline void sw_factor_src_alpha_saturate(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst) { factor[0] = factor[1] = factor[2] = 1.0f; - factor[3] = (src[3] < 1.0f) ? src[3] : 1.0f; + factor[3] = (src[3] < 1.0f)? src[3] : 1.0f; } -static inline void sw_blend_colors(float* SW_RESTRICT dst/*[4]*/, const float* SW_RESTRICT src/*[4]*/) +static inline void sw_blend_colors(float *SW_RESTRICT dst/*[4]*/, const float *SW_RESTRICT src/*[4]*/) { float srcFactor[4], dstFactor[4]; RLSW.srcFactorFunc(srcFactor, src, dst); RLSW.dstFactorFunc(dstFactor, src, dst); - dst[0] = srcFactor[0] * src[0] + dstFactor[0] * dst[0]; - dst[1] = srcFactor[1] * src[1] + dstFactor[1] * dst[1]; - dst[2] = srcFactor[2] * src[2] + dstFactor[2] * dst[2]; - dst[3] = srcFactor[3] * src[3] + dstFactor[3] * dst[3]; + dst[0] = srcFactor[0]*src[0] + dstFactor[0]*dst[0]; + dst[1] = srcFactor[1]*src[1] + dstFactor[1]*dst[1]; + dst[2] = srcFactor[2]*src[2] + dstFactor[2]*dst[2]; + dst[3] = srcFactor[3]*src[3] + dstFactor[3]*dst[3]; } -/* === Projection Helper Functions === */ +// Projection helper functions static inline void sw_project_ndc_to_screen(float screen[2], const float ndc[4]) { - screen[0] = RLSW.vpCenter[0] + ndc[0] * RLSW.vpHalfSize[0]; - screen[1] = RLSW.vpCenter[1] - ndc[1] * RLSW.vpHalfSize[1]; + screen[0] = RLSW.vpCenter[0] + ndc[0]*RLSW.vpHalfSize[0]; + screen[1] = RLSW.vpCenter[1] - ndc[1]*RLSW.vpHalfSize[1]; } -/* === Polygon Clipping Part === */ +// Polygon Clipping management #define DEFINE_CLIP_FUNC(name, FUNC_IS_INSIDE, FUNC_COMPUTE_T) \ static inline int sw_clip_##name( \ @@ -2311,7 +2359,7 @@ static inline int sw_clip_##name( return outputCount; \ } -// Frustum clip functions +// Frustum cliping functions #define IS_INSIDE_PLANE_W(h) ((h)[3] >= SW_CLIP_EPSILON) #define IS_INSIDE_PLANE_X_POS(h) ((h)[0] <= (h)[3]) @@ -2321,13 +2369,13 @@ static inline int sw_clip_##name( #define IS_INSIDE_PLANE_Z_POS(h) ((h)[2] <= (h)[3]) #define IS_INSIDE_PLANE_Z_NEG(h) (-(h)[2] <= (h)[3]) -#define COMPUTE_T_PLANE_W(hPrev, hCurr) ((SW_CLIP_EPSILON - (hPrev)[3]) / ((hCurr)[3] - (hPrev)[3])) -#define COMPUTE_T_PLANE_X_POS(hPrev, hCurr) (((hPrev)[3] - (hPrev)[0]) / (((hPrev)[3] - (hPrev)[0]) - ((hCurr)[3] - (hCurr)[0]))) -#define COMPUTE_T_PLANE_X_NEG(hPrev, hCurr) (((hPrev)[3] + (hPrev)[0]) / (((hPrev)[3] + (hPrev)[0]) - ((hCurr)[3] + (hCurr)[0]))) -#define COMPUTE_T_PLANE_Y_POS(hPrev, hCurr) (((hPrev)[3] - (hPrev)[1]) / (((hPrev)[3] - (hPrev)[1]) - ((hCurr)[3] - (hCurr)[1]))) -#define COMPUTE_T_PLANE_Y_NEG(hPrev, hCurr) (((hPrev)[3] + (hPrev)[1]) / (((hPrev)[3] + (hPrev)[1]) - ((hCurr)[3] + (hCurr)[1]))) -#define COMPUTE_T_PLANE_Z_POS(hPrev, hCurr) (((hPrev)[3] - (hPrev)[2]) / (((hPrev)[3] - (hPrev)[2]) - ((hCurr)[3] - (hCurr)[2]))) -#define COMPUTE_T_PLANE_Z_NEG(hPrev, hCurr) (((hPrev)[3] + (hPrev)[2]) / (((hPrev)[3] + (hPrev)[2]) - ((hCurr)[3] + (hCurr)[2]))) +#define COMPUTE_T_PLANE_W(hPrev, hCurr) ((SW_CLIP_EPSILON - (hPrev)[3])/((hCurr)[3] - (hPrev)[3])) +#define COMPUTE_T_PLANE_X_POS(hPrev, hCurr) (((hPrev)[3] - (hPrev)[0])/(((hPrev)[3] - (hPrev)[0]) - ((hCurr)[3] - (hCurr)[0]))) +#define COMPUTE_T_PLANE_X_NEG(hPrev, hCurr) (((hPrev)[3] + (hPrev)[0])/(((hPrev)[3] + (hPrev)[0]) - ((hCurr)[3] + (hCurr)[0]))) +#define COMPUTE_T_PLANE_Y_POS(hPrev, hCurr) (((hPrev)[3] - (hPrev)[1])/(((hPrev)[3] - (hPrev)[1]) - ((hCurr)[3] - (hCurr)[1]))) +#define COMPUTE_T_PLANE_Y_NEG(hPrev, hCurr) (((hPrev)[3] + (hPrev)[1])/(((hPrev)[3] + (hPrev)[1]) - ((hCurr)[3] + (hCurr)[1]))) +#define COMPUTE_T_PLANE_Z_POS(hPrev, hCurr) (((hPrev)[3] - (hPrev)[2])/(((hPrev)[3] - (hPrev)[2]) - ((hCurr)[3] - (hCurr)[2]))) +#define COMPUTE_T_PLANE_Z_NEG(hPrev, hCurr) (((hPrev)[3] + (hPrev)[2])/(((hPrev)[3] + (hPrev)[2]) - ((hCurr)[3] + (hCurr)[2]))) DEFINE_CLIP_FUNC(w, IS_INSIDE_PLANE_W, COMPUTE_T_PLANE_W) DEFINE_CLIP_FUNC(x_pos, IS_INSIDE_PLANE_X_POS, COMPUTE_T_PLANE_X_POS) @@ -2339,15 +2387,15 @@ DEFINE_CLIP_FUNC(z_neg, IS_INSIDE_PLANE_Z_NEG, COMPUTE_T_PLANE_Z_NEG) // Scissor clip functions -#define COMPUTE_T_SCISSOR_X_MIN(hPrev, hCurr) (((RLSW.scClipMin[0]) * (hPrev)[3] - (hPrev)[0]) / (((hCurr)[0] - (RLSW.scClipMin[0]) * (hCurr)[3]) - ((hPrev)[0] - (RLSW.scClipMin[0]) * (hPrev)[3]))) -#define COMPUTE_T_SCISSOR_X_MAX(hPrev, hCurr) (((RLSW.scClipMax[0]) * (hPrev)[3] - (hPrev)[0]) / (((hCurr)[0] - (RLSW.scClipMax[0]) * (hCurr)[3]) - ((hPrev)[0] - (RLSW.scClipMax[0]) * (hPrev)[3]))) -#define COMPUTE_T_SCISSOR_Y_MIN(hPrev, hCurr) (((RLSW.scClipMin[1]) * (hPrev)[3] - (hPrev)[1]) / (((hCurr)[1] - (RLSW.scClipMin[1]) * (hCurr)[3]) - ((hPrev)[1] - (RLSW.scClipMin[1]) * (hPrev)[3]))) -#define COMPUTE_T_SCISSOR_Y_MAX(hPrev, hCurr) (((RLSW.scClipMax[1]) * (hPrev)[3] - (hPrev)[1]) / (((hCurr)[1] - (RLSW.scClipMax[1]) * (hCurr)[3]) - ((hPrev)[1] - (RLSW.scClipMax[1]) * (hPrev)[3]))) +#define COMPUTE_T_SCISSOR_X_MIN(hPrev, hCurr) (((RLSW.scClipMin[0])*(hPrev)[3] - (hPrev)[0])/(((hCurr)[0] - (RLSW.scClipMin[0])*(hCurr)[3]) - ((hPrev)[0] - (RLSW.scClipMin[0])*(hPrev)[3]))) +#define COMPUTE_T_SCISSOR_X_MAX(hPrev, hCurr) (((RLSW.scClipMax[0])*(hPrev)[3] - (hPrev)[0])/(((hCurr)[0] - (RLSW.scClipMax[0])*(hCurr)[3]) - ((hPrev)[0] - (RLSW.scClipMax[0])*(hPrev)[3]))) +#define COMPUTE_T_SCISSOR_Y_MIN(hPrev, hCurr) (((RLSW.scClipMin[1])*(hPrev)[3] - (hPrev)[1])/(((hCurr)[1] - (RLSW.scClipMin[1])*(hCurr)[3]) - ((hPrev)[1] - (RLSW.scClipMin[1])*(hPrev)[3]))) +#define COMPUTE_T_SCISSOR_Y_MAX(hPrev, hCurr) (((RLSW.scClipMax[1])*(hPrev)[3] - (hPrev)[1])/(((hCurr)[1] - (RLSW.scClipMax[1])*(hCurr)[3]) - ((hPrev)[1] - (RLSW.scClipMax[1])*(hPrev)[3]))) -#define IS_INSIDE_SCISSOR_X_MIN(h) ((h)[0] >= (RLSW.scClipMin[0]) * (h)[3]) -#define IS_INSIDE_SCISSOR_X_MAX(h) ((h)[0] <= (RLSW.scClipMax[0]) * (h)[3]) -#define IS_INSIDE_SCISSOR_Y_MIN(h) ((h)[1] >= (RLSW.scClipMin[1]) * (h)[3]) -#define IS_INSIDE_SCISSOR_Y_MAX(h) ((h)[1] <= (RLSW.scClipMax[1]) * (h)[3]) +#define IS_INSIDE_SCISSOR_X_MIN(h) ((h)[0] >= (RLSW.scClipMin[0])*(h)[3]) +#define IS_INSIDE_SCISSOR_X_MAX(h) ((h)[0] <= (RLSW.scClipMax[0])*(h)[3]) +#define IS_INSIDE_SCISSOR_Y_MIN(h) ((h)[1] >= (RLSW.scClipMin[1])*(h)[3]) +#define IS_INSIDE_SCISSOR_Y_MAX(h) ((h)[1] <= (RLSW.scClipMax[1])*(h)[3]) DEFINE_CLIP_FUNC(scissor_x_min, IS_INSIDE_SCISSOR_X_MIN, COMPUTE_T_SCISSOR_X_MIN) DEFINE_CLIP_FUNC(scissor_x_max, IS_INSIDE_SCISSOR_X_MAX, COMPUTE_T_SCISSOR_X_MAX) @@ -2356,7 +2404,7 @@ DEFINE_CLIP_FUNC(scissor_y_max, IS_INSIDE_SCISSOR_Y_MAX, COMPUTE_T_SCISSOR_Y_MAX // Main clip function -static inline bool sw_polygon_clip(sw_vertex_t polygon[SW_MAX_CLIPPED_POLYGON_VERTICES], int* vertexCounter) +static inline bool sw_polygon_clip(sw_vertex_t polygon[SW_MAX_CLIPPED_POLYGON_VERTICES], int *vertexCounter) { static sw_vertex_t tmp[SW_MAX_CLIPPED_POLYGON_VERTICES]; @@ -2365,13 +2413,12 @@ static inline bool sw_polygon_clip(sw_vertex_t polygon[SW_MAX_CLIPPED_POLYGON_VE #define CLIP_AGAINST_PLANE(FUNC_CLIP) \ { \ n = FUNC_CLIP(tmp, polygon, n); \ - if (n < 3) { \ + if (n < 3) \ + { \ *vertexCounter = 0; \ return false; \ } \ - for (int i = 0; i < n; i++) { \ - polygon[i] = tmp[i]; \ - } \ + for (int i = 0; i < n; i++) polygon[i] = tmp[i]; \ } CLIP_AGAINST_PLANE(sw_clip_w); @@ -2382,7 +2429,8 @@ static inline bool sw_polygon_clip(sw_vertex_t polygon[SW_MAX_CLIPPED_POLYGON_VE CLIP_AGAINST_PLANE(sw_clip_z_pos); CLIP_AGAINST_PLANE(sw_clip_z_neg); - if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST) { + if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST) + { CLIP_AGAINST_PLANE(sw_clip_scissor_x_min); CLIP_AGAINST_PLANE(sw_clip_scissor_x_max); CLIP_AGAINST_PLANE(sw_clip_scissor_y_min); @@ -2394,7 +2442,7 @@ static inline bool sw_polygon_clip(sw_vertex_t polygon[SW_MAX_CLIPPED_POLYGON_VE return (n >= 3); } -/* === Triangle Rendering Part === */ +// Triangle rendering logic static inline bool sw_triangle_face_culling(void) { @@ -2407,9 +2455,9 @@ static inline bool sw_triangle_face_culling(void) // even with negative w values. // Preload homogeneous coordinates into local variables - const float* h0 = RLSW.vertexBuffer[0].homogeneous; - const float* h1 = RLSW.vertexBuffer[1].homogeneous; - const float* h2 = RLSW.vertexBuffer[2].homogeneous; + const float *h0 = RLSW.vertexBuffer[0].homogeneous; + const float *h1 = RLSW.vertexBuffer[1].homogeneous; + const float *h2 = RLSW.vertexBuffer[2].homogeneous; // Compute a value proportional to the signed area in the projected 2D plane, // calculated directly using homogeneous coordinates BEFORE division by w. @@ -2418,14 +2466,14 @@ static inline bool sw_triangle_face_culling(void) // space and its relationship to the projected 2D winding order, even with // negative w values. // The determinant formula used here is: - // h0.x * (h1.y * h2.w - h2.y * h1.w) + - // h1.x * (h2.y * h0.w - h0.y * h2.w) + - // h2.x * (h0.y * h1.w - h1.y * h0.w) + // h0.x*(h1.y*h2.w - h2.y*h1.w) + + // h1.x*(h2.y*h0.w - h0.y*h2.w) + + // h2.x*(h0.y*h1.w - h1.y*h0.w) const float hSgnArea = - h0[0] * (h1[1] * h2[3] - h2[1] * h1[3]) + - h1[0] * (h2[1] * h0[3] - h0[1] * h2[3]) + - h2[0] * (h0[1] * h1[3] - h1[1] * h0[3]); + h0[0]*(h1[1]*h2[3] - h2[1]*h1[3]) + + h1[0]*(h2[1]*h0[3] - h0[1]*h2[3]) + + h2[0]*(h0[1]*h1[3] - h1[1]*h0[3]); // Discard the triangle if its winding order (determined by the sign // of the homogeneous area/determinant) matches the culled direction. @@ -2446,18 +2494,19 @@ static inline bool sw_triangle_face_culling(void) static inline void sw_triangle_clip_and_project(void) { - sw_vertex_t* polygon = RLSW.vertexBuffer; - int* vertexCounter = &RLSW.vertexCounter; - - if (sw_polygon_clip(polygon, vertexCounter)) { + sw_vertex_t *polygon = RLSW.vertexBuffer; + int *vertexCounter = &RLSW.vertexCounter; + if (sw_polygon_clip(polygon, vertexCounter)) + { // Transformation to screen space and normalization - for (int i = 0; i < *vertexCounter; i++) { + for (int i = 0; i < *vertexCounter; i++) + { sw_vertex_t *v = &polygon[i]; // Calculation of the reciprocal of W for normalization // as well as perspective-correct attributes - const float invW = 1.0f / v->homogeneous[3]; + const float invW = 1.0f/v->homogeneous[3]; v->homogeneous[3] = invW; // Division of XYZ coordinates by weight @@ -2474,7 +2523,7 @@ static inline void sw_triangle_clip_and_project(void) v->color[1] *= invW; v->color[2] *= invW; v->color[3] *= invW; - + // Transformation to screen space sw_project_ndc_to_screen(v->screen, v->homogeneous); } @@ -2482,69 +2531,59 @@ static inline void sw_triangle_clip_and_project(void) } #define DEFINE_TRIANGLE_RASTER_SCANLINE(FUNC_NAME, ENABLE_TEXTURE, ENABLE_DEPTH_TEST, ENABLE_COLOR_BLEND) \ -static inline void FUNC_NAME(const sw_texture_t* tex, const sw_vertex_t* start, \ - const sw_vertex_t* end, float duDy, float dvDy) \ +static inline void FUNC_NAME(const sw_texture_t *tex, const sw_vertex_t *start, \ + const sw_vertex_t *end, float duDy, float dvDy) \ { \ /* Convert and center the screen coordinates */ \ - \ int xStart = (int)(start->screen[0] + 0.5f); \ int xEnd = (int)(end->screen[0] + 0.5f); \ int y = (int)start->screen[1]; \ \ /* Compute the inverse horizontal distance along the X axis */ \ - \ float dx = end->screen[0] - start->screen[0]; \ if (fabsf(dx) < 1e-6f) return; \ - float dxRcp = 1.0f / dx; \ + float dxRcp = 1.0f/dx; \ \ /* Compute the interpolation steps along the X axis */ \ + float dzDx = (end->homogeneous[2] - start->homogeneous[2])*dxRcp; \ + float dwDx = (end->homogeneous[3] - start->homogeneous[3])*dxRcp; \ \ - float dzDx = (end->homogeneous[2] - start->homogeneous[2]) * dxRcp; \ - float dwDx = (end->homogeneous[3] - start->homogeneous[3]) * dxRcp; \ + float dcDx[4] = { 0 }; \ + dcDx[0] = (end->color[0] - start->color[0])*dxRcp; \ + dcDx[1] = (end->color[1] - start->color[1])*dxRcp; \ + dcDx[2] = (end->color[2] - start->color[2])*dxRcp; \ + dcDx[3] = (end->color[3] - start->color[3])*dxRcp; \ \ - float dcDx[4]; \ - dcDx[0] = (end->color[0] - start->color[0]) * dxRcp; \ - dcDx[1] = (end->color[1] - start->color[1]) * dxRcp; \ - dcDx[2] = (end->color[2] - start->color[2]) * dxRcp; \ - dcDx[3] = (end->color[3] - start->color[3]) * dxRcp; \ - \ - float duDx, dvDx; \ + float duDx = 0.0f, dvDx = 0.0f; \ if (ENABLE_TEXTURE) { \ - duDx = (end->texcoord[0] - start->texcoord[0]) * dxRcp; \ - dvDx = (end->texcoord[1] - start->texcoord[1]) * dxRcp; \ + duDx = (end->texcoord[0] - start->texcoord[0])*dxRcp; \ + dvDx = (end->texcoord[1] - start->texcoord[1])*dxRcp; \ } \ \ - /* Initializing the interpolation starting values */ \ - \ + /* Initializing the interpolation starting values */ \ float z = start->homogeneous[2]; \ float w = start->homogeneous[3]; \ \ - float color[4]; \ + float color[4] = { 0 }; \ color[0] = start->color[0]; \ color[1] = start->color[1]; \ color[2] = start->color[2]; \ color[3] = start->color[3]; \ \ - float u, v; \ + float u = 0.0f, v = 0.0f; \ if (ENABLE_TEXTURE) { \ u = start->texcoord[0]; \ v = start->texcoord[1]; \ } \ \ /* Pre-calculate the starting pointers for the framebuffer row */ \ - \ - void* cptr = sw_framebuffer_get_color_addr( \ - RLSW.framebuffer.color, y * RLSW.framebuffer.width + xStart); \ - \ - void* dptr = sw_framebuffer_get_depth_addr( \ - RLSW.framebuffer.depth, y * RLSW.framebuffer.width + xStart); \ + void *cptr = sw_framebuffer_get_color_addr(RLSW.framebuffer.color, y*RLSW.framebuffer.width + xStart); \ + void *dptr = sw_framebuffer_get_depth_addr(RLSW.framebuffer.depth, y*RLSW.framebuffer.width + xStart); \ \ /* Scanline rasterization */ \ - \ for (int x = xStart; x < xEnd; x++) \ { \ /* Test and write depth */ \ - \ if (ENABLE_DEPTH_TEST) \ { \ /* TODO: Implement different depth funcs? */ \ @@ -2555,21 +2594,19 @@ static inline void FUNC_NAME(const sw_texture_t* tex, const sw_vertex_t* start, sw_framebuffer_write_depth(dptr, z); \ \ /* Pixel color computation */ \ - \ - float wRcp = 1.0f / w; \ - \ + float wRcp = 1.0f/w; \ float srcColor[4] = { \ - color[0] * wRcp, \ - color[1] * wRcp, \ - color[2] * wRcp, \ - color[3] * wRcp \ + color[0]*wRcp, \ + color[1]*wRcp, \ + color[2]*wRcp, \ + color[3]*wRcp \ }; \ \ if (ENABLE_TEXTURE) \ { \ float texColor[4]; \ - float s = u * wRcp; \ - float t = v * wRcp; \ + float s = u*wRcp; \ + float t = v*wRcp; \ sw_texture_sample(texColor, tex, s, t, duDx, duDy, dvDx, dvDy); \ srcColor[0] *= texColor[0]; \ srcColor[1] *= texColor[1]; \ @@ -2595,16 +2632,15 @@ static inline void FUNC_NAME(const sw_texture_t* tex, const sw_vertex_t* start, } \ \ /* Increment the interpolation parameter, UVs, and pointers */ \ - \ discard: \ - \ z += dzDx; \ w += dwDx; \ color[0] += dcDx[0]; \ color[1] += dcDx[1]; \ color[2] += dcDx[2]; \ color[3] += dcDx[3]; \ - if (ENABLE_TEXTURE) { \ + if (ENABLE_TEXTURE) \ + { \ u += duDx; \ v += dvDx; \ } \ @@ -2615,102 +2651,79 @@ static inline void FUNC_NAME(const sw_texture_t* tex, const sw_vertex_t* start, } #define DEFINE_TRIANGLE_RASTER(FUNC_NAME, FUNC_SCANLINE, ENABLE_TEXTURE) \ -static inline void FUNC_NAME(const sw_vertex_t* v0, const sw_vertex_t* v1, const sw_vertex_t* v2, \ - const sw_texture_t* tex) \ +static inline void FUNC_NAME(const sw_vertex_t *v0, const sw_vertex_t *v1, \ + const sw_vertex_t *v2, const sw_texture_t *tex) \ { \ /* Swap vertices by increasing y */ \ - \ - if (v0->screen[1] > v1->screen[1]) { const sw_vertex_t* tmp = v0; v0 = v1; v1 = tmp; } \ - if (v1->screen[1] > v2->screen[1]) { const sw_vertex_t* tmp = v1; v1 = v2; v2 = tmp; } \ - if (v0->screen[1] > v1->screen[1]) { const sw_vertex_t* tmp = v0; v0 = v1; v1 = tmp; } \ + if (v0->screen[1] > v1->screen[1]) { const sw_vertex_t *tmp = v0; v0 = v1; v1 = tmp; } \ + if (v1->screen[1] > v2->screen[1]) { const sw_vertex_t *tmp = v1; v1 = v2; v2 = tmp; } \ + if (v0->screen[1] > v1->screen[1]) { const sw_vertex_t *tmp = v0; v0 = v1; v1 = tmp; } \ \ /* Extracting coordinates from the sorted vertices */ \ - \ float x0 = v0->screen[0], y0 = v0->screen[1]; \ float x1 = v1->screen[0], y1 = v1->screen[1]; \ float x2 = v2->screen[0], y2 = v2->screen[1]; \ \ /* Compute height differences */ \ - \ float h02 = y2 - y0; \ float h01 = y1 - y0; \ float h12 = y2 - y1; \ \ - if (h02 < 1e-6f) { \ - return; \ - } \ + if (h02 < 1e-6f) return; \ \ /* Precompute the inverse values without additional checks */ \ - \ - float invH02 = 1.0f / h02; \ - float invH01 = (h01 > 1e-6f) ? 1.0f / h01 : 0.0f; \ - float invH12 = (h12 > 1e-6f) ? 1.0f / h12 : 0.0f; \ + float invH02 = 1.0f/h02; \ + float invH01 = (h01 > 1e-6f)? 1.0f/h01 : 0.0f; \ + float invH12 = (h12 > 1e-6f)? 1.0f/h12 : 0.0f; \ \ /* Pre-calculation of slopes */ \ - \ - float dx02 = (x2 - x0) * invH02; \ - float dx01 = (x1 - x0) * invH01; \ - float dx12 = (x2 - x1) * invH12; \ + float dx02 = (x2 - x0)*invH02; \ + float dx01 = (x1 - x0)*invH01; \ + float dx12 = (x2 - x1)*invH12; \ \ /* Y bounds (vertical clipping) */ \ - \ int yTop = (int)(y0 + 0.5f); \ int yMiddle = (int)(y1 + 0.5f); \ int yBottom = (int)(y2 + 0.5f); \ \ /* Compute gradients for each side of the triangle */ \ - \ sw_vertex_t vDy02, vDy01, vDy12; \ sw_get_vertex_grad_PTCH(&vDy02, v0, v2, invH02); \ sw_get_vertex_grad_PTCH(&vDy01, v0, v1, invH01); \ sw_get_vertex_grad_PTCH(&vDy12, v1, v2, invH12); \ \ /* Initializing scanline variables */ \ - \ sw_vertex_t vLeft = *v0; \ vLeft.screen[0] = x0; \ - \ sw_vertex_t vRight = *v0; \ vRight.screen[0] = x0; \ \ /* Scanline for the upper part of the triangle */ \ - \ for (int y = yTop; y < yMiddle; y++) \ { \ vLeft.screen[1] = vRight.screen[1] = y; \ \ - if (vLeft.screen[0] < vRight.screen[0]) { \ - FUNC_SCANLINE(tex, &vLeft, &vRight, vDy02.texcoord[0], vDy02.texcoord[1]); \ - } \ - else { \ - FUNC_SCANLINE(tex, &vRight, &vLeft, vDy02.texcoord[0], vDy02.texcoord[1]); \ - } \ + if (vLeft.screen[0] < vRight.screen[0]) FUNC_SCANLINE(tex, &vLeft, &vRight, vDy02.texcoord[0], vDy02.texcoord[1]); \ + else FUNC_SCANLINE(tex, &vRight, &vLeft, vDy02.texcoord[0], vDy02.texcoord[1]); \ \ sw_add_vertex_grad_PTCH(&vLeft, &vDy02); \ vLeft.screen[0] += dx02; \ - \ sw_add_vertex_grad_PTCH(&vRight, &vDy01); \ vRight.screen[0] += dx01; \ } \ \ /* Scanline for the lower part of the triangle */ \ - \ vRight = *v1, vRight.screen[0] = x1; \ \ for (int y = yMiddle; y < yBottom; y++) \ { \ vLeft.screen[1] = vRight.screen[1] = y; \ \ - if (vLeft.screen[0] < vRight.screen[0]) { \ - FUNC_SCANLINE(tex, &vLeft, &vRight, vDy02.texcoord[0], vDy02.texcoord[1]); \ - } \ - else { \ - FUNC_SCANLINE(tex, &vRight, &vLeft, vDy02.texcoord[0], vDy02.texcoord[1]); \ - } \ + if (vLeft.screen[0] < vRight.screen[0]) FUNC_SCANLINE(tex, &vLeft, &vRight, vDy02.texcoord[0], vDy02.texcoord[1]); \ + else FUNC_SCANLINE(tex, &vRight, &vLeft, vDy02.texcoord[0], vDy02.texcoord[1]); \ \ sw_add_vertex_grad_PTCH(&vLeft, &vDy02); \ vLeft.screen[0] += dx02; \ - \ sw_add_vertex_grad_PTCH(&vRight, &vDy12); \ vRight.screen[0] += dx12; \ } \ @@ -2736,21 +2749,19 @@ DEFINE_TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH_BLEND, sw_triangle_raster_sc static inline void sw_triangle_render(void) { - if (RLSW.stateFlags & SW_STATE_CULL_FACE) { - if (!sw_triangle_face_culling()) { - return; - } + if (RLSW.stateFlags & SW_STATE_CULL_FACE) + { + if (!sw_triangle_face_culling()) return; } sw_triangle_clip_and_project(); - if (RLSW.vertexCounter < 3) { - return; - } + if (RLSW.vertexCounter < 3) return; -# define TRIANGLE_RASTER(RASTER_FUNC) \ + #define TRIANGLE_RASTER(RASTER_FUNC) \ { \ - for (int i = 0; i < RLSW.vertexCounter - 2; i++) { \ + for (int i = 0; i < RLSW.vertexCounter - 2; i++) \ + { \ RASTER_FUNC( \ &RLSW.vertexBuffer[0], \ &RLSW.vertexBuffer[i + 1], \ @@ -2760,35 +2771,19 @@ static inline void sw_triangle_render(void) } \ } - if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) { - TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH_BLEND) - } - else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) { - TRIANGLE_RASTER(sw_triangle_raster_DEPTH_BLEND) - } - else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_BLEND)) { - TRIANGLE_RASTER(sw_triangle_raster_TEX_BLEND) - } - else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST)) { - TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH) - } - else if (SW_STATE_CHECK(SW_STATE_BLEND)) { - TRIANGLE_RASTER(sw_triangle_raster_BLEND) - } - else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST)) { - TRIANGLE_RASTER(sw_triangle_raster_DEPTH) - } - else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D)) { - TRIANGLE_RASTER(sw_triangle_raster_TEX) - } - else { - TRIANGLE_RASTER(sw_triangle_raster) - } + if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH_BLEND) + else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_DEPTH_BLEND) + else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_TEX_BLEND) + else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST)) TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH) + else if (SW_STATE_CHECK(SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_BLEND) + else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST)) TRIANGLE_RASTER(sw_triangle_raster_DEPTH) + else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D)) TRIANGLE_RASTER(sw_triangle_raster_TEX) + else TRIANGLE_RASTER(sw_triangle_raster) -# undef TRIANGLE_RASTER + #undef TRIANGLE_RASTER } -/* === Quad Rendering Part === */ +// Quad rendering logic static inline bool sw_quad_face_culling(void) { @@ -2802,12 +2797,12 @@ static inline bool sw_quad_face_culling(void) // winding test on this first triangle. // Preload homogeneous coordinates into local variables - const float* h0 = RLSW.vertexBuffer[0].homogeneous; - const float* h1 = RLSW.vertexBuffer[1].homogeneous; - const float* h2 = RLSW.vertexBuffer[2].homogeneous; + const float *h0 = RLSW.vertexBuffer[0].homogeneous; + const float *h1 = RLSW.vertexBuffer[1].homogeneous; + const float *h2 = RLSW.vertexBuffer[2].homogeneous; // NOTE: h3 is not needed for this test - // const float* h3 = RLSW.vertexBuffer[3].homogeneous; + // const float *h3 = RLSW.vertexBuffer[3].homogeneous; // Compute a value proportional to the signed area of the triangle P0 P1 P2 // in the projected 2D plane, calculated directly using homogeneous coordinates @@ -2817,14 +2812,14 @@ static inline bool sw_quad_face_culling(void) // in homogeneous space and its relationship to the projected 2D winding order, // even with negative w values. // The determinant formula used here is: - // h0.x * (h1.y * h2.w - h2.y * h1.w) + - // h1.x * (h2.y * h0.w - h0.y * h2.w) + - // h2.x * (h0.y * h1.w - h1.y * h0.w) + // h0.x*(h1.y*h2.w - h2.y*h1.w) + + // h1.x*(h2.y*h0.w - h0.y*h2.w) + + // h2.x*(h0.y*h1.w - h1.y*h0.w) const float hSgnArea = - h0[0] * (h1[1] * h2[3] - h2[1] * h1[3]) + - h1[0] * (h2[1] * h0[3] - h0[1] * h2[3]) + - h2[0] * (h0[1] * h1[3] - h1[1] * h0[3]); + h0[0]*(h1[1]*h2[3] - h2[1]*h1[3]) + + h1[0]*(h2[1]*h0[3] - h0[1]*h2[3]) + + h2[0]*(h0[1]*h1[3] - h1[1]*h0[3]); // Perform face culling based on the winding order determined by the sign // of the homogeneous area/determinant of triangle P0 P1 P2. @@ -2846,18 +2841,19 @@ static inline bool sw_quad_face_culling(void) static inline void sw_quad_clip_and_project(void) { - sw_vertex_t* polygon = RLSW.vertexBuffer; - int* vertexCounter = &RLSW.vertexCounter; - - if (sw_polygon_clip(polygon, vertexCounter)) { + sw_vertex_t *polygon = RLSW.vertexBuffer; + int *vertexCounter = &RLSW.vertexCounter; + if (sw_polygon_clip(polygon, vertexCounter)) + { // Transformation to screen space and normalization - for (int i = 0; i < *vertexCounter; i++) { + for (int i = 0; i < *vertexCounter; i++) + { sw_vertex_t *v = &polygon[i]; // Calculation of the reciprocal of W for normalization // as well as perspective-correct attributes - const float invW = 1.0f / v->homogeneous[3]; + const float invW = 1.0f/v->homogeneous[3]; v->homogeneous[3] = invW; // Division of XYZ coordinates by weight @@ -2874,7 +2870,7 @@ static inline void sw_quad_clip_and_project(void) v->color[1] *= invW; v->color[2] *= invW; v->color[3] *= invW; - + // Transformation to screen space sw_project_ndc_to_screen(v->screen, v->homogeneous); } @@ -2888,32 +2884,23 @@ static inline bool sw_quad_is_axis_aligned(void) for (int i = 0; i < 4; i++) { - if (RLSW.vertexBuffer[i].homogeneous[3] != 1.0f) { - return false; - } + if (RLSW.vertexBuffer[i].homogeneous[3] != 1.0f) return false; - const float* v0 = RLSW.vertexBuffer[i].position; - const float* v1 = RLSW.vertexBuffer[(i + 1) % 4].position; + const float *v0 = RLSW.vertexBuffer[i].position; + const float *v1 = RLSW.vertexBuffer[(i + 1)%4].position; 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++; - } - else { - // Diagonal edge -> not axis-aligned - return false; - } + 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 } - return (horizontal == 2 && vertical == 2); + return ((horizontal == 2) && (vertical == 2)); } -static inline void sw_quad_sort_cw(const sw_vertex_t** output) +static inline void sw_quad_sort_cw(const sw_vertex_t* *output) { // Sort 4 quad vertices into clockwise order with fixed layout: // @@ -2926,58 +2913,56 @@ static inline void sw_quad_sort_cw(const sw_vertex_t** output) // - v1: top-right (minimum Y row, maximum X) // - v2: bottom-right (maximum Y, maximum X) // - v3: bottom-left (maximum Y, minimum X) - - const sw_vertex_t* input = RLSW.vertexBuffer; + const sw_vertex_t *input = RLSW.vertexBuffer; // Separate vertices into top and bottom based on Y-coordinate - const sw_vertex_t* top[2] = {NULL, NULL}; - const sw_vertex_t* bottom[2] = {NULL, NULL}; + const sw_vertex_t *top[2] = {NULL, NULL}; + const sw_vertex_t *bottom[2] = {NULL, NULL}; int topCount = 0, bottomCount = 0; // Find minimum and maximum Y float minY = input[0].screen[1]; float maxY = input[0].screen[1]; - for (int i = 1; i < 4; i++) { + for (int i = 1; i < 4; i++) + { if (input[i].screen[1] < minY) minY = input[i].screen[1]; if (input[i].screen[1] > maxY) maxY = input[i].screen[1]; } // 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]; - } + 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 we don't have enough top/bottom vertices (e.g., Y values are all different), // classify vertices as top or bottom based on whether they're closer to minY or maxY - for (int i = 0; i < 4; i++) { - if (topCount < 2 && &input[i] != top[0] && &input[i] != bottom[0] && &input[i] != bottom[1]) { - if (fabs(input[i].screen[1] - minY) <= fabs(input[i].screen[1] - maxY)) { - top[topCount++] = &input[i]; - } + for (int i = 0; i < 4; i++) + { + if ((topCount < 2) && (&input[i] != top[0]) && (&input[i] != bottom[0]) && (&input[i] != bottom[1])) + { + if (fabsf(input[i].screen[1] - minY) <= fabsf(input[i].screen[1] - maxY)) top[topCount++] = &input[i]; } - if (bottomCount < 2 && &input[i] != top[0] && &input[i] != top[1] && &input[i] != bottom[0]) { - if (fabs(input[i].screen[1] - maxY) < fabs(input[i].screen[1] - minY)) { - bottom[bottomCount++] = &input[i]; - } + if ((bottomCount < 2) && (&input[i] != top[0]) && (&input[i] != top[1]) && (&input[i] != bottom[0])) + { + if (fabsf(input[i].screen[1] - maxY) < fabsf(input[i].screen[1] - minY)) bottom[bottomCount++] = &input[i]; } } // Sort top vertices by X (left to right) - if (topCount == 2 && top[0]->screen[0] > top[1]->screen[0]) { - const sw_vertex_t* temp = top[0]; + if ((topCount == 2) && (top[0]->screen[0] > top[1]->screen[0])) + { + const sw_vertex_t *temp = top[0]; top[0] = top[1]; top[1] = temp; } // Sort bottom vertices by X (left to right) - if (bottomCount == 2 && bottom[0]->screen[0] > bottom[1]->screen[0]) { - const sw_vertex_t* temp = bottom[0]; + if (bottomCount == 2 && bottom[0]->screen[0] > bottom[1]->screen[0]) + { + const sw_vertex_t *temp = bottom[0]; bottom[0] = bottom[1]; bottom[1] = temp; } @@ -2989,21 +2974,21 @@ static inline void sw_quad_sort_cw(const sw_vertex_t** output) output[3] = bottom[0]; // v3: bottom-left } -// REVIEW: Could a perfectly aligned quad, where one of the four points has a different depth, still appear perfectly aligned from a certain point of view? -// Because in that case, we would still need to perform perspective division for textures and colors... +// TODO: REVIEW: Could a perfectly aligned quad, where one of the four points has a different depth, +// still appear perfectly aligned from a certain point of view? +// Because in that case, we would still need to perform perspective division for textures and colors... #define DEFINE_QUAD_RASTER_AXIS_ALIGNED(FUNC_NAME, ENABLE_TEXTURE, ENABLE_DEPTH_TEST, ENABLE_COLOR_BLEND) \ static inline void FUNC_NAME(void) \ { \ - const sw_vertex_t* sortedVerts[4]; \ + const sw_vertex_t *sortedVerts[4]; \ sw_quad_sort_cw(sortedVerts); \ \ - const sw_vertex_t* v0 = sortedVerts[0]; \ - const sw_vertex_t* v1 = sortedVerts[1]; \ - const sw_vertex_t* v2 = sortedVerts[2]; \ - const sw_vertex_t* v3 = sortedVerts[3]; \ + const sw_vertex_t *v0 = sortedVerts[0]; \ + const sw_vertex_t *v1 = sortedVerts[1]; \ + const sw_vertex_t *v2 = sortedVerts[2]; \ + const sw_vertex_t *v3 = sortedVerts[3]; \ \ /* Screen bounds (axis-aligned) */ \ - \ int xMin = (int)(v0->screen[0] + 0.5f); \ int yMin = (int)(v0->screen[1] + 0.5f); \ int xMax = (int)(v2->screen[0] + 0.5f); \ @@ -3014,42 +2999,38 @@ static inline void FUNC_NAME(void) \ 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; \ + float wRcp = (width > 0.0f)? 1.0f/width : 0.0f; \ + float hRcp = (height > 0.0f)? 1.0f/height : 0.0f; \ \ /* Calculation of vertex gradients in X and Y */ \ - \ float tcDx[2], tcDy[2]; \ if (ENABLE_TEXTURE) { \ - tcDx[0] = (v1->texcoord[0] - v0->texcoord[0]) * wRcp; \ - tcDx[1] = (v1->texcoord[1] - v0->texcoord[1]) * wRcp; \ - tcDy[0] = (v3->texcoord[0] - v0->texcoord[0]) * hRcp; \ - tcDy[1] = (v3->texcoord[1] - v0->texcoord[1]) * hRcp; \ + tcDx[0] = (v1->texcoord[0] - v0->texcoord[0])*wRcp; \ + tcDx[1] = (v1->texcoord[1] - v0->texcoord[1])*wRcp; \ + tcDy[0] = (v3->texcoord[0] - v0->texcoord[0])*hRcp; \ + tcDy[1] = (v3->texcoord[1] - v0->texcoord[1])*hRcp; \ } \ \ float cDx[4], cDy[4]; \ - cDx[0] = (v1->color[0] - v0->color[0]) * wRcp; \ - cDx[1] = (v1->color[1] - v0->color[1]) * wRcp; \ - cDx[2] = (v1->color[2] - v0->color[2]) * wRcp; \ - cDx[3] = (v1->color[3] - v0->color[3]) * wRcp; \ - cDy[0] = (v3->color[0] - v0->color[0]) * hRcp; \ - cDy[1] = (v3->color[1] - v0->color[1]) * hRcp; \ - cDy[2] = (v3->color[2] - v0->color[2]) * hRcp; \ - cDy[3] = (v3->color[3] - v0->color[3]) * hRcp; \ + cDx[0] = (v1->color[0] - v0->color[0])*wRcp; \ + cDx[1] = (v1->color[1] - v0->color[1])*wRcp; \ + cDx[2] = (v1->color[2] - v0->color[2])*wRcp; \ + cDx[3] = (v1->color[3] - v0->color[3])*wRcp; \ + cDy[0] = (v3->color[0] - v0->color[0])*hRcp; \ + cDy[1] = (v3->color[1] - v0->color[1])*hRcp; \ + cDy[2] = (v3->color[2] - v0->color[2])*hRcp; \ + cDy[3] = (v3->color[3] - v0->color[3])*hRcp; \ \ float zDx, zDy; \ - zDx = (v1->homogeneous[2] - v0->homogeneous[2]) * wRcp; \ - zDy = (v3->homogeneous[2] - v0->homogeneous[2]) * hRcp; \ + zDx = (v1->homogeneous[2] - v0->homogeneous[2])*wRcp; \ + zDy = (v3->homogeneous[2] - v0->homogeneous[2])*hRcp; \ \ /* Start of quad rasterization */ \ + const sw_texture_t *tex; \ + if (ENABLE_TEXTURE) tex = &RLSW.loadedTextures[RLSW.currentTexture]; \ \ - const sw_texture_t* tex; \ - if (ENABLE_TEXTURE) { \ - tex = &RLSW.loadedTextures[RLSW.currentTexture]; \ - } \ - \ - void* cDstBase = RLSW.framebuffer.color; \ - void* dDstBase = RLSW.framebuffer.depth; \ + void *cDstBase = RLSW.framebuffer.color; \ + void *dDstBase = RLSW.framebuffer.depth; \ int wDst = RLSW.framebuffer.width; \ \ float zScanline = v0->homogeneous[2]; \ @@ -3065,8 +3046,8 @@ static inline void FUNC_NAME(void) \ for (int y = yMin; y < yMax; y++) \ { \ - void* cptr = sw_framebuffer_get_color_addr(cDstBase, y * wDst + xMin); \ - void* dptr = sw_framebuffer_get_depth_addr(dDstBase, y * wDst + xMin); \ + void *cptr = sw_framebuffer_get_color_addr(cDstBase, y*wDst + xMin); \ + void *dptr = sw_framebuffer_get_depth_addr(dDstBase, y*wDst + xMin); \ \ float z = zScanline; \ float u = uScanline; \ @@ -3080,11 +3061,9 @@ static inline void FUNC_NAME(void) }; \ \ /* Scanline rasterization */ \ - \ for (int x = xMin; x < xMax; x++) \ { \ /* Test and write depth */ \ - \ if (ENABLE_DEPTH_TEST) \ { \ /* TODO: Implement different depth funcs? */ \ @@ -3095,7 +3074,6 @@ static inline void FUNC_NAME(void) sw_framebuffer_write_depth(dptr, z); \ \ /* Pixel color computation */ \ - \ float srcColor[4] = { \ color[0], \ color[1], \ @@ -3126,21 +3104,17 @@ static inline void FUNC_NAME(void) \ sw_framebuffer_write_color(cptr, dstColor); \ } \ - else \ - { \ - sw_framebuffer_write_color(cptr, srcColor); \ - } \ + else sw_framebuffer_write_color(cptr, srcColor); \ \ discard: \ - \ z += zDx; \ - \ color[0] += cDx[0]; \ color[1] += cDx[1]; \ color[2] += cDx[2]; \ color[3] += cDx[3]; \ \ - if (ENABLE_TEXTURE) { \ + if (ENABLE_TEXTURE) \ + { \ u += tcDx[0]; \ v += tcDx[1]; \ } \ @@ -3150,13 +3124,13 @@ static inline void FUNC_NAME(void) } \ \ zScanline += zDy; \ - \ colorScanline[0] += cDy[0]; \ colorScanline[1] += cDy[1]; \ colorScanline[2] += cDy[2]; \ colorScanline[3] += cDy[3]; \ \ - if (ENABLE_TEXTURE) { \ + if (ENABLE_TEXTURE) \ + { \ uScanline += tcDy[0]; \ vScanline += tcDy[1]; \ } \ @@ -3174,50 +3148,32 @@ DEFINE_QUAD_RASTER_AXIS_ALIGNED(sw_quad_raster_axis_aligned_TEX_DEPTH_BLEND, 1, static inline void sw_quad_render(void) { - if (RLSW.stateFlags & SW_STATE_CULL_FACE) { - if (!sw_quad_face_culling()) { - return; - } + if (RLSW.stateFlags & SW_STATE_CULL_FACE) + { + if (!sw_quad_face_culling()) return; } sw_quad_clip_and_project(); - if (RLSW.vertexCounter < 3) { - return; - } + if (RLSW.vertexCounter < 3) return; 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(); - } - else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_BLEND)) { - sw_quad_raster_axis_aligned_TEX_BLEND(); - } - else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST)) { - sw_quad_raster_axis_aligned_TEX_DEPTH(); - } - else if (SW_STATE_CHECK(SW_STATE_BLEND)) { - sw_quad_raster_axis_aligned_BLEND(); - } - else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST)) { - sw_quad_raster_axis_aligned_DEPTH(); - } - else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D)) { - sw_quad_raster_axis_aligned_TEX(); - } - else { - sw_quad_raster_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(); + else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_BLEND)) sw_quad_raster_axis_aligned_TEX_BLEND(); + else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST)) sw_quad_raster_axis_aligned_TEX_DEPTH(); + else if (SW_STATE_CHECK(SW_STATE_BLEND)) sw_quad_raster_axis_aligned_BLEND(); + else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST)) sw_quad_raster_axis_aligned_DEPTH(); + else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D)) sw_quad_raster_axis_aligned_TEX(); + else sw_quad_raster_axis_aligned(); return; } -# define TRIANGLE_RASTER(RASTER_FUNC) \ + #define TRIANGLE_RASTER(RASTER_FUNC) \ { \ - for (int i = 0; i < RLSW.vertexCounter - 2; i++) { \ + for (int i = 0; i < RLSW.vertexCounter - 2; i++) \ + { \ RASTER_FUNC( \ &RLSW.vertexBuffer[0], \ &RLSW.vertexBuffer[i + 1], \ @@ -3227,51 +3183,38 @@ static inline void sw_quad_render(void) } \ } - if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) { - TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH_BLEND) - } - else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) { - TRIANGLE_RASTER(sw_triangle_raster_DEPTH_BLEND) - } - else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_BLEND)) { - TRIANGLE_RASTER(sw_triangle_raster_TEX_BLEND) - } - else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST)) { - TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH) - } - else if (SW_STATE_CHECK(SW_STATE_BLEND)) { - TRIANGLE_RASTER(sw_triangle_raster_BLEND) - } - else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST)) { - TRIANGLE_RASTER(sw_triangle_raster_DEPTH) - } - else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D)) { - TRIANGLE_RASTER(sw_triangle_raster_TEX) - } - else { - TRIANGLE_RASTER(sw_triangle_raster) - } + if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH_BLEND) + else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_DEPTH_BLEND) + else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_TEX_BLEND) + else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST)) TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH) + else if (SW_STATE_CHECK(SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_BLEND) + else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST)) TRIANGLE_RASTER(sw_triangle_raster_DEPTH) + else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D)) TRIANGLE_RASTER(sw_triangle_raster_TEX) + else TRIANGLE_RASTER(sw_triangle_raster) -# undef TRIANGLE_RASTER + #undef TRIANGLE_RASTER } -/* === Line Rendering Part === */ +// Line rendering logic -static inline bool sw_line_clip_coord(float q, float p, float* t0, float* t1) +static inline bool sw_line_clip_coord(float q, float p, float *t0, float *t1) { - if (fabsf(p) < SW_CLIP_EPSILON) { + if (fabsf(p) < SW_CLIP_EPSILON) + { // Check if the line is entirely outside the window if (q < -SW_CLIP_EPSILON) return 0; // Completely outside - return 1; // Completely inside or on the edges + return 1; // Completely inside or on the edges } - const float r = q / p; + const float r = q/p; - if (p < 0) { + if (p < 0) + { if (r > *t1) return 0; if (r > *t0) *t0 = r; } - else { + else + { if (r < *t0) return 0; if (r < *t1) *t1 = r; } @@ -3279,12 +3222,13 @@ static inline bool sw_line_clip_coord(float q, float p, float* t0, float* t1) return 1; } -static inline bool sw_line_clip(sw_vertex_t* v0, sw_vertex_t* v1) +static inline bool sw_line_clip(sw_vertex_t *v0, sw_vertex_t *v1) { float t0 = 0.0f, t1 = 1.0f; float dH[4], dC[4]; - for (int i = 0; i < 4; i++) { + for (int i = 0; i < 4; i++) + { dH[i] = v1->homogeneous[i] - v0->homogeneous[i]; dC[i] = v1->color[i] - v0->color[i]; } @@ -3298,40 +3242,45 @@ static inline bool sw_line_clip(sw_vertex_t* v0, sw_vertex_t* v1) if (!sw_line_clip_coord(v0->homogeneous[3] + v0->homogeneous[2], -dH[3] - dH[2], &t0, &t1)) return false; // Clipping Scissor - if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST) { - if (!sw_line_clip_coord(v0->homogeneous[0] - RLSW.scClipMin[0] * v0->homogeneous[3], RLSW.scClipMin[0] * dH[3] - dH[0], &t0, &t1)) return false; - if (!sw_line_clip_coord(RLSW.scClipMax[0] * v0->homogeneous[3] - v0->homogeneous[0], dH[0] - RLSW.scClipMax[0] * dH[3], &t0, &t1)) return false; - if (!sw_line_clip_coord(v0->homogeneous[1] - RLSW.scClipMin[1] * v0->homogeneous[3], RLSW.scClipMin[1] * dH[3] - dH[1], &t0, &t1)) return false; - if (!sw_line_clip_coord(RLSW.scClipMax[1] * v0->homogeneous[3] - v0->homogeneous[1], dH[1] - RLSW.scClipMax[1] * dH[3], &t0, &t1)) return false; + if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST) + { + if (!sw_line_clip_coord(v0->homogeneous[0] - RLSW.scClipMin[0]*v0->homogeneous[3], RLSW.scClipMin[0]*dH[3] - dH[0], &t0, &t1)) return false; + if (!sw_line_clip_coord(RLSW.scClipMax[0]*v0->homogeneous[3] - v0->homogeneous[0], dH[0] - RLSW.scClipMax[0]*dH[3], &t0, &t1)) return false; + if (!sw_line_clip_coord(v0->homogeneous[1] - RLSW.scClipMin[1]*v0->homogeneous[3], RLSW.scClipMin[1]*dH[3] - dH[1], &t0, &t1)) return false; + if (!sw_line_clip_coord(RLSW.scClipMax[1]*v0->homogeneous[3] - v0->homogeneous[1], dH[1] - RLSW.scClipMax[1]*dH[3], &t0, &t1)) return false; } // Interpolation of new coordinates - if (t1 < 1.0f) { - for (int i = 0; i < 4; i++) { - v1->homogeneous[i] = v0->homogeneous[i] + t1 * dH[i]; - v1->color[i] = v0->color[i] + t1 * dC[i]; + if (t1 < 1.0f) + { + for (int i = 0; i < 4; i++) + { + v1->homogeneous[i] = v0->homogeneous[i] + t1*dH[i]; + v1->color[i] = v0->color[i] + t1*dC[i]; } } - if (t0 > 0.0f) { - for (int i = 0; i < 4; i++) { - v0->homogeneous[i] += t0 * dH[i]; - v0->color[i] += t0 * dC[i]; + + if (t0 > 0.0f) + { + for (int i = 0; i < 4; i++) + { + v0->homogeneous[i] += t0*dH[i]; + v0->color[i] += t0*dC[i]; } } return true; } -static inline bool sw_line_clip_and_project(sw_vertex_t* v0, sw_vertex_t* v1) +static inline bool sw_line_clip_and_project(sw_vertex_t *v0, sw_vertex_t *v1) { - if (!sw_line_clip(v0, v1)) { - return false; - } + if (!sw_line_clip(v0, v1)) return false; // Convert homogeneous coordinates to NDC - v0->homogeneous[3] = 1.0f / v0->homogeneous[3]; - v1->homogeneous[3] = 1.0f / v1->homogeneous[3]; - for (int i = 0; i < 3; i++) { + v0->homogeneous[3] = 1.0f/v0->homogeneous[3]; + v1->homogeneous[3] = 1.0f/v1->homogeneous[3]; + for (int i = 0; i < 3; i++) + { v0->homogeneous[i] *= v0->homogeneous[3]; v1->homogeneous[i] *= v1->homogeneous[3]; } @@ -3344,7 +3293,7 @@ static inline bool sw_line_clip_and_project(sw_vertex_t* v0, sw_vertex_t* v1) } #define DEFINE_LINE_RASTER(FUNC_NAME, ENABLE_DEPTH_TEST, ENABLE_COLOR_BLEND) \ -static inline void FUNC_NAME(const sw_vertex_t* v0, const sw_vertex_t* v1) \ +static inline void FUNC_NAME(const sw_vertex_t *v0, const sw_vertex_t *v1) \ { \ int x1 = (int)(v0->screen[0] + 0.5f); \ int y1 = (int)(v0->screen[1] + 0.5f); \ @@ -3355,8 +3304,8 @@ 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; \ } \ @@ -3364,36 +3313,33 @@ static inline void FUNC_NAME(const sw_vertex_t* v0, const sw_vertex_t* v1) \ bool yLonger = (abs(dy) > abs(dx)); \ int longLen, shortLen; \ \ - if (yLonger) { \ + if (yLonger) \ + { \ longLen = dy; \ shortLen = dx; \ } \ - else { \ + else \ + { \ longLen = dx; \ shortLen = dy; \ } \ \ /* Handling of traversal direction */ \ - \ - int sgnInc = (longLen < 0) ? -1 : 1; \ + int sgnInc = (longLen < 0)? -1 : 1; \ int abslongLen = abs(longLen); \ \ /* Calculation of the increment step for the shorter coordinate */ \ - \ int decInc = 0; \ - if (abslongLen != 0) { \ - decInc = (shortLen << 16) / abslongLen; \ - } \ + if (abslongLen != 0) decInc = (shortLen << 16)/abslongLen; \ \ - float longLenRcp = (abslongLen != 0) ? (1.0f / abslongLen) : 0.0f; \ + float longLenRcp = (abslongLen != 0)? (1.0f/abslongLen) : 0.0f; \ \ /* Calculation of interpolation steps */ \ - \ - const float zStep = (v1->homogeneous[2] - v0->homogeneous[2]) * longLenRcp; \ - const float rStep = (v1->color[0] - v0->color[0]) * longLenRcp; \ - const float gStep = (v1->color[1] - v0->color[1]) * longLenRcp; \ - const float bStep = (v1->color[2] - v0->color[2]) * longLenRcp; \ - const float aStep = (v1->color[3] - v0->color[3]) * longLenRcp; \ + const float zStep = (v1->homogeneous[2] - v0->homogeneous[2])*longLenRcp; \ + const float rStep = (v1->color[0] - v0->color[0])*longLenRcp; \ + const float gStep = (v1->color[1] - v0->color[1])*longLenRcp; \ + const float bStep = (v1->color[2] - v0->color[2])*longLenRcp; \ + const float aStep = (v1->color[3] - v0->color[3])*longLenRcp; \ \ float z = v0->homogeneous[2]; \ \ @@ -3405,27 +3351,26 @@ static inline void FUNC_NAME(const sw_vertex_t* v0, const sw_vertex_t* v1) \ }; \ \ const int fbWidth = RLSW.framebuffer.width; \ - void* cBuffer = RLSW.framebuffer.color; \ - void* dBuffer = RLSW.framebuffer.depth; \ + void *cBuffer = RLSW.framebuffer.color; \ + void *dBuffer = RLSW.framebuffer.depth; \ \ int j = 0; \ - \ if (yLonger) \ { \ for (int i = 0; i != longLen; i += sgnInc) \ { \ - int offset = (y1 + i) * fbWidth + (x1 + (j >> 16)); \ + int offset = (y1 + i)*fbWidth + (x1 + (j >> 16)); \ + void *dptr = sw_framebuffer_get_depth_addr(dBuffer, offset); \ \ - void* dptr = sw_framebuffer_get_depth_addr(dBuffer, offset); \ - \ - if (ENABLE_DEPTH_TEST) { \ + if (ENABLE_DEPTH_TEST) \ + { \ float depth = sw_framebuffer_read_depth(dptr); \ if (z > depth) goto discardA; \ } \ \ sw_framebuffer_write_depth(dptr, z); \ \ - void* cptr = sw_framebuffer_get_color_addr(cBuffer, offset); \ + void *cptr = sw_framebuffer_get_color_addr(cBuffer, offset); \ \ if (ENABLE_COLOR_BLEND) \ { \ @@ -3435,10 +3380,7 @@ static inline void FUNC_NAME(const sw_vertex_t* v0, const sw_vertex_t* v1) \ sw_blend_colors(dstColor, color); \ sw_framebuffer_write_color(cptr, dstColor); \ } \ - else \ - { \ - sw_framebuffer_write_color(cptr, color); \ - } \ + else sw_framebuffer_write_color(cptr, color); \ \ discardA: \ j += decInc; \ @@ -3453,18 +3395,18 @@ static inline void FUNC_NAME(const sw_vertex_t* v0, const sw_vertex_t* v1) \ { \ for (int i = 0; i != longLen; i += sgnInc) \ { \ - int offset = (y1 + (j >> 16)) * fbWidth + (x1 + i); \ + int offset = (y1 + (j >> 16))*fbWidth + (x1 + i); \ + void *dptr = sw_framebuffer_get_depth_addr(dBuffer, offset); \ \ - void* dptr = sw_framebuffer_get_depth_addr(dBuffer, offset); \ - \ - if (ENABLE_DEPTH_TEST) { \ + if (ENABLE_DEPTH_TEST) \ + { \ float depth = sw_framebuffer_read_depth(dptr); \ if (z > depth) goto discardB; \ } \ \ sw_framebuffer_write_depth(dptr, z); \ \ - void* cptr = sw_framebuffer_get_color_addr(cBuffer, offset); \ + void *cptr = sw_framebuffer_get_color_addr(cBuffer, offset); \ \ if (ENABLE_COLOR_BLEND) \ { \ @@ -3474,10 +3416,7 @@ static inline void FUNC_NAME(const sw_vertex_t* v0, const sw_vertex_t* v1) \ sw_blend_colors(dstColor, color); \ sw_framebuffer_write_color(cptr, dstColor); \ } \ - else \ - { \ - sw_framebuffer_write_color(cptr, color); \ - } \ + else sw_framebuffer_write_color(cptr, color); \ \ discardB: \ j += decInc; \ @@ -3491,7 +3430,7 @@ static inline void FUNC_NAME(const sw_vertex_t* v0, const sw_vertex_t* v1) \ } #define DEFINE_LINE_THICK_RASTER(FUNC_NAME, RASTER_FUNC) \ -void FUNC_NAME(const sw_vertex_t* v1, const sw_vertex_t* v2) \ +void FUNC_NAME(const sw_vertex_t *v1, const sw_vertex_t *v2) \ { \ sw_vertex_t tv1, tv2; \ \ @@ -3505,10 +3444,12 @@ void FUNC_NAME(const sw_vertex_t* v1, const sw_vertex_t* v2) \ \ RASTER_FUNC(v1, v2); \ \ - if (dx != 0 && abs(dy / dx) < 1) { \ - int wy = (int)((RLSW.lineWidth - 1.0f) * abs(dx) / sqrtf(dx * dx + dy * dy)); \ - wy >>= 1; /* Division by 2 via bit shift */ \ - for (int i = 1; i <= wy; i++) { \ + if (dx != 0 && abs(dy/dx) < 1) \ + { \ + int wy = (int)((RLSW.lineWidth - 1.0f)*abs(dx)/sqrtf(dx*dx + dy*dy)); \ + wy >>= 1; \ + for (int i = 1; i <= wy; i++) \ + { \ tv1 = *v1, tv2 = *v2; \ tv1.screen[1] -= i; \ tv2.screen[1] -= i; \ @@ -3519,10 +3460,12 @@ void FUNC_NAME(const sw_vertex_t* v1, const sw_vertex_t* v2) \ RASTER_FUNC(&tv1, &tv2); \ } \ } \ - else if (dy != 0) { \ - int wx = (int)((RLSW.lineWidth - 1.0f) * abs(dy) / sqrtf(dx * dx + dy * dy)); \ - wx >>= 1; /* Division by 2 via bit shift */ \ - for (int i = 1; i <= wx; i++) { \ + else if (dy != 0) \ + { \ + int wx = (int)((RLSW.lineWidth - 1.0f)*abs(dy)/sqrtf(dx*dx + dy*dy)); \ + wx >>= 1; \ + for (int i = 1; i <= wx; i++) \ + { \ tv1 = *v1, tv2 = *v2; \ tv1.screen[0] -= i; \ tv2.screen[0] -= i; \ @@ -3545,53 +3488,38 @@ DEFINE_LINE_THICK_RASTER(sw_line_thick_raster_DEPTH, sw_line_raster_DEPTH) DEFINE_LINE_THICK_RASTER(sw_line_thick_raster_BLEND, sw_line_raster_BLEND) DEFINE_LINE_THICK_RASTER(sw_line_thick_raster_DEPTH_BLEND, sw_line_raster_DEPTH_BLEND) -static inline void sw_line_render(sw_vertex_t* vertices) +static inline void sw_line_render(sw_vertex_t *vertices) { - if (!sw_line_clip_and_project(&vertices[0], &vertices[1])) { - return; - } + if (!sw_line_clip_and_project(&vertices[0], &vertices[1])) return; - if (RLSW.lineWidth >= 2.0f) { - if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) { - sw_line_thick_raster_DEPTH_BLEND(&vertices[0], &vertices[1]); - } - else if (SW_STATE_CHECK(SW_STATE_BLEND)) { - sw_line_thick_raster_BLEND(&vertices[0], &vertices[1]); - } - else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST)) { - sw_line_thick_raster_DEPTH(&vertices[0], &vertices[1]); - } - else { - sw_line_thick_raster(&vertices[0], &vertices[1]); - } + if (RLSW.lineWidth >= 2.0f) + { + if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) sw_line_thick_raster_DEPTH_BLEND(&vertices[0], &vertices[1]); + else if (SW_STATE_CHECK(SW_STATE_BLEND)) sw_line_thick_raster_BLEND(&vertices[0], &vertices[1]); + else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST)) sw_line_thick_raster_DEPTH(&vertices[0], &vertices[1]); + else sw_line_thick_raster(&vertices[0], &vertices[1]); } - else { - if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) { - sw_line_raster_DEPTH_BLEND(&vertices[0], &vertices[1]); - } - else if (SW_STATE_CHECK(SW_STATE_BLEND)) { - sw_line_raster_BLEND(&vertices[0], &vertices[1]); - } - else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST)) { - sw_line_raster_DEPTH(&vertices[0], &vertices[1]); - } - else { - sw_line_raster(&vertices[0], &vertices[1]); - } + else + { + if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) sw_line_raster_DEPTH_BLEND(&vertices[0], &vertices[1]); + else if (SW_STATE_CHECK(SW_STATE_BLEND)) sw_line_raster_BLEND(&vertices[0], &vertices[1]); + else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST)) sw_line_raster_DEPTH(&vertices[0], &vertices[1]); + else sw_line_raster(&vertices[0], &vertices[1]); } } -/* === Point Rendering Part === */ +// Point rendering logic -static inline bool sw_point_clip_and_project(sw_vertex_t* v) +static inline bool sw_point_clip_and_project(sw_vertex_t *v) { - if (v->homogeneous[3] != 1.0f) { - for (int_fast8_t i = 0; i < 3; i++) { - if (v->homogeneous[i] < -v->homogeneous[3] || v->homogeneous[i] > v->homogeneous[3]) { - return false; - } + if (v->homogeneous[3] != 1.0f) + { + for (int_fast8_t i = 0; i < 3; i++) + { + if ((v->homogeneous[i] < -v->homogeneous[3]) || (v->homogeneous[i] > v->homogeneous[3])) return false; } - v->homogeneous[3] = 1.0f / v->homogeneous[3]; + + v->homogeneous[3] = 1.0f/v->homogeneous[3]; v->homogeneous[0] *= v->homogeneous[3]; v->homogeneous[1] *= v->homogeneous[3]; v->homogeneous[2] *= v->homogeneous[3]; @@ -3599,24 +3527,23 @@ static inline bool sw_point_clip_and_project(sw_vertex_t* v) sw_project_ndc_to_screen(v->screen, v->homogeneous); - const int *min, *max; + const int *min = NULL, *max = NULL; - if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST) { + if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST) + { min = RLSW.scMin; max = RLSW.scMax; } - else { + else + { min = RLSW.vpMin; max = RLSW.vpMax; } - bool insideX = v->screen[0] - RLSW.pointRadius < max[0] - && v->screen[0] + RLSW.pointRadius > min[0]; + bool insideX = (v->screen[0] - RLSW.pointRadius < max[0]) && (v->screen[0] + RLSW.pointRadius > min[0]); + bool insideY = (v->screen[1] - RLSW.pointRadius < max[1]) && (v->screen[1] + RLSW.pointRadius > min[1]); - bool insideY = v->screen[1] - RLSW.pointRadius < max[1] - && v->screen[1] + RLSW.pointRadius > min[1]; - - return insideX && insideY; + return (insideX && insideY); } #define DEFINE_POINT_RASTER(FUNC_NAME, ENABLE_DEPTH_TEST, ENABLE_COLOR_BLEND, CHECK_BOUNDS) \ @@ -3633,11 +3560,9 @@ static inline void FUNC_NAME(int x, int y, float z, const float color[4]) \ if (y < RLSW.scMin[1] || y >= RLSW.scMax[1]) return; \ } \ \ - int offset = y * RLSW.framebuffer.width + x; \ + int offset = y*RLSW.framebuffer.width + x; \ \ - void* dptr = sw_framebuffer_get_depth_addr( \ - RLSW.framebuffer.depth, offset \ - ); \ + void *dptr = sw_framebuffer_get_depth_addr(RLSW.framebuffer.depth, offset); \ \ if (ENABLE_DEPTH_TEST) \ { \ @@ -3647,9 +3572,7 @@ static inline void FUNC_NAME(int x, int y, float z, const float color[4]) \ \ sw_framebuffer_write_depth(dptr, z); \ \ - void* cptr = sw_framebuffer_get_color_addr( \ - RLSW.framebuffer.color, offset \ - ); \ + void *cptr = sw_framebuffer_get_color_addr(RLSW.framebuffer.color, offset); \ \ if (ENABLE_COLOR_BLEND) \ { \ @@ -3659,41 +3582,40 @@ static inline void FUNC_NAME(int x, int y, float z, const float color[4]) \ sw_blend_colors(dstColor, color); \ sw_framebuffer_write_color(cptr, dstColor); \ } \ - else \ - { \ - sw_framebuffer_write_color(cptr, color); \ - } \ + else sw_framebuffer_write_color(cptr, color); \ } #define DEFINE_POINT_THICK_RASTER(FUNC_NAME, RASTER_FUNC) \ -static inline void FUNC_NAME(sw_vertex_t* v) \ +static inline void FUNC_NAME(sw_vertex_t *v) \ { \ int cx = v->screen[0]; \ int cy = v->screen[1]; \ float cz = v->homogeneous[2]; \ int radius = RLSW.pointRadius; \ - const float* color = v->color; \ + const float *color = v->color; \ \ int x = 0; \ int y = radius; \ - int d = 3 - 2 * radius; \ + int d = 3 - 2*radius; \ \ - while (x <= y) { \ - for (int i = -x; i <= x; i++) { \ + while (x <= y) \ + { \ + for (int i = -x; i <= x; i++) \ + { \ RASTER_FUNC(cx + i, cy + y, cz, color); \ RASTER_FUNC(cx + i, cy - y, cz, color); \ } \ - for (int i = -y; i <= y; i++) { \ + for (int i = -y; i <= y; i++) \ + { \ RASTER_FUNC(cx + i, cy + x, cz, color); \ RASTER_FUNC(cx + i, cy - x, cz, color); \ } \ - if (d > 0) { \ + if (d > 0) \ + { \ y--; \ - d = d + 4 * (x - y) + 10; \ - } \ - else { \ - d = d + 4 * x + 6; \ + d = d + 4*(x - y) + 10; \ } \ + else d = d + 4*x + 6; \ x++; \ } \ } @@ -3723,114 +3645,65 @@ DEFINE_POINT_THICK_RASTER(sw_point_thick_raster_DEPTH_SCISSOR, sw_point_raster_D DEFINE_POINT_THICK_RASTER(sw_point_thick_raster_BLEND_SCISSOR, sw_point_raster_BLEND_CHECK_SCISSOR) DEFINE_POINT_THICK_RASTER(sw_point_thick_raster_DEPTH_BLEND_SCISSOR, sw_point_raster_DEPTH_BLEND_CHECK_SCISSOR) -static inline void sw_point_render(sw_vertex_t* v) +static inline void sw_point_render(sw_vertex_t *v) { - if (!sw_point_clip_and_project(v)) { - return; - } + if (!sw_point_clip_and_project(v)) return; - if (RLSW.pointRadius >= 1.0f) { - if (SW_STATE_CHECK(SW_STATE_SCISSOR_TEST)) { - if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) { - sw_point_thick_raster_DEPTH_BLEND_SCISSOR(v); - } - else if (SW_STATE_CHECK(SW_STATE_BLEND)) { - sw_point_thick_raster_BLEND_SCISSOR(v); - } - else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST)) { - sw_point_thick_raster_DEPTH_SCISSOR(v); - } - else { - sw_point_thick_raster_SCISSOR(v); - } + if (RLSW.pointRadius >= 1.0f) + { + if (SW_STATE_CHECK(SW_STATE_SCISSOR_TEST)) + { + if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) sw_point_thick_raster_DEPTH_BLEND_SCISSOR(v); + else if (SW_STATE_CHECK(SW_STATE_BLEND)) sw_point_thick_raster_BLEND_SCISSOR(v); + else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST)) sw_point_thick_raster_DEPTH_SCISSOR(v); + else sw_point_thick_raster_SCISSOR(v); } - else { - if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) { - sw_point_thick_raster_DEPTH_BLEND(v); - } - else if (SW_STATE_CHECK(SW_STATE_BLEND)) { - sw_point_thick_raster_BLEND(v); - } - else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST)) { - sw_point_thick_raster_DEPTH(v); - } - else { - sw_point_thick_raster(v); - } + else + { + if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) sw_point_thick_raster_DEPTH_BLEND(v); + else if (SW_STATE_CHECK(SW_STATE_BLEND)) sw_point_thick_raster_BLEND(v); + else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST)) sw_point_thick_raster_DEPTH(v); + else sw_point_thick_raster(v); } } - else { - if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) { - sw_point_raster_DEPTH_BLEND( - v->screen[0], v->screen[1], - v->homogeneous[2], v->color - ); - } - else if (SW_STATE_CHECK(SW_STATE_BLEND)) { - sw_point_raster_BLEND( - v->screen[0], v->screen[1], - v->homogeneous[2], v->color - ); - } - else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST)) { - sw_point_raster_DEPTH( - v->screen[0], v->screen[1], - v->homogeneous[2], v->color - ); - } - else { - sw_point_raster( - v->screen[0], v->screen[1], - v->homogeneous[2], v->color - ); - } + else + { + if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) sw_point_raster_DEPTH_BLEND(v->screen[0], v->screen[1], v->homogeneous[2], v->color); + else if (SW_STATE_CHECK(SW_STATE_BLEND)) sw_point_raster_BLEND(v->screen[0], v->screen[1], v->homogeneous[2], v->color); + else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST)) sw_point_raster_DEPTH(v->screen[0], v->screen[1], v->homogeneous[2], v->color); + else sw_point_raster(v->screen[0], v->screen[1], v->homogeneous[2], v->color); } } -/* === Polygon Modes Rendering Part === */ +// Polygon modes mendering logic static inline void sw_poly_point_render(void) { - for (int i = 0; i < RLSW.vertexCounter; i++) { - sw_point_render(&RLSW.vertexBuffer[i]); - } + for (int i = 0; i < RLSW.vertexCounter; i++) sw_point_render(&RLSW.vertexBuffer[i]); } static inline void sw_poly_line_render(void) { - const sw_vertex_t* vertices = RLSW.vertexBuffer; + const sw_vertex_t *vertices = RLSW.vertexBuffer; int cm1 = RLSW.vertexCounter - 1; - for (int i = 0; i < cm1; i++) { - sw_line_render((sw_vertex_t[2]){ - vertices[i], vertices[i + 1] - }); - } + for (int i = 0; i < cm1; i++) sw_line_render((sw_vertex_t[2]){ vertices[i], vertices[i + 1] }); - sw_line_render((sw_vertex_t[2]){ - vertices[cm1], vertices[0] - }); + sw_line_render((sw_vertex_t[2]){ vertices[cm1], vertices[0] }); } static inline void sw_poly_fill_render(void) { - switch (RLSW.drawMode) { - case SW_POINTS: - sw_point_render(&RLSW.vertexBuffer[0]); - break; - case SW_LINES: - sw_line_render(RLSW.vertexBuffer); - break; - case SW_TRIANGLES: - sw_triangle_render(); - break; - case SW_QUADS: - sw_quad_render(); - break; + switch (RLSW.drawMode) + { + case SW_POINTS: sw_point_render(&RLSW.vertexBuffer[0]); break; + case SW_LINES: sw_line_render(RLSW.vertexBuffer); break; + case SW_TRIANGLES: sw_triangle_render(); break; + case SW_QUADS: sw_quad_render(); break; } } -/* === Some Validity Check Helper === */ +// Validity check helper functions static inline bool sw_is_texture_valid(uint32_t id) { @@ -3857,15 +3730,13 @@ static inline bool sw_is_draw_mode_valid(int mode) { bool result = false; - switch (mode) { - case SW_POINTS: - case SW_LINES: - case SW_TRIANGLES: - case SW_QUADS: - result = true; - break; - default: - break; + switch (mode) + { + case SW_POINTS: + case SW_LINES: + case SW_TRIANGLES: + case SW_QUADS: result = true; break; + default: break; } return result; @@ -3875,14 +3746,12 @@ static inline bool sw_is_poly_mode_valid(int mode) { bool result = false; - switch (mode) { - case SW_POINT: - case SW_LINE: - case SW_FILL: - result = true; - break; - default: - break; + switch (mode) + { + case SW_POINT: + case SW_LINE: + case SW_FILL: result = true; break; + default: break; } return result; @@ -3897,22 +3766,20 @@ static inline bool sw_is_blend_src_factor_valid(int blend) { bool result = false; - switch (blend) { - case SW_ZERO: - case SW_ONE: - case SW_SRC_COLOR: - case SW_ONE_MINUS_SRC_COLOR: - case SW_SRC_ALPHA: - case SW_ONE_MINUS_SRC_ALPHA: - case SW_DST_ALPHA: - case SW_ONE_MINUS_DST_ALPHA: - case SW_DST_COLOR: - case SW_ONE_MINUS_DST_COLOR: - case SW_SRC_ALPHA_SATURATE: - result = true; - break; - default: - break; + switch (blend) + { + case SW_ZERO: + case SW_ONE: + case SW_SRC_COLOR: + case SW_ONE_MINUS_SRC_COLOR: + case SW_SRC_ALPHA: + case SW_ONE_MINUS_SRC_ALPHA: + case SW_DST_ALPHA: + case SW_ONE_MINUS_DST_ALPHA: + case SW_DST_COLOR: + case SW_ONE_MINUS_DST_COLOR: + case SW_SRC_ALPHA_SATURATE: result = true; break; + default: break; } return result; @@ -3922,41 +3789,38 @@ static inline bool sw_is_blend_dst_factor_valid(int blend) { bool result = false; - switch (blend) { - case SW_ZERO: - case SW_ONE: - case SW_SRC_COLOR: - case SW_ONE_MINUS_SRC_COLOR: - case SW_SRC_ALPHA: - case SW_ONE_MINUS_SRC_ALPHA: - case SW_DST_ALPHA: - case SW_ONE_MINUS_DST_ALPHA: - case SW_DST_COLOR: - case SW_ONE_MINUS_DST_COLOR: - result = true; - break; - default: - break; + switch (blend) + { + case SW_ZERO: + case SW_ONE: + case SW_SRC_COLOR: + case SW_ONE_MINUS_SRC_COLOR: + case SW_SRC_ALPHA: + case SW_ONE_MINUS_SRC_ALPHA: + case SW_DST_ALPHA: + case SW_ONE_MINUS_DST_ALPHA: + case SW_DST_COLOR: + case SW_ONE_MINUS_DST_COLOR: result = true; break; + default: break; } return result; } -/* === Public Implementation === */ - +//---------------------------------------------------------------------------------- +// Module Functions Definition +//---------------------------------------------------------------------------------- bool swInit(int w, int h) { - if (!sw_framebuffer_load(w, h)) { - swClose(); return false; - } + if (!sw_framebuffer_load(w, h)) { swClose(); return false; } swViewport(0, 0, w, h); swScissor(0, 0, w, h); - RLSW.loadedTextures = SW_MALLOC(SW_MAX_TEXTURES * sizeof(sw_texture_t)); + RLSW.loadedTextures = SW_MALLOC(SW_MAX_TEXTURES*sizeof(sw_texture_t)); if (RLSW.loadedTextures == NULL) { swClose(); return false; } - RLSW.freeTextureIds = SW_MALLOC(SW_MAX_TEXTURES * sizeof(uint32_t)); + RLSW.freeTextureIds = SW_MALLOC(SW_MAX_TEXTURES*sizeof(uint32_t)); if (RLSW.loadedTextures == NULL) { swClose(); return false; } RLSW.clearColor[0] = 0.0f; @@ -3995,8 +3859,7 @@ bool swInit(int w, int h) RLSW.polyMode = SW_FILL; RLSW.cullFace = SW_BACK; - static const float defTex[3*2*2] = - { + static const float defTex[3*2*2] = { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, @@ -4024,11 +3887,10 @@ bool swInit(int w, int h) void swClose(void) { - for (int i = 1; i < RLSW.loadedTextureCount; i++) { - sw_texture_t* texture = &RLSW.loadedTextures[i]; - if (sw_is_texture_valid(i) && texture->copy) { - SW_FREE(texture->pixels.ptr); - } + for (int i = 1; i < RLSW.loadedTextureCount; i++) + { + sw_texture_t *texture = &RLSW.loadedTextures[i]; + if (sw_is_texture_valid(i) && texture->copy) SW_FREE(texture->pixels.ptr); } SW_FREE(RLSW.framebuffer.color); @@ -4044,147 +3906,89 @@ bool swResizeFramebuffer(int w, int h) return sw_framebuffer_resize(w, h); } -void swCopyFramebuffer(int x, int y, int w, int h, SWformat format, SWtype type, void* pixels) +void swCopyFramebuffer(int x, int y, int w, int h, SWformat format, SWtype type, void *pixels) { sw_pixelformat_t pFormat = sw_get_pixel_format(format, type); - if (w <= 0) { + if (w <= 0) + { RLSW.errCode = SW_INVALID_VALUE; return; } - if (h <= 0) { + if (h <= 0) + { RLSW.errCode = SW_INVALID_VALUE; return; } - if (w > RLSW.framebuffer.width) - w = RLSW.framebuffer.width; - - if (h > RLSW.framebuffer.height) - h = RLSW.framebuffer.height; + if (w > RLSW.framebuffer.width) w = RLSW.framebuffer.width; + if (h > RLSW.framebuffer.height) h = RLSW.framebuffer.height; x = sw_clampi(x, 0, w); y = sw_clampi(y, 0, h); - switch (pFormat) { - case SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: - sw_framebuffer_copy_to_GRAYALPHA(x, y, w, h, pixels); - break; - case SW_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: - sw_framebuffer_copy_to_GRAYALPHA(x, y, w, h, pixels); - break; - case SW_PIXELFORMAT_UNCOMPRESSED_R5G6B5: - sw_framebuffer_copy_to_R5G6B5(x, y, w, h, pixels); - break; - case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8: - sw_framebuffer_copy_to_R8G8B8(x, y, w, h, pixels); - break; - case SW_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: - sw_framebuffer_copy_to_R5G5B5A1(x, y, w, h, pixels); - break; - case SW_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: - sw_framebuffer_copy_to_R4G4B4A4(x, y, w, h, pixels); - break; - case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: - sw_framebuffer_copy_to_R8G8B8A8(x, y, w, h, pixels); - break; - case SW_PIXELFORMAT_UNCOMPRESSED_R32: - sw_framebuffer_copy_to_R32(x, y, w, h, pixels); - break; - case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32: - sw_framebuffer_copy_to_R32G32B32(x, y, w, h, pixels); - break; - case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: - sw_framebuffer_copy_to_R32G32B32A32(x, y, w, h, pixels); - break; - case SW_PIXELFORMAT_UNCOMPRESSED_R16: - sw_framebuffer_copy_to_R16(x, y, w, h, pixels); - break; - case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16: - sw_framebuffer_copy_to_R16G16B16(x, y, w, h, pixels); - break; - case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: - sw_framebuffer_copy_to_R16G16B16A16(x, y, w, h, pixels); - break; - default: - RLSW.errCode = SW_INVALID_ENUM; - break; + switch (pFormat) + { + case SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: sw_framebuffer_copy_to_GRAYALPHA(x, y, w, h, pixels); break; + case SW_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: sw_framebuffer_copy_to_GRAYALPHA(x, y, w, h, pixels); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R5G6B5: sw_framebuffer_copy_to_R5G6B5(x, y, w, h, pixels); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8: sw_framebuffer_copy_to_R8G8B8(x, y, w, h, pixels); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: sw_framebuffer_copy_to_R5G5B5A1(x, y, w, h, pixels); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: sw_framebuffer_copy_to_R4G4B4A4(x, y, w, h, pixels); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: sw_framebuffer_copy_to_R8G8B8A8(x, y, w, h, pixels); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R32: sw_framebuffer_copy_to_R32(x, y, w, h, pixels); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32: sw_framebuffer_copy_to_R32G32B32(x, y, w, h, pixels); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: sw_framebuffer_copy_to_R32G32B32A32(x, y, w, h, pixels); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R16: sw_framebuffer_copy_to_R16(x, y, w, h, pixels); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16: sw_framebuffer_copy_to_R16G16B16(x, y, w, h, pixels); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: sw_framebuffer_copy_to_R16G16B16A16(x, y, w, h, pixels); break; + default: RLSW.errCode = SW_INVALID_ENUM; break; } } -void swBlitFramebuffer(int xDst, int yDst, int wDst, int hDst, - int xSrc, int ySrc, int wSrc, int hSrc, - SWformat format, SWtype type, void* pixels) +void swBlitFramebuffer(int xDst, int yDst, int wDst, int hDst, int xSrc, int ySrc, int wSrc, int hSrc, SWformat format, SWtype type, void *pixels) { sw_pixelformat_t pFormat = sw_get_pixel_format(format, type); - if (wSrc <= 0) { + if (wSrc <= 0) + { RLSW.errCode = SW_INVALID_VALUE; return; } - if (hSrc <= 0) { + if (hSrc <= 0) + { RLSW.errCode = SW_INVALID_VALUE; return; } - if (wSrc > RLSW.framebuffer.width) - wSrc = RLSW.framebuffer.width; - - if (hSrc > RLSW.framebuffer.height) - hSrc = RLSW.framebuffer.height; + if (wSrc > RLSW.framebuffer.width) wSrc = RLSW.framebuffer.width; + if (hSrc > RLSW.framebuffer.height) hSrc = RLSW.framebuffer.height; xSrc = sw_clampi(xSrc, 0, wSrc); ySrc = sw_clampi(ySrc, 0, hSrc); - switch (pFormat) { - case SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: - sw_framebuffer_blit_to_GRAYALPHA(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); - break; - case SW_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: - sw_framebuffer_blit_to_GRAYALPHA(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); - break; - case SW_PIXELFORMAT_UNCOMPRESSED_R5G6B5: - sw_framebuffer_blit_to_R5G6B5(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); - break; - case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8: - sw_framebuffer_blit_to_R8G8B8(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); - break; - case SW_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: - sw_framebuffer_blit_to_R5G5B5A1(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); - break; - case SW_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: - sw_framebuffer_blit_to_R4G4B4A4(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); - break; - case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: - sw_framebuffer_blit_to_R8G8B8A8(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); - break; - case SW_PIXELFORMAT_UNCOMPRESSED_R32: - sw_framebuffer_blit_to_R32(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); - break; - case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32: - sw_framebuffer_blit_to_R32G32B32(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); - break; - case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: - sw_framebuffer_blit_to_R32G32B32A32(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); - break; - case SW_PIXELFORMAT_UNCOMPRESSED_R16: - sw_framebuffer_blit_to_R16(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); - break; - case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16: - sw_framebuffer_blit_to_R16G16B16(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); - break; - case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: - sw_framebuffer_blit_to_R16G16B16A16(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); - break; - default: - RLSW.errCode = SW_INVALID_ENUM; - break; + switch (pFormat) + { + case SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: sw_framebuffer_blit_to_GRAYALPHA(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break; + case SW_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: sw_framebuffer_blit_to_GRAYALPHA(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R5G6B5: sw_framebuffer_blit_to_R5G6B5(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8: sw_framebuffer_blit_to_R8G8B8(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: sw_framebuffer_blit_to_R5G5B5A1(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: sw_framebuffer_blit_to_R4G4B4A4(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: sw_framebuffer_blit_to_R8G8B8A8(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R32: sw_framebuffer_blit_to_R32(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32: sw_framebuffer_blit_to_R32G32B32(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: sw_framebuffer_blit_to_R32G32B32A32(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R16: sw_framebuffer_blit_to_R16(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16: sw_framebuffer_blit_to_R16G16B16(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break; + case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: sw_framebuffer_blit_to_R16G16B16A16(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break; + default: RLSW.errCode = SW_INVALID_ENUM; break; } } -void* swGetColorBuffer(int* w, int* h) +void *swGetColorBuffer(int *w, int *h) { if (w) *w = RLSW.framebuffer.width; if (h) *h = RLSW.framebuffer.height; @@ -4194,136 +3998,102 @@ void* swGetColorBuffer(int* w, int* h) void swEnable(SWstate state) { - switch (state) { - case SW_SCISSOR_TEST: - RLSW.stateFlags |= SW_STATE_SCISSOR_TEST; - break; - case SW_TEXTURE_2D: - RLSW.stateFlags |= SW_STATE_TEXTURE_2D; - break; - case SW_DEPTH_TEST: - RLSW.stateFlags |= SW_STATE_DEPTH_TEST; - break; - case SW_CULL_FACE: - RLSW.stateFlags |= SW_STATE_CULL_FACE; - break; - case SW_BLEND: - RLSW.stateFlags |= SW_STATE_BLEND; - break; - default: - RLSW.errCode = SW_INVALID_ENUM; - break; + switch (state) + { + case SW_SCISSOR_TEST: RLSW.stateFlags |= SW_STATE_SCISSOR_TEST; break; + case SW_TEXTURE_2D: RLSW.stateFlags |= SW_STATE_TEXTURE_2D; break; + case SW_DEPTH_TEST: RLSW.stateFlags |= SW_STATE_DEPTH_TEST; break; + case SW_CULL_FACE: RLSW.stateFlags |= SW_STATE_CULL_FACE; break; + case SW_BLEND: RLSW.stateFlags |= SW_STATE_BLEND; break; + default: RLSW.errCode = SW_INVALID_ENUM; break; } } void swDisable(SWstate state) { - switch (state) { - case SW_SCISSOR_TEST: - RLSW.stateFlags &= ~SW_STATE_SCISSOR_TEST; - break; - case SW_TEXTURE_2D: - RLSW.stateFlags &= ~SW_STATE_TEXTURE_2D; - break; - case SW_DEPTH_TEST: - RLSW.stateFlags &= ~SW_STATE_DEPTH_TEST; - break; - case SW_CULL_FACE: - RLSW.stateFlags &= ~SW_STATE_CULL_FACE; - break; - case SW_BLEND: - RLSW.stateFlags &= ~SW_STATE_BLEND; - break; - default: - RLSW.errCode = SW_INVALID_ENUM; - break; + switch (state) + { + case SW_SCISSOR_TEST: RLSW.stateFlags &= ~SW_STATE_SCISSOR_TEST; break; + case SW_TEXTURE_2D: RLSW.stateFlags &= ~SW_STATE_TEXTURE_2D; break; + case SW_DEPTH_TEST: RLSW.stateFlags &= ~SW_STATE_DEPTH_TEST; break; + case SW_CULL_FACE: RLSW.stateFlags &= ~SW_STATE_CULL_FACE; break; + case SW_BLEND: RLSW.stateFlags &= ~SW_STATE_BLEND; break; + default: RLSW.errCode = SW_INVALID_ENUM; break; } } -void swGetIntegerv(SWget name, int* v) +void swGetIntegerv(SWget name, int *v) { - switch (name) { - case SW_MODELVIEW_STACK_DEPTH: - *v = SW_MODELVIEW_STACK_DEPTH; - break; - case SW_PROJECTION_STACK_DEPTH: - *v = SW_PROJECTION_STACK_DEPTH; - break; - case SW_TEXTURE_STACK_DEPTH: - *v = SW_TEXTURE_STACK_DEPTH; - break; - default: - RLSW.errCode = SW_INVALID_ENUM; - break; + switch (name) + { + case SW_MODELVIEW_STACK_DEPTH: *v = SW_MODELVIEW_STACK_DEPTH; break; + case SW_PROJECTION_STACK_DEPTH: *v = SW_PROJECTION_STACK_DEPTH; break; + case SW_TEXTURE_STACK_DEPTH: *v = SW_TEXTURE_STACK_DEPTH; break; + default: RLSW.errCode = SW_INVALID_ENUM; break; } } -void swGetFloatv(SWget name, float* v) +void swGetFloatv(SWget name, float *v) { - switch (name) { - case SW_COLOR_CLEAR_VALUE: - v[0] = RLSW.clearColor[0]; - v[1] = RLSW.clearColor[1]; - v[2] = RLSW.clearColor[2]; - v[3] = RLSW.clearColor[3]; - break; - case SW_CURRENT_COLOR: - v[0] = RLSW.vertexBuffer[RLSW.vertexCounter - 1].color[0]; - v[1] = RLSW.vertexBuffer[RLSW.vertexCounter - 1].color[1]; - v[2] = RLSW.vertexBuffer[RLSW.vertexCounter - 1].color[2]; - v[3] = RLSW.vertexBuffer[RLSW.vertexCounter - 1].color[3]; - break; - case SW_CURRENT_TEXTURE_COORDS: - v[0] = RLSW.vertexBuffer[RLSW.vertexCounter - 1].texcoord[0]; - v[1] = RLSW.vertexBuffer[RLSW.vertexCounter - 1].texcoord[1]; - break; - case SW_POINT_SIZE: - v[0] = 2.0f * RLSW.pointRadius; - break; - case SW_LINE_WIDTH: - v[0] = RLSW.lineWidth; - break; - case SW_MODELVIEW_MATRIX: - for (int i = 0; i < 16; i++) { - v[i] = RLSW.stackModelview[RLSW.stackModelviewCounter - 1][i]; - } - break; - case SW_PROJECTION_MATRIX: - for (int i = 0; i < 16; i++) { - v[i] = RLSW.stackProjection[RLSW.stackProjectionCounter - 1][i]; - } - break; - case SW_TEXTURE_MATRIX: - for (int i = 0; i < 16; i++) { - v[i] = RLSW.stackTexture[RLSW.stackTextureCounter - 1][i]; - } - break; - default: - RLSW.errCode = SW_INVALID_ENUM; - break; + switch (name) + { + case SW_COLOR_CLEAR_VALUE: + { + v[0] = RLSW.clearColor[0]; + v[1] = RLSW.clearColor[1]; + v[2] = RLSW.clearColor[2]; + v[3] = RLSW.clearColor[3]; + } break; + case SW_CURRENT_COLOR: + { + v[0] = RLSW.vertexBuffer[RLSW.vertexCounter - 1].color[0]; + v[1] = RLSW.vertexBuffer[RLSW.vertexCounter - 1].color[1]; + v[2] = RLSW.vertexBuffer[RLSW.vertexCounter - 1].color[2]; + v[3] = RLSW.vertexBuffer[RLSW.vertexCounter - 1].color[3]; + } break; + case SW_CURRENT_TEXTURE_COORDS: + { + v[0] = RLSW.vertexBuffer[RLSW.vertexCounter - 1].texcoord[0]; + v[1] = RLSW.vertexBuffer[RLSW.vertexCounter - 1].texcoord[1]; + } break; + case SW_POINT_SIZE: + { + v[0] = 2.0f*RLSW.pointRadius; + } break; + case SW_LINE_WIDTH: + { + v[0] = RLSW.lineWidth; + } break; + case SW_MODELVIEW_MATRIX: + { + for (int i = 0; i < 16; i++) v[i] = RLSW.stackModelview[RLSW.stackModelviewCounter - 1][i]; + + } break; + case SW_PROJECTION_MATRIX: + { + for (int i = 0; i < 16; i++) v[i] = RLSW.stackProjection[RLSW.stackProjectionCounter - 1][i]; + + } break; + case SW_TEXTURE_MATRIX: + { + for (int i = 0; i < 16; i++) v[i] = RLSW.stackTexture[RLSW.stackTextureCounter - 1][i]; + + } break; + default: RLSW.errCode = SW_INVALID_ENUM; break; } } -const char* swGetString(SWget name) +const char *swGetString(SWget name) { - const char* result = NULL; + const char *result = NULL; - switch (name) { - case SW_VENDOR: - result = "RLSW Header"; - break; - case SW_RENDERER: - result = "RLSW Software Renderer"; - break; - case SW_VERSION: - result = "RLSW 1.0"; - break; - case SW_EXTENSIONS: - result = "None"; - break; - default: - RLSW.errCode = SW_INVALID_ENUM; - break; + switch (name) + { + case SW_VENDOR: result = "RLSW Header"; break; + case SW_RENDERER: result = "RLSW Software Renderer"; break; + case SW_VERSION: result = "RLSW 1.0"; break; + case SW_EXTENSIONS: result = "None"; break; + default: RLSW.errCode = SW_INVALID_ENUM; break; } return result; @@ -4338,7 +4108,8 @@ SWerrcode swGetError(void) void swViewport(int x, int y, int width, int height) { - if (width < 0 || height < 0) { + if ((width < 0) || (height < 0)) + { RLSW.errCode = SW_INVALID_VALUE; return; } @@ -4346,8 +4117,8 @@ void swViewport(int x, int y, int width, int height) RLSW.vpSize[0] = width; RLSW.vpSize[1] = height; - RLSW.vpHalfSize[0] = (int)(width / 2.0f + 0.5f); - RLSW.vpHalfSize[1] = (int)(height / 2.0f + 0.5f); + RLSW.vpHalfSize[0] = (int)(width/2.0f + 0.5f); + RLSW.vpHalfSize[1] = (int)(height/2.0f + 0.5f); RLSW.vpCenter[0] = x + RLSW.vpHalfSize[0]; RLSW.vpCenter[1] = y + RLSW.vpHalfSize[1]; @@ -4360,7 +4131,8 @@ void swViewport(int x, int y, int width, int height) void swScissor(int x, int y, int width, int height) { - if (width < 0 || height < 0) { + if ((width < 0) || (height < 0)) + { RLSW.errCode = SW_INVALID_VALUE; return; } @@ -4370,10 +4142,10 @@ void swScissor(int x, int y, int width, int height) RLSW.scMax[0] = sw_clampi(x + width, 0, RLSW.framebuffer.width - 1); RLSW.scMax[1] = sw_clampi(y + height, 0, RLSW.framebuffer.height - 1); - RLSW.scClipMin[0] = (2.0f * (float)RLSW.scMin[0] / (float)RLSW.vpSize[0]) - 1.0f; - RLSW.scClipMax[0] = (2.0f * (float)RLSW.scMax[0] / (float)RLSW.vpSize[0]) - 1.0f; - RLSW.scClipMax[1] = 1.0f - (2.0f * (float)RLSW.scMin[1] / (float)RLSW.vpSize[1]); - RLSW.scClipMin[1] = 1.0f - (2.0f * (float)RLSW.scMax[1] / (float)RLSW.vpSize[1]); + RLSW.scClipMin[0] = (2.0f*(float)RLSW.scMin[0]/(float)RLSW.vpSize[0]) - 1.0f; + RLSW.scClipMax[0] = (2.0f*(float)RLSW.scMax[0]/(float)RLSW.vpSize[0]) - 1.0f; + RLSW.scClipMax[1] = 1.0f - (2.0f*(float)RLSW.scMin[1]/(float)RLSW.vpSize[1]); + RLSW.scClipMin[1] = 1.0f - (2.0f*(float)RLSW.scMax[1]/(float)RLSW.vpSize[1]); } void swClearColor(float r, float g, float b, float a) @@ -4386,126 +4158,92 @@ void swClearColor(float r, float g, float b, float a) void swClear(uint32_t bitmask) { - int size = RLSW.framebuffer.width * RLSW.framebuffer.height; + int size = RLSW.framebuffer.width*RLSW.framebuffer.height; - if ((bitmask & (SW_COLOR_BUFFER_BIT | SW_DEPTH_BUFFER_BIT)) == (SW_COLOR_BUFFER_BIT | SW_DEPTH_BUFFER_BIT)) { - sw_framebuffer_fill( - RLSW.framebuffer.color, RLSW.framebuffer.depth, - size, RLSW.clearColor, RLSW.clearDepth - ); + if ((bitmask & (SW_COLOR_BUFFER_BIT | SW_DEPTH_BUFFER_BIT)) == (SW_COLOR_BUFFER_BIT | SW_DEPTH_BUFFER_BIT)) + { + sw_framebuffer_fill(RLSW.framebuffer.color, RLSW.framebuffer.depth,size, RLSW.clearColor, RLSW.clearDepth); } - else if (bitmask & (SW_COLOR_BUFFER_BIT)) { + else if (bitmask & (SW_COLOR_BUFFER_BIT)) + { sw_framebuffer_fill_color(RLSW.framebuffer.color, size, RLSW.clearColor); } - else if (bitmask & SW_DEPTH_BUFFER_BIT) { + else if (bitmask & SW_DEPTH_BUFFER_BIT) + { sw_framebuffer_fill_depth(RLSW.framebuffer.depth, size, RLSW.clearDepth); } } void swBlendFunc(SWfactor sfactor, SWfactor dfactor) { - if (!sw_is_blend_src_factor_valid(sfactor) - || !sw_is_blend_dst_factor_valid(dfactor)) { + if (!sw_is_blend_src_factor_valid(sfactor) || + !sw_is_blend_dst_factor_valid(dfactor)) + { RLSW.errCode = SW_INVALID_ENUM; return; } + RLSW.srcFactor = sfactor; RLSW.dstFactor = dfactor; - switch (sfactor) { - case SW_ZERO: - RLSW.srcFactorFunc = sw_factor_zero; - break; - case SW_ONE: - RLSW.srcFactorFunc = sw_factor_one; - break; - case SW_SRC_COLOR: - RLSW.srcFactorFunc = sw_factor_src_color; - break; - case SW_ONE_MINUS_SRC_COLOR: - RLSW.srcFactorFunc = sw_factor_one_minus_src_color; - break; - case SW_SRC_ALPHA: - RLSW.srcFactorFunc = sw_factor_src_alpha; - break; - case SW_ONE_MINUS_SRC_ALPHA: - RLSW.srcFactorFunc = sw_factor_one_minus_src_alpha; - break; - case SW_DST_ALPHA: - RLSW.srcFactorFunc = sw_factor_dst_alpha; - break; - case SW_ONE_MINUS_DST_ALPHA: - RLSW.srcFactorFunc = sw_factor_one_minus_dst_alpha; - break; - case SW_DST_COLOR: - RLSW.srcFactorFunc = sw_factor_dst_color; - break; - case SW_ONE_MINUS_DST_COLOR: - RLSW.srcFactorFunc = sw_factor_one_minus_dst_color; - break; - case SW_SRC_ALPHA_SATURATE: - RLSW.srcFactorFunc = sw_factor_src_alpha_saturate; - break; + switch (sfactor) + { + case SW_ZERO: RLSW.srcFactorFunc = sw_factor_zero; break; + case SW_ONE: RLSW.srcFactorFunc = sw_factor_one; break; + case SW_SRC_COLOR: RLSW.srcFactorFunc = sw_factor_src_color; break; + case SW_ONE_MINUS_SRC_COLOR: RLSW.srcFactorFunc = sw_factor_one_minus_src_color; break; + case SW_SRC_ALPHA: RLSW.srcFactorFunc = sw_factor_src_alpha; break; + case SW_ONE_MINUS_SRC_ALPHA: RLSW.srcFactorFunc = sw_factor_one_minus_src_alpha; break; + case SW_DST_ALPHA: RLSW.srcFactorFunc = sw_factor_dst_alpha; break; + case SW_ONE_MINUS_DST_ALPHA: RLSW.srcFactorFunc = sw_factor_one_minus_dst_alpha; break; + case SW_DST_COLOR: RLSW.srcFactorFunc = sw_factor_dst_color; break; + case SW_ONE_MINUS_DST_COLOR: RLSW.srcFactorFunc = sw_factor_one_minus_dst_color; break; + case SW_SRC_ALPHA_SATURATE: RLSW.srcFactorFunc = sw_factor_src_alpha_saturate; break; + default: break; } - switch (dfactor) { - case SW_ZERO: - RLSW.dstFactorFunc = sw_factor_zero; - break; - case SW_ONE: - RLSW.dstFactorFunc = sw_factor_one; - break; - case SW_SRC_COLOR: - RLSW.dstFactorFunc = sw_factor_src_color; - break; - case SW_ONE_MINUS_SRC_COLOR: - RLSW.dstFactorFunc = sw_factor_one_minus_src_color; - break; - case SW_SRC_ALPHA: - RLSW.dstFactorFunc = sw_factor_src_alpha; - break; - case SW_ONE_MINUS_SRC_ALPHA: - RLSW.dstFactorFunc = sw_factor_one_minus_src_alpha; - break; - case SW_DST_ALPHA: - RLSW.dstFactorFunc = sw_factor_dst_alpha; - break; - case SW_ONE_MINUS_DST_ALPHA: - RLSW.dstFactorFunc = sw_factor_one_minus_dst_alpha; - break; - case SW_DST_COLOR: - RLSW.dstFactorFunc = sw_factor_dst_color; - break; - case SW_ONE_MINUS_DST_COLOR: - RLSW.dstFactorFunc = sw_factor_one_minus_dst_color; - break; - case SW_SRC_ALPHA_SATURATE: - // NOTE: Should never be reached - break; + switch (dfactor) + { + case SW_ZERO: RLSW.dstFactorFunc = sw_factor_zero; break; + case SW_ONE: RLSW.dstFactorFunc = sw_factor_one; break; + case SW_SRC_COLOR: RLSW.dstFactorFunc = sw_factor_src_color; break; + case SW_ONE_MINUS_SRC_COLOR: RLSW.dstFactorFunc = sw_factor_one_minus_src_color; break; + case SW_SRC_ALPHA: RLSW.dstFactorFunc = sw_factor_src_alpha; break; + case SW_ONE_MINUS_SRC_ALPHA: RLSW.dstFactorFunc = sw_factor_one_minus_src_alpha; break; + case SW_DST_ALPHA: RLSW.dstFactorFunc = sw_factor_dst_alpha; break; + case SW_ONE_MINUS_DST_ALPHA: RLSW.dstFactorFunc = sw_factor_one_minus_dst_alpha; break; + case SW_DST_COLOR: RLSW.dstFactorFunc = sw_factor_dst_color; break; + case SW_ONE_MINUS_DST_COLOR: RLSW.dstFactorFunc = sw_factor_one_minus_dst_color; break; + case SW_SRC_ALPHA_SATURATE: break; + default: break; } } void swPolygonMode(SWpoly mode) { - if (!sw_is_poly_mode_valid(mode)) { + if (!sw_is_poly_mode_valid(mode)) + { RLSW.errCode = SW_INVALID_ENUM; return; } + RLSW.polyMode = mode; } void swCullFace(SWface face) { - if (!sw_is_face_valid(face)) { + if (!sw_is_face_valid(face)) + { RLSW.errCode = SW_INVALID_ENUM; return; } + RLSW.cullFace = face; } void swPointSize(float size) { - RLSW.pointRadius = floorf(size * 0.5f); + RLSW.pointRadius = floorf(size*0.5f); } void swLineWidth(float width) @@ -4515,19 +4253,12 @@ void swLineWidth(float width) void swMatrixMode(SWmatrix mode) { - switch (mode) { - case SW_PROJECTION: - RLSW.currentMatrix = &RLSW.stackProjection[RLSW.stackProjectionCounter - 1]; - break; - case SW_MODELVIEW: - RLSW.currentMatrix = &RLSW.stackModelview[RLSW.stackModelviewCounter - 1]; - break; - case SW_TEXTURE: - RLSW.currentMatrix = &RLSW.stackTexture[RLSW.stackTextureCounter - 1]; - break; - default: - RLSW.errCode = SW_INVALID_ENUM; - return; + switch (mode) + { + case SW_PROJECTION: RLSW.currentMatrix = &RLSW.stackProjection[RLSW.stackProjectionCounter - 1]; break; + case SW_MODELVIEW: RLSW.currentMatrix = &RLSW.stackModelview[RLSW.stackModelviewCounter - 1]; break; + case SW_TEXTURE: RLSW.currentMatrix = &RLSW.stackTexture[RLSW.stackTextureCounter - 1]; break; + default: RLSW.errCode = SW_INVALID_ENUM; return; } RLSW.currentMatrixMode = mode; @@ -4535,10 +4266,12 @@ void swMatrixMode(SWmatrix mode) void swPushMatrix(void) { - switch (RLSW.currentMatrixMode) { - case SW_PROJECTION: + switch (RLSW.currentMatrixMode) + { + case SW_PROJECTION: { - if (RLSW.stackProjectionCounter >= SW_MAX_PROJECTION_STACK_SIZE) { + if (RLSW.stackProjectionCounter >= SW_MAX_PROJECTION_STACK_SIZE) + { RLSW.errCode = SW_STACK_OVERFLOW; return; } @@ -4546,16 +4279,17 @@ void swPushMatrix(void) int iOld = RLSW.stackProjectionCounter - 1; int iNew = RLSW.stackProjectionCounter++; - for (int i = 0; i < 16; i++) { + for (int i = 0; i < 16; i++) + { RLSW.stackProjection[iNew][i] = RLSW.stackProjection[iOld][i]; } RLSW.currentMatrix = &RLSW.stackProjection[iNew]; - } - break; - case SW_MODELVIEW: + } break; + case SW_MODELVIEW: { - if (RLSW.stackModelviewCounter >= SW_MAX_MODELVIEW_STACK_SIZE) { + if (RLSW.stackModelviewCounter >= SW_MAX_MODELVIEW_STACK_SIZE) + { RLSW.errCode = SW_STACK_OVERFLOW; return; } @@ -4563,16 +4297,17 @@ void swPushMatrix(void) int iOld = RLSW.stackModelviewCounter - 1; int iNew = RLSW.stackModelviewCounter++; - for (int i = 0; i < 16; i++) { + for (int i = 0; i < 16; i++) + { RLSW.stackModelview[iNew][i] = RLSW.stackModelview[iOld][i]; } RLSW.currentMatrix = &RLSW.stackModelview[iNew]; - } - break; - case SW_TEXTURE: + } break; + case SW_TEXTURE: { - if (RLSW.stackTextureCounter >= SW_MAX_TEXTURE_STACK_SIZE) { + if (RLSW.stackTextureCounter >= SW_MAX_TEXTURE_STACK_SIZE) + { RLSW.errCode = SW_STACK_OVERFLOW; return; } @@ -4580,60 +4315,61 @@ void swPushMatrix(void) int iOld = RLSW.stackTextureCounter - 1; int iNew = RLSW.stackTextureCounter++; - for (int i = 0; i < 16; i++) { + for (int i = 0; i < 16; i++) + { RLSW.stackTexture[iNew][i] = RLSW.stackTexture[iOld][i]; } RLSW.currentMatrix = &RLSW.stackTexture[iNew]; - } - break; + } break; + default: break; } } void swPopMatrix(void) { - switch (RLSW.currentMatrixMode) { - case SW_PROJECTION: + switch (RLSW.currentMatrixMode) + { + case SW_PROJECTION: { - if (RLSW.stackProjectionCounter <= 0) { + if (RLSW.stackProjectionCounter <= 0) + { RLSW.errCode = SW_STACK_UNDERFLOW; return; } RLSW.currentMatrix = &RLSW.stackProjection[--RLSW.stackProjectionCounter]; RLSW.isDirtyMVP = true; //< The MVP is considered to have been changed - } - break; - case SW_MODELVIEW: + } break; + case SW_MODELVIEW: { - if (RLSW.stackModelviewCounter <= 0) { + if (RLSW.stackModelviewCounter <= 0) + { RLSW.errCode = SW_STACK_UNDERFLOW; return; } RLSW.currentMatrix = &RLSW.stackModelview[--RLSW.stackModelviewCounter]; RLSW.isDirtyMVP = true; //< The MVP is considered to have been changed - } - break; - case SW_TEXTURE: + } break; + case SW_TEXTURE: { - if (RLSW.stackTextureCounter <= 0) { + if (RLSW.stackTextureCounter <= 0) + { RLSW.errCode = SW_STACK_UNDERFLOW; return; } RLSW.currentMatrix = &RLSW.stackTexture[--RLSW.stackTextureCounter]; - } - break; + } break; + default: break; } } void swLoadIdentity(void) { sw_matrix_id(*RLSW.currentMatrix); - if (RLSW.currentMatrixMode != SW_TEXTURE) { - RLSW.isDirtyMVP = true; - } + if (RLSW.currentMatrixMode != SW_TEXTURE) RLSW.isDirtyMVP = true; } void swTranslatef(float x, float y, float z) @@ -4647,9 +4383,7 @@ void swTranslatef(float x, float y, float z) sw_matrix_mul(*RLSW.currentMatrix, mat, *RLSW.currentMatrix); - if (RLSW.currentMatrixMode != SW_TEXTURE) { - RLSW.isDirtyMVP = true; - } + if (RLSW.currentMatrixMode != SW_TEXTURE) RLSW.isDirtyMVP = true; } void swRotatef(float angle, float x, float y, float z) @@ -4658,7 +4392,8 @@ 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; y *= invLength; @@ -4693,9 +4428,7 @@ void swRotatef(float angle, float x, float y, float z) sw_matrix_mul(*RLSW.currentMatrix, mat, *RLSW.currentMatrix); - if (RLSW.currentMatrixMode != SW_TEXTURE) { - RLSW.isDirtyMVP = true; - } + if (RLSW.currentMatrixMode != SW_TEXTURE) RLSW.isDirtyMVP = true; } void swScalef(float x, float y, float z) @@ -4709,18 +4442,14 @@ void swScalef(float x, float y, float z) sw_matrix_mul(*RLSW.currentMatrix, mat, *RLSW.currentMatrix); - if (RLSW.currentMatrixMode != SW_TEXTURE) { - RLSW.isDirtyMVP = true; - } + if (RLSW.currentMatrixMode != SW_TEXTURE) RLSW.isDirtyMVP = true; } -void swMultMatrixf(const float* mat) +void swMultMatrixf(const float *mat) { sw_matrix_mul(*RLSW.currentMatrix, mat, *RLSW.currentMatrix); - if (RLSW.currentMatrixMode != SW_TEXTURE) { - RLSW.isDirtyMVP = true; - } + if (RLSW.currentMatrixMode != SW_TEXTURE) RLSW.isDirtyMVP = true; } void swFrustum(double left, double right, double bottom, double top, double znear, double zfar) @@ -4731,19 +4460,19 @@ void swFrustum(double left, double right, double bottom, double top, double znea double tb = top - bottom; double fn = zfar - znear; - mat[0] = (znear*2.0)/rl; + mat[0] = (float)(znear*2.0)/rl; mat[1] = 0.0f; mat[2] = 0.0f; mat[3] = 0.0f; mat[4] = 0.0f; - mat[5] = (znear*2.0)/tb; + mat[5] = (float)(znear*2.0)/tb; mat[6] = 0.0f; mat[7] = 0.0f; - mat[8] = (right + left)/rl; - mat[9] = (top + bottom)/tb; - mat[10] = -(zfar + znear)/fn; + mat[8] = (float)(right + left)/rl; + mat[9] = (float)(top + bottom)/tb; + mat[10] = -(float)(zfar + znear)/fn; mat[11] = -1.0f; mat[12] = 0.0f; @@ -4753,9 +4482,7 @@ void swFrustum(double left, double right, double bottom, double top, double znea sw_matrix_mul(*RLSW.currentMatrix, *RLSW.currentMatrix, mat); - if (RLSW.currentMatrixMode != SW_TEXTURE) { - RLSW.isDirtyMVP = true; - } + if (RLSW.currentMatrixMode != SW_TEXTURE) RLSW.isDirtyMVP = true; } void swOrtho(double left, double right, double bottom, double top, double znear, double zfar) @@ -4766,72 +4493,60 @@ void swOrtho(double left, double right, double bottom, double top, double znear, double tb = top - bottom; double fn = zfar - znear; - mat[0] = 2.0f/rl; + mat[0] = 2.0f/(float)rl; mat[1] = 0.0f; mat[2] = 0.0f; mat[3] = 0.0f; mat[4] = 0.0f; - mat[5] = 2.0f/tb; + mat[5] = 2.0f/(float)tb; mat[6] = 0.0f; mat[7] = 0.0f; mat[8] = 0.0f; mat[9] = 0.0f; - mat[10] = -2.0f/fn; + mat[10] = -2.0f/(float)fn; mat[11] = 0.0f; - mat[12] = -(left + right)/rl; - mat[13] = -(top + bottom)/tb; - mat[14] = -(zfar + znear)/fn; + mat[12] = -(float)(left + right)/rl; + mat[13] = -(float)(top + bottom)/tb; + mat[14] = -(float)(zfar + znear)/fn; mat[15] = 1.0f; sw_matrix_mul(*RLSW.currentMatrix, *RLSW.currentMatrix, mat); - if (RLSW.currentMatrixMode != SW_TEXTURE) { - RLSW.isDirtyMVP = true; - } + if (RLSW.currentMatrixMode != SW_TEXTURE) RLSW.isDirtyMVP = true; } void swBegin(SWdraw mode) { - /* --- Check if the draw mode is valid --- */ - - if (!sw_is_draw_mode_valid(mode)) { + // Check if the draw mode is valid + if (!sw_is_draw_mode_valid(mode)) + { RLSW.errCode = SW_INVALID_ENUM; return; } - /* --- Recalculate the MVP if this is needed --- */ - - if (RLSW.isDirtyMVP) { - sw_matrix_mul_rst( - RLSW.matMVP, + // Recalculate the MVP if this is needed + if (RLSW.isDirtyMVP) + { + sw_matrix_mul_rst(RLSW.matMVP, RLSW.stackModelview[RLSW.stackModelviewCounter - 1], - RLSW.stackProjection[RLSW.stackProjectionCounter - 1] - ); + RLSW.stackProjection[RLSW.stackProjectionCounter - 1]); + RLSW.isDirtyMVP = false; } - /* --- Obtaining the number of vertices needed for this primitive --- */ - - switch (mode) { - case SW_POINTS: - RLSW.reqVertices = 1; - break; - case SW_LINES: - RLSW.reqVertices = 2; - break; - case SW_TRIANGLES: - RLSW.reqVertices = 3; - break; - case SW_QUADS: - RLSW.reqVertices = 4; - break; + // Obtain the number of vertices needed for this primitive + switch (mode) + { + case SW_POINTS: RLSW.reqVertices = 1; break; + case SW_LINES: RLSW.reqVertices = 2; break; + case SW_TRIANGLES: RLSW.reqVertices = 3; break; + case SW_QUADS: RLSW.reqVertices = 4; break; } - - /* --- Initialize some values --- */ + // Initialize required values RLSW.vertexCounter = 0; RLSW.drawMode = mode; } @@ -4853,7 +4568,7 @@ void swVertex2f(float x, float y) swVertex4fv(v); } -void swVertex2fv(const float* v) +void swVertex2fv(const float *v) { const float v4[4] = { v[0], v[1], 0.0f, 1.0f }; swVertex4fv(v4); @@ -4871,7 +4586,7 @@ void swVertex3f(float x, float y, float z) swVertex4fv(v); } -void swVertex3fv(const float* v) +void swVertex3fv(const float *v) { const float v4[4] = { v[0], v[1], v[2], 1.0f }; swVertex4fv(v4); @@ -4889,49 +4604,34 @@ void swVertex4f(float x, float y, float z, float w) swVertex4fv(v); } -void swVertex4fv(const float* v) +void swVertex4fv(const float *v) { - /* --- Copy the position in the current vertex --- */ + // Copy the position in the current vertex + sw_vertex_t *vertex = &RLSW.vertexBuffer[RLSW.vertexCounter++]; + for (int i = 0; i < 4; i++) vertex->position[i] = v[i]; - sw_vertex_t* vertex = &RLSW.vertexBuffer[RLSW.vertexCounter++]; + // Copy additonal vertex data + for (int i = 0; i < 2; i++) vertex->texcoord[i] = RLSW.current.texcoord[i]; + for (int i = 0; i < 4; i++) vertex->color[i] = RLSW.current.color[i]; - for (int i = 0; i < 4; i++) { - vertex->position[i] = v[i]; - } + // Calculation of homogeneous coordinates + const float *m = RLSW.matMVP; + vertex->homogeneous[0] = m[0]*v[0] + m[4]*v[1] + m[8]*v[2] + m[12]*v[3]; + vertex->homogeneous[1] = m[1]*v[0] + m[5]*v[1] + m[9]*v[2] + m[13]*v[3]; + vertex->homogeneous[2] = m[2]*v[0] + m[6]*v[1] + m[10]*v[2] + m[14]*v[3]; + vertex->homogeneous[3] = m[3]*v[0] + m[7]*v[1] + m[11]*v[2] + m[15]*v[3]; - /* --- Copy additonal vertex data --- */ - - for (int i = 0; i < 2; i++) { - vertex->texcoord[i] = RLSW.current.texcoord[i]; - } - - for (int i = 0; i < 4; i++) { - vertex->color[i] = RLSW.current.color[i]; - } - - /* --- Calculation of homogeneous coordinates --- */ - - const float* m = RLSW.matMVP; - - vertex->homogeneous[0] = m[0] * v[0] + m[4] * v[1] + m[8] * v[2] + m[12] * v[3]; - vertex->homogeneous[1] = m[1] * v[0] + m[5] * v[1] + m[9] * v[2] + m[13] * v[3]; - vertex->homogeneous[2] = m[2] * v[0] + m[6] * v[1] + m[10] * v[2] + m[14] * v[3]; - vertex->homogeneous[3] = m[3] * v[0] + m[7] * v[1] + m[11] * v[2] + m[15] * v[3]; - - /* --- Immediate rendering of the primitive if the required number is reached --- */ - - if (RLSW.vertexCounter == RLSW.reqVertices) { - switch (RLSW.polyMode) { - case SW_FILL: - sw_poly_fill_render(); - break; - case SW_LINE: - sw_poly_line_render(); - break; - case SW_POINT: - sw_poly_point_render(); - break; + // Immediate rendering of the primitive if the required number is reached + if (RLSW.vertexCounter == RLSW.reqVertices) + { + switch (RLSW.polyMode) + { + case SW_FILL: sw_poly_fill_render(); break; + case SW_LINE: sw_poly_line_render(); break; + case SW_POINT: sw_poly_point_render(); break; + default: break; } + RLSW.vertexCounter = 0; } } @@ -4939,20 +4639,20 @@ void swVertex4fv(const float* v) void swColor3ub(uint8_t r, uint8_t g, uint8_t b) { float cv[4]; - cv[0] = (float)r / 255; - cv[1] = (float)g / 255; - cv[2] = (float)b / 255; + cv[0] = (float)r/255; + cv[1] = (float)g/255; + cv[2] = (float)b/255; cv[3] = 1.0f; swColor4fv(cv); } -void swColor3ubv(const uint8_t* v) +void swColor3ubv(const uint8_t *v) { float cv[4]; - cv[0] = (float)v[0] / 255; - cv[1] = (float)v[1] / 255; - cv[2] = (float)v[2] / 255; + cv[0] = (float)v[0]/255; + cv[1] = (float)v[1]/255; + cv[2] = (float)v[2]/255; cv[3] = 1.0f; swColor4fv(cv); @@ -4969,7 +4669,7 @@ void swColor3f(float r, float g, float b) swColor4fv(cv); } -void swColor3fv(const float* v) +void swColor3fv(const float *v) { float cv[4]; cv[0] = v[0]; @@ -4983,21 +4683,21 @@ void swColor3fv(const float* v) void swColor4ub(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { float cv[4]; - cv[0] = (float)r / 255; - cv[1] = (float)g / 255; - cv[2] = (float)b / 255; - cv[3] = (float)a / 255; + cv[0] = (float)r/255; + cv[1] = (float)g/255; + cv[2] = (float)b/255; + cv[3] = (float)a/255; swColor4fv(cv); } -void swColor4ubv(const uint8_t* v) +void swColor4ubv(const uint8_t *v) { float cv[4]; - cv[0] = (float)v[0] / 255; - cv[1] = (float)v[1] / 255; - cv[2] = (float)v[2] / 255; - cv[3] = (float)v[3] / 255; + cv[0] = (float)v[0]/255; + cv[1] = (float)v[1]/255; + cv[2] = (float)v[2]/255; + cv[3] = (float)v[3]/255; swColor4fv(cv); } @@ -5013,49 +4713,42 @@ void swColor4f(float r, float g, float b, float a) swColor4fv(cv); } -void swColor4fv(const float* v) +void swColor4fv(const float *v) { - for (int i = 0; i < 4; i++) { - RLSW.current.color[i] = v[i]; - } + for (int i = 0; i < 4; i++) RLSW.current.color[i] = v[i]; } void swTexCoord2f(float u, float v) { - const float* m = RLSW.stackTexture[RLSW.stackTextureCounter - 1]; + const float *m = RLSW.stackTexture[RLSW.stackTextureCounter - 1]; - RLSW.current.texcoord[0] = m[0] * u + m[4] * v + m[12]; - RLSW.current.texcoord[1] = m[1] * u + m[5] * v + m[13]; + RLSW.current.texcoord[0] = m[0]*u + m[4]*v + m[12]; + RLSW.current.texcoord[1] = m[1]*u + m[5]*v + m[13]; } -void swTexCoord2fv(const float* v) +void swTexCoord2fv(const float *v) { - const float* m = RLSW.stackTexture[RLSW.stackTextureCounter - 1]; + const float *m = RLSW.stackTexture[RLSW.stackTextureCounter - 1]; - RLSW.current.texcoord[0] = m[0] * v[0] + m[4] * v[1] + m[12]; - RLSW.current.texcoord[1] = m[1] * v[0] + m[5] * v[1] + m[13]; + RLSW.current.texcoord[0] = m[0]*v[0] + m[4]*v[1] + m[12]; + RLSW.current.texcoord[1] = m[1]*v[0] + m[5]*v[1] + m[13]; } void swBindArray(SWarray type, void *buffer) { - switch (type) { - case SW_VERTEX_ARRAY: - RLSW.array.positions = buffer; - break; - case SW_TEXTURE_COORD_ARRAY: - RLSW.array.texcoords = buffer; - break; - case SW_COLOR_ARRAY: - RLSW.array.colors = buffer; - break; - default: - break; + switch (type) + { + case SW_VERTEX_ARRAY: RLSW.array.positions = buffer; break; + case SW_TEXTURE_COORD_ARRAY: RLSW.array.texcoords = buffer; break; + case SW_COLOR_ARRAY: RLSW.array.colors = buffer; break; + default: break; } } void swDrawArrays(SWdraw mode, int offset, int count) { - if (RLSW.array.positions == 0) { + if (RLSW.array.positions == 0) + { RLSW.errCode = SW_INVALID_OPERATION; return; } @@ -5065,98 +4758,105 @@ void swDrawArrays(SWdraw mode, int offset, int count) swTexCoord2f(0.0f, 0.0f); swColor4f(1.0f, 1.0f, 1.0f, 1.0f); - for (int i = offset; i < count; i++) { - if (RLSW.array.texcoords) swTexCoord2fv(RLSW.array.texcoords + 2 * i); - if (RLSW.array.colors) swColor4ubv(RLSW.array.colors + 4 * i); - swVertex3fv(RLSW.array.positions + 3 * i); + for (int i = offset; i < count; i++) + { + if (RLSW.array.texcoords) swTexCoord2fv(RLSW.array.texcoords + 2*i); + if (RLSW.array.colors) swColor4ubv(RLSW.array.colors + 4*i); + swVertex3fv(RLSW.array.positions + 3*i); } } swEnd(); } -void swGenTextures(int count, uint32_t* textures) +void swGenTextures(int count, uint32_t *textures) { - if (count == 0 || textures == NULL) { - return; - } + if ((count == 0) || (textures == NULL)) return; - for (int i = 0; i < count; i++) { - if (RLSW.loadedTextureCount >= SW_MAX_TEXTURES) { - RLSW.errCode = SW_STACK_OVERFLOW; //< Out of memory, not really stack overflow + for (int i = 0; i < count; i++) + { + if (RLSW.loadedTextureCount >= SW_MAX_TEXTURES) + { + RLSW.errCode = SW_STACK_OVERFLOW; // WARNING: Out of memory, not really stack overflow return; } + uint32_t id = 0; - if (RLSW.freeTextureIdCount > 0) { - id = RLSW.freeTextureIds[--RLSW.freeTextureIdCount]; - } - else { - id = RLSW.loadedTextureCount++; - } + if (RLSW.freeTextureIdCount > 0) id = RLSW.freeTextureIds[--RLSW.freeTextureIdCount]; + else id = RLSW.loadedTextureCount++; + RLSW.loadedTextures[id] = RLSW.loadedTextures[0]; textures[i] = id; } } -void swDeleteTextures(int count, uint32_t* textures) +void swDeleteTextures(int count, uint32_t *textures) { - if (count == 0 || textures == NULL) { - return; - } + if ((count == 0) || (textures == NULL)) return; - for (int i = 0; i < count; i++) { - if (!sw_is_texture_valid(textures[i])) { + for (int i = 0; i < count; i++) + { + if (!sw_is_texture_valid(textures[i])) + { RLSW.errCode = SW_INVALID_VALUE; continue; } - if (RLSW.loadedTextures[textures[i]].copy) { + + if (RLSW.loadedTextures[textures[i]].copy) + { SW_FREE(RLSW.loadedTextures[textures[i]].pixels.ptr); } + RLSW.loadedTextures[textures[i]].pixels.cptr = NULL; RLSW.freeTextureIds[RLSW.freeTextureIdCount++] = textures[i]; } } -void swTexImage2D(int width, int height, SWformat format, SWtype type, bool copy, const void* data) +void swTexImage2D(int width, int height, SWformat format, SWtype type, bool copy, const void *data) { uint32_t id = RLSW.currentTexture; - if (!sw_is_texture_valid(id)) { + if (!sw_is_texture_valid(id)) + { RLSW.errCode = SW_INVALID_VALUE; return; } int pixelFormat = sw_get_pixel_format(format, type); - if (pixelFormat <= SW_PIXELFORMAT_UNKNOWN) { + if (pixelFormat <= SW_PIXELFORMAT_UNKNOWN) + { RLSW.errCode = SW_INVALID_ENUM; return; } - sw_texture_t* texture = &RLSW.loadedTextures[id]; + sw_texture_t *texture = &RLSW.loadedTextures[id]; - if (copy) { + if (copy) + { int bytes = sw_get_pixel_bytes(pixelFormat); - int size = bytes * width * height; + int size = bytes*width*height; texture->pixels.ptr = SW_MALLOC(size); - if (texture->pixels.ptr == NULL) { - RLSW.errCode = SW_STACK_OVERFLOW; //< Out of memory... + + if (texture->pixels.ptr == NULL) + { + RLSW.errCode = SW_STACK_OVERFLOW; // WARING: Out of memory... return; } - for (int i = 0; i < size; i++) { - ((uint8_t*)texture->pixels.ptr)[i] = ((uint8_t*)data)[i]; + + for (int i = 0; i < size; i++) + { + ((uint8_t *)texture->pixels.ptr)[i] = ((uint8_t *)data)[i]; } } - else { - texture->pixels.cptr = data; - } + else texture->pixels.cptr = data; texture->width = width; texture->height = height; texture->wMinus1 = width - 1; texture->hMinus1 = height - 1; texture->format = pixelFormat; - texture->tx = 1.0f / width; - texture->ty = 1.0f / height; + texture->tx = 1.0f/width; + texture->ty = 1.0f/height; texture->copy = copy; } @@ -5164,62 +4864,70 @@ void swTexParameteri(int param, int value) { uint32_t id = RLSW.currentTexture; - if (!sw_is_texture_valid(id)) { + if (!sw_is_texture_valid(id)) + { RLSW.errCode = SW_INVALID_VALUE; return; } - sw_texture_t* texture = &RLSW.loadedTextures[id]; + sw_texture_t *texture = &RLSW.loadedTextures[id]; - switch (param) { + switch (param) + { + case SW_TEXTURE_MIN_FILTER: + { + if (!sw_is_texture_filter_valid(value)) + { + RLSW.errCode = SW_INVALID_ENUM; + return; + } - case SW_TEXTURE_MIN_FILTER: - if (!sw_is_texture_filter_valid(value)) { - RLSW.errCode = SW_INVALID_ENUM; - return; - } - texture->minFilter = value; - break; + texture->minFilter = value; + } break; + case SW_TEXTURE_MAG_FILTER: + { + if (!sw_is_texture_filter_valid(value)) + { + RLSW.errCode = SW_INVALID_ENUM; + return; + } - case SW_TEXTURE_MAG_FILTER: - if (!sw_is_texture_filter_valid(value)) { - RLSW.errCode = SW_INVALID_ENUM; - return; - } - texture->magFilter = value; - break; + texture->magFilter = value; + } break; + case SW_TEXTURE_WRAP_S: + { + if (!sw_is_texture_wrap_valid(value)) + { + RLSW.errCode = SW_INVALID_ENUM; + return; + } - case SW_TEXTURE_WRAP_S: - if (!sw_is_texture_wrap_valid(value)) { - RLSW.errCode = SW_INVALID_ENUM; - return; - } - texture->sWrap = value; - break; - - case SW_TEXTURE_WRAP_T: - if (!sw_is_texture_wrap_valid(value)) { - RLSW.errCode = SW_INVALID_ENUM; - return; - } - texture->tWrap = value; - break; - - default: - RLSW.errCode = SW_INVALID_ENUM; - return; + texture->sWrap = value; + } break; + case SW_TEXTURE_WRAP_T: + { + if (!sw_is_texture_wrap_valid(value)) + { + RLSW.errCode = SW_INVALID_ENUM; + return; + } + texture->tWrap = value; + } break; + default: RLSW.errCode = SW_INVALID_ENUM; break; } } void swBindTexture(uint32_t id) { - if (id >= SW_MAX_TEXTURES) { + if (id >= SW_MAX_TEXTURES) + { RLSW.errCode = SW_INVALID_VALUE; return; } - if (RLSW.loadedTextures[id].pixels.cptr == NULL) { + if (RLSW.loadedTextures[id].pixels.cptr == NULL) + { RLSW.errCode = SW_INVALID_OPERATION; return; } @@ -5227,4 +4935,4 @@ void swBindTexture(uint32_t id) RLSW.currentTexture = id; } -#endif // RLSW_IMPL +#endif // RLSW_IMPLEMENTATION diff --git a/src/platforms/rcore_desktop_sdl.c b/src/platforms/rcore_desktop_sdl.c index 00a6ccc47..6655db460 100644 --- a/src/platforms/rcore_desktop_sdl.c +++ b/src/platforms/rcore_desktop_sdl.c @@ -1233,7 +1233,7 @@ void SwapScreenBuffer(void) { #if defined(GRAPHICS_API_OPENGL_11_SOFTWARE) // NOTE: We use a preprocessor condition here because `rlCopyFramebuffer` is only declared for software rendering - SDL_Surface* surface = SDL_GetWindowSurface(platform.window); + SDL_Surface *surface = SDL_GetWindowSurface(platform.window); rlCopyFramebuffer(0, 0, CORE.Window.render.width, CORE.Window.render.height, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, surface->pixels); SDL_UpdateWindowSurface(platform.window); #else diff --git a/src/platforms/rcore_drm.c b/src/platforms/rcore_drm.c index fe0ac5fd8..e067fd82a 100644 --- a/src/platforms/rcore_drm.c +++ b/src/platforms/rcore_drm.c @@ -818,14 +818,14 @@ void SwapScreenBuffer(void) platform.prevBO = bo; #else // Software rendering buffer swap - if ((-1 == platform.fd) || !platform.connector || (platform.modeIndex < 0)) + if ((platform.fd == -1) || !platform.connector || (platform.modeIndex < 0)) { TRACELOG(LOG_ERROR, "DISPLAY: DRM initialization failed to swap"); return; } // Get the software rendered color buffer - int bufferWidth, bufferHeight; + int bufferWidth = 0, bufferHeight = 0; void *colorBuffer = swGetColorBuffer(&bufferWidth, &bufferHeight); if (!colorBuffer) { @@ -849,7 +849,7 @@ void SwapScreenBuffer(void) #endif // Create a dumb buffer for software rendering - struct drm_mode_create_dumb creq = {0}; + struct drm_mode_create_dumb creq = { 0 }; creq.width = width; creq.height = height; creq.bpp = bpp; @@ -863,28 +863,25 @@ 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); + result = drmModeAddFB(platform.fd, width, height, depth, bpp, creq.pitch, creq.handle, &fb); if (result != 0) { TRACELOG(LOG_ERROR, "DISPLAY: drmModeAddFB() failed with result: %d (%s)", result, strerror(errno)); - struct drm_mode_destroy_dumb dreq = {0}; + struct drm_mode_destroy_dumb dreq = { 0 }; dreq.handle = creq.handle; drmIoctl(platform.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq); return; } // Map the dumb buffer to copy our software rendered buffer - struct drm_mode_map_dumb mreq = {0}; + struct drm_mode_map_dumb mreq = { 0 }; mreq.handle = creq.handle; result = drmIoctl(platform.fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq); if (result != 0) { TRACELOG(LOG_ERROR, "DISPLAY: Failed to map dumb buffer: %s", strerror(errno)); drmModeRmFB(platform.fd, fb); - struct drm_mode_destroy_dumb dreq = {0}; + struct drm_mode_destroy_dumb dreq = { 0 }; dreq.handle = creq.handle; drmIoctl(platform.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq); return; @@ -896,7 +893,7 @@ void SwapScreenBuffer(void) { TRACELOG(LOG_ERROR, "DISPLAY: Failed to mmap dumb buffer: %s", strerror(errno)); drmModeRmFB(platform.fd, fb); - struct drm_mode_destroy_dumb dreq = {0}; + struct drm_mode_destroy_dumb dreq = { 0 }; dreq.handle = creq.handle; drmIoctl(platform.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq); return; @@ -919,10 +916,7 @@ void SwapScreenBuffer(void) // Find a CRTC compatible with the connector uint32_t crtcId = 0; - if (platform.crtc) - { - crtcId = platform.crtc->crtc_id; - } + if (platform.crtc) crtcId = platform.crtc->crtc_id; else { // Find a CRTC that's compatible with this connector @@ -939,10 +933,7 @@ void SwapScreenBuffer(void) // Check which CRTCs are compatible with this connector drmModeEncoder *encoder = NULL; - if (platform.connector->encoder_id) - { - encoder = drmModeGetEncoder(platform.fd, platform.connector->encoder_id); - } + if (platform.connector->encoder_id) encoder = drmModeGetEncoder(platform.fd, platform.connector->encoder_id); if (encoder && encoder->crtc_id) { @@ -962,6 +953,7 @@ void SwapScreenBuffer(void) platform.crtc = crtc; break; } + if (crtc) drmModeFreeCrtc(crtc); } } @@ -981,9 +973,7 @@ void SwapScreenBuffer(void) } // Set CRTC with better error handling - result = drmModeSetCrtc(platform.fd, crtcId, fb, 0, 0, - &platform.connector->connector_id, 1, - mode); + result = drmModeSetCrtc(platform.fd, crtcId, fb, 0, 0, &platform.connector->connector_id, 1, mode); if (result != 0) { TRACELOG(LOG_ERROR, "DISPLAY: drmModeSetCrtc() failed with result: %d (%s)", result, strerror(errno)); @@ -1001,10 +991,7 @@ void SwapScreenBuffer(void) if (platform.prevFB) { result = drmModeRmFB(platform.fd, platform.prevFB); - if (result != 0) - { - TRACELOG(LOG_WARNING, "DISPLAY: drmModeRmFB() failed with result: %d", result); - } + if (result != 0) TRACELOG(LOG_WARNING, "DISPLAY: drmModeRmFB() failed with result: %d", result); } platform.prevFB = fb; @@ -1249,7 +1236,7 @@ int InitPlatform(void) // In certain cases the status of the conneciton is reported as UKNOWN, but it is still connected // This might be a hardware or software limitation like on Raspberry Pi Zero with composite output // WARNING: Accept CONNECTED, UNKNOWN and even those without encoder_id connectors for software mode - if (((con->connection == DRM_MODE_CONNECTED) || (con->connection == DRM_MODE_UNKNOWNCONNECTION)) && (con->count_modes > 0)//(con->encoder_id)) + if (((con->connection == DRM_MODE_CONNECTED) || (con->connection == DRM_MODE_UNKNOWNCONNECTION)) && (con->count_modes > 0)) { #if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE) // For hardware rendering, we need an encoder_id @@ -1259,10 +1246,7 @@ int InitPlatform(void) platform.connector = con; break; } - else - { - TRACELOG(LOG_TRACE, "DISPLAY: DRM connector %i connected but no encoder", i); - } + else TRACELOG(LOG_TRACE, "DISPLAY: DRM connector %i connected but no encoder", i); #else // For software rendering, we can accept even without encoder_id TRACELOG(LOG_TRACE, "DISPLAY: DRM connector %i suitable for software rendering", i); diff --git a/src/rlgl.h b/src/rlgl.h index 5e8cf2bfa..ecd3795a9 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -776,8 +776,8 @@ RLAPI void rlFramebufferAttach(unsigned int fboId, unsigned int texId, int attac RLAPI bool rlFramebufferComplete(unsigned int id); // Verify framebuffer is complete RLAPI void rlUnloadFramebuffer(unsigned int id); // Delete framebuffer from GPU #if defined(GRAPHICS_API_OPENGL_11_SOFTWARE) -RLAPI void rlCopyFramebuffer(int x, int y, int w, int h, int format, void* pixels); -RLAPI void rlResizeFramebuffer(int width, int height); +RLAPI void rlCopyFramebuffer(int x, int y, int width, int height, int format, void *pixels); // Copy framebuffer pixel data to internal buffer +RLAPI void rlResizeFramebuffer(int width, int height); // Resize internal framebuffer #endif // Shaders management @@ -846,7 +846,7 @@ RLAPI void rlLoadDrawQuad(void); // Load and draw a quad #if defined(GRAPHICS_API_OPENGL_11) #if defined(GRAPHICS_API_OPENGL_11_SOFTWARE) - #define RLSW_IMPL + #define RLSW_IMPLEMENTATION #define SW_MALLOC(sz) RL_MALLOC(sz) #define SW_REALLOC(ptr, newSz) RL_REALLOC(ptr, newSz) #define SW_FREE(ptr) RL_FREE(ptr) @@ -2357,9 +2357,10 @@ void rlglInit(int width, int height) #endif #if defined(GRAPHICS_API_OPENGL_11_SOFTWARE) - if (!swInit(width, height)) + int result = swInit(width, height); // Initialize software renderer backend + if (result == 0) { - TRACELOG(RL_LOG_ERROR, "RLGL: Software renderer initialization failed!"); + TRACELOG(RL_LOG_ERROR, "RLSW: Software renderer initialization failed!"); exit(-1); } #endif @@ -2385,14 +2386,14 @@ void rlglClose(void) #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) rlUnloadRenderBatch(RLGL.defaultBatch); - rlUnloadShaderDefault(); // Unload default shader + rlUnloadShaderDefault(); // Unload default shader glDeleteTextures(1, &RLGL.State.defaultTextureId); // Unload default texture TRACELOG(RL_LOG_INFO, "TEXTURE: [ID %i] Default texture unloaded successfully", RLGL.State.defaultTextureId); #endif #if defined(GRAPHICS_API_OPENGL_11_SOFTWARE) - swClose(); + swClose(); // Unload sofware renderer resources #endif } @@ -2703,6 +2704,7 @@ void *rlGetProcAddress(const char *procName) int rlGetVersion(void) { int glVersion = 0; + #if defined(GRAPHICS_API_OPENGL_11_SOFTWARE) glVersion = RL_OPENGL_11_SOFTWARE; #elif defined(GRAPHICS_API_OPENGL_11) @@ -3747,13 +3749,15 @@ void *rlReadTexturePixels(unsigned int id, int width, int height, int format) } #if defined(GRAPHICS_API_OPENGL_11_SOFTWARE) -void rlCopyFramebuffer(int x, int y, int w, int h, int format, void* pixels) +// Copy framebuffer pixel data to internal buffer +void rlCopyFramebuffer(int x, int y, int width, int height, int format, void* pixels) { unsigned int glInternalFormat, glFormat, glType; - rlGetGlTextureFormats(format, &glInternalFormat, &glFormat, &glType); - swCopyFramebuffer(x, y, w, h, glFormat, glType, pixels); + rlGetGlTextureFormats(format, &glInternalFormat, &glFormat, &glType); // Get OpenGL texture format + swCopyFramebuffer(x, y, width, height, glFormat, glType, pixels); } +// Resize internal framebuffer void rlResizeFramebuffer(int width, int height) { swResizeFramebuffer(width, height); From 37149082e85cfa40550bed7c9b3d53638c71994f Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 29 Sep 2025 18:05:16 +0200 Subject: [PATCH 052/167] Avoid warnings --- src/rtext.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/rtext.c b/src/rtext.c index edfe33c8b..ce9f381c4 100644 --- a/src/rtext.c +++ b/src/rtext.c @@ -1452,7 +1452,7 @@ Rectangle GetGlyphAtlasRec(Font font, int codepoint) char **LoadTextLines(const char *text, int *count) { int lineCount = 1; - int textSize = strlen(text); + int textSize = (int)strlen(text); // Text pass to get required line count for (int i = 0; i < textSize; i++) @@ -1679,7 +1679,7 @@ char *GetTextBetween(const char *text, const char *begin, const char *end) if (beginIndex > -1) { - int beginLen = strlen(begin); + int beginLen = (int)strlen(begin); int endIndex = TextFindIndex(text + beginIndex + beginLen, end); if (endIndex > -1) @@ -1758,15 +1758,15 @@ char *TextReplaceBetween(const char *text, const char *begin, const char *end, c if (beginIndex > -1) { - int beginLen = strlen(begin); + int beginLen = (int)strlen(begin); int endIndex = TextFindIndex(text + beginIndex + beginLen, end); if (endIndex > -1) { endIndex += (beginIndex + beginLen); - int textLen = strlen(text); - int replaceLen = (replacement == NULL)? 0 : strlen(replacement); + int textLen = (int)strlen(text); + int replaceLen = (replacement == NULL)? 0 : (int)strlen(replacement); int toreplaceLen = endIndex - beginIndex - beginLen; result = (char *)RL_CALLOC(textLen + replaceLen - toreplaceLen + 1, sizeof(char)); From 56e32f2c3ed7add455e8c90d158df43b3690a900 Mon Sep 17 00:00:00 2001 From: zero <103244351+zerohorsepower@users.noreply.github.com> Date: Tue, 30 Sep 2025 06:59:44 -0300 Subject: [PATCH 053/167] ADDED: example: `shapes_bullet_hell` (#5218) * add shapes_bullet_hell example * adjust example count --- examples/Makefile | 1 + examples/Makefile.Web | 4 + examples/README.md | 5 +- examples/examples_list.txt | 1 + examples/shapes/shapes_bullet_hell.c | 286 +++++++++++++++++++++++++ examples/shapes/shapes_bullet_hell.png | Bin 0 -> 38660 bytes 6 files changed, 295 insertions(+), 2 deletions(-) create mode 100644 examples/shapes/shapes_bullet_hell.c create mode 100644 examples/shapes/shapes_bullet_hell.png diff --git a/examples/Makefile b/examples/Makefile index 36faed3b3..de02ae085 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -541,6 +541,7 @@ CORE = \ SHAPES = \ shapes/shapes_basic_shapes \ shapes/shapes_bouncing_ball \ + shapes/shapes_bullet_hell \ shapes/shapes_circle_sector_drawing \ shapes/shapes_collision_area \ shapes/shapes_colors_palette \ diff --git a/examples/Makefile.Web b/examples/Makefile.Web index b1b1f0779..8c9707274 100644 --- a/examples/Makefile.Web +++ b/examples/Makefile.Web @@ -541,6 +541,7 @@ CORE = \ SHAPES = \ shapes/shapes_basic_shapes \ shapes/shapes_bouncing_ball \ + shapes/shapes_bullet_hell \ shapes/shapes_circle_sector_drawing \ shapes/shapes_collision_area \ shapes/shapes_colors_palette \ @@ -807,6 +808,9 @@ shapes/shapes_basic_shapes: shapes/shapes_basic_shapes.c shapes/shapes_bouncing_ball: shapes/shapes_bouncing_ball.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) +shapes/shapes_bullet_hell: shapes/shapes_bullet_hell.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) + shapes/shapes_circle_sector_drawing: shapes/shapes_circle_sector_drawing.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) diff --git a/examples/README.md b/examples/README.md index 48e83c852..92ea9aa07 100644 --- a/examples/README.md +++ b/examples/README.md @@ -17,7 +17,7 @@ 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: 164] +## EXAMPLES COLLECTION [TOTAL: 165] ### category: core [38] @@ -64,7 +64,7 @@ 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) | -### category: shapes [20] +### category: shapes [21] Examples using raylib shapes drawing functionality, provided by raylib [shapes](../src/rshapes.c) module. @@ -72,6 +72,7 @@ Examples using raylib shapes drawing functionality, provided by raylib [shapes]( |-----------|--------|:-------------------:|:------------------:|:-----------------------:|:----------------------| | [shapes_basic_shapes](shapes/shapes_basic_shapes.c) | shapes_basic_shapes | ⭐☆☆☆ | 1.0 | 4.2 | [Ramon Santamaria](https://github.com/raysan5) | | [shapes_bouncing_ball](shapes/shapes_bouncing_ball.c) | shapes_bouncing_ball | ⭐☆☆☆ | 2.5 | 2.5 | [Ramon Santamaria](https://github.com/raysan5) | +| [shapes_bullet_hell](shapes/shapes_bullet_hell.c) | shapes_bullet_hell | ⭐☆☆☆ | 5.6 | 5.6 | [Zero](https://github.com/zerohorsepower) | | [shapes_colors_palette](shapes/shapes_colors_palette.c) | shapes_colors_palette | ⭐⭐☆☆ | 1.0 | 2.5 | [Ramon Santamaria](https://github.com/raysan5) | | [shapes_logo_raylib](shapes/shapes_logo_raylib.c) | shapes_logo_raylib | ⭐☆☆☆ | 1.0 | 1.0 | [Ramon Santamaria](https://github.com/raysan5) | | [shapes_logo_raylib_anim](shapes/shapes_logo_raylib_anim.c) | shapes_logo_raylib_anim | ⭐⭐☆☆ | 2.5 | 4.0 | [Ramon Santamaria](https://github.com/raysan5) | diff --git a/examples/examples_list.txt b/examples/examples_list.txt index b5682123f..6af9bb6eb 100644 --- a/examples/examples_list.txt +++ b/examples/examples_list.txt @@ -47,6 +47,7 @@ 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 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 shapes;shapes_colors_palette;★★☆☆;1.0;2.5;2014;2025;"Ramon Santamaria";@raysan5 shapes;shapes_logo_raylib;★☆☆☆;1.0;1.0;2014;2025;"Ramon Santamaria";@raysan5 shapes;shapes_logo_raylib_anim;★★☆☆;2.5;4.0;2014;2025;"Ramon Santamaria";@raysan5 diff --git a/examples/shapes/shapes_bullet_hell.c b/examples/shapes/shapes_bullet_hell.c new file mode 100644 index 000000000..011be9e84 --- /dev/null +++ b/examples/shapes/shapes_bullet_hell.c @@ -0,0 +1,286 @@ +/******************************************************************************************* +* +* raylib [shapes] example - bullet hell +* +* Example complexity rating: [★☆☆☆] 1/4 +* +* Example originally created with raylib 5.6, last time updated with raylib 5.6 +* +* Example contributed by Zero (@zerohorsepower) 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 Zero (@zerohorsepower) +* +********************************************************************************************/ + +#include "raylib.h" +#include // Required for: malloc(), free() +#include // Required for: cosf(), sinf() + +#define MAX_BULLETS 500000 // Max bullets that 800x450 can keep on minimum settings is 130.000 bullets + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- +typedef struct Bullet { + Vector2 position; + Vector2 acceleration; // the amount of pixels to be incremented to position every frame + bool disabled; // skip processing and draw case out of screen + Color color; +} Bullet; + +//---------------------------------------------------------------------------------- +// Module Functions Declaration +//---------------------------------------------------------------------------------- + + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [shapes] example - bullet hell"); + + // Bullet + Bullet *bullets = (Bullet *)malloc(MAX_BULLETS*sizeof(Bullet)); // Bullets array + int bulletCount = 0; + int bulletDisabledCount = 0; // Used to calculate how many bullets are on screen + int bulletRadius = 10; + float bulletSpeed = 3.0f; + int bulletRows = 6; + Color bulletColor[2] = { RED, BLUE }; + + // Spawner + float baseDirection = 0; + int angleIncrement = 5; // After spawn all bullet rows, increment this value on the baseDirection for next the frame + float spawnCooldown = 2; + float spawnCooldownTimer = spawnCooldown; + + // Magic circle + float magicCircleRotation = 0; + + // Used on performance drawing + RenderTexture bulletTexture = LoadRenderTexture(24, 24); + + // Draw circle to bullet texture, then draw bullet using DrawTexture() + // This is being done to improve the performance, since DrawCircle() is slow + BeginDrawing(); + BeginTextureMode(bulletTexture); + DrawCircle(12, 12, bulletRadius, WHITE); + DrawCircleLines(12, 12, bulletRadius, BLACK); + EndTextureMode(); + EndDrawing(); + + bool drawInPerformanceMode = true; + + SetTargetFPS(60); + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + + // Reset the bullet index + // New bullets will replace the old ones that are already disabled due to out-of-screen + if (bulletCount >= MAX_BULLETS) + { + bulletCount = 0; + bulletDisabledCount = 0; + } + + spawnCooldownTimer--; + if (spawnCooldownTimer < 0) + { + spawnCooldownTimer = spawnCooldown; + + // Spawn bullets + float degreesPerRow = 360.0f / bulletRows; + for (int row = 0; row < bulletRows; row++) + { + + if (bulletCount < MAX_BULLETS) + { + + bullets[bulletCount].position = (Vector2){(float) screenWidth/2, (float) screenHeight/2}; + bullets[bulletCount].disabled = false; + bullets[bulletCount].color = bulletColor[row % 2]; + + float bulletDirection = baseDirection + (degreesPerRow * row); + + // bullet speed * bullet direction, this will determine how much pixels will be incremented/decremented + // from the bullet position every frame. Since the bullets doesn't change its direction and speed, + // only need to calculate it at the spawning time. + // 0 degrees = right, 90 degrees = down, 180 degrees = left and 270 degrees = up, basically clockwise. + // Case you want it to be anti-clockwise, add "* -1" at the y acceleration + bullets[bulletCount].acceleration = (Vector2){ + bulletSpeed * cosf(bulletDirection * DEG2RAD), + bulletSpeed * sinf(bulletDirection * DEG2RAD) + }; + + bulletCount++; + } + } + + baseDirection += angleIncrement; + + } + + + // Update bullets position based on its acceleration + for (int i = 0; i < bulletCount; i++) + { + + // Only update bullet if inside the screen + if (!bullets[i].disabled) + { + + bullets[i].position.x += bullets[i].acceleration.x; + bullets[i].position.y += bullets[i].acceleration.y; + + // Disable bullet if out of screen + if + ( + bullets[i].position.x < -bulletRadius*2 || + bullets[i].position.x > screenWidth + bulletRadius*2 || + bullets[i].position.y < -bulletRadius*2 || + bullets[i].position.y > screenHeight + bulletRadius*2 + ) + { + bullets[i].disabled = true; + bulletDisabledCount++; + } + } + } + + // Input + if ((IsKeyPressed(KEY_RIGHT) || IsKeyPressed(KEY_D)) && bulletRows < 359) bulletRows++; + if ((IsKeyPressed(KEY_LEFT) || IsKeyPressed(KEY_A)) && bulletRows > 1) bulletRows--; + if (IsKeyPressed(KEY_UP) || IsKeyPressed(KEY_W)) bulletSpeed += 0.25f; + if ((IsKeyPressed(KEY_DOWN) || IsKeyPressed(KEY_S)) && bulletSpeed > 0.50f) bulletSpeed -= 0.25f; + if (IsKeyPressed(KEY_Z) && spawnCooldown > 1) spawnCooldown--; + if (IsKeyPressed(KEY_X)) spawnCooldown++; + if (IsKeyPressed(KEY_ENTER)) drawInPerformanceMode = !drawInPerformanceMode; + + if (IsKeyDown(KEY_SPACE)) + { + angleIncrement += 1; + angleIncrement %= 360; + } + + if (IsKeyPressed(KEY_C)) + { + bulletCount = 0; + bulletDisabledCount = 0; + } + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + // Draw magic circle + magicCircleRotation++; + DrawRectanglePro( + (Rectangle) { (float) screenWidth/2, (float) screenHeight/2, 120, 120 }, + (Vector2) { 60, 60 }, + magicCircleRotation, + PURPLE + ); + DrawRectanglePro( + (Rectangle) { (float) screenWidth/2, (float) screenHeight/2, 120, 120 }, + (Vector2) { 60, 60 }, + magicCircleRotation + 45, + PURPLE + ); + DrawCircleLines(screenWidth/2, screenHeight/2, 70, BLACK); + DrawCircleLines(screenWidth/2, screenHeight/2, 50, BLACK); + DrawCircleLines(screenWidth/2, screenHeight/2, 30, BLACK); + + + // Draw bullets + // DrawInPerformanceMode = draw bullets using DrawTexture, DrawCircle is vary slow + if (drawInPerformanceMode) + { + for (int i = 0; i < bulletCount; i++) + { + // Do not draw disabled bullets (out of screen) + if (!bullets[i].disabled) + { + DrawTexture( + bulletTexture.texture, + bullets[i].position.x - bulletTexture.texture.width*0.5f, + bullets[i].position.y - bulletTexture.texture.height*0.5f, + bullets[i].color + ); + } + } + } else { + + for (int i = 0; i < bulletCount; i++) + { + // Do not draw disabled bullets (out of screen) + if (!bullets[i].disabled) + { + DrawCircleV(bullets[i].position, bulletRadius, bullets[i].color); + DrawCircleLinesV(bullets[i].position, bulletRadius, BLACK); + } + } + } + + // Draw UI + DrawRectangle(10, 10, 280, 150, (Color){0,0, 0, 200 }); + DrawText("Controls:", 20, 20, 10, LIGHTGRAY); + DrawText("- Right/Left or A/D: Change rows number", 40, 40, 10, LIGHTGRAY); + DrawText("- Up/Down or W/S: Change bullet speed", 40, 60, 10, LIGHTGRAY); + DrawText("- Z or X: Change spawn cooldown", 40, 80, 10, LIGHTGRAY); + DrawText("- Space (Hold): Change the angle increment", 40, 100, 10, LIGHTGRAY); + DrawText("- Enter: Switch draw method (Performance)", 40, 120, 10, LIGHTGRAY); + DrawText("- C: Clear bullets", 40, 140, 10, LIGHTGRAY); + + DrawRectangle(610, 10, 170, 30, (Color){0,0, 0, 200 }); + if (drawInPerformanceMode) + { + DrawText("Draw method: DrawTexture(*)", 620, 20, 10, GREEN); + } else { + DrawText("Draw method: DrawCircle(*)", 620, 20, 10, RED); + } + + + DrawRectangle(135, 410, 530, 30, (Color){0,0, 0, 200 }); + DrawText( + TextFormat( + "[ FPS: %d, Bullets: %d, Rows: %d, Bullet speed: %.2f, Angle increment per frame: %d, Cooldown: %.0f ]", + GetFPS(), bulletCount - bulletDisabledCount, bulletRows, bulletSpeed, angleIncrement, spawnCooldown + ), + 155, + 420, + 10, + GREEN + ); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + + UnloadRenderTexture(bulletTexture); + + free(bullets); + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} \ No newline at end of file diff --git a/examples/shapes/shapes_bullet_hell.png b/examples/shapes/shapes_bullet_hell.png new file mode 100644 index 0000000000000000000000000000000000000000..cf8e5d8f638b7ef0ef5d4269cbdae98a6c2d945a GIT binary patch literal 38660 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 Sv)Ds0@bmQ!@VY|dWc&|@=gc?& literal 0 HcmV?d00001 From 5d9352a0a195a3275d07a54b0fe9e2c1fa619168 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 30 Sep 2025 18:27:59 +0200 Subject: [PATCH 054/167] Update shapes_bullet_hell.c --- examples/shapes/shapes_bullet_hell.c | 140 ++++++++++----------------- 1 file changed, 51 insertions(+), 89 deletions(-) diff --git a/examples/shapes/shapes_bullet_hell.c b/examples/shapes/shapes_bullet_hell.c index 011be9e84..2635ee02c 100644 --- a/examples/shapes/shapes_bullet_hell.c +++ b/examples/shapes/shapes_bullet_hell.c @@ -16,26 +16,22 @@ ********************************************************************************************/ #include "raylib.h" -#include // Required for: malloc(), free() -#include // Required for: cosf(), sinf() -#define MAX_BULLETS 500000 // Max bullets that 800x450 can keep on minimum settings is 130.000 bullets +#include // Required for: calloc(), free() +#include // Required for: cosf(), sinf() + +#define MAX_BULLETS 500000 // Max bullets to be processed //---------------------------------------------------------------------------------- // Types and Structures Definition //---------------------------------------------------------------------------------- typedef struct Bullet { - Vector2 position; - Vector2 acceleration; // the amount of pixels to be incremented to position every frame - bool disabled; // skip processing and draw case out of screen - Color color; + Vector2 position; // Bullet position on screen + Vector2 acceleration; // Amount of pixels to be incremented to position every frame + bool disabled; // Skip processing and draw case out of screen + Color color; // Bullet color } Bullet; -//---------------------------------------------------------------------------------- -// Module Functions Declaration -//---------------------------------------------------------------------------------- - - //------------------------------------------------------------------------------------ // Program main entry point //------------------------------------------------------------------------------------ @@ -48,8 +44,8 @@ int main(void) InitWindow(screenWidth, screenHeight, "raylib [shapes] example - bullet hell"); - // Bullet - Bullet *bullets = (Bullet *)malloc(MAX_BULLETS*sizeof(Bullet)); // Bullets array + // Bullets definition + Bullet *bullets = (Bullet *)RL_CALLOC(MAX_BULLETS, sizeof(Bullet)); // Bullets array int bulletCount = 0; int bulletDisabledCount = 0; // Used to calculate how many bullets are on screen int bulletRadius = 10; @@ -57,7 +53,7 @@ int main(void) int bulletRows = 6; Color bulletColor[2] = { RED, BLUE }; - // Spawner + // Spawner variables float baseDirection = 0; int angleIncrement = 5; // After spawn all bullet rows, increment this value on the baseDirection for next the frame float spawnCooldown = 2; @@ -70,15 +66,13 @@ int main(void) RenderTexture bulletTexture = LoadRenderTexture(24, 24); // Draw circle to bullet texture, then draw bullet using DrawTexture() - // This is being done to improve the performance, since DrawCircle() is slow - BeginDrawing(); + // NOTE: This is done to improve the performance, since DrawCircle() is very slow BeginTextureMode(bulletTexture); - DrawCircle(12, 12, bulletRadius, WHITE); - DrawCircleLines(12, 12, bulletRadius, BLACK); + DrawCircle(12, 12, bulletRadius, WHITE); + DrawCircleLines(12, 12, bulletRadius, BLACK); EndTextureMode(); - EndDrawing(); - bool drawInPerformanceMode = true; + bool drawInPerformanceMode = true; // Switch between DrawCircle() and DrawTexture() SetTargetFPS(60); //-------------------------------------------------------------------------------------- @@ -88,7 +82,6 @@ int main(void) { // Update //---------------------------------------------------------------------------------- - // Reset the bullet index // New bullets will replace the old ones that are already disabled due to out-of-screen if (bulletCount >= MAX_BULLETS) @@ -103,27 +96,25 @@ int main(void) spawnCooldownTimer = spawnCooldown; // Spawn bullets - float degreesPerRow = 360.0f / bulletRows; + float degreesPerRow = 360.0f/bulletRows; for (int row = 0; row < bulletRows; row++) { - if (bulletCount < MAX_BULLETS) { - bullets[bulletCount].position = (Vector2){(float) screenWidth/2, (float) screenHeight/2}; bullets[bulletCount].disabled = false; - bullets[bulletCount].color = bulletColor[row % 2]; + bullets[bulletCount].color = bulletColor[row%2]; - float bulletDirection = baseDirection + (degreesPerRow * row); + float bulletDirection = baseDirection + (degreesPerRow*row); - // bullet speed * bullet direction, this will determine how much pixels will be incremented/decremented + // Bullet speed * bullet direction, this will determine how much pixels will be incremented/decremented // from the bullet position every frame. Since the bullets doesn't change its direction and speed, - // only need to calculate it at the spawning time. - // 0 degrees = right, 90 degrees = down, 180 degrees = left and 270 degrees = up, basically clockwise. + // only need to calculate it at the spawning time + // 0 degrees = right, 90 degrees = down, 180 degrees = left and 270 degrees = up, basically clockwise // Case you want it to be anti-clockwise, add "* -1" at the y acceleration bullets[bulletCount].acceleration = (Vector2){ - bulletSpeed * cosf(bulletDirection * DEG2RAD), - bulletSpeed * sinf(bulletDirection * DEG2RAD) + bulletSpeed*cosf(bulletDirection*DEG2RAD), + bulletSpeed*sinf(bulletDirection*DEG2RAD) }; bulletCount++; @@ -131,29 +122,22 @@ int main(void) } baseDirection += angleIncrement; - } - // Update bullets position based on its acceleration for (int i = 0; i < bulletCount; i++) { - // Only update bullet if inside the screen if (!bullets[i].disabled) { - bullets[i].position.x += bullets[i].acceleration.x; bullets[i].position.y += bullets[i].acceleration.y; // Disable bullet if out of screen - if - ( - bullets[i].position.x < -bulletRadius*2 || - bullets[i].position.x > screenWidth + bulletRadius*2 || - bullets[i].position.y < -bulletRadius*2 || - bullets[i].position.y > screenHeight + bulletRadius*2 - ) + if ((bullets[i].position.x < -bulletRadius*2) || + (bullets[i].position.x > screenWidth + bulletRadius*2) || + (bullets[i].position.y < -bulletRadius*2) || + (bullets[i].position.y > screenHeight + bulletRadius*2)) { bullets[i].disabled = true; bulletDisabledCount++; @@ -161,12 +145,12 @@ int main(void) } } - // Input - if ((IsKeyPressed(KEY_RIGHT) || IsKeyPressed(KEY_D)) && bulletRows < 359) bulletRows++; - if ((IsKeyPressed(KEY_LEFT) || IsKeyPressed(KEY_A)) && bulletRows > 1) bulletRows--; + // Input logic + if ((IsKeyPressed(KEY_RIGHT) || IsKeyPressed(KEY_D)) && (bulletRows < 359)) bulletRows++; + if ((IsKeyPressed(KEY_LEFT) || IsKeyPressed(KEY_A)) && (bulletRows > 1)) bulletRows--; if (IsKeyPressed(KEY_UP) || IsKeyPressed(KEY_W)) bulletSpeed += 0.25f; - if ((IsKeyPressed(KEY_DOWN) || IsKeyPressed(KEY_S)) && bulletSpeed > 0.50f) bulletSpeed -= 0.25f; - if (IsKeyPressed(KEY_Z) && spawnCooldown > 1) spawnCooldown--; + if ((IsKeyPressed(KEY_DOWN) || IsKeyPressed(KEY_S)) && (bulletSpeed > 0.50f)) bulletSpeed -= 0.25f; + if (IsKeyPressed(KEY_Z) && (spawnCooldown > 1)) spawnCooldown--; if (IsKeyPressed(KEY_X)) spawnCooldown++; if (IsKeyPressed(KEY_ENTER)) drawInPerformanceMode = !drawInPerformanceMode; @@ -181,51 +165,42 @@ int main(void) bulletCount = 0; bulletDisabledCount = 0; } + //---------------------------------------------------------------------------------- // Draw //---------------------------------------------------------------------------------- BeginDrawing(); - ClearBackground(RAYWHITE); // Draw magic circle magicCircleRotation++; - DrawRectanglePro( - (Rectangle) { (float) screenWidth/2, (float) screenHeight/2, 120, 120 }, - (Vector2) { 60, 60 }, - magicCircleRotation, - PURPLE - ); - DrawRectanglePro( - (Rectangle) { (float) screenWidth/2, (float) screenHeight/2, 120, 120 }, - (Vector2) { 60, 60 }, - magicCircleRotation + 45, - PURPLE - ); + DrawRectanglePro((Rectangle){ (float)screenWidth/2, (float)screenHeight/2, 120, 120 }, + (Vector2){ 60.0f, 60.0f }, magicCircleRotation, PURPLE); + DrawRectanglePro((Rectangle){ (float)screenWidth/2, (float)screenHeight/2, 120, 120 }, + (Vector2){ 60.0f, 60.0f }, magicCircleRotation + 45, PURPLE); DrawCircleLines(screenWidth/2, screenHeight/2, 70, BLACK); DrawCircleLines(screenWidth/2, screenHeight/2, 50, BLACK); DrawCircleLines(screenWidth/2, screenHeight/2, 30, BLACK); - // Draw bullets - // DrawInPerformanceMode = draw bullets using DrawTexture, DrawCircle is vary slow if (drawInPerformanceMode) { + // Draw bullets using pre-rendered texture containing circle for (int i = 0; i < bulletCount; i++) { // Do not draw disabled bullets (out of screen) if (!bullets[i].disabled) { - DrawTexture( - bulletTexture.texture, + DrawTexture(bulletTexture.texture, bullets[i].position.x - bulletTexture.texture.width*0.5f, bullets[i].position.y - bulletTexture.texture.height*0.5f, - bullets[i].color - ); + bullets[i].color); } } - } else { - + } + else + { + // Draw bullets using DrawCircle(), less performant for (int i = 0; i < bulletCount; i++) { // Do not draw disabled bullets (out of screen) @@ -248,25 +223,13 @@ int main(void) DrawText("- C: Clear bullets", 40, 140, 10, LIGHTGRAY); DrawRectangle(610, 10, 170, 30, (Color){0,0, 0, 200 }); - if (drawInPerformanceMode) - { - DrawText("Draw method: DrawTexture(*)", 620, 20, 10, GREEN); - } else { - DrawText("Draw method: DrawCircle(*)", 620, 20, 10, RED); - } - + if (drawInPerformanceMode) DrawText("Draw method: DrawTexture(*)", 620, 20, 10, GREEN); + else DrawText("Draw method: DrawCircle(*)", 620, 20, 10, RED); DrawRectangle(135, 410, 530, 30, (Color){0,0, 0, 200 }); - DrawText( - TextFormat( - "[ FPS: %d, Bullets: %d, Rows: %d, Bullet speed: %.2f, Angle increment per frame: %d, Cooldown: %.0f ]", - GetFPS(), bulletCount - bulletDisabledCount, bulletRows, bulletSpeed, angleIncrement, spawnCooldown - ), - 155, - 420, - 10, - GREEN - ); + DrawText(TextFormat("[ FPS: %d, Bullets: %d, Rows: %d, Bullet speed: %.2f, Angle increment per frame: %d, Cooldown: %.0f ]", + GetFPS(), bulletCount - bulletDisabledCount, bulletRows, bulletSpeed, angleIncrement, spawnCooldown), + 155, 420, 10, GREEN); EndDrawing(); //---------------------------------------------------------------------------------- @@ -274,10 +237,9 @@ int main(void) // De-Initialization //-------------------------------------------------------------------------------------- + UnloadRenderTexture(bulletTexture); // Unload bullet texture - UnloadRenderTexture(bulletTexture); - - free(bullets); + RL_FREE(bullets); // Free bullets array data CloseWindow(); // Close window and OpenGL context //-------------------------------------------------------------------------------------- From 0e2e8ce22527c79f25845c06c31aa10e0de1e718 Mon Sep 17 00:00:00 2001 From: Jopestpe <47086979+Jopestpe@users.noreply.github.com> Date: Tue, 30 Sep 2025 13:32:25 -0300 Subject: [PATCH 055/167] [examples] Update `shapes_bouncing_ball` with gravity (#5217) * [examples] Add shapes_bouncing_ball with gravity * gravity could be enabled/disabled --- examples/shapes/shapes_bouncing_ball.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/examples/shapes/shapes_bouncing_ball.c b/examples/shapes/shapes_bouncing_ball.c index 187cd41af..73dca0011 100644 --- a/examples/shapes/shapes_bouncing_ball.c +++ b/examples/shapes/shapes_bouncing_ball.c @@ -4,8 +4,10 @@ * * Example complexity rating: [★☆☆☆] 1/4 * -* Example originally created with raylib 2.5, last time updated with raylib 2.5 +* Example originally created with raylib 2.5, last time updated with raylib 5.6 * +* Example contributed by Jopestpe (@jopestpe) +* * Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, * BSD-like license that allows static linking with closed source software * @@ -31,7 +33,9 @@ int main(void) Vector2 ballPosition = { GetScreenWidth()/2.0f, GetScreenHeight()/2.0f }; Vector2 ballSpeed = { 5.0f, 4.0f }; int ballRadius = 20; + float gravity = 0.2f; + bool useGravity = true; bool pause = 0; int framesCounter = 0; @@ -43,16 +47,19 @@ int main(void) { // Update //----------------------------------------------------- + if (IsKeyPressed(KEY_G)) useGravity = !useGravity; if (IsKeyPressed(KEY_SPACE)) pause = !pause; - + if (!pause) { ballPosition.x += ballSpeed.x; ballPosition.y += ballSpeed.y; + if (useGravity) ballSpeed.y += gravity; + // Check walls collision for bouncing if ((ballPosition.x >= (GetScreenWidth() - ballRadius)) || (ballPosition.x <= ballRadius)) ballSpeed.x *= -1.0f; - if ((ballPosition.y >= (GetScreenHeight() - ballRadius)) || (ballPosition.y <= ballRadius)) ballSpeed.y *= -1.0f; + if ((ballPosition.y >= (GetScreenHeight() - ballRadius)) || (ballPosition.y <= ballRadius)) ballSpeed.y *= -0.95f; } else framesCounter++; //----------------------------------------------------- @@ -65,12 +72,15 @@ int main(void) DrawCircleV(ballPosition, (float)ballRadius, MAROON); DrawText("PRESS SPACE to PAUSE BALL MOVEMENT", 10, GetScreenHeight() - 25, 20, LIGHTGRAY); + + if (useGravity) DrawText("GRAVITY: ON (Press G to disable)", 10, GetScreenHeight() - 50, 20, DARKGREEN); + else DrawText("GRAVITY: OFF (Press G to enable)", 10, GetScreenHeight() - 50, 20, RED); // On pause, we draw a blinking message if (pause && ((framesCounter/30)%2)) DrawText("PAUSED", 350, 200, 30, GRAY); DrawFPS(10, 10); - + EndDrawing(); //----------------------------------------------------- } From a553fbd0c76c29d4d2581d4959da5a75c3041e9c Mon Sep 17 00:00:00 2001 From: Maicon Santana Date: Tue, 30 Sep 2025 17:34:06 +0100 Subject: [PATCH 056/167] [examples] Fix `shaders_ascii_rendering` (#5219) * Add ascii post processing * Fix broken characters and add more comments * Rename example * Refactored as requested --- .../resources/shaders/glsl100/ascii.fs | 59 +++++++++++------- .../resources/shaders/glsl120/ascii.fs | 57 ++++++++++------- .../resources/shaders/glsl330/ascii.fs | 44 ++++++++----- examples/shaders/shaders_ascii_rendering.c | 44 ++++++++----- examples/shaders/shaders_ascii_rendering.png | Bin 45176 -> 43045 bytes 5 files changed, 125 insertions(+), 79 deletions(-) diff --git a/examples/shaders/resources/shaders/glsl100/ascii.fs b/examples/shaders/resources/shaders/glsl100/ascii.fs index a4a930c3c..54e20bf66 100644 --- a/examples/shaders/resources/shaders/glsl100/ascii.fs +++ b/examples/shaders/resources/shaders/glsl100/ascii.fs @@ -10,58 +10,71 @@ varying vec4 finalColor; uniform sampler2D texture0; uniform vec2 resolution; + +// Fontsize less then 9 may be not complete uniform float fontSize; -float greyScale(in vec3 col) { +float GreyScale(in vec3 col) +{ return dot(col, vec3(0.2126, 0.7152, 0.0722)); } -float character(float n, vec2 p) +float GetCharacter(float n, vec2 p) { - p = floor(p * vec2(4.0, -4.0) + 2.5); - - // Check if the coordinate is inside the 5x5 grid (0 to 4). - if (clamp(p.x, 0.0, 4.0) == p.x && clamp(p.y, 0.0, 4.0) == p.y) { - - if (int(mod(n / exp2(p.x + 5.0 * p.y), 2.0)) == 1) { - return 1.0; // The bit is on, so draw this part of the character. + p = floor(p*vec2(-4.0, 4.0) + 2.5); + + // Check if the calculated coordinate is inside the 5x5 grid (from 0.0 to 4.0) + if (clamp(p.x, 0.0, 4.0) == p.x && clamp(p.y, 0.0, 4.0) == p.y) + { + float a = floor(p.x + 0.5) + 5.0*floor(p.y + 0.5); + + // This checked if the 'a'-th bit of 'n' was set + float shiftedN = floor(n/pow(2.0, a)); + + if (mod(shiftedN, 2.0) == 1.0) + { + return 1.0; // The bit is on } } - return 0.0; // The bit is off, or we are outside the grid. + return 0.0; // The bit is off, or we are outside the grid } // ----------------------------------------------------------------------------- // Main shader logic // ----------------------------------------------------------------------------- + void main() { - vec2 charPixelSize = vec2(fontSize, fontSize * 1.8); - vec2 uvCellSize = charPixelSize / resolution; + vec2 charPixelSize = vec2(fontSize, fontSize); + vec2 uvCellSize = charPixelSize/resolution; - vec2 cellUV = floor(fragTexCoord / uvCellSize) * uvCellSize; + // The cell size is based on the fontSize set by application + vec2 cellUV = floor(fragTexCoord/uvCellSize)*uvCellSize; vec3 cellColor = texture2D(texture0, cellUV).rgb; - float gray = greyScale(cellColor); - float n = 4096; + // Gray is used to define what character will be selected to draw + float gray = GreyScale(cellColor); + + float n = 4096.0; - // limited character set + // Character set from https://www.shadertoy.com/view/lssGDj + // Create new bitmaps https://thrill-project.com/archiv/coding/bitmap/ if (gray > 0.2) n = 65600.0; // : - if (gray > 0.3) n = 163153.0; // * + if (gray > 0.3) n = 18725316.0; // v if (gray > 0.4) n = 15255086.0; // o if (gray > 0.5) n = 13121101.0; // & if (gray > 0.6) n = 15252014.0; // 8 if (gray > 0.7) n = 13195790.0; // @ if (gray > 0.8) n = 11512810.0; // # - vec2 localUV = (fragTexCoord - cellUV) / uvCellSize; // Range [0.0, 1.0] + vec2 localUV = (fragTexCoord - cellUV)/uvCellSize; // Range [0.0, 1.0] - vec2 p = localUV * 2.0 - 1.0; + vec2 p = localUV*2.0 - 1.0; // Range [-1.0, 1.0] - float charShape = character(n, p); + // cellColor and charShape will define the color of the char + vec3 color = cellColor*GetCharacter(n, p); - vec3 final_col = cellColor * charShape; - - gl_FragColor = vec4(final_col, 1.0); + gl_FragColor = vec4(color, 1.0); } \ No newline at end of file diff --git a/examples/shaders/resources/shaders/glsl120/ascii.fs b/examples/shaders/resources/shaders/glsl120/ascii.fs index 3521c8b33..09c572ae5 100644 --- a/examples/shaders/resources/shaders/glsl120/ascii.fs +++ b/examples/shaders/resources/shaders/glsl120/ascii.fs @@ -8,58 +8,71 @@ varying vec4 finalColor; uniform sampler2D texture0; uniform vec2 resolution; + +// Fontsize less then 9 may be not complete uniform float fontSize; -float greyScale(in vec3 col) { +float GreyScale(in vec3 col) +{ return dot(col, vec3(0.2126, 0.7152, 0.0722)); } -float character(float n, vec2 p) +float GetCharacter(float n, vec2 p) { - p = floor(p * vec2(4.0, -4.0) + 2.5); - - // Check if the coordinate is inside the 5x5 grid (0 to 4). - if (clamp(p.x, 0.0, 4.0) == p.x && clamp(p.y, 0.0, 4.0) == p.y) { - - if (int(mod(n / exp2(p.x + 5.0 * p.y), 2.0)) == 1) { - return 1.0; // The bit is on, so draw this part of the character. + p = floor(p*vec2(-4.0, 4.0) + 2.5); + + // Check if the calculated coordinate is inside the 5x5 grid (from 0.0 to 4.0) + if (clamp(p.x, 0.0, 4.0) == p.x && clamp(p.y, 0.0, 4.0) == p.y) + { + float a = floor(p.x + 0.5) + 5.0*floor(p.y + 0.5); + + // This checked if the 'a'-th bit of 'n' was set + float shiftedN = floor(n/pow(2.0, a)); + + if (mod(shiftedN, 2.0) == 1.0) + { + return 1.0; // The bit is on } } - return 0.0; // The bit is off, or we are outside the grid. + return 0.0; // The bit is off, or we are outside the grid } // ----------------------------------------------------------------------------- // Main shader logic // ----------------------------------------------------------------------------- + void main() { - vec2 charPixelSize = vec2(fontSize, fontSize * 1.8); + vec2 charPixelSize = vec2(fontSize, fontSize); vec2 uvCellSize = charPixelSize / resolution; - vec2 cellUV = floor(fragTexCoord / uvCellSize) * uvCellSize; + // The cell size is based on the fontSize set by application + vec2 cellUV = floor(fragTexCoord / uvCellSize)*uvCellSize; vec3 cellColor = texture2D(texture0, cellUV).rgb; - float gray = greyScale(cellColor); - float n = 4096; + // Gray is used to define what character will be selected to draw + float gray = GreyScale(cellColor); + + float n = 4096.0; - // limited character set + // Character set from https://www.shadertoy.com/view/lssGDj + // Create new bitmaps https://thrill-project.com/archiv/coding/bitmap/ if (gray > 0.2) n = 65600.0; // : - if (gray > 0.3) n = 163153.0; // * + if (gray > 0.3) n = 18725316.0; // v if (gray > 0.4) n = 15255086.0; // o if (gray > 0.5) n = 13121101.0; // & if (gray > 0.6) n = 15252014.0; // 8 if (gray > 0.7) n = 13195790.0; // @ if (gray > 0.8) n = 11512810.0; // # - vec2 localUV = (fragTexCoord - cellUV) / uvCellSize; // Range [0.0, 1.0] + vec2 localUV = (fragTexCoord - cellUV)/uvCellSize; // Range [0.0, 1.0] - vec2 p = localUV * 2.0 - 1.0; + vec2 p = localUV*2.0 - 1.0; // Range [-1.0, 1.0] - float charShape = character(n, p); + // cellColor and charShape will define the color of the char + vec3 color = cellColor*GetCharacter(n, p); - vec3 final_col = cellColor * charShape; - - gl_FragColor = vec4(final_col, 1.0); + gl_FragColor = vec4(color, 1.0); } \ No newline at end of file diff --git a/examples/shaders/resources/shaders/glsl330/ascii.fs b/examples/shaders/resources/shaders/glsl330/ascii.fs index 014966835..3f73bf288 100644 --- a/examples/shaders/resources/shaders/glsl330/ascii.fs +++ b/examples/shaders/resources/shaders/glsl330/ascii.fs @@ -8,6 +8,8 @@ out vec4 finalColor; uniform sampler2D texture0; uniform vec2 resolution; + +// Fontsize less then 9 may be not complete uniform float fontSize; float GreyScale(in vec3 col) @@ -15,16 +17,17 @@ float GreyScale(in vec3 col) return dot(col, vec3(0.2126, 0.7152, 0.0722)); } -float GetCharacter(float n, vec2 p) +float GetCharacter(int n, vec2 p) { - p = floor(p*vec2(4.0, -4.0) + 2.5); + p = floor(p*vec2(-4.0, 4.0) + 2.5); // Check if the coordinate is inside the 5x5 grid (0 to 4) if (clamp(p.x, 0.0, 4.0) == p.x && clamp(p.y, 0.0, 4.0) == p.y) { - if (int(mod(n/exp2(p.x + 5.0 * p.y), 2.0)) == 1) + int a = int(round(p.x) + 5.0*round(p.y)); + if (((n >> a) & 1) == 1) { - return 1.0; // The bit is on, so draw this part of the character + return 1.0; } } @@ -34,30 +37,37 @@ float GetCharacter(float n, vec2 p) // ----------------------------------------------------------------------------- // Main shader logic // ----------------------------------------------------------------------------- + void main() { - vec2 charPixelSize = vec2(fontSize, fontSize*1.8); + vec2 charPixelSize = vec2(fontSize, fontSize); vec2 uvCellSize = charPixelSize/resolution; + + // The cell size is based on the fontSize set by application vec2 cellUV = floor(fragTexCoord/uvCellSize)*uvCellSize; vec3 cellColor = texture(texture0, cellUV).rgb; + + // Gray is used to define what character will be selected to draw float gray = GreyScale(cellColor); - float n = 4096; + int n = 4096; - // Limited character set - if (gray > 0.2) n = 65600.0; // : - if (gray > 0.3) n = 163153.0; // * - if (gray > 0.4) n = 15255086.0; // o - if (gray > 0.5) n = 13121101.0; // & - if (gray > 0.6) n = 15252014.0; // 8 - if (gray > 0.7) n = 13195790.0; // @ - if (gray > 0.8) n = 11512810.0; // # + // Character set from https://www.shadertoy.com/view/lssGDj + // Create new bitmaps https://thrill-project.com/archiv/coding/bitmap/ + if (gray > 0.2) n = 65600; // : + if (gray > 0.3) n = 18725316; // v + if (gray > 0.4) n = 15255086; // o + if (gray > 0.5) n = 13121101; // & + if (gray > 0.6) n = 15252014; // 8 + if (gray > 0.7) n = 13195790; // @ + if (gray > 0.8) n = 11512810; // # vec2 localUV = (fragTexCoord - cellUV)/uvCellSize; // Range [0.0, 1.0] - vec2 p = localUV*2.0 - 1.0; - float charShape = GetCharacter(n, p); + vec2 p = localUV*2.0 - 1.0; // Range [-1.0, 1.0] - finalColor = vec4(cellColor*charShape, 1.0); + vec3 color = cellColor*GetCharacter(n, p); + + finalColor = vec4(color, 1.0); } \ No newline at end of file diff --git a/examples/shaders/shaders_ascii_rendering.c b/examples/shaders/shaders_ascii_rendering.c index 5444caeee..23ba1f549 100644 --- a/examples/shaders/shaders_ascii_rendering.c +++ b/examples/shaders/shaders_ascii_rendering.c @@ -48,14 +48,14 @@ int main(void) int fontSizeLoc = GetShaderLocation(shader, "fontSize"); // Set the character size for the ASCII effect - float fontSize = 4.0f; + // Fontsize should be 9 or more + float fontSize = 9.0f; // Send the updated values to the shader float resolution[2] = { (float)screenWidth, (float)screenHeight }; SetShaderValue(shader, resolutionLoc, resolution, SHADER_UNIFORM_VEC2); - SetShaderValue(shader, fontSizeLoc, &fontSize, SHADER_UNIFORM_FLOAT); - Vector2 circlePos = (Vector2){40.0f, (float)screenHeight * 0.5f}; + Vector2 circlePos = (Vector2){40.0f, (float)screenHeight*0.5f}; float circleSpeed = 1.0f; // RenderTexture to apply the postprocessing later @@ -67,37 +67,47 @@ int main(void) // Main game loop while (!WindowShouldClose()) // Detect window close button or ESC key { + // Update //---------------------------------------------------------------------------------- + if (IsKeyPressed(KEY_LEFT) && fontSize > 9.0) fontSize -= 1; // Reduce fontSize + + if (IsKeyPressed(KEY_RIGHT) && fontSize < 15.0) fontSize += 1; // Increase fontSize + + if (circlePos.x > 200.0f || circlePos.x < 40.0f) circleSpeed *= -1; // Revert speed + circlePos.x += circleSpeed; - - if ((circlePos.x > 200.0f) || (circlePos.x < 40.0f)) circleSpeed *= -1; - //---------------------------------------------------------------------------------- + + // Set fontsize for the shader + SetShaderValue(shader, fontSizeLoc, &fontSize, SHADER_UNIFORM_FLOAT); // Draw //---------------------------------------------------------------------------------- - // Draw our scene to a render texture first + BeginTextureMode(target); - ClearBackground(WHITE); - + ClearBackground(WHITE); // The background of the scene itself + + // Samples Using custom shader DrawTexture(fudesumi, 500, -30, WHITE); DrawTextureV(raysan, circlePos, WHITE); - + EndTextureMode(); - BeginDrawing(); + ClearBackground(RAYWHITE); BeginShaderMode(shader); - // Draw the render texture containing scene - // The shader will process every pixel on the screen - DrawTextureRec(target.texture, - (Rectangle){ 0, 0, (float)target.texture.width, (float)-target.texture.height }, - (Vector2){ 0, 0 }, WHITE); + + // Draw the scene texture (that we rendered earlier) to the screen + // The shader will process every pixel of this texture + DrawTextureRec(target.texture, + (Rectangle){ 0, 0, (float)target.texture.width, (float)-target.texture.height }, + (Vector2){ 0, 0 }, + WHITE); EndShaderMode(); DrawRectangle(0, 0, screenWidth, 40, BLACK); - DrawText("Ascii effect", 120, 10, 20, LIGHTGRAY); + DrawText(TextFormat("Ascii effect - FontSize:%2.0f - [Left] -1 [Right] +1 ", fontSize), 120, 10, 20, LIGHTGRAY); DrawFPS(10, 10); EndDrawing(); diff --git a/examples/shaders/shaders_ascii_rendering.png b/examples/shaders/shaders_ascii_rendering.png index eee5cc90b620c14cc111bb9a8348765cb77e827d..59ecc83954129a13030476092ef346d16e943869 100644 GIT binary patch literal 43045 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 J3RE9F`#i6Q_1 literal 45176 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 ntY^P`$Sott Date: Tue, 30 Sep 2025 12:35:15 -0400 Subject: [PATCH 057/167] [examples] Add `core_delta_time` (#5216) * delta example * clarification * made it more clear what delta time is * more explanation * vector2 positions, removed all warnings * removed keys, moved global to local, conventions & comments, show target fps * new png * remove more periods * another period * remove note about conventions, remove period --- examples/core/core_delta_time.c | 131 ++++++++++++++++++++++++++++++ examples/core/core_delta_time.png | Bin 0 -> 16554 bytes 2 files changed, 131 insertions(+) create mode 100644 examples/core/core_delta_time.c create mode 100644 examples/core/core_delta_time.png diff --git a/examples/core/core_delta_time.c b/examples/core/core_delta_time.c new file mode 100644 index 000000000..aeedd7fff --- /dev/null +++ b/examples/core/core_delta_time.c @@ -0,0 +1,131 @@ +/******************************************************************************************* +* +* raylib [core] example - delta time +* +* Example complexity rating: [★☆☆☆] 1/4 +* +* Example originally created with raylib 5.5 +* +* 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" + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [core] example - delta time"); + + int currentFps = 60; + + // Store the position for the both of the circles + Vector2 deltaCircle = {0, screenHeight / 3.0f}; + Vector2 frameCircle = {0, screenHeight * (2.0f/3.0f)}; + + // The speed applied to both circles + const float speed = 10.0; + const float circleRadius = 32; + + SetTargetFPS(currentFps); + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------- + if (IsKeyPressed(KEY_R)) // Reset both circles' positions when you press R + { + deltaCircle.x = 0; + frameCircle.x = 0; + } + + // Adjust the FPS target based on the mouse wheel + float mouseWheel = GetMouseWheelMove(); + if (mouseWheel != 0) + { + currentFps += (int)mouseWheel; + SetTargetFPS(currentFps); + } + + // GetFrameTime() returns the time it took to draw the last frame, in seconds (usually called delta time) + // Uses the delta time to make the circle look like it's moving at a "consistent" speed regardless of FPS + + // Multiply by 6.0 (an arbitrary value) in order to make the speed visually closer to the other circle (at 60 fps), for comparison + deltaCircle.x += GetFrameTime() * 6.0f * speed; + // This circle can move faster or slower visually depending on the FPS + frameCircle.x += .1f * speed; + + // If either circle is off the screen, reset it back to the start + if (deltaCircle.x > screenWidth) + { + deltaCircle.x = 0; + } + + if (frameCircle.x > screenWidth) + { + frameCircle.x = 0; + } + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + // Draw both circles to the screen + DrawCircleV(deltaCircle, circleRadius, RED); + DrawCircleV(frameCircle, circleRadius, BLUE); + + // Determine what help text to show depending on the current FPS target + const char* fpsText; + + if (currentFps <= 0) + { + if (currentFps < 0) + { + // Clamp values below 0 + currentFps = 0; + } + + // Special text for when the FPS target is set to 0 or less, which makes it unlimited + fpsText = TextFormat("fps: unlimited (%i)", GetFPS()); + } + else + { + fpsText = TextFormat("fps: %i (target: %i)", GetFPS(), currentFps); + } + + // Draw the help text + DrawText(fpsText, 10, 10, 20, DARKGRAY); + DrawText(TextFormat("frame time: %02.02f ms", GetFrameTime()), 10, 30, 20, DARKGRAY); + DrawText("use the scroll wheel to change the fps limit, r to reset", 10, 50, 20, DARKGRAY); + + // Draw the text above the circles + DrawText("x += GetFrameTime() * speed", 10, 90, 20, RED); + DrawText("x += speed", 10, 240, 20, BLUE); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} \ No newline at end of file diff --git a/examples/core/core_delta_time.png b/examples/core/core_delta_time.png new file mode 100644 index 0000000000000000000000000000000000000000..cf8aa7c54e50ac477f8ea1011e0b61f1cedcb8ad GIT binary patch literal 16554 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 Date: Tue, 30 Sep 2025 18:39:27 +0200 Subject: [PATCH 058/167] Update shaders_ascii_rendering.c --- examples/shaders/shaders_ascii_rendering.c | 34 +++++++++------------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/examples/shaders/shaders_ascii_rendering.c b/examples/shaders/shaders_ascii_rendering.c index 23ba1f549..33fb052f7 100644 --- a/examples/shaders/shaders_ascii_rendering.c +++ b/examples/shaders/shaders_ascii_rendering.c @@ -67,58 +67,52 @@ int main(void) // Main game loop while (!WindowShouldClose()) // Detect window close button or ESC key { - // Update //---------------------------------------------------------------------------------- - if (IsKeyPressed(KEY_LEFT) && fontSize > 9.0) fontSize -= 1; // Reduce fontSize - - if (IsKeyPressed(KEY_RIGHT) && fontSize < 15.0) fontSize += 1; // Increase fontSize - - if (circlePos.x > 200.0f || circlePos.x < 40.0f) circleSpeed *= -1; // Revert speed - circlePos.x += circleSpeed; + if ((circlePos.x > 200.0f) || (circlePos.x < 40.0f)) circleSpeed *= -1; // Revert speed + + if (IsKeyPressed(KEY_LEFT) && (fontSize > 9.0)) fontSize -= 1; // Reduce fontSize + if (IsKeyPressed(KEY_RIGHT) && (fontSize < 15.0)) fontSize += 1; // Increase fontSize // Set fontsize for the shader SetShaderValue(shader, fontSizeLoc, &fontSize, SHADER_UNIFORM_FLOAT); // Draw //---------------------------------------------------------------------------------- - BeginTextureMode(target); - ClearBackground(WHITE); // The background of the scene itself + ClearBackground(WHITE); - // Samples Using custom shader + // Draw scene in our render texture DrawTexture(fudesumi, 500, -30, WHITE); DrawTextureV(raysan, circlePos, WHITE); - EndTextureMode(); + BeginDrawing(); - ClearBackground(RAYWHITE); BeginShaderMode(shader); - // Draw the scene texture (that we rendered earlier) to the screen // The shader will process every pixel of this texture DrawTextureRec(target.texture, - (Rectangle){ 0, 0, (float)target.texture.width, (float)-target.texture.height }, - (Vector2){ 0, 0 }, - WHITE); + (Rectangle){ 0, 0, (float)target.texture.width, (float)-target.texture.height }, + (Vector2){ 0, 0 }, WHITE); EndShaderMode(); DrawRectangle(0, 0, screenWidth, 40, BLACK); DrawText(TextFormat("Ascii effect - FontSize:%2.0f - [Left] -1 [Right] +1 ", fontSize), 120, 10, 20, LIGHTGRAY); DrawFPS(10, 10); - EndDrawing(); //---------------------------------------------------------------------------------- } // De-Initialization //-------------------------------------------------------------------------------------- - UnloadShader(shader); // Unload shader - UnloadTexture(fudesumi); // Unload texture - UnloadTexture(raysan); // Unload texture + UnloadRenderTexture(target); // Unload render texture + + UnloadShader(shader); // Unload shader + UnloadTexture(fudesumi); // Unload texture + UnloadTexture(raysan); // Unload texture CloseWindow(); // Close window and OpenGL context //-------------------------------------------------------------------------------------- From 8932ba0b0af037ffb27733a77e5a44e80915d66e Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 30 Sep 2025 18:48:42 +0200 Subject: [PATCH 059/167] Update core_delta_time.c --- examples/core/core_delta_time.c | 81 +++++++++++++-------------------- 1 file changed, 31 insertions(+), 50 deletions(-) diff --git a/examples/core/core_delta_time.c b/examples/core/core_delta_time.c index aeedd7fff..86bc969b3 100644 --- a/examples/core/core_delta_time.c +++ b/examples/core/core_delta_time.c @@ -32,12 +32,12 @@ int main(void) int currentFps = 60; // Store the position for the both of the circles - Vector2 deltaCircle = {0, screenHeight / 3.0f}; - Vector2 frameCircle = {0, screenHeight * (2.0f/3.0f)}; + Vector2 deltaCircle = { 0, (float)screenHeight/3.0f }; + Vector2 frameCircle = { 0, (float)screenHeight*(2.0f/3.0f) }; // The speed applied to both circles - const float speed = 10.0; - const float circleRadius = 32; + const float speed = 10.0f; + const float circleRadius = 32.0f; SetTargetFPS(currentFps); //-------------------------------------------------------------------------------------- @@ -46,77 +46,58 @@ int main(void) while (!WindowShouldClose()) // Detect window close button or ESC key { // Update - //---------------------------------------------- - if (IsKeyPressed(KEY_R)) // Reset both circles' positions when you press R - { - deltaCircle.x = 0; - frameCircle.x = 0; - } - + //---------------------------------------------------------------------------------- // Adjust the FPS target based on the mouse wheel float mouseWheel = GetMouseWheelMove(); if (mouseWheel != 0) { currentFps += (int)mouseWheel; + if (currentFps < 0) currentFps = 0; SetTargetFPS(currentFps); } // GetFrameTime() returns the time it took to draw the last frame, in seconds (usually called delta time) // Uses the delta time to make the circle look like it's moving at a "consistent" speed regardless of FPS - // Multiply by 6.0 (an arbitrary value) in order to make the speed visually closer to the other circle (at 60 fps), for comparison - deltaCircle.x += GetFrameTime() * 6.0f * speed; + // Multiply by 6.0 (an arbitrary value) in order to make the speed + // visually closer to the other circle (at 60 fps), for comparison + deltaCircle.x += GetFrameTime()*6.0f*speed; // This circle can move faster or slower visually depending on the FPS - frameCircle.x += .1f * speed; + frameCircle.x += 0.1f*speed; // If either circle is off the screen, reset it back to the start - if (deltaCircle.x > screenWidth) + if (deltaCircle.x > screenWidth) deltaCircle.x = 0; + if (frameCircle.x > screenWidth) frameCircle.x = 0; + + // Reset both circles positions + if (IsKeyPressed(KEY_R)) { deltaCircle.x = 0; - } - - if (frameCircle.x > screenWidth) - { frameCircle.x = 0; } + //---------------------------------------------------------------------------------- // Draw //---------------------------------------------------------------------------------- BeginDrawing(); + ClearBackground(RAYWHITE); - ClearBackground(RAYWHITE); + // Draw both circles to the screen + DrawCircleV(deltaCircle, circleRadius, RED); + DrawCircleV(frameCircle, circleRadius, BLUE); - // Draw both circles to the screen - DrawCircleV(deltaCircle, circleRadius, RED); - DrawCircleV(frameCircle, circleRadius, BLUE); + // Draw the help text + // Determine what help text to show depending on the current FPS target + const char *fpsText = 0; + if (currentFps <= 0) fpsText = TextFormat("FPS: unlimited (%i)", GetFPS()); + else fpsText = TextFormat("FPS: %i (target: %i)", GetFPS(), currentFps); + DrawText(fpsText, 10, 10, 20, DARKGRAY); + DrawText(TextFormat("Frame time: %02.02f ms", GetFrameTime()), 10, 30, 20, DARKGRAY); + DrawText("Use the scroll wheel to change the fps limit, r to reset", 10, 50, 20, DARKGRAY); - // Determine what help text to show depending on the current FPS target - const char* fpsText; - - if (currentFps <= 0) - { - if (currentFps < 0) - { - // Clamp values below 0 - currentFps = 0; - } - - // Special text for when the FPS target is set to 0 or less, which makes it unlimited - fpsText = TextFormat("fps: unlimited (%i)", GetFPS()); - } - else - { - fpsText = TextFormat("fps: %i (target: %i)", GetFPS(), currentFps); - } - - // Draw the help text - DrawText(fpsText, 10, 10, 20, DARKGRAY); - DrawText(TextFormat("frame time: %02.02f ms", GetFrameTime()), 10, 30, 20, DARKGRAY); - DrawText("use the scroll wheel to change the fps limit, r to reset", 10, 50, 20, DARKGRAY); - - // Draw the text above the circles - DrawText("x += GetFrameTime() * speed", 10, 90, 20, RED); - DrawText("x += speed", 10, 240, 20, BLUE); + // Draw the text above the circles + DrawText("FUNC: x += GetFrameTime()*speed", 10, 90, 20, RED); + DrawText("FUNC: x += speed", 10, 240, 20, BLUE); EndDrawing(); //---------------------------------------------------------------------------------- From 6ed61e107b5e21a09d13ed261e3110c7b2c035b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robin=20=E2=9D=A4=EF=B8=8F?= Date: Tue, 30 Sep 2025 15:49:58 -0400 Subject: [PATCH 060/167] flipped binary check to fix bug (#5220) --- examples/core/core_input_mouse.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/core/core_input_mouse.c b/examples/core/core_input_mouse.c index bbe519f82..f429018b0 100644 --- a/examples/core/core_input_mouse.c +++ b/examples/core/core_input_mouse.c @@ -72,7 +72,7 @@ int main(void) DrawText("move ball with mouse and click mouse button to change color", 10, 10, 20, DARKGRAY); DrawText("Press 'H' to toggle cursor visibility", 10, 30, 20, DARKGRAY); - if (!IsCursorHidden()) DrawText("CURSOR HIDDEN", 20, 60, 20, RED); + if (IsCursorHidden()) DrawText("CURSOR HIDDEN", 20, 60, 20, RED); else DrawText("CURSOR VISIBLE", 20, 60, 20, LIME); EndDrawing(); From e5f809f534d335e030c5ae71756e1ca6e5613862 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robin=20=E2=9D=A4=EF=B8=8F?= Date: Wed, 1 Oct 2025 05:42:35 -0400 Subject: [PATCH 061/167] switch to enum (#5223) --- examples/core/core_3d_camera_free.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/core/core_3d_camera_free.c b/examples/core/core_3d_camera_free.c index dde6a6c7d..448eb583e 100644 --- a/examples/core/core_3d_camera_free.c +++ b/examples/core/core_3d_camera_free.c @@ -49,7 +49,7 @@ int main(void) //---------------------------------------------------------------------------------- UpdateCamera(&camera, CAMERA_FREE); - if (IsKeyPressed('Z')) camera.target = (Vector3){ 0.0f, 0.0f, 0.0f }; + if (IsKeyPressed(KEY_Z)) camera.target = (Vector3){ 0.0f, 0.0f, 0.0f }; //---------------------------------------------------------------------------------- // Draw From f680776941823a56142f61ec93bb062cc792fbde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Almeida?= <60551627+luis605@users.noreply.github.com> Date: Wed, 1 Oct 2025 10:43:38 +0100 Subject: [PATCH 062/167] feat:Added DrawLineDashed() and a new example explaining how to use this new function. (#5222) --- examples/Makefile | 5 +- examples/Makefile.Web | 5 +- examples/README.md | 1 + examples/examples_list.txt | 1 + examples/shapes/shapes_dashed_line.c | 103 +++++++++++++++++++++++++ examples/shapes/shapes_dashed_line.png | Bin 0 -> 16908 bytes src/raylib.h | 1 + src/rshapes.c | 49 ++++++++++++ 8 files changed, 161 insertions(+), 4 deletions(-) create mode 100644 examples/shapes/shapes_dashed_line.c create mode 100644 examples/shapes/shapes_dashed_line.png diff --git a/examples/Makefile b/examples/Makefile index de02ae085..9a3f640b7 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -355,7 +355,7 @@ ifeq ($(TARGET_PLATFORM),$(filter $(TARGET_PLATFORM),PLATFORM_WEB PLATFORM_WEB_R ifeq ($(BUILD_WEB_WEBGL2),TRUE) LDFLAGS += -sMIN_WEBGL_VERSION=2 -sMAX_WEBGL_VERSION=2 endif - + # Add resources building if required ifeq ($(BUILD_WEB_RESOURCES),TRUE) LDFLAGS += --preload-file $(BUILD_WEB_RESOURCES_PATH) @@ -559,7 +559,8 @@ SHAPES = \ shapes/shapes_ring_drawing \ shapes/shapes_rounded_rectangle_drawing \ shapes/shapes_splines_drawing \ - shapes/shapes_top_down_lights + shapes/shapes_top_down_lights \ + shapes/shapes_dashed_line TEXTURES = \ textures/textures_background_scrolling \ diff --git a/examples/Makefile.Web b/examples/Makefile.Web index 8c9707274..20d737c38 100644 --- a/examples/Makefile.Web +++ b/examples/Makefile.Web @@ -355,7 +355,7 @@ ifeq ($(TARGET_PLATFORM),$(filter $(TARGET_PLATFORM),PLATFORM_WEB PLATFORM_WEB_R ifeq ($(BUILD_WEB_WEBGL2),TRUE) LDFLAGS += -sMIN_WEBGL_VERSION=2 -sMAX_WEBGL_VERSION=2 endif - + # Add resources building if required ifeq ($(BUILD_WEB_RESOURCES),TRUE) LDFLAGS += --preload-file $(BUILD_WEB_RESOURCES_PATH) @@ -559,7 +559,8 @@ SHAPES = \ shapes/shapes_ring_drawing \ shapes/shapes_rounded_rectangle_drawing \ shapes/shapes_splines_drawing \ - shapes/shapes_top_down_lights + shapes/shapes_top_down_lights \ + shapes/shapes_dashed_line TEXTURES = \ textures/textures_background_scrolling \ diff --git a/examples/README.md b/examples/README.md index 92ea9aa07..a5ee53afd 100644 --- a/examples/README.md +++ b/examples/README.md @@ -91,6 +91,7 @@ Examples using raylib shapes drawing functionality, provided by raylib [shapes]( | [shapes_splines_drawing](shapes/shapes_splines_drawing.c) | shapes_splines_drawing | ⭐⭐⭐☆ | 5.0 | 5.0 | [Ramon Santamaria](https://github.com/raysan5) | | [shapes_digital_clock](shapes/shapes_digital_clock.c) | shapes_digital_clock | ⭐⭐⭐⭐️ | 5.5 | 5.6 | [Hamza RAHAL](https://github.com/hmz-rhl) | | [shapes_double_pendulum](shapes/shapes_double_pendulum.c) | shapes_double_pendulum | ⭐⭐☆☆ | 5.5 | 5.5 | [JoeCheong](https://github.com/Joecheong2006) | +| [shapes_dashed_line](shapes/shapes_dashed_line.c) | shapes_dashed_line | ⭐☆☆☆ | 5.5 | 5.5 | [Luís Almeida](https://github.com/luis605) | ### category: textures [26] diff --git a/examples/examples_list.txt b/examples/examples_list.txt index 6af9bb6eb..10bf09ceb 100644 --- a/examples/examples_list.txt +++ b/examples/examples_list.txt @@ -66,6 +66,7 @@ shapes;shapes_rectangle_advanced;★★★★;5.5;5.5;2024;2025;"Everton Jr.";@e shapes;shapes_splines_drawing;★★★☆;5.0;5.0;2023;2025;"Ramon Santamaria";@raysan5 shapes;shapes_digital_clock;★★★★;5.5;5.6;2025;2025;"Hamza RAHAL";@hmz-rhl shapes;shapes_double_pendulum;★★☆☆;5.5;5.5;2025;2025;"JoeCheong";@Joecheong2006 +shapes;shapes_dashed_line;★☆☆☆;5.5;5.5;2025;2025;"Luís Almeida";@luis605 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 diff --git a/examples/shapes/shapes_dashed_line.c b/examples/shapes/shapes_dashed_line.c new file mode 100644 index 000000000..fd017562f --- /dev/null +++ b/examples/shapes/shapes_dashed_line.c @@ -0,0 +1,103 @@ +/******************************************************************************************* +* +* raylib [shapes] example - dashed line drawing +* +* Example complexity rating: [★☆☆☆] 1/4 +* +* Example originally created with raylib 2.5, last time updated with raylib 2.5 +* +* Example contributed by Luís Almeida (@luis605) +* +* 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 Luís Almeida (@luis605) +* +********************************************************************************************/ + +#include "raylib.h" +#define RAYGUI_IMPLEMENTATION +#include "raygui.h" // Required for GUI controls + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [shapes] example - interactive dashed line"); + + // Line Properties + Vector2 lineStartPosition = { 20.0f, 50.0f }; + Vector2 lineEndPosition = { 780.0f, 400.0f }; + float dashLength = 25.0f; + float blankLength = 15.0f; + + // Color selection + Color lineColors[] = { RED, ORANGE, GOLD, GREEN, BLUE, VIOLET, PINK, BLACK }; + int colorIndex = 0; + + 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 + //---------------------------------------------------------------------------------- + lineEndPosition = GetMousePosition(); // Line endpoint follows the mouse + + // --- Keyboard Controls --- + + // Change Dash Length (UP/DOWN arrows) + if (IsKeyDown(KEY_UP)) dashLength += 1.0f; + if (IsKeyDown(KEY_DOWN) && dashLength > 1.0f) dashLength -= 1.0f; + + // Change Space Length (LEFT/RIGHT arrows) + if (IsKeyDown(KEY_RIGHT)) blankLength += 1.0f; + if (IsKeyDown(KEY_LEFT) && blankLength > 1.0f) blankLength -= 1.0f; + + // Cycle through colors ('C' key) + if (IsKeyPressed(KEY_C)) + { + colorIndex = (colorIndex + 1) % (sizeof(lineColors)/sizeof(Color)); + } + + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + // Draw the dashed line with the current properties + DrawLineDashed(lineStartPosition, lineEndPosition, dashLength, blankLength, lineColors[colorIndex]); + + // Draw UI and Instructions + DrawRectangle(5, 5, 265, 95, Fade(SKYBLUE, 0.5f)); + DrawRectangleLines(5, 5, 265, 95, BLUE); + + DrawText("CONTROLS:", 15, 15, 10, BLACK); + DrawText("UP/DOWN: Change Dash Length", 15, 35, 10, BLACK); + DrawText("LEFT/RIGHT: Change Space Length", 15, 55, 10, BLACK); + DrawText("C: Cycle Color", 15, 75, 10, BLACK); + + DrawText(TextFormat("Dash: %.0f | Space: %.0f", dashLength, blankLength), 15, 115, 10, DARKGRAY); + + DrawFPS(screenWidth - 80, 10); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} \ No newline at end of file diff --git a/examples/shapes/shapes_dashed_line.png b/examples/shapes/shapes_dashed_line.png new file mode 100644 index 0000000000000000000000000000000000000000..5c3ce3ef3fc5ae84996f01b90b56b235fcd42308 GIT binary patch literal 16908 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 literal 0 HcmV?d00001 diff --git a/src/raylib.h b/src/raylib.h index 642f9318c..b7ccaae22 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1258,6 +1258,7 @@ RLAPI Rectangle GetShapesTextureRectangle(void); // Get texture source re RLAPI void DrawPixel(int posX, int posY, Color color); // Draw a pixel using geometry [Can be slow, use with care] RLAPI void DrawPixelV(Vector2 position, Color color); // Draw a pixel using geometry (Vector version) [Can be slow, use with care] RLAPI void DrawLine(int startPosX, int startPosY, int endPosX, int endPosY, Color color); // Draw a line +RLAPI void DrawLineDashed(Vector2 startPos, Vector2 endPos, int dashSize, int whiteSpaceSize, Color color); // Draw a dashed line RLAPI void DrawLineV(Vector2 startPos, Vector2 endPos, Color color); // Draw a line (using gl lines) RLAPI void DrawLineEx(Vector2 startPos, Vector2 endPos, float thick, Color color); // Draw a line (using triangles/quads) RLAPI void DrawLineStrip(const Vector2 *points, int pointCount, Color color); // Draw lines sequence (using gl lines) diff --git a/src/rshapes.c b/src/rshapes.c index 14e3f856a..a62b1c5f8 100644 --- a/src/rshapes.c +++ b/src/rshapes.c @@ -182,6 +182,55 @@ void DrawLine(int startPosX, int startPosY, int endPosX, int endPosY, Color colo rlEnd(); } +void DrawLineDashed(Vector2 startPos, Vector2 endPos, int dashSize, int whiteSpaceSize, Color color) +{ + // Calculate the vector and length of the line + float dx = endPos.x - startPos.x; + float dy = endPos.y - startPos.y; + float lineLength = sqrtf(dx*dx + dy*dy); + + // If the line is too short for dashing or dash size is invalid, draw a solid thick line + if (lineLength < (dashSize + whiteSpaceSize) || dashSize <= 0) + { + DrawLineV(startPos, endPos, color); + return; + } + + // Calculate the normalized direction vector of the line + float invLineLength = 1 / lineLength; + float dirX = dx * invLineLength; + float dirY = dy * invLineLength; + + Vector2 currentPos = startPos; + float distanceTraveled = 0; + + rlBegin(RL_LINES); + rlColor4ub(color.r, color.g, color.b, color.a); + + while (distanceTraveled < lineLength) + { + // Calculate the end of the current dash + float dashEndDist = distanceTraveled + dashSize; + if (dashEndDist > lineLength) + { + dashEndDist = lineLength; + } + + Vector2 dashEndPos = { startPos.x + dashEndDist * dirX, startPos.y + dashEndDist * dirY }; + + // Draw the dash segment + rlVertex2f(currentPos.x, currentPos.y); + rlVertex2f(dashEndPos.x, dashEndPos.y); + + // Update the distance traveled and move the current position for the next dash + distanceTraveled = dashEndDist + whiteSpaceSize; + currentPos.x = startPos.x + distanceTraveled * dirX; + currentPos.y = startPos.y + distanceTraveled * dirY; + } + + rlEnd(); +} + // Draw a line (using gl lines) void DrawLineV(Vector2 startPos, Vector2 endPos, Color color) { From 6f1077737e48d447380cf5573adf1394dfe3aac6 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 1 Oct 2025 09:43:50 +0000 Subject: [PATCH 063/167] Update raylib_api.* by CI --- tools/parser/output/raylib_api.json | 27 + tools/parser/output/raylib_api.lua | 12 + tools/parser/output/raylib_api.txt | 759 ++++++++++++++-------------- tools/parser/output/raylib_api.xml | 9 +- 4 files changed, 431 insertions(+), 376 deletions(-) diff --git a/tools/parser/output/raylib_api.json b/tools/parser/output/raylib_api.json index 5c641bac3..7b2ffdc9d 100644 --- a/tools/parser/output/raylib_api.json +++ b/tools/parser/output/raylib_api.json @@ -5508,6 +5508,33 @@ } ] }, + { + "name": "DrawLineDashed", + "description": "Draw a dashed line", + "returnType": "void", + "params": [ + { + "type": "Vector2", + "name": "startPos" + }, + { + "type": "Vector2", + "name": "endPos" + }, + { + "type": "int", + "name": "dashSize" + }, + { + "type": "int", + "name": "whiteSpaceSize" + }, + { + "type": "Color", + "name": "color" + } + ] + }, { "name": "DrawLineV", "description": "Draw a line (using gl lines)", diff --git a/tools/parser/output/raylib_api.lua b/tools/parser/output/raylib_api.lua index ce3671159..62dc9b25d 100644 --- a/tools/parser/output/raylib_api.lua +++ b/tools/parser/output/raylib_api.lua @@ -4758,6 +4758,18 @@ return { {type = "Color", name = "color"} } }, + { + name = "DrawLineDashed", + description = "Draw a dashed line", + returnType = "void", + params = { + {type = "Vector2", name = "startPos"}, + {type = "Vector2", name = "endPos"}, + {type = "int", name = "dashSize"}, + {type = "int", name = "whiteSpaceSize"}, + {type = "Color", name = "color"} + } + }, { name = "DrawLineV", description = "Draw a line (using gl lines)", diff --git a/tools/parser/output/raylib_api.txt b/tools/parser/output/raylib_api.txt index 94568b690..ea00fc74e 100644 --- a/tools/parser/output/raylib_api.txt +++ b/tools/parser/output/raylib_api.txt @@ -993,7 +993,7 @@ Callback 006: AudioCallback() (2 input parameters) Param[1]: bufferData (type: void *) Param[2]: frames (type: unsigned int) -Functions found: 595 +Functions found: 596 Function 001: InitWindow() (3 input parameters) Name: InitWindow @@ -2190,14 +2190,23 @@ Function 221: DrawLine() (5 input parameters) Param[3]: endPosX (type: int) Param[4]: endPosY (type: int) Param[5]: color (type: Color) -Function 222: DrawLineV() (3 input parameters) +Function 222: DrawLineDashed() (5 input parameters) + Name: DrawLineDashed + Return type: void + Description: Draw a dashed line + Param[1]: startPos (type: Vector2) + Param[2]: endPos (type: Vector2) + Param[3]: dashSize (type: int) + Param[4]: whiteSpaceSize (type: int) + Param[5]: color (type: Color) +Function 223: DrawLineV() (3 input parameters) Name: DrawLineV Return type: void Description: Draw a line (using gl lines) Param[1]: startPos (type: Vector2) Param[2]: endPos (type: Vector2) Param[3]: color (type: Color) -Function 223: DrawLineEx() (4 input parameters) +Function 224: DrawLineEx() (4 input parameters) Name: DrawLineEx Return type: void Description: Draw a line (using triangles/quads) @@ -2205,14 +2214,14 @@ Function 223: DrawLineEx() (4 input parameters) Param[2]: endPos (type: Vector2) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 224: DrawLineStrip() (3 input parameters) +Function 225: DrawLineStrip() (3 input parameters) Name: DrawLineStrip Return type: void Description: Draw lines sequence (using gl lines) Param[1]: points (type: const Vector2 *) Param[2]: pointCount (type: int) Param[3]: color (type: Color) -Function 225: DrawLineBezier() (4 input parameters) +Function 226: DrawLineBezier() (4 input parameters) Name: DrawLineBezier Return type: void Description: Draw line segment cubic-bezier in-out interpolation @@ -2220,7 +2229,7 @@ Function 225: DrawLineBezier() (4 input parameters) Param[2]: endPos (type: Vector2) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 226: DrawCircle() (4 input parameters) +Function 227: DrawCircle() (4 input parameters) Name: DrawCircle Return type: void Description: Draw a color-filled circle @@ -2228,7 +2237,7 @@ Function 226: DrawCircle() (4 input parameters) Param[2]: centerY (type: int) Param[3]: radius (type: float) Param[4]: color (type: Color) -Function 227: DrawCircleSector() (6 input parameters) +Function 228: DrawCircleSector() (6 input parameters) Name: DrawCircleSector Return type: void Description: Draw a piece of a circle @@ -2238,7 +2247,7 @@ Function 227: DrawCircleSector() (6 input parameters) Param[4]: endAngle (type: float) Param[5]: segments (type: int) Param[6]: color (type: Color) -Function 228: DrawCircleSectorLines() (6 input parameters) +Function 229: DrawCircleSectorLines() (6 input parameters) Name: DrawCircleSectorLines Return type: void Description: Draw circle sector outline @@ -2248,7 +2257,7 @@ Function 228: DrawCircleSectorLines() (6 input parameters) Param[4]: endAngle (type: float) Param[5]: segments (type: int) Param[6]: color (type: Color) -Function 229: DrawCircleGradient() (5 input parameters) +Function 230: DrawCircleGradient() (5 input parameters) Name: DrawCircleGradient Return type: void Description: Draw a gradient-filled circle @@ -2257,14 +2266,14 @@ Function 229: DrawCircleGradient() (5 input parameters) Param[3]: radius (type: float) Param[4]: inner (type: Color) Param[5]: outer (type: Color) -Function 230: DrawCircleV() (3 input parameters) +Function 231: DrawCircleV() (3 input parameters) Name: DrawCircleV Return type: void Description: Draw a color-filled circle (Vector version) Param[1]: center (type: Vector2) Param[2]: radius (type: float) Param[3]: color (type: Color) -Function 231: DrawCircleLines() (4 input parameters) +Function 232: DrawCircleLines() (4 input parameters) Name: DrawCircleLines Return type: void Description: Draw circle outline @@ -2272,14 +2281,14 @@ Function 231: DrawCircleLines() (4 input parameters) Param[2]: centerY (type: int) Param[3]: radius (type: float) Param[4]: color (type: Color) -Function 232: DrawCircleLinesV() (3 input parameters) +Function 233: DrawCircleLinesV() (3 input parameters) Name: DrawCircleLinesV Return type: void Description: Draw circle outline (Vector version) Param[1]: center (type: Vector2) Param[2]: radius (type: float) Param[3]: color (type: Color) -Function 233: DrawEllipse() (5 input parameters) +Function 234: DrawEllipse() (5 input parameters) Name: DrawEllipse Return type: void Description: Draw ellipse @@ -2288,7 +2297,7 @@ Function 233: DrawEllipse() (5 input parameters) Param[3]: radiusH (type: float) Param[4]: radiusV (type: float) Param[5]: color (type: Color) -Function 234: DrawEllipseV() (4 input parameters) +Function 235: DrawEllipseV() (4 input parameters) Name: DrawEllipseV Return type: void Description: Draw ellipse (Vector version) @@ -2296,7 +2305,7 @@ Function 234: DrawEllipseV() (4 input parameters) Param[2]: radiusH (type: float) Param[3]: radiusV (type: float) Param[4]: color (type: Color) -Function 235: DrawEllipseLines() (5 input parameters) +Function 236: DrawEllipseLines() (5 input parameters) Name: DrawEllipseLines Return type: void Description: Draw ellipse outline @@ -2305,7 +2314,7 @@ Function 235: DrawEllipseLines() (5 input parameters) Param[3]: radiusH (type: float) Param[4]: radiusV (type: float) Param[5]: color (type: Color) -Function 236: DrawEllipseLinesV() (4 input parameters) +Function 237: DrawEllipseLinesV() (4 input parameters) Name: DrawEllipseLinesV Return type: void Description: Draw ellipse outline (Vector version) @@ -2313,7 +2322,7 @@ Function 236: DrawEllipseLinesV() (4 input parameters) Param[2]: radiusH (type: float) Param[3]: radiusV (type: float) Param[4]: color (type: Color) -Function 237: DrawRing() (7 input parameters) +Function 238: DrawRing() (7 input parameters) Name: DrawRing Return type: void Description: Draw ring @@ -2324,7 +2333,7 @@ Function 237: DrawRing() (7 input parameters) Param[5]: endAngle (type: float) Param[6]: segments (type: int) Param[7]: color (type: Color) -Function 238: DrawRingLines() (7 input parameters) +Function 239: DrawRingLines() (7 input parameters) Name: DrawRingLines Return type: void Description: Draw ring outline @@ -2335,7 +2344,7 @@ Function 238: DrawRingLines() (7 input parameters) Param[5]: endAngle (type: float) Param[6]: segments (type: int) Param[7]: color (type: Color) -Function 239: DrawRectangle() (5 input parameters) +Function 240: DrawRectangle() (5 input parameters) Name: DrawRectangle Return type: void Description: Draw a color-filled rectangle @@ -2344,20 +2353,20 @@ Function 239: DrawRectangle() (5 input parameters) Param[3]: width (type: int) Param[4]: height (type: int) Param[5]: color (type: Color) -Function 240: DrawRectangleV() (3 input parameters) +Function 241: DrawRectangleV() (3 input parameters) Name: DrawRectangleV Return type: void Description: Draw a color-filled rectangle (Vector version) Param[1]: position (type: Vector2) Param[2]: size (type: Vector2) Param[3]: color (type: Color) -Function 241: DrawRectangleRec() (2 input parameters) +Function 242: DrawRectangleRec() (2 input parameters) Name: DrawRectangleRec Return type: void Description: Draw a color-filled rectangle Param[1]: rec (type: Rectangle) Param[2]: color (type: Color) -Function 242: DrawRectanglePro() (4 input parameters) +Function 243: DrawRectanglePro() (4 input parameters) Name: DrawRectanglePro Return type: void Description: Draw a color-filled rectangle with pro parameters @@ -2365,7 +2374,7 @@ Function 242: DrawRectanglePro() (4 input parameters) Param[2]: origin (type: Vector2) Param[3]: rotation (type: float) Param[4]: color (type: Color) -Function 243: DrawRectangleGradientV() (6 input parameters) +Function 244: DrawRectangleGradientV() (6 input parameters) Name: DrawRectangleGradientV Return type: void Description: Draw a vertical-gradient-filled rectangle @@ -2375,7 +2384,7 @@ Function 243: DrawRectangleGradientV() (6 input parameters) Param[4]: height (type: int) Param[5]: top (type: Color) Param[6]: bottom (type: Color) -Function 244: DrawRectangleGradientH() (6 input parameters) +Function 245: DrawRectangleGradientH() (6 input parameters) Name: DrawRectangleGradientH Return type: void Description: Draw a horizontal-gradient-filled rectangle @@ -2385,7 +2394,7 @@ Function 244: DrawRectangleGradientH() (6 input parameters) Param[4]: height (type: int) Param[5]: left (type: Color) Param[6]: right (type: Color) -Function 245: DrawRectangleGradientEx() (5 input parameters) +Function 246: DrawRectangleGradientEx() (5 input parameters) Name: DrawRectangleGradientEx Return type: void Description: Draw a gradient-filled rectangle with custom vertex colors @@ -2394,7 +2403,7 @@ Function 245: DrawRectangleGradientEx() (5 input parameters) Param[3]: bottomLeft (type: Color) Param[4]: bottomRight (type: Color) Param[5]: topRight (type: Color) -Function 246: DrawRectangleLines() (5 input parameters) +Function 247: DrawRectangleLines() (5 input parameters) Name: DrawRectangleLines Return type: void Description: Draw rectangle outline @@ -2403,14 +2412,14 @@ Function 246: DrawRectangleLines() (5 input parameters) Param[3]: width (type: int) Param[4]: height (type: int) Param[5]: color (type: Color) -Function 247: DrawRectangleLinesEx() (3 input parameters) +Function 248: DrawRectangleLinesEx() (3 input parameters) Name: DrawRectangleLinesEx Return type: void Description: Draw rectangle outline with extended parameters Param[1]: rec (type: Rectangle) Param[2]: lineThick (type: float) Param[3]: color (type: Color) -Function 248: DrawRectangleRounded() (4 input parameters) +Function 249: DrawRectangleRounded() (4 input parameters) Name: DrawRectangleRounded Return type: void Description: Draw rectangle with rounded edges @@ -2418,7 +2427,7 @@ Function 248: DrawRectangleRounded() (4 input parameters) Param[2]: roundness (type: float) Param[3]: segments (type: int) Param[4]: color (type: Color) -Function 249: DrawRectangleRoundedLines() (4 input parameters) +Function 250: DrawRectangleRoundedLines() (4 input parameters) Name: DrawRectangleRoundedLines Return type: void Description: Draw rectangle lines with rounded edges @@ -2426,7 +2435,7 @@ Function 249: DrawRectangleRoundedLines() (4 input parameters) Param[2]: roundness (type: float) Param[3]: segments (type: int) Param[4]: color (type: Color) -Function 250: DrawRectangleRoundedLinesEx() (5 input parameters) +Function 251: DrawRectangleRoundedLinesEx() (5 input parameters) Name: DrawRectangleRoundedLinesEx Return type: void Description: Draw rectangle with rounded edges outline @@ -2435,7 +2444,7 @@ Function 250: DrawRectangleRoundedLinesEx() (5 input parameters) Param[3]: segments (type: int) Param[4]: lineThick (type: float) Param[5]: color (type: Color) -Function 251: DrawTriangle() (4 input parameters) +Function 252: DrawTriangle() (4 input parameters) Name: DrawTriangle Return type: void Description: Draw a color-filled triangle (vertex in counter-clockwise order!) @@ -2443,7 +2452,7 @@ Function 251: DrawTriangle() (4 input parameters) Param[2]: v2 (type: Vector2) Param[3]: v3 (type: Vector2) Param[4]: color (type: Color) -Function 252: DrawTriangleLines() (4 input parameters) +Function 253: DrawTriangleLines() (4 input parameters) Name: DrawTriangleLines Return type: void Description: Draw triangle outline (vertex in counter-clockwise order!) @@ -2451,21 +2460,21 @@ Function 252: DrawTriangleLines() (4 input parameters) Param[2]: v2 (type: Vector2) Param[3]: v3 (type: Vector2) Param[4]: color (type: Color) -Function 253: DrawTriangleFan() (3 input parameters) +Function 254: DrawTriangleFan() (3 input parameters) Name: DrawTriangleFan Return type: void Description: Draw a triangle fan defined by points (first vertex is the center) Param[1]: points (type: const Vector2 *) Param[2]: pointCount (type: int) Param[3]: color (type: Color) -Function 254: DrawTriangleStrip() (3 input parameters) +Function 255: DrawTriangleStrip() (3 input parameters) Name: DrawTriangleStrip Return type: void Description: Draw a triangle strip defined by points Param[1]: points (type: const Vector2 *) Param[2]: pointCount (type: int) Param[3]: color (type: Color) -Function 255: DrawPoly() (5 input parameters) +Function 256: DrawPoly() (5 input parameters) Name: DrawPoly Return type: void Description: Draw a regular polygon (Vector version) @@ -2474,7 +2483,7 @@ Function 255: DrawPoly() (5 input parameters) Param[3]: radius (type: float) Param[4]: rotation (type: float) Param[5]: color (type: Color) -Function 256: DrawPolyLines() (5 input parameters) +Function 257: DrawPolyLines() (5 input parameters) Name: DrawPolyLines Return type: void Description: Draw a polygon outline of n sides @@ -2483,7 +2492,7 @@ Function 256: DrawPolyLines() (5 input parameters) Param[3]: radius (type: float) Param[4]: rotation (type: float) Param[5]: color (type: Color) -Function 257: DrawPolyLinesEx() (6 input parameters) +Function 258: DrawPolyLinesEx() (6 input parameters) Name: DrawPolyLinesEx Return type: void Description: Draw a polygon outline of n sides with extended parameters @@ -2493,7 +2502,7 @@ Function 257: DrawPolyLinesEx() (6 input parameters) Param[4]: rotation (type: float) Param[5]: lineThick (type: float) Param[6]: color (type: Color) -Function 258: DrawSplineLinear() (4 input parameters) +Function 259: DrawSplineLinear() (4 input parameters) Name: DrawSplineLinear Return type: void Description: Draw spline: Linear, minimum 2 points @@ -2501,7 +2510,7 @@ Function 258: DrawSplineLinear() (4 input parameters) Param[2]: pointCount (type: int) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 259: DrawSplineBasis() (4 input parameters) +Function 260: DrawSplineBasis() (4 input parameters) Name: DrawSplineBasis Return type: void Description: Draw spline: B-Spline, minimum 4 points @@ -2509,7 +2518,7 @@ Function 259: DrawSplineBasis() (4 input parameters) Param[2]: pointCount (type: int) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 260: DrawSplineCatmullRom() (4 input parameters) +Function 261: DrawSplineCatmullRom() (4 input parameters) Name: DrawSplineCatmullRom Return type: void Description: Draw spline: Catmull-Rom, minimum 4 points @@ -2517,7 +2526,7 @@ Function 260: DrawSplineCatmullRom() (4 input parameters) Param[2]: pointCount (type: int) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 261: DrawSplineBezierQuadratic() (4 input parameters) +Function 262: DrawSplineBezierQuadratic() (4 input parameters) Name: DrawSplineBezierQuadratic Return type: void Description: Draw spline: Quadratic Bezier, minimum 3 points (1 control point): [p1, c2, p3, c4...] @@ -2525,7 +2534,7 @@ Function 261: DrawSplineBezierQuadratic() (4 input parameters) Param[2]: pointCount (type: int) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 262: DrawSplineBezierCubic() (4 input parameters) +Function 263: DrawSplineBezierCubic() (4 input parameters) Name: DrawSplineBezierCubic Return type: void Description: Draw spline: Cubic Bezier, minimum 4 points (2 control points): [p1, c2, c3, p4, c5, c6...] @@ -2533,7 +2542,7 @@ Function 262: DrawSplineBezierCubic() (4 input parameters) Param[2]: pointCount (type: int) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 263: DrawSplineSegmentLinear() (4 input parameters) +Function 264: DrawSplineSegmentLinear() (4 input parameters) Name: DrawSplineSegmentLinear Return type: void Description: Draw spline segment: Linear, 2 points @@ -2541,7 +2550,7 @@ Function 263: DrawSplineSegmentLinear() (4 input parameters) Param[2]: p2 (type: Vector2) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 264: DrawSplineSegmentBasis() (6 input parameters) +Function 265: DrawSplineSegmentBasis() (6 input parameters) Name: DrawSplineSegmentBasis Return type: void Description: Draw spline segment: B-Spline, 4 points @@ -2551,7 +2560,7 @@ Function 264: DrawSplineSegmentBasis() (6 input parameters) Param[4]: p4 (type: Vector2) Param[5]: thick (type: float) Param[6]: color (type: Color) -Function 265: DrawSplineSegmentCatmullRom() (6 input parameters) +Function 266: DrawSplineSegmentCatmullRom() (6 input parameters) Name: DrawSplineSegmentCatmullRom Return type: void Description: Draw spline segment: Catmull-Rom, 4 points @@ -2561,7 +2570,7 @@ Function 265: DrawSplineSegmentCatmullRom() (6 input parameters) Param[4]: p4 (type: Vector2) Param[5]: thick (type: float) Param[6]: color (type: Color) -Function 266: DrawSplineSegmentBezierQuadratic() (5 input parameters) +Function 267: DrawSplineSegmentBezierQuadratic() (5 input parameters) Name: DrawSplineSegmentBezierQuadratic Return type: void Description: Draw spline segment: Quadratic Bezier, 2 points, 1 control point @@ -2570,7 +2579,7 @@ Function 266: DrawSplineSegmentBezierQuadratic() (5 input parameters) Param[3]: p3 (type: Vector2) Param[4]: thick (type: float) Param[5]: color (type: Color) -Function 267: DrawSplineSegmentBezierCubic() (6 input parameters) +Function 268: DrawSplineSegmentBezierCubic() (6 input parameters) Name: DrawSplineSegmentBezierCubic Return type: void Description: Draw spline segment: Cubic Bezier, 2 points, 2 control points @@ -2580,14 +2589,14 @@ Function 267: DrawSplineSegmentBezierCubic() (6 input parameters) Param[4]: p4 (type: Vector2) Param[5]: thick (type: float) Param[6]: color (type: Color) -Function 268: GetSplinePointLinear() (3 input parameters) +Function 269: GetSplinePointLinear() (3 input parameters) Name: GetSplinePointLinear Return type: Vector2 Description: Get (evaluate) spline point: Linear Param[1]: startPos (type: Vector2) Param[2]: endPos (type: Vector2) Param[3]: t (type: float) -Function 269: GetSplinePointBasis() (5 input parameters) +Function 270: GetSplinePointBasis() (5 input parameters) Name: GetSplinePointBasis Return type: Vector2 Description: Get (evaluate) spline point: B-Spline @@ -2596,7 +2605,7 @@ Function 269: GetSplinePointBasis() (5 input parameters) Param[3]: p3 (type: Vector2) Param[4]: p4 (type: Vector2) Param[5]: t (type: float) -Function 270: GetSplinePointCatmullRom() (5 input parameters) +Function 271: GetSplinePointCatmullRom() (5 input parameters) Name: GetSplinePointCatmullRom Return type: Vector2 Description: Get (evaluate) spline point: Catmull-Rom @@ -2605,7 +2614,7 @@ Function 270: GetSplinePointCatmullRom() (5 input parameters) Param[3]: p3 (type: Vector2) Param[4]: p4 (type: Vector2) Param[5]: t (type: float) -Function 271: GetSplinePointBezierQuad() (4 input parameters) +Function 272: GetSplinePointBezierQuad() (4 input parameters) Name: GetSplinePointBezierQuad Return type: Vector2 Description: Get (evaluate) spline point: Quadratic Bezier @@ -2613,7 +2622,7 @@ Function 271: GetSplinePointBezierQuad() (4 input parameters) Param[2]: c2 (type: Vector2) Param[3]: p3 (type: Vector2) Param[4]: t (type: float) -Function 272: GetSplinePointBezierCubic() (5 input parameters) +Function 273: GetSplinePointBezierCubic() (5 input parameters) Name: GetSplinePointBezierCubic Return type: Vector2 Description: Get (evaluate) spline point: Cubic Bezier @@ -2622,13 +2631,13 @@ Function 272: GetSplinePointBezierCubic() (5 input parameters) Param[3]: c3 (type: Vector2) Param[4]: p4 (type: Vector2) Param[5]: t (type: float) -Function 273: CheckCollisionRecs() (2 input parameters) +Function 274: CheckCollisionRecs() (2 input parameters) Name: CheckCollisionRecs Return type: bool Description: Check collision between two rectangles Param[1]: rec1 (type: Rectangle) Param[2]: rec2 (type: Rectangle) -Function 274: CheckCollisionCircles() (4 input parameters) +Function 275: CheckCollisionCircles() (4 input parameters) Name: CheckCollisionCircles Return type: bool Description: Check collision between two circles @@ -2636,14 +2645,14 @@ Function 274: CheckCollisionCircles() (4 input parameters) Param[2]: radius1 (type: float) Param[3]: center2 (type: Vector2) Param[4]: radius2 (type: float) -Function 275: CheckCollisionCircleRec() (3 input parameters) +Function 276: CheckCollisionCircleRec() (3 input parameters) Name: CheckCollisionCircleRec Return type: bool Description: Check collision between circle and rectangle Param[1]: center (type: Vector2) Param[2]: radius (type: float) Param[3]: rec (type: Rectangle) -Function 276: CheckCollisionCircleLine() (4 input parameters) +Function 277: CheckCollisionCircleLine() (4 input parameters) Name: CheckCollisionCircleLine Return type: bool Description: Check if circle collides with a line created betweeen two points [p1] and [p2] @@ -2651,20 +2660,20 @@ Function 276: CheckCollisionCircleLine() (4 input parameters) Param[2]: radius (type: float) Param[3]: p1 (type: Vector2) Param[4]: p2 (type: Vector2) -Function 277: CheckCollisionPointRec() (2 input parameters) +Function 278: CheckCollisionPointRec() (2 input parameters) Name: CheckCollisionPointRec Return type: bool Description: Check if point is inside rectangle Param[1]: point (type: Vector2) Param[2]: rec (type: Rectangle) -Function 278: CheckCollisionPointCircle() (3 input parameters) +Function 279: CheckCollisionPointCircle() (3 input parameters) Name: CheckCollisionPointCircle Return type: bool Description: Check if point is inside circle Param[1]: point (type: Vector2) Param[2]: center (type: Vector2) Param[3]: radius (type: float) -Function 279: CheckCollisionPointTriangle() (4 input parameters) +Function 280: CheckCollisionPointTriangle() (4 input parameters) Name: CheckCollisionPointTriangle Return type: bool Description: Check if point is inside a triangle @@ -2672,7 +2681,7 @@ Function 279: CheckCollisionPointTriangle() (4 input parameters) Param[2]: p1 (type: Vector2) Param[3]: p2 (type: Vector2) Param[4]: p3 (type: Vector2) -Function 280: CheckCollisionPointLine() (4 input parameters) +Function 281: CheckCollisionPointLine() (4 input parameters) Name: CheckCollisionPointLine Return type: bool Description: Check if point belongs to line created between two points [p1] and [p2] with defined margin in pixels [threshold] @@ -2680,14 +2689,14 @@ Function 280: CheckCollisionPointLine() (4 input parameters) Param[2]: p1 (type: Vector2) Param[3]: p2 (type: Vector2) Param[4]: threshold (type: int) -Function 281: CheckCollisionPointPoly() (3 input parameters) +Function 282: CheckCollisionPointPoly() (3 input parameters) Name: CheckCollisionPointPoly Return type: bool Description: Check if point is within a polygon described by array of vertices Param[1]: point (type: Vector2) Param[2]: points (type: const Vector2 *) Param[3]: pointCount (type: int) -Function 282: CheckCollisionLines() (5 input parameters) +Function 283: CheckCollisionLines() (5 input parameters) Name: CheckCollisionLines Return type: bool Description: Check the collision between two lines defined by two points each, returns collision point by reference @@ -2696,18 +2705,18 @@ Function 282: CheckCollisionLines() (5 input parameters) Param[3]: startPos2 (type: Vector2) Param[4]: endPos2 (type: Vector2) Param[5]: collisionPoint (type: Vector2 *) -Function 283: GetCollisionRec() (2 input parameters) +Function 284: GetCollisionRec() (2 input parameters) Name: GetCollisionRec Return type: Rectangle Description: Get collision rectangle for two rectangles collision Param[1]: rec1 (type: Rectangle) Param[2]: rec2 (type: Rectangle) -Function 284: LoadImage() (1 input parameters) +Function 285: LoadImage() (1 input parameters) Name: LoadImage Return type: Image Description: Load image from file into CPU memory (RAM) Param[1]: fileName (type: const char *) -Function 285: LoadImageRaw() (5 input parameters) +Function 286: LoadImageRaw() (5 input parameters) Name: LoadImageRaw Return type: Image Description: Load image from RAW file data @@ -2716,13 +2725,13 @@ Function 285: LoadImageRaw() (5 input parameters) Param[3]: height (type: int) Param[4]: format (type: int) Param[5]: headerSize (type: int) -Function 286: LoadImageAnim() (2 input parameters) +Function 287: LoadImageAnim() (2 input parameters) Name: LoadImageAnim Return type: Image Description: Load image sequence from file (frames appended to image.data) Param[1]: fileName (type: const char *) Param[2]: frames (type: int *) -Function 287: LoadImageAnimFromMemory() (4 input parameters) +Function 288: LoadImageAnimFromMemory() (4 input parameters) Name: LoadImageAnimFromMemory Return type: Image Description: Load image sequence from memory buffer @@ -2730,60 +2739,60 @@ Function 287: LoadImageAnimFromMemory() (4 input parameters) Param[2]: fileData (type: const unsigned char *) Param[3]: dataSize (type: int) Param[4]: frames (type: int *) -Function 288: LoadImageFromMemory() (3 input parameters) +Function 289: LoadImageFromMemory() (3 input parameters) Name: LoadImageFromMemory Return type: Image Description: Load image from memory buffer, fileType refers to extension: i.e. '.png' Param[1]: fileType (type: const char *) Param[2]: fileData (type: const unsigned char *) Param[3]: dataSize (type: int) -Function 289: LoadImageFromTexture() (1 input parameters) +Function 290: LoadImageFromTexture() (1 input parameters) Name: LoadImageFromTexture Return type: Image Description: Load image from GPU texture data Param[1]: texture (type: Texture2D) -Function 290: LoadImageFromScreen() (0 input parameters) +Function 291: LoadImageFromScreen() (0 input parameters) Name: LoadImageFromScreen Return type: Image Description: Load image from screen buffer and (screenshot) No input parameters -Function 291: IsImageValid() (1 input parameters) +Function 292: IsImageValid() (1 input parameters) Name: IsImageValid Return type: bool Description: Check if an image is valid (data and parameters) Param[1]: image (type: Image) -Function 292: UnloadImage() (1 input parameters) +Function 293: UnloadImage() (1 input parameters) Name: UnloadImage Return type: void Description: Unload image from CPU memory (RAM) Param[1]: image (type: Image) -Function 293: ExportImage() (2 input parameters) +Function 294: ExportImage() (2 input parameters) Name: ExportImage Return type: bool Description: Export image data to file, returns true on success Param[1]: image (type: Image) Param[2]: fileName (type: const char *) -Function 294: ExportImageToMemory() (3 input parameters) +Function 295: ExportImageToMemory() (3 input parameters) Name: ExportImageToMemory Return type: unsigned char * Description: Export image to memory buffer Param[1]: image (type: Image) Param[2]: fileType (type: const char *) Param[3]: fileSize (type: int *) -Function 295: ExportImageAsCode() (2 input parameters) +Function 296: ExportImageAsCode() (2 input parameters) Name: ExportImageAsCode Return type: bool Description: Export image as code file defining an array of bytes, returns true on success Param[1]: image (type: Image) Param[2]: fileName (type: const char *) -Function 296: GenImageColor() (3 input parameters) +Function 297: GenImageColor() (3 input parameters) Name: GenImageColor Return type: Image Description: Generate image: plain color Param[1]: width (type: int) Param[2]: height (type: int) Param[3]: color (type: Color) -Function 297: GenImageGradientLinear() (5 input parameters) +Function 298: GenImageGradientLinear() (5 input parameters) Name: GenImageGradientLinear Return type: Image Description: Generate image: linear gradient, direction in degrees [0..360], 0=Vertical gradient @@ -2792,7 +2801,7 @@ Function 297: GenImageGradientLinear() (5 input parameters) Param[3]: direction (type: int) Param[4]: start (type: Color) Param[5]: end (type: Color) -Function 298: GenImageGradientRadial() (5 input parameters) +Function 299: GenImageGradientRadial() (5 input parameters) Name: GenImageGradientRadial Return type: Image Description: Generate image: radial gradient @@ -2801,7 +2810,7 @@ Function 298: GenImageGradientRadial() (5 input parameters) Param[3]: density (type: float) Param[4]: inner (type: Color) Param[5]: outer (type: Color) -Function 299: GenImageGradientSquare() (5 input parameters) +Function 300: GenImageGradientSquare() (5 input parameters) Name: GenImageGradientSquare Return type: Image Description: Generate image: square gradient @@ -2810,7 +2819,7 @@ Function 299: GenImageGradientSquare() (5 input parameters) Param[3]: density (type: float) Param[4]: inner (type: Color) Param[5]: outer (type: Color) -Function 300: GenImageChecked() (6 input parameters) +Function 301: GenImageChecked() (6 input parameters) Name: GenImageChecked Return type: Image Description: Generate image: checked @@ -2820,14 +2829,14 @@ Function 300: GenImageChecked() (6 input parameters) Param[4]: checksY (type: int) Param[5]: col1 (type: Color) Param[6]: col2 (type: Color) -Function 301: GenImageWhiteNoise() (3 input parameters) +Function 302: GenImageWhiteNoise() (3 input parameters) Name: GenImageWhiteNoise Return type: Image Description: Generate image: white noise Param[1]: width (type: int) Param[2]: height (type: int) Param[3]: factor (type: float) -Function 302: GenImagePerlinNoise() (5 input parameters) +Function 303: GenImagePerlinNoise() (5 input parameters) Name: GenImagePerlinNoise Return type: Image Description: Generate image: perlin noise @@ -2836,45 +2845,45 @@ Function 302: GenImagePerlinNoise() (5 input parameters) Param[3]: offsetX (type: int) Param[4]: offsetY (type: int) Param[5]: scale (type: float) -Function 303: GenImageCellular() (3 input parameters) +Function 304: GenImageCellular() (3 input parameters) Name: GenImageCellular Return type: Image Description: Generate image: cellular algorithm, bigger tileSize means bigger cells Param[1]: width (type: int) Param[2]: height (type: int) Param[3]: tileSize (type: int) -Function 304: GenImageText() (3 input parameters) +Function 305: GenImageText() (3 input parameters) Name: GenImageText Return type: Image Description: Generate image: grayscale image from text data Param[1]: width (type: int) Param[2]: height (type: int) Param[3]: text (type: const char *) -Function 305: ImageCopy() (1 input parameters) +Function 306: ImageCopy() (1 input parameters) Name: ImageCopy Return type: Image Description: Create an image duplicate (useful for transformations) Param[1]: image (type: Image) -Function 306: ImageFromImage() (2 input parameters) +Function 307: ImageFromImage() (2 input parameters) Name: ImageFromImage Return type: Image Description: Create an image from another image piece Param[1]: image (type: Image) Param[2]: rec (type: Rectangle) -Function 307: ImageFromChannel() (2 input parameters) +Function 308: ImageFromChannel() (2 input parameters) Name: ImageFromChannel Return type: Image Description: Create an image from a selected channel of another image (GRAYSCALE) Param[1]: image (type: Image) Param[2]: selectedChannel (type: int) -Function 308: ImageText() (3 input parameters) +Function 309: ImageText() (3 input parameters) Name: ImageText Return type: Image Description: Create an image from text (default font) Param[1]: text (type: const char *) Param[2]: fontSize (type: int) Param[3]: color (type: Color) -Function 309: ImageTextEx() (5 input parameters) +Function 310: ImageTextEx() (5 input parameters) Name: ImageTextEx Return type: Image Description: Create an image from text (custom sprite font) @@ -2883,76 +2892,76 @@ Function 309: ImageTextEx() (5 input parameters) Param[3]: fontSize (type: float) Param[4]: spacing (type: float) Param[5]: tint (type: Color) -Function 310: ImageFormat() (2 input parameters) +Function 311: ImageFormat() (2 input parameters) Name: ImageFormat Return type: void Description: Convert image data to desired format Param[1]: image (type: Image *) Param[2]: newFormat (type: int) -Function 311: ImageToPOT() (2 input parameters) +Function 312: ImageToPOT() (2 input parameters) Name: ImageToPOT Return type: void Description: Convert image to POT (power-of-two) Param[1]: image (type: Image *) Param[2]: fill (type: Color) -Function 312: ImageCrop() (2 input parameters) +Function 313: ImageCrop() (2 input parameters) Name: ImageCrop Return type: void Description: Crop an image to a defined rectangle Param[1]: image (type: Image *) Param[2]: crop (type: Rectangle) -Function 313: ImageAlphaCrop() (2 input parameters) +Function 314: ImageAlphaCrop() (2 input parameters) Name: ImageAlphaCrop Return type: void Description: Crop image depending on alpha value Param[1]: image (type: Image *) Param[2]: threshold (type: float) -Function 314: ImageAlphaClear() (3 input parameters) +Function 315: ImageAlphaClear() (3 input parameters) Name: ImageAlphaClear Return type: void Description: Clear alpha channel to desired color Param[1]: image (type: Image *) Param[2]: color (type: Color) Param[3]: threshold (type: float) -Function 315: ImageAlphaMask() (2 input parameters) +Function 316: ImageAlphaMask() (2 input parameters) Name: ImageAlphaMask Return type: void Description: Apply alpha mask to image Param[1]: image (type: Image *) Param[2]: alphaMask (type: Image) -Function 316: ImageAlphaPremultiply() (1 input parameters) +Function 317: ImageAlphaPremultiply() (1 input parameters) Name: ImageAlphaPremultiply Return type: void Description: Premultiply alpha channel Param[1]: image (type: Image *) -Function 317: ImageBlurGaussian() (2 input parameters) +Function 318: ImageBlurGaussian() (2 input parameters) Name: ImageBlurGaussian Return type: void Description: Apply Gaussian blur using a box blur approximation Param[1]: image (type: Image *) Param[2]: blurSize (type: int) -Function 318: ImageKernelConvolution() (3 input parameters) +Function 319: ImageKernelConvolution() (3 input parameters) Name: ImageKernelConvolution Return type: void Description: Apply custom square convolution kernel to image Param[1]: image (type: Image *) Param[2]: kernel (type: const float *) Param[3]: kernelSize (type: int) -Function 319: ImageResize() (3 input parameters) +Function 320: ImageResize() (3 input parameters) Name: ImageResize Return type: void Description: Resize image (Bicubic scaling algorithm) Param[1]: image (type: Image *) Param[2]: newWidth (type: int) Param[3]: newHeight (type: int) -Function 320: ImageResizeNN() (3 input parameters) +Function 321: ImageResizeNN() (3 input parameters) Name: ImageResizeNN Return type: void Description: Resize image (Nearest-Neighbor scaling algorithm) Param[1]: image (type: Image *) Param[2]: newWidth (type: int) Param[3]: newHeight (type: int) -Function 321: ImageResizeCanvas() (6 input parameters) +Function 322: ImageResizeCanvas() (6 input parameters) Name: ImageResizeCanvas Return type: void Description: Resize canvas and fill with color @@ -2962,12 +2971,12 @@ Function 321: ImageResizeCanvas() (6 input parameters) Param[4]: offsetX (type: int) Param[5]: offsetY (type: int) Param[6]: fill (type: Color) -Function 322: ImageMipmaps() (1 input parameters) +Function 323: ImageMipmaps() (1 input parameters) Name: ImageMipmaps Return type: void Description: Compute all mipmap levels for a provided image Param[1]: image (type: Image *) -Function 323: ImageDither() (5 input parameters) +Function 324: ImageDither() (5 input parameters) Name: ImageDither Return type: void Description: Dither image data to 16bpp or lower (Floyd-Steinberg dithering) @@ -2976,109 +2985,109 @@ Function 323: ImageDither() (5 input parameters) Param[3]: gBpp (type: int) Param[4]: bBpp (type: int) Param[5]: aBpp (type: int) -Function 324: ImageFlipVertical() (1 input parameters) +Function 325: ImageFlipVertical() (1 input parameters) Name: ImageFlipVertical Return type: void Description: Flip image vertically Param[1]: image (type: Image *) -Function 325: ImageFlipHorizontal() (1 input parameters) +Function 326: ImageFlipHorizontal() (1 input parameters) Name: ImageFlipHorizontal Return type: void Description: Flip image horizontally Param[1]: image (type: Image *) -Function 326: ImageRotate() (2 input parameters) +Function 327: ImageRotate() (2 input parameters) Name: ImageRotate Return type: void Description: Rotate image by input angle in degrees (-359 to 359) Param[1]: image (type: Image *) Param[2]: degrees (type: int) -Function 327: ImageRotateCW() (1 input parameters) +Function 328: ImageRotateCW() (1 input parameters) Name: ImageRotateCW Return type: void Description: Rotate image clockwise 90deg Param[1]: image (type: Image *) -Function 328: ImageRotateCCW() (1 input parameters) +Function 329: ImageRotateCCW() (1 input parameters) Name: ImageRotateCCW Return type: void Description: Rotate image counter-clockwise 90deg Param[1]: image (type: Image *) -Function 329: ImageColorTint() (2 input parameters) +Function 330: ImageColorTint() (2 input parameters) Name: ImageColorTint Return type: void Description: Modify image color: tint Param[1]: image (type: Image *) Param[2]: color (type: Color) -Function 330: ImageColorInvert() (1 input parameters) +Function 331: ImageColorInvert() (1 input parameters) Name: ImageColorInvert Return type: void Description: Modify image color: invert Param[1]: image (type: Image *) -Function 331: ImageColorGrayscale() (1 input parameters) +Function 332: ImageColorGrayscale() (1 input parameters) Name: ImageColorGrayscale Return type: void Description: Modify image color: grayscale Param[1]: image (type: Image *) -Function 332: ImageColorContrast() (2 input parameters) +Function 333: ImageColorContrast() (2 input parameters) Name: ImageColorContrast Return type: void Description: Modify image color: contrast (-100 to 100) Param[1]: image (type: Image *) Param[2]: contrast (type: float) -Function 333: ImageColorBrightness() (2 input parameters) +Function 334: ImageColorBrightness() (2 input parameters) Name: ImageColorBrightness Return type: void Description: Modify image color: brightness (-255 to 255) Param[1]: image (type: Image *) Param[2]: brightness (type: int) -Function 334: ImageColorReplace() (3 input parameters) +Function 335: ImageColorReplace() (3 input parameters) Name: ImageColorReplace Return type: void Description: Modify image color: replace color Param[1]: image (type: Image *) Param[2]: color (type: Color) Param[3]: replace (type: Color) -Function 335: LoadImageColors() (1 input parameters) +Function 336: LoadImageColors() (1 input parameters) Name: LoadImageColors Return type: Color * Description: Load color data from image as a Color array (RGBA - 32bit) Param[1]: image (type: Image) -Function 336: LoadImagePalette() (3 input parameters) +Function 337: LoadImagePalette() (3 input parameters) Name: LoadImagePalette Return type: Color * Description: Load colors palette from image as a Color array (RGBA - 32bit) Param[1]: image (type: Image) Param[2]: maxPaletteSize (type: int) Param[3]: colorCount (type: int *) -Function 337: UnloadImageColors() (1 input parameters) +Function 338: UnloadImageColors() (1 input parameters) Name: UnloadImageColors Return type: void Description: Unload color data loaded with LoadImageColors() Param[1]: colors (type: Color *) -Function 338: UnloadImagePalette() (1 input parameters) +Function 339: UnloadImagePalette() (1 input parameters) Name: UnloadImagePalette Return type: void Description: Unload colors palette loaded with LoadImagePalette() Param[1]: colors (type: Color *) -Function 339: GetImageAlphaBorder() (2 input parameters) +Function 340: GetImageAlphaBorder() (2 input parameters) Name: GetImageAlphaBorder Return type: Rectangle Description: Get image alpha border rectangle Param[1]: image (type: Image) Param[2]: threshold (type: float) -Function 340: GetImageColor() (3 input parameters) +Function 341: GetImageColor() (3 input parameters) Name: GetImageColor Return type: Color Description: Get image pixel color at (x, y) position Param[1]: image (type: Image) Param[2]: x (type: int) Param[3]: y (type: int) -Function 341: ImageClearBackground() (2 input parameters) +Function 342: ImageClearBackground() (2 input parameters) Name: ImageClearBackground Return type: void Description: Clear image background with given color Param[1]: dst (type: Image *) Param[2]: color (type: Color) -Function 342: ImageDrawPixel() (4 input parameters) +Function 343: ImageDrawPixel() (4 input parameters) Name: ImageDrawPixel Return type: void Description: Draw pixel within an image @@ -3086,14 +3095,14 @@ Function 342: ImageDrawPixel() (4 input parameters) Param[2]: posX (type: int) Param[3]: posY (type: int) Param[4]: color (type: Color) -Function 343: ImageDrawPixelV() (3 input parameters) +Function 344: ImageDrawPixelV() (3 input parameters) Name: ImageDrawPixelV Return type: void Description: Draw pixel within an image (Vector version) Param[1]: dst (type: Image *) Param[2]: position (type: Vector2) Param[3]: color (type: Color) -Function 344: ImageDrawLine() (6 input parameters) +Function 345: ImageDrawLine() (6 input parameters) Name: ImageDrawLine Return type: void Description: Draw line within an image @@ -3103,7 +3112,7 @@ Function 344: ImageDrawLine() (6 input parameters) Param[4]: endPosX (type: int) Param[5]: endPosY (type: int) Param[6]: color (type: Color) -Function 345: ImageDrawLineV() (4 input parameters) +Function 346: ImageDrawLineV() (4 input parameters) Name: ImageDrawLineV Return type: void Description: Draw line within an image (Vector version) @@ -3111,7 +3120,7 @@ Function 345: ImageDrawLineV() (4 input parameters) Param[2]: start (type: Vector2) Param[3]: end (type: Vector2) Param[4]: color (type: Color) -Function 346: ImageDrawLineEx() (5 input parameters) +Function 347: ImageDrawLineEx() (5 input parameters) Name: ImageDrawLineEx Return type: void Description: Draw a line defining thickness within an image @@ -3120,7 +3129,7 @@ Function 346: ImageDrawLineEx() (5 input parameters) Param[3]: end (type: Vector2) Param[4]: thick (type: int) Param[5]: color (type: Color) -Function 347: ImageDrawCircle() (5 input parameters) +Function 348: ImageDrawCircle() (5 input parameters) Name: ImageDrawCircle Return type: void Description: Draw a filled circle within an image @@ -3129,7 +3138,7 @@ Function 347: ImageDrawCircle() (5 input parameters) Param[3]: centerY (type: int) Param[4]: radius (type: int) Param[5]: color (type: Color) -Function 348: ImageDrawCircleV() (4 input parameters) +Function 349: ImageDrawCircleV() (4 input parameters) Name: ImageDrawCircleV Return type: void Description: Draw a filled circle within an image (Vector version) @@ -3137,7 +3146,7 @@ Function 348: ImageDrawCircleV() (4 input parameters) Param[2]: center (type: Vector2) Param[3]: radius (type: int) Param[4]: color (type: Color) -Function 349: ImageDrawCircleLines() (5 input parameters) +Function 350: ImageDrawCircleLines() (5 input parameters) Name: ImageDrawCircleLines Return type: void Description: Draw circle outline within an image @@ -3146,7 +3155,7 @@ Function 349: ImageDrawCircleLines() (5 input parameters) Param[3]: centerY (type: int) Param[4]: radius (type: int) Param[5]: color (type: Color) -Function 350: ImageDrawCircleLinesV() (4 input parameters) +Function 351: ImageDrawCircleLinesV() (4 input parameters) Name: ImageDrawCircleLinesV Return type: void Description: Draw circle outline within an image (Vector version) @@ -3154,7 +3163,7 @@ Function 350: ImageDrawCircleLinesV() (4 input parameters) Param[2]: center (type: Vector2) Param[3]: radius (type: int) Param[4]: color (type: Color) -Function 351: ImageDrawRectangle() (6 input parameters) +Function 352: ImageDrawRectangle() (6 input parameters) Name: ImageDrawRectangle Return type: void Description: Draw rectangle within an image @@ -3164,7 +3173,7 @@ Function 351: ImageDrawRectangle() (6 input parameters) Param[4]: width (type: int) Param[5]: height (type: int) Param[6]: color (type: Color) -Function 352: ImageDrawRectangleV() (4 input parameters) +Function 353: ImageDrawRectangleV() (4 input parameters) Name: ImageDrawRectangleV Return type: void Description: Draw rectangle within an image (Vector version) @@ -3172,14 +3181,14 @@ Function 352: ImageDrawRectangleV() (4 input parameters) Param[2]: position (type: Vector2) Param[3]: size (type: Vector2) Param[4]: color (type: Color) -Function 353: ImageDrawRectangleRec() (3 input parameters) +Function 354: ImageDrawRectangleRec() (3 input parameters) Name: ImageDrawRectangleRec Return type: void Description: Draw rectangle within an image Param[1]: dst (type: Image *) Param[2]: rec (type: Rectangle) Param[3]: color (type: Color) -Function 354: ImageDrawRectangleLines() (4 input parameters) +Function 355: ImageDrawRectangleLines() (4 input parameters) Name: ImageDrawRectangleLines Return type: void Description: Draw rectangle lines within an image @@ -3187,7 +3196,7 @@ Function 354: ImageDrawRectangleLines() (4 input parameters) Param[2]: rec (type: Rectangle) Param[3]: thick (type: int) Param[4]: color (type: Color) -Function 355: ImageDrawTriangle() (5 input parameters) +Function 356: ImageDrawTriangle() (5 input parameters) Name: ImageDrawTriangle Return type: void Description: Draw triangle within an image @@ -3196,7 +3205,7 @@ Function 355: ImageDrawTriangle() (5 input parameters) Param[3]: v2 (type: Vector2) Param[4]: v3 (type: Vector2) Param[5]: color (type: Color) -Function 356: ImageDrawTriangleEx() (7 input parameters) +Function 357: ImageDrawTriangleEx() (7 input parameters) Name: ImageDrawTriangleEx Return type: void Description: Draw triangle with interpolated colors within an image @@ -3207,7 +3216,7 @@ Function 356: ImageDrawTriangleEx() (7 input parameters) Param[5]: c1 (type: Color) Param[6]: c2 (type: Color) Param[7]: c3 (type: Color) -Function 357: ImageDrawTriangleLines() (5 input parameters) +Function 358: ImageDrawTriangleLines() (5 input parameters) Name: ImageDrawTriangleLines Return type: void Description: Draw triangle outline within an image @@ -3216,7 +3225,7 @@ Function 357: ImageDrawTriangleLines() (5 input parameters) Param[3]: v2 (type: Vector2) Param[4]: v3 (type: Vector2) Param[5]: color (type: Color) -Function 358: ImageDrawTriangleFan() (4 input parameters) +Function 359: ImageDrawTriangleFan() (4 input parameters) Name: ImageDrawTriangleFan Return type: void Description: Draw a triangle fan defined by points within an image (first vertex is the center) @@ -3224,7 +3233,7 @@ Function 358: ImageDrawTriangleFan() (4 input parameters) Param[2]: points (type: const Vector2 *) Param[3]: pointCount (type: int) Param[4]: color (type: Color) -Function 359: ImageDrawTriangleStrip() (4 input parameters) +Function 360: ImageDrawTriangleStrip() (4 input parameters) Name: ImageDrawTriangleStrip Return type: void Description: Draw a triangle strip defined by points within an image @@ -3232,7 +3241,7 @@ Function 359: ImageDrawTriangleStrip() (4 input parameters) Param[2]: points (type: const Vector2 *) Param[3]: pointCount (type: int) Param[4]: color (type: Color) -Function 360: ImageDraw() (5 input parameters) +Function 361: ImageDraw() (5 input parameters) Name: ImageDraw Return type: void Description: Draw a source image within a destination image (tint applied to source) @@ -3241,7 +3250,7 @@ Function 360: ImageDraw() (5 input parameters) Param[3]: srcRec (type: Rectangle) Param[4]: dstRec (type: Rectangle) Param[5]: tint (type: Color) -Function 361: ImageDrawText() (6 input parameters) +Function 362: ImageDrawText() (6 input parameters) Name: ImageDrawText Return type: void Description: Draw text (using default font) within an image (destination) @@ -3251,7 +3260,7 @@ Function 361: ImageDrawText() (6 input parameters) Param[4]: posY (type: int) Param[5]: fontSize (type: int) Param[6]: color (type: Color) -Function 362: ImageDrawTextEx() (7 input parameters) +Function 363: ImageDrawTextEx() (7 input parameters) Name: ImageDrawTextEx Return type: void Description: Draw text (custom sprite font) within an image (destination) @@ -3262,79 +3271,79 @@ Function 362: ImageDrawTextEx() (7 input parameters) Param[5]: fontSize (type: float) Param[6]: spacing (type: float) Param[7]: tint (type: Color) -Function 363: LoadTexture() (1 input parameters) +Function 364: LoadTexture() (1 input parameters) Name: LoadTexture Return type: Texture2D Description: Load texture from file into GPU memory (VRAM) Param[1]: fileName (type: const char *) -Function 364: LoadTextureFromImage() (1 input parameters) +Function 365: LoadTextureFromImage() (1 input parameters) Name: LoadTextureFromImage Return type: Texture2D Description: Load texture from image data Param[1]: image (type: Image) -Function 365: LoadTextureCubemap() (2 input parameters) +Function 366: LoadTextureCubemap() (2 input parameters) Name: LoadTextureCubemap Return type: TextureCubemap Description: Load cubemap from image, multiple image cubemap layouts supported Param[1]: image (type: Image) Param[2]: layout (type: int) -Function 366: LoadRenderTexture() (2 input parameters) +Function 367: LoadRenderTexture() (2 input parameters) Name: LoadRenderTexture Return type: RenderTexture2D Description: Load texture for rendering (framebuffer) Param[1]: width (type: int) Param[2]: height (type: int) -Function 367: IsTextureValid() (1 input parameters) +Function 368: IsTextureValid() (1 input parameters) Name: IsTextureValid Return type: bool Description: Check if a texture is valid (loaded in GPU) Param[1]: texture (type: Texture2D) -Function 368: UnloadTexture() (1 input parameters) +Function 369: UnloadTexture() (1 input parameters) Name: UnloadTexture Return type: void Description: Unload texture from GPU memory (VRAM) Param[1]: texture (type: Texture2D) -Function 369: IsRenderTextureValid() (1 input parameters) +Function 370: IsRenderTextureValid() (1 input parameters) Name: IsRenderTextureValid Return type: bool Description: Check if a render texture is valid (loaded in GPU) Param[1]: target (type: RenderTexture2D) -Function 370: UnloadRenderTexture() (1 input parameters) +Function 371: UnloadRenderTexture() (1 input parameters) Name: UnloadRenderTexture Return type: void Description: Unload render texture from GPU memory (VRAM) Param[1]: target (type: RenderTexture2D) -Function 371: UpdateTexture() (2 input parameters) +Function 372: UpdateTexture() (2 input parameters) Name: UpdateTexture Return type: void Description: Update GPU texture with new data (pixels should be able to fill texture) Param[1]: texture (type: Texture2D) Param[2]: pixels (type: const void *) -Function 372: UpdateTextureRec() (3 input parameters) +Function 373: UpdateTextureRec() (3 input parameters) Name: UpdateTextureRec Return type: void Description: Update GPU texture rectangle with new data (pixels and rec should fit in texture) Param[1]: texture (type: Texture2D) Param[2]: rec (type: Rectangle) Param[3]: pixels (type: const void *) -Function 373: GenTextureMipmaps() (1 input parameters) +Function 374: GenTextureMipmaps() (1 input parameters) Name: GenTextureMipmaps Return type: void Description: Generate GPU mipmaps for a texture Param[1]: texture (type: Texture2D *) -Function 374: SetTextureFilter() (2 input parameters) +Function 375: SetTextureFilter() (2 input parameters) Name: SetTextureFilter Return type: void Description: Set texture scaling filter mode Param[1]: texture (type: Texture2D) Param[2]: filter (type: int) -Function 375: SetTextureWrap() (2 input parameters) +Function 376: SetTextureWrap() (2 input parameters) Name: SetTextureWrap Return type: void Description: Set texture wrapping mode Param[1]: texture (type: Texture2D) Param[2]: wrap (type: int) -Function 376: DrawTexture() (4 input parameters) +Function 377: DrawTexture() (4 input parameters) Name: DrawTexture Return type: void Description: Draw a Texture2D @@ -3342,14 +3351,14 @@ Function 376: DrawTexture() (4 input parameters) Param[2]: posX (type: int) Param[3]: posY (type: int) Param[4]: tint (type: Color) -Function 377: DrawTextureV() (3 input parameters) +Function 378: DrawTextureV() (3 input parameters) Name: DrawTextureV Return type: void Description: Draw a Texture2D with position defined as Vector2 Param[1]: texture (type: Texture2D) Param[2]: position (type: Vector2) Param[3]: tint (type: Color) -Function 378: DrawTextureEx() (5 input parameters) +Function 379: DrawTextureEx() (5 input parameters) Name: DrawTextureEx Return type: void Description: Draw a Texture2D with extended parameters @@ -3358,7 +3367,7 @@ Function 378: DrawTextureEx() (5 input parameters) Param[3]: rotation (type: float) Param[4]: scale (type: float) Param[5]: tint (type: Color) -Function 379: DrawTextureRec() (4 input parameters) +Function 380: DrawTextureRec() (4 input parameters) Name: DrawTextureRec Return type: void Description: Draw a part of a texture defined by a rectangle @@ -3366,7 +3375,7 @@ Function 379: DrawTextureRec() (4 input parameters) Param[2]: source (type: Rectangle) Param[3]: position (type: Vector2) Param[4]: tint (type: Color) -Function 380: DrawTexturePro() (6 input parameters) +Function 381: DrawTexturePro() (6 input parameters) Name: DrawTexturePro Return type: void Description: Draw a part of a texture defined by a rectangle with 'pro' parameters @@ -3376,7 +3385,7 @@ Function 380: DrawTexturePro() (6 input parameters) Param[4]: origin (type: Vector2) Param[5]: rotation (type: float) Param[6]: tint (type: Color) -Function 381: DrawTextureNPatch() (6 input parameters) +Function 382: DrawTextureNPatch() (6 input parameters) Name: DrawTextureNPatch Return type: void Description: Draws a texture (or part of it) that stretches or shrinks nicely @@ -3386,119 +3395,119 @@ Function 381: DrawTextureNPatch() (6 input parameters) Param[4]: origin (type: Vector2) Param[5]: rotation (type: float) Param[6]: tint (type: Color) -Function 382: ColorIsEqual() (2 input parameters) +Function 383: ColorIsEqual() (2 input parameters) Name: ColorIsEqual Return type: bool Description: Check if two colors are equal Param[1]: col1 (type: Color) Param[2]: col2 (type: Color) -Function 383: Fade() (2 input parameters) +Function 384: Fade() (2 input parameters) Name: Fade Return type: Color Description: Get color with alpha applied, alpha goes from 0.0f to 1.0f Param[1]: color (type: Color) Param[2]: alpha (type: float) -Function 384: ColorToInt() (1 input parameters) +Function 385: ColorToInt() (1 input parameters) Name: ColorToInt Return type: int Description: Get hexadecimal value for a Color (0xRRGGBBAA) Param[1]: color (type: Color) -Function 385: ColorNormalize() (1 input parameters) +Function 386: ColorNormalize() (1 input parameters) Name: ColorNormalize Return type: Vector4 Description: Get Color normalized as float [0..1] Param[1]: color (type: Color) -Function 386: ColorFromNormalized() (1 input parameters) +Function 387: ColorFromNormalized() (1 input parameters) Name: ColorFromNormalized Return type: Color Description: Get Color from normalized values [0..1] Param[1]: normalized (type: Vector4) -Function 387: ColorToHSV() (1 input parameters) +Function 388: ColorToHSV() (1 input parameters) Name: ColorToHSV Return type: Vector3 Description: Get HSV values for a Color, hue [0..360], saturation/value [0..1] Param[1]: color (type: Color) -Function 388: ColorFromHSV() (3 input parameters) +Function 389: ColorFromHSV() (3 input parameters) Name: ColorFromHSV Return type: Color Description: Get a Color from HSV values, hue [0..360], saturation/value [0..1] Param[1]: hue (type: float) Param[2]: saturation (type: float) Param[3]: value (type: float) -Function 389: ColorTint() (2 input parameters) +Function 390: ColorTint() (2 input parameters) Name: ColorTint Return type: Color Description: Get color multiplied with another color Param[1]: color (type: Color) Param[2]: tint (type: Color) -Function 390: ColorBrightness() (2 input parameters) +Function 391: ColorBrightness() (2 input parameters) Name: ColorBrightness Return type: Color Description: Get color with brightness correction, brightness factor goes from -1.0f to 1.0f Param[1]: color (type: Color) Param[2]: factor (type: float) -Function 391: ColorContrast() (2 input parameters) +Function 392: ColorContrast() (2 input parameters) Name: ColorContrast Return type: Color Description: Get color with contrast correction, contrast values between -1.0f and 1.0f Param[1]: color (type: Color) Param[2]: contrast (type: float) -Function 392: ColorAlpha() (2 input parameters) +Function 393: ColorAlpha() (2 input parameters) Name: ColorAlpha Return type: Color Description: Get color with alpha applied, alpha goes from 0.0f to 1.0f Param[1]: color (type: Color) Param[2]: alpha (type: float) -Function 393: ColorAlphaBlend() (3 input parameters) +Function 394: ColorAlphaBlend() (3 input parameters) Name: ColorAlphaBlend Return type: Color Description: Get src alpha-blended into dst color with tint Param[1]: dst (type: Color) Param[2]: src (type: Color) Param[3]: tint (type: Color) -Function 394: ColorLerp() (3 input parameters) +Function 395: ColorLerp() (3 input parameters) Name: ColorLerp Return type: Color Description: Get color lerp interpolation between two colors, factor [0.0f..1.0f] Param[1]: color1 (type: Color) Param[2]: color2 (type: Color) Param[3]: factor (type: float) -Function 395: GetColor() (1 input parameters) +Function 396: GetColor() (1 input parameters) Name: GetColor Return type: Color Description: Get Color structure from hexadecimal value Param[1]: hexValue (type: unsigned int) -Function 396: GetPixelColor() (2 input parameters) +Function 397: GetPixelColor() (2 input parameters) Name: GetPixelColor Return type: Color Description: Get Color from a source pixel pointer of certain format Param[1]: srcPtr (type: void *) Param[2]: format (type: int) -Function 397: SetPixelColor() (3 input parameters) +Function 398: SetPixelColor() (3 input parameters) Name: SetPixelColor Return type: void Description: Set color formatted into destination pixel pointer Param[1]: dstPtr (type: void *) Param[2]: color (type: Color) Param[3]: format (type: int) -Function 398: GetPixelDataSize() (3 input parameters) +Function 399: GetPixelDataSize() (3 input parameters) Name: GetPixelDataSize Return type: int Description: Get pixel data size in bytes for certain format Param[1]: width (type: int) Param[2]: height (type: int) Param[3]: format (type: int) -Function 399: GetFontDefault() (0 input parameters) +Function 400: GetFontDefault() (0 input parameters) Name: GetFontDefault Return type: Font Description: Get the default Font No input parameters -Function 400: LoadFont() (1 input parameters) +Function 401: LoadFont() (1 input parameters) Name: LoadFont Return type: Font Description: Load font from file into GPU memory (VRAM) Param[1]: fileName (type: const char *) -Function 401: LoadFontEx() (4 input parameters) +Function 402: LoadFontEx() (4 input parameters) Name: LoadFontEx Return type: Font Description: Load font from file with extended parameters, use NULL for codepoints and 0 for codepointCount to load the default character set, font size is provided in pixels height @@ -3506,14 +3515,14 @@ Function 401: LoadFontEx() (4 input parameters) Param[2]: fontSize (type: int) Param[3]: codepoints (type: const int *) Param[4]: codepointCount (type: int) -Function 402: LoadFontFromImage() (3 input parameters) +Function 403: LoadFontFromImage() (3 input parameters) Name: LoadFontFromImage Return type: Font Description: Load font from Image (XNA style) Param[1]: image (type: Image) Param[2]: key (type: Color) Param[3]: firstChar (type: int) -Function 403: LoadFontFromMemory() (6 input parameters) +Function 404: LoadFontFromMemory() (6 input parameters) Name: LoadFontFromMemory Return type: Font Description: Load font from memory buffer, fileType refers to extension: i.e. '.ttf' @@ -3523,12 +3532,12 @@ Function 403: LoadFontFromMemory() (6 input parameters) Param[4]: fontSize (type: int) Param[5]: codepoints (type: const int *) Param[6]: codepointCount (type: int) -Function 404: IsFontValid() (1 input parameters) +Function 405: IsFontValid() (1 input parameters) Name: IsFontValid Return type: bool Description: Check if a font is valid (font data loaded, WARNING: GPU texture not checked) Param[1]: font (type: Font) -Function 405: LoadFontData() (7 input parameters) +Function 406: LoadFontData() (7 input parameters) Name: LoadFontData Return type: GlyphInfo * Description: Load font data for further use @@ -3539,7 +3548,7 @@ Function 405: LoadFontData() (7 input parameters) Param[5]: codepointCount (type: int) Param[6]: type (type: int) Param[7]: glyphCount (type: int *) -Function 406: GenImageFontAtlas() (6 input parameters) +Function 407: GenImageFontAtlas() (6 input parameters) Name: GenImageFontAtlas Return type: Image Description: Generate image font atlas using chars info @@ -3549,30 +3558,30 @@ Function 406: GenImageFontAtlas() (6 input parameters) Param[4]: fontSize (type: int) Param[5]: padding (type: int) Param[6]: packMethod (type: int) -Function 407: UnloadFontData() (2 input parameters) +Function 408: UnloadFontData() (2 input parameters) Name: UnloadFontData Return type: void Description: Unload font chars info data (RAM) Param[1]: glyphs (type: GlyphInfo *) Param[2]: glyphCount (type: int) -Function 408: UnloadFont() (1 input parameters) +Function 409: UnloadFont() (1 input parameters) Name: UnloadFont Return type: void Description: Unload font from GPU memory (VRAM) Param[1]: font (type: Font) -Function 409: ExportFontAsCode() (2 input parameters) +Function 410: ExportFontAsCode() (2 input parameters) Name: ExportFontAsCode Return type: bool Description: Export font as code file, returns true on success Param[1]: font (type: Font) Param[2]: fileName (type: const char *) -Function 410: DrawFPS() (2 input parameters) +Function 411: DrawFPS() (2 input parameters) Name: DrawFPS Return type: void Description: Draw current FPS Param[1]: posX (type: int) Param[2]: posY (type: int) -Function 411: DrawText() (5 input parameters) +Function 412: DrawText() (5 input parameters) Name: DrawText Return type: void Description: Draw text (using default font) @@ -3581,7 +3590,7 @@ Function 411: DrawText() (5 input parameters) Param[3]: posY (type: int) Param[4]: fontSize (type: int) Param[5]: color (type: Color) -Function 412: DrawTextEx() (6 input parameters) +Function 413: DrawTextEx() (6 input parameters) Name: DrawTextEx Return type: void Description: Draw text using font and additional parameters @@ -3591,7 +3600,7 @@ Function 412: DrawTextEx() (6 input parameters) Param[4]: fontSize (type: float) Param[5]: spacing (type: float) Param[6]: tint (type: Color) -Function 413: DrawTextPro() (8 input parameters) +Function 414: DrawTextPro() (8 input parameters) Name: DrawTextPro Return type: void Description: Draw text using Font and pro parameters (rotation) @@ -3603,7 +3612,7 @@ Function 413: DrawTextPro() (8 input parameters) Param[6]: fontSize (type: float) Param[7]: spacing (type: float) Param[8]: tint (type: Color) -Function 414: DrawTextCodepoint() (5 input parameters) +Function 415: DrawTextCodepoint() (5 input parameters) Name: DrawTextCodepoint Return type: void Description: Draw one character (codepoint) @@ -3612,7 +3621,7 @@ Function 414: DrawTextCodepoint() (5 input parameters) Param[3]: position (type: Vector2) Param[4]: fontSize (type: float) Param[5]: tint (type: Color) -Function 415: DrawTextCodepoints() (7 input parameters) +Function 416: DrawTextCodepoints() (7 input parameters) Name: DrawTextCodepoints Return type: void Description: Draw multiple character (codepoint) @@ -3623,18 +3632,18 @@ Function 415: DrawTextCodepoints() (7 input parameters) Param[5]: fontSize (type: float) Param[6]: spacing (type: float) Param[7]: tint (type: Color) -Function 416: SetTextLineSpacing() (1 input parameters) +Function 417: SetTextLineSpacing() (1 input parameters) Name: SetTextLineSpacing Return type: void Description: Set vertical line spacing when drawing with line-breaks Param[1]: spacing (type: int) -Function 417: MeasureText() (2 input parameters) +Function 418: MeasureText() (2 input parameters) Name: MeasureText Return type: int Description: Measure string width for default font Param[1]: text (type: const char *) Param[2]: fontSize (type: int) -Function 418: MeasureTextEx() (4 input parameters) +Function 419: MeasureTextEx() (4 input parameters) Name: MeasureTextEx Return type: Vector2 Description: Measure string size for Font @@ -3642,137 +3651,137 @@ Function 418: MeasureTextEx() (4 input parameters) Param[2]: text (type: const char *) Param[3]: fontSize (type: float) Param[4]: spacing (type: float) -Function 419: GetGlyphIndex() (2 input parameters) +Function 420: GetGlyphIndex() (2 input parameters) Name: GetGlyphIndex Return type: int Description: Get glyph index position in font for a codepoint (unicode character), fallback to '?' if not found Param[1]: font (type: Font) Param[2]: codepoint (type: int) -Function 420: GetGlyphInfo() (2 input parameters) +Function 421: GetGlyphInfo() (2 input parameters) Name: GetGlyphInfo Return type: GlyphInfo Description: Get glyph font info data for a codepoint (unicode character), fallback to '?' if not found Param[1]: font (type: Font) Param[2]: codepoint (type: int) -Function 421: GetGlyphAtlasRec() (2 input parameters) +Function 422: GetGlyphAtlasRec() (2 input parameters) Name: GetGlyphAtlasRec Return type: Rectangle Description: Get glyph rectangle in font atlas for a codepoint (unicode character), fallback to '?' if not found Param[1]: font (type: Font) Param[2]: codepoint (type: int) -Function 422: LoadUTF8() (2 input parameters) +Function 423: LoadUTF8() (2 input parameters) Name: LoadUTF8 Return type: char * Description: Load UTF-8 text encoded from codepoints array Param[1]: codepoints (type: const int *) Param[2]: length (type: int) -Function 423: UnloadUTF8() (1 input parameters) +Function 424: UnloadUTF8() (1 input parameters) Name: UnloadUTF8 Return type: void Description: Unload UTF-8 text encoded from codepoints array Param[1]: text (type: char *) -Function 424: LoadCodepoints() (2 input parameters) +Function 425: LoadCodepoints() (2 input parameters) Name: LoadCodepoints Return type: int * Description: Load all codepoints from a UTF-8 text string, codepoints count returned by parameter Param[1]: text (type: const char *) Param[2]: count (type: int *) -Function 425: UnloadCodepoints() (1 input parameters) +Function 426: UnloadCodepoints() (1 input parameters) Name: UnloadCodepoints Return type: void Description: Unload codepoints data from memory Param[1]: codepoints (type: int *) -Function 426: GetCodepointCount() (1 input parameters) +Function 427: GetCodepointCount() (1 input parameters) Name: GetCodepointCount Return type: int Description: Get total number of codepoints in a UTF-8 encoded string Param[1]: text (type: const char *) -Function 427: GetCodepoint() (2 input parameters) +Function 428: GetCodepoint() (2 input parameters) Name: GetCodepoint Return type: int Description: Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure Param[1]: text (type: const char *) Param[2]: codepointSize (type: int *) -Function 428: GetCodepointNext() (2 input parameters) +Function 429: GetCodepointNext() (2 input parameters) Name: GetCodepointNext Return type: int Description: Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure Param[1]: text (type: const char *) Param[2]: codepointSize (type: int *) -Function 429: GetCodepointPrevious() (2 input parameters) +Function 430: GetCodepointPrevious() (2 input parameters) Name: GetCodepointPrevious Return type: int Description: Get previous codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure Param[1]: text (type: const char *) Param[2]: codepointSize (type: int *) -Function 430: CodepointToUTF8() (2 input parameters) +Function 431: CodepointToUTF8() (2 input parameters) Name: CodepointToUTF8 Return type: const char * Description: Encode one codepoint into UTF-8 byte array (array length returned as parameter) Param[1]: codepoint (type: int) Param[2]: utf8Size (type: int *) -Function 431: LoadTextLines() (2 input parameters) +Function 432: LoadTextLines() (2 input parameters) Name: LoadTextLines Return type: char ** Description: Load text as separate lines ('\n') Param[1]: text (type: const char *) Param[2]: count (type: int *) -Function 432: UnloadTextLines() (2 input parameters) +Function 433: UnloadTextLines() (2 input parameters) Name: UnloadTextLines Return type: void Description: Unload text lines Param[1]: text (type: char **) Param[2]: lineCount (type: int) -Function 433: TextCopy() (2 input parameters) +Function 434: TextCopy() (2 input parameters) Name: TextCopy Return type: int Description: Copy one string to another, returns bytes copied Param[1]: dst (type: char *) Param[2]: src (type: const char *) -Function 434: TextIsEqual() (2 input parameters) +Function 435: TextIsEqual() (2 input parameters) Name: TextIsEqual Return type: bool Description: Check if two text string are equal Param[1]: text1 (type: const char *) Param[2]: text2 (type: const char *) -Function 435: TextLength() (1 input parameters) +Function 436: TextLength() (1 input parameters) Name: TextLength Return type: unsigned int Description: Get text length, checks for '\0' ending Param[1]: text (type: const char *) -Function 436: TextFormat() (2 input parameters) +Function 437: TextFormat() (2 input parameters) Name: TextFormat Return type: const char * Description: Text formatting with variables (sprintf() style) Param[1]: text (type: const char *) Param[2]: args (type: ...) -Function 437: TextSubtext() (3 input parameters) +Function 438: TextSubtext() (3 input parameters) Name: TextSubtext Return type: const char * Description: Get a piece of a text string Param[1]: text (type: const char *) Param[2]: position (type: int) Param[3]: length (type: int) -Function 438: TextRemoveSpaces() (1 input parameters) +Function 439: TextRemoveSpaces() (1 input parameters) Name: TextRemoveSpaces Return type: const char * Description: Remove text spaces, concat words Param[1]: text (type: const char *) -Function 439: GetTextBetween() (3 input parameters) +Function 440: GetTextBetween() (3 input parameters) Name: GetTextBetween Return type: char * Description: Get text between two strings Param[1]: text (type: const char *) Param[2]: begin (type: const char *) Param[3]: end (type: const char *) -Function 440: TextReplace() (3 input parameters) +Function 441: TextReplace() (3 input parameters) Name: TextReplace Return type: char * Description: Replace text string (WARNING: memory must be freed!) Param[1]: text (type: const char *) Param[2]: search (type: const char *) Param[3]: replacement (type: const char *) -Function 441: TextReplaceBetween() (4 input parameters) +Function 442: TextReplaceBetween() (4 input parameters) Name: TextReplaceBetween Return type: char * Description: Replace text between two specific strings (WARNING: memory must be freed!) @@ -3780,89 +3789,89 @@ Function 441: TextReplaceBetween() (4 input parameters) Param[2]: begin (type: const char *) Param[3]: end (type: const char *) Param[4]: replacement (type: const char *) -Function 442: TextInsert() (3 input parameters) +Function 443: TextInsert() (3 input parameters) Name: TextInsert Return type: char * Description: Insert text in a position (WARNING: memory must be freed!) Param[1]: text (type: const char *) Param[2]: insert (type: const char *) Param[3]: position (type: int) -Function 443: TextJoin() (3 input parameters) +Function 444: TextJoin() (3 input parameters) Name: TextJoin Return type: char * Description: Join text strings with delimiter Param[1]: textList (type: char **) Param[2]: count (type: int) Param[3]: delimiter (type: const char *) -Function 444: TextSplit() (3 input parameters) +Function 445: TextSplit() (3 input parameters) Name: TextSplit Return type: char ** Description: Split text into multiple strings, using MAX_TEXTSPLIT_COUNT static strings Param[1]: text (type: const char *) Param[2]: delimiter (type: char) Param[3]: count (type: int *) -Function 445: TextAppend() (3 input parameters) +Function 446: TextAppend() (3 input parameters) Name: TextAppend Return type: void Description: Append text at specific position and move cursor Param[1]: text (type: char *) Param[2]: append (type: const char *) Param[3]: position (type: int *) -Function 446: TextFindIndex() (2 input parameters) +Function 447: TextFindIndex() (2 input parameters) Name: TextFindIndex Return type: int Description: Find first text occurrence within a string, -1 if not found Param[1]: text (type: const char *) Param[2]: search (type: const char *) -Function 447: TextToUpper() (1 input parameters) +Function 448: TextToUpper() (1 input parameters) Name: TextToUpper Return type: char * Description: Get upper case version of provided string Param[1]: text (type: const char *) -Function 448: TextToLower() (1 input parameters) +Function 449: TextToLower() (1 input parameters) Name: TextToLower Return type: char * Description: Get lower case version of provided string Param[1]: text (type: const char *) -Function 449: TextToPascal() (1 input parameters) +Function 450: TextToPascal() (1 input parameters) Name: TextToPascal Return type: char * Description: Get Pascal case notation version of provided string Param[1]: text (type: const char *) -Function 450: TextToSnake() (1 input parameters) +Function 451: TextToSnake() (1 input parameters) Name: TextToSnake Return type: char * Description: Get Snake case notation version of provided string Param[1]: text (type: const char *) -Function 451: TextToCamel() (1 input parameters) +Function 452: TextToCamel() (1 input parameters) Name: TextToCamel Return type: char * Description: Get Camel case notation version of provided string Param[1]: text (type: const char *) -Function 452: TextToInteger() (1 input parameters) +Function 453: TextToInteger() (1 input parameters) Name: TextToInteger Return type: int Description: Get integer value from text Param[1]: text (type: const char *) -Function 453: TextToFloat() (1 input parameters) +Function 454: TextToFloat() (1 input parameters) Name: TextToFloat Return type: float Description: Get float value from text Param[1]: text (type: const char *) -Function 454: DrawLine3D() (3 input parameters) +Function 455: DrawLine3D() (3 input parameters) Name: DrawLine3D Return type: void Description: Draw a line in 3D world space Param[1]: startPos (type: Vector3) Param[2]: endPos (type: Vector3) Param[3]: color (type: Color) -Function 455: DrawPoint3D() (2 input parameters) +Function 456: DrawPoint3D() (2 input parameters) Name: DrawPoint3D Return type: void Description: Draw a point in 3D space, actually a small line Param[1]: position (type: Vector3) Param[2]: color (type: Color) -Function 456: DrawCircle3D() (5 input parameters) +Function 457: DrawCircle3D() (5 input parameters) Name: DrawCircle3D Return type: void Description: Draw a circle in 3D world space @@ -3871,7 +3880,7 @@ Function 456: DrawCircle3D() (5 input parameters) Param[3]: rotationAxis (type: Vector3) Param[4]: rotationAngle (type: float) Param[5]: color (type: Color) -Function 457: DrawTriangle3D() (4 input parameters) +Function 458: DrawTriangle3D() (4 input parameters) Name: DrawTriangle3D Return type: void Description: Draw a color-filled triangle (vertex in counter-clockwise order!) @@ -3879,14 +3888,14 @@ Function 457: DrawTriangle3D() (4 input parameters) Param[2]: v2 (type: Vector3) Param[3]: v3 (type: Vector3) Param[4]: color (type: Color) -Function 458: DrawTriangleStrip3D() (3 input parameters) +Function 459: DrawTriangleStrip3D() (3 input parameters) Name: DrawTriangleStrip3D Return type: void Description: Draw a triangle strip defined by points Param[1]: points (type: const Vector3 *) Param[2]: pointCount (type: int) Param[3]: color (type: Color) -Function 459: DrawCube() (5 input parameters) +Function 460: DrawCube() (5 input parameters) Name: DrawCube Return type: void Description: Draw cube @@ -3895,14 +3904,14 @@ Function 459: DrawCube() (5 input parameters) Param[3]: height (type: float) Param[4]: length (type: float) Param[5]: color (type: Color) -Function 460: DrawCubeV() (3 input parameters) +Function 461: DrawCubeV() (3 input parameters) Name: DrawCubeV Return type: void Description: Draw cube (Vector version) Param[1]: position (type: Vector3) Param[2]: size (type: Vector3) Param[3]: color (type: Color) -Function 461: DrawCubeWires() (5 input parameters) +Function 462: DrawCubeWires() (5 input parameters) Name: DrawCubeWires Return type: void Description: Draw cube wires @@ -3911,21 +3920,21 @@ Function 461: DrawCubeWires() (5 input parameters) Param[3]: height (type: float) Param[4]: length (type: float) Param[5]: color (type: Color) -Function 462: DrawCubeWiresV() (3 input parameters) +Function 463: DrawCubeWiresV() (3 input parameters) Name: DrawCubeWiresV Return type: void Description: Draw cube wires (Vector version) Param[1]: position (type: Vector3) Param[2]: size (type: Vector3) Param[3]: color (type: Color) -Function 463: DrawSphere() (3 input parameters) +Function 464: DrawSphere() (3 input parameters) Name: DrawSphere Return type: void Description: Draw sphere Param[1]: centerPos (type: Vector3) Param[2]: radius (type: float) Param[3]: color (type: Color) -Function 464: DrawSphereEx() (5 input parameters) +Function 465: DrawSphereEx() (5 input parameters) Name: DrawSphereEx Return type: void Description: Draw sphere with extended parameters @@ -3934,7 +3943,7 @@ Function 464: DrawSphereEx() (5 input parameters) Param[3]: rings (type: int) Param[4]: slices (type: int) Param[5]: color (type: Color) -Function 465: DrawSphereWires() (5 input parameters) +Function 466: DrawSphereWires() (5 input parameters) Name: DrawSphereWires Return type: void Description: Draw sphere wires @@ -3943,7 +3952,7 @@ Function 465: DrawSphereWires() (5 input parameters) Param[3]: rings (type: int) Param[4]: slices (type: int) Param[5]: color (type: Color) -Function 466: DrawCylinder() (6 input parameters) +Function 467: DrawCylinder() (6 input parameters) Name: DrawCylinder Return type: void Description: Draw a cylinder/cone @@ -3953,7 +3962,7 @@ Function 466: DrawCylinder() (6 input parameters) Param[4]: height (type: float) Param[5]: slices (type: int) Param[6]: color (type: Color) -Function 467: DrawCylinderEx() (6 input parameters) +Function 468: DrawCylinderEx() (6 input parameters) Name: DrawCylinderEx Return type: void Description: Draw a cylinder with base at startPos and top at endPos @@ -3963,7 +3972,7 @@ Function 467: DrawCylinderEx() (6 input parameters) Param[4]: endRadius (type: float) Param[5]: sides (type: int) Param[6]: color (type: Color) -Function 468: DrawCylinderWires() (6 input parameters) +Function 469: DrawCylinderWires() (6 input parameters) Name: DrawCylinderWires Return type: void Description: Draw a cylinder/cone wires @@ -3973,7 +3982,7 @@ Function 468: DrawCylinderWires() (6 input parameters) Param[4]: height (type: float) Param[5]: slices (type: int) Param[6]: color (type: Color) -Function 469: DrawCylinderWiresEx() (6 input parameters) +Function 470: DrawCylinderWiresEx() (6 input parameters) Name: DrawCylinderWiresEx Return type: void Description: Draw a cylinder wires with base at startPos and top at endPos @@ -3983,7 +3992,7 @@ Function 469: DrawCylinderWiresEx() (6 input parameters) Param[4]: endRadius (type: float) Param[5]: sides (type: int) Param[6]: color (type: Color) -Function 470: DrawCapsule() (6 input parameters) +Function 471: DrawCapsule() (6 input parameters) Name: DrawCapsule Return type: void Description: Draw a capsule with the center of its sphere caps at startPos and endPos @@ -3993,7 +4002,7 @@ Function 470: DrawCapsule() (6 input parameters) Param[4]: slices (type: int) Param[5]: rings (type: int) Param[6]: color (type: Color) -Function 471: DrawCapsuleWires() (6 input parameters) +Function 472: DrawCapsuleWires() (6 input parameters) Name: DrawCapsuleWires Return type: void Description: Draw capsule wireframe with the center of its sphere caps at startPos and endPos @@ -4003,51 +4012,51 @@ Function 471: DrawCapsuleWires() (6 input parameters) Param[4]: slices (type: int) Param[5]: rings (type: int) Param[6]: color (type: Color) -Function 472: DrawPlane() (3 input parameters) +Function 473: DrawPlane() (3 input parameters) Name: DrawPlane Return type: void Description: Draw a plane XZ Param[1]: centerPos (type: Vector3) Param[2]: size (type: Vector2) Param[3]: color (type: Color) -Function 473: DrawRay() (2 input parameters) +Function 474: DrawRay() (2 input parameters) Name: DrawRay Return type: void Description: Draw a ray line Param[1]: ray (type: Ray) Param[2]: color (type: Color) -Function 474: DrawGrid() (2 input parameters) +Function 475: DrawGrid() (2 input parameters) Name: DrawGrid Return type: void Description: Draw a grid (centered at (0, 0, 0)) Param[1]: slices (type: int) Param[2]: spacing (type: float) -Function 475: LoadModel() (1 input parameters) +Function 476: LoadModel() (1 input parameters) Name: LoadModel Return type: Model Description: Load model from files (meshes and materials) Param[1]: fileName (type: const char *) -Function 476: LoadModelFromMesh() (1 input parameters) +Function 477: LoadModelFromMesh() (1 input parameters) Name: LoadModelFromMesh Return type: Model Description: Load model from generated mesh (default material) Param[1]: mesh (type: Mesh) -Function 477: IsModelValid() (1 input parameters) +Function 478: IsModelValid() (1 input parameters) Name: IsModelValid Return type: bool Description: Check if a model is valid (loaded in GPU, VAO/VBOs) Param[1]: model (type: Model) -Function 478: UnloadModel() (1 input parameters) +Function 479: UnloadModel() (1 input parameters) Name: UnloadModel Return type: void Description: Unload model (including meshes) from memory (RAM and/or VRAM) Param[1]: model (type: Model) -Function 479: GetModelBoundingBox() (1 input parameters) +Function 480: GetModelBoundingBox() (1 input parameters) Name: GetModelBoundingBox Return type: BoundingBox Description: Compute model bounding box limits (considers all meshes) Param[1]: model (type: Model) -Function 480: DrawModel() (4 input parameters) +Function 481: DrawModel() (4 input parameters) Name: DrawModel Return type: void Description: Draw a model (with texture if set) @@ -4055,7 +4064,7 @@ Function 480: DrawModel() (4 input parameters) Param[2]: position (type: Vector3) Param[3]: scale (type: float) Param[4]: tint (type: Color) -Function 481: DrawModelEx() (6 input parameters) +Function 482: DrawModelEx() (6 input parameters) Name: DrawModelEx Return type: void Description: Draw a model with extended parameters @@ -4065,7 +4074,7 @@ Function 481: DrawModelEx() (6 input parameters) Param[4]: rotationAngle (type: float) Param[5]: scale (type: Vector3) Param[6]: tint (type: Color) -Function 482: DrawModelWires() (4 input parameters) +Function 483: DrawModelWires() (4 input parameters) Name: DrawModelWires Return type: void Description: Draw a model wires (with texture if set) @@ -4073,7 +4082,7 @@ Function 482: DrawModelWires() (4 input parameters) Param[2]: position (type: Vector3) Param[3]: scale (type: float) Param[4]: tint (type: Color) -Function 483: DrawModelWiresEx() (6 input parameters) +Function 484: DrawModelWiresEx() (6 input parameters) Name: DrawModelWiresEx Return type: void Description: Draw a model wires (with texture if set) with extended parameters @@ -4083,7 +4092,7 @@ Function 483: DrawModelWiresEx() (6 input parameters) Param[4]: rotationAngle (type: float) Param[5]: scale (type: Vector3) Param[6]: tint (type: Color) -Function 484: DrawModelPoints() (4 input parameters) +Function 485: DrawModelPoints() (4 input parameters) Name: DrawModelPoints Return type: void Description: Draw a model as points @@ -4091,7 +4100,7 @@ Function 484: DrawModelPoints() (4 input parameters) Param[2]: position (type: Vector3) Param[3]: scale (type: float) Param[4]: tint (type: Color) -Function 485: DrawModelPointsEx() (6 input parameters) +Function 486: DrawModelPointsEx() (6 input parameters) Name: DrawModelPointsEx Return type: void Description: Draw a model as points with extended parameters @@ -4101,13 +4110,13 @@ Function 485: DrawModelPointsEx() (6 input parameters) Param[4]: rotationAngle (type: float) Param[5]: scale (type: Vector3) Param[6]: tint (type: Color) -Function 486: DrawBoundingBox() (2 input parameters) +Function 487: DrawBoundingBox() (2 input parameters) Name: DrawBoundingBox Return type: void Description: Draw bounding box (wires) Param[1]: box (type: BoundingBox) Param[2]: color (type: Color) -Function 487: DrawBillboard() (5 input parameters) +Function 488: DrawBillboard() (5 input parameters) Name: DrawBillboard Return type: void Description: Draw a billboard texture @@ -4116,7 +4125,7 @@ Function 487: DrawBillboard() (5 input parameters) Param[3]: position (type: Vector3) Param[4]: scale (type: float) Param[5]: tint (type: Color) -Function 488: DrawBillboardRec() (6 input parameters) +Function 489: DrawBillboardRec() (6 input parameters) Name: DrawBillboardRec Return type: void Description: Draw a billboard texture defined by source @@ -4126,7 +4135,7 @@ Function 488: DrawBillboardRec() (6 input parameters) Param[4]: position (type: Vector3) Param[5]: size (type: Vector2) Param[6]: tint (type: Color) -Function 489: DrawBillboardPro() (9 input parameters) +Function 490: DrawBillboardPro() (9 input parameters) Name: DrawBillboardPro Return type: void Description: Draw a billboard texture defined by source and rotation @@ -4139,13 +4148,13 @@ Function 489: DrawBillboardPro() (9 input parameters) Param[7]: origin (type: Vector2) Param[8]: rotation (type: float) Param[9]: tint (type: Color) -Function 490: UploadMesh() (2 input parameters) +Function 491: UploadMesh() (2 input parameters) Name: UploadMesh Return type: void Description: Upload mesh vertex data in GPU and provide VAO/VBO ids Param[1]: mesh (type: Mesh *) Param[2]: dynamic (type: bool) -Function 491: UpdateMeshBuffer() (5 input parameters) +Function 492: UpdateMeshBuffer() (5 input parameters) Name: UpdateMeshBuffer Return type: void Description: Update mesh vertex data in GPU for a specific buffer index @@ -4154,19 +4163,19 @@ Function 491: UpdateMeshBuffer() (5 input parameters) Param[3]: data (type: const void *) Param[4]: dataSize (type: int) Param[5]: offset (type: int) -Function 492: UnloadMesh() (1 input parameters) +Function 493: UnloadMesh() (1 input parameters) Name: UnloadMesh Return type: void Description: Unload mesh data from CPU and GPU Param[1]: mesh (type: Mesh) -Function 493: DrawMesh() (3 input parameters) +Function 494: DrawMesh() (3 input parameters) Name: DrawMesh Return type: void Description: Draw a 3d mesh with material and transform Param[1]: mesh (type: Mesh) Param[2]: material (type: Material) Param[3]: transform (type: Matrix) -Function 494: DrawMeshInstanced() (4 input parameters) +Function 495: DrawMeshInstanced() (4 input parameters) Name: DrawMeshInstanced Return type: void Description: Draw multiple mesh instances with material and different transforms @@ -4174,35 +4183,35 @@ Function 494: DrawMeshInstanced() (4 input parameters) Param[2]: material (type: Material) Param[3]: transforms (type: const Matrix *) Param[4]: instances (type: int) -Function 495: GetMeshBoundingBox() (1 input parameters) +Function 496: GetMeshBoundingBox() (1 input parameters) Name: GetMeshBoundingBox Return type: BoundingBox Description: Compute mesh bounding box limits Param[1]: mesh (type: Mesh) -Function 496: GenMeshTangents() (1 input parameters) +Function 497: GenMeshTangents() (1 input parameters) Name: GenMeshTangents Return type: void Description: Compute mesh tangents Param[1]: mesh (type: Mesh *) -Function 497: ExportMesh() (2 input parameters) +Function 498: ExportMesh() (2 input parameters) Name: ExportMesh Return type: bool Description: Export mesh data to file, returns true on success Param[1]: mesh (type: Mesh) Param[2]: fileName (type: const char *) -Function 498: ExportMeshAsCode() (2 input parameters) +Function 499: ExportMeshAsCode() (2 input parameters) Name: ExportMeshAsCode Return type: bool Description: Export mesh as code file (.h) defining multiple arrays of vertex attributes Param[1]: mesh (type: Mesh) Param[2]: fileName (type: const char *) -Function 499: GenMeshPoly() (2 input parameters) +Function 500: GenMeshPoly() (2 input parameters) Name: GenMeshPoly Return type: Mesh Description: Generate polygonal mesh Param[1]: sides (type: int) Param[2]: radius (type: float) -Function 500: GenMeshPlane() (4 input parameters) +Function 501: GenMeshPlane() (4 input parameters) Name: GenMeshPlane Return type: Mesh Description: Generate plane mesh (with subdivisions) @@ -4210,42 +4219,42 @@ Function 500: GenMeshPlane() (4 input parameters) Param[2]: length (type: float) Param[3]: resX (type: int) Param[4]: resZ (type: int) -Function 501: GenMeshCube() (3 input parameters) +Function 502: GenMeshCube() (3 input parameters) Name: GenMeshCube Return type: Mesh Description: Generate cuboid mesh Param[1]: width (type: float) Param[2]: height (type: float) Param[3]: length (type: float) -Function 502: GenMeshSphere() (3 input parameters) +Function 503: GenMeshSphere() (3 input parameters) Name: GenMeshSphere Return type: Mesh Description: Generate sphere mesh (standard sphere) Param[1]: radius (type: float) Param[2]: rings (type: int) Param[3]: slices (type: int) -Function 503: GenMeshHemiSphere() (3 input parameters) +Function 504: GenMeshHemiSphere() (3 input parameters) Name: GenMeshHemiSphere Return type: Mesh Description: Generate half-sphere mesh (no bottom cap) Param[1]: radius (type: float) Param[2]: rings (type: int) Param[3]: slices (type: int) -Function 504: GenMeshCylinder() (3 input parameters) +Function 505: GenMeshCylinder() (3 input parameters) Name: GenMeshCylinder Return type: Mesh Description: Generate cylinder mesh Param[1]: radius (type: float) Param[2]: height (type: float) Param[3]: slices (type: int) -Function 505: GenMeshCone() (3 input parameters) +Function 506: GenMeshCone() (3 input parameters) Name: GenMeshCone Return type: Mesh Description: Generate cone/pyramid mesh Param[1]: radius (type: float) Param[2]: height (type: float) Param[3]: slices (type: int) -Function 506: GenMeshTorus() (4 input parameters) +Function 507: GenMeshTorus() (4 input parameters) Name: GenMeshTorus Return type: Mesh Description: Generate torus mesh @@ -4253,7 +4262,7 @@ Function 506: GenMeshTorus() (4 input parameters) Param[2]: size (type: float) Param[3]: radSeg (type: int) Param[4]: sides (type: int) -Function 507: GenMeshKnot() (4 input parameters) +Function 508: GenMeshKnot() (4 input parameters) Name: GenMeshKnot Return type: Mesh Description: Generate trefoil knot mesh @@ -4261,91 +4270,91 @@ Function 507: GenMeshKnot() (4 input parameters) Param[2]: size (type: float) Param[3]: radSeg (type: int) Param[4]: sides (type: int) -Function 508: GenMeshHeightmap() (2 input parameters) +Function 509: GenMeshHeightmap() (2 input parameters) Name: GenMeshHeightmap Return type: Mesh Description: Generate heightmap mesh from image data Param[1]: heightmap (type: Image) Param[2]: size (type: Vector3) -Function 509: GenMeshCubicmap() (2 input parameters) +Function 510: GenMeshCubicmap() (2 input parameters) Name: GenMeshCubicmap Return type: Mesh Description: Generate cubes-based map mesh from image data Param[1]: cubicmap (type: Image) Param[2]: cubeSize (type: Vector3) -Function 510: LoadMaterials() (2 input parameters) +Function 511: LoadMaterials() (2 input parameters) Name: LoadMaterials Return type: Material * Description: Load materials from model file Param[1]: fileName (type: const char *) Param[2]: materialCount (type: int *) -Function 511: LoadMaterialDefault() (0 input parameters) +Function 512: LoadMaterialDefault() (0 input parameters) Name: LoadMaterialDefault Return type: Material Description: Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps) No input parameters -Function 512: IsMaterialValid() (1 input parameters) +Function 513: IsMaterialValid() (1 input parameters) Name: IsMaterialValid Return type: bool Description: Check if a material is valid (shader assigned, map textures loaded in GPU) Param[1]: material (type: Material) -Function 513: UnloadMaterial() (1 input parameters) +Function 514: UnloadMaterial() (1 input parameters) Name: UnloadMaterial Return type: void Description: Unload material from GPU memory (VRAM) Param[1]: material (type: Material) -Function 514: SetMaterialTexture() (3 input parameters) +Function 515: SetMaterialTexture() (3 input parameters) Name: SetMaterialTexture Return type: void Description: Set texture for a material map type (MATERIAL_MAP_DIFFUSE, MATERIAL_MAP_SPECULAR...) Param[1]: material (type: Material *) Param[2]: mapType (type: int) Param[3]: texture (type: Texture2D) -Function 515: SetModelMeshMaterial() (3 input parameters) +Function 516: SetModelMeshMaterial() (3 input parameters) Name: SetModelMeshMaterial Return type: void Description: Set material for a mesh Param[1]: model (type: Model *) Param[2]: meshId (type: int) Param[3]: materialId (type: int) -Function 516: LoadModelAnimations() (2 input parameters) +Function 517: LoadModelAnimations() (2 input parameters) Name: LoadModelAnimations Return type: ModelAnimation * Description: Load model animations from file Param[1]: fileName (type: const char *) Param[2]: animCount (type: int *) -Function 517: UpdateModelAnimation() (3 input parameters) +Function 518: UpdateModelAnimation() (3 input parameters) Name: UpdateModelAnimation Return type: void Description: Update model animation pose (CPU) Param[1]: model (type: Model) Param[2]: anim (type: ModelAnimation) Param[3]: frame (type: int) -Function 518: UpdateModelAnimationBones() (3 input parameters) +Function 519: UpdateModelAnimationBones() (3 input parameters) Name: UpdateModelAnimationBones Return type: void Description: Update model animation mesh bone matrices (GPU skinning) Param[1]: model (type: Model) Param[2]: anim (type: ModelAnimation) Param[3]: frame (type: int) -Function 519: UnloadModelAnimation() (1 input parameters) +Function 520: UnloadModelAnimation() (1 input parameters) Name: UnloadModelAnimation Return type: void Description: Unload animation data Param[1]: anim (type: ModelAnimation) -Function 520: UnloadModelAnimations() (2 input parameters) +Function 521: UnloadModelAnimations() (2 input parameters) Name: UnloadModelAnimations Return type: void Description: Unload animation array data Param[1]: animations (type: ModelAnimation *) Param[2]: animCount (type: int) -Function 521: IsModelAnimationValid() (2 input parameters) +Function 522: IsModelAnimationValid() (2 input parameters) Name: IsModelAnimationValid Return type: bool Description: Check model animation skeleton match Param[1]: model (type: Model) Param[2]: anim (type: ModelAnimation) -Function 522: CheckCollisionSpheres() (4 input parameters) +Function 523: CheckCollisionSpheres() (4 input parameters) Name: CheckCollisionSpheres Return type: bool Description: Check collision between two spheres @@ -4353,40 +4362,40 @@ Function 522: CheckCollisionSpheres() (4 input parameters) Param[2]: radius1 (type: float) Param[3]: center2 (type: Vector3) Param[4]: radius2 (type: float) -Function 523: CheckCollisionBoxes() (2 input parameters) +Function 524: CheckCollisionBoxes() (2 input parameters) Name: CheckCollisionBoxes Return type: bool Description: Check collision between two bounding boxes Param[1]: box1 (type: BoundingBox) Param[2]: box2 (type: BoundingBox) -Function 524: CheckCollisionBoxSphere() (3 input parameters) +Function 525: CheckCollisionBoxSphere() (3 input parameters) Name: CheckCollisionBoxSphere Return type: bool Description: Check collision between box and sphere Param[1]: box (type: BoundingBox) Param[2]: center (type: Vector3) Param[3]: radius (type: float) -Function 525: GetRayCollisionSphere() (3 input parameters) +Function 526: GetRayCollisionSphere() (3 input parameters) Name: GetRayCollisionSphere Return type: RayCollision Description: Get collision info between ray and sphere Param[1]: ray (type: Ray) Param[2]: center (type: Vector3) Param[3]: radius (type: float) -Function 526: GetRayCollisionBox() (2 input parameters) +Function 527: GetRayCollisionBox() (2 input parameters) Name: GetRayCollisionBox Return type: RayCollision Description: Get collision info between ray and box Param[1]: ray (type: Ray) Param[2]: box (type: BoundingBox) -Function 527: GetRayCollisionMesh() (3 input parameters) +Function 528: GetRayCollisionMesh() (3 input parameters) Name: GetRayCollisionMesh Return type: RayCollision Description: Get collision info between ray and mesh Param[1]: ray (type: Ray) Param[2]: mesh (type: Mesh) Param[3]: transform (type: Matrix) -Function 528: GetRayCollisionTriangle() (4 input parameters) +Function 529: GetRayCollisionTriangle() (4 input parameters) Name: GetRayCollisionTriangle Return type: RayCollision Description: Get collision info between ray and triangle @@ -4394,7 +4403,7 @@ Function 528: GetRayCollisionTriangle() (4 input parameters) Param[2]: p1 (type: Vector3) Param[3]: p2 (type: Vector3) Param[4]: p3 (type: Vector3) -Function 529: GetRayCollisionQuad() (5 input parameters) +Function 530: GetRayCollisionQuad() (5 input parameters) Name: GetRayCollisionQuad Return type: RayCollision Description: Get collision info between ray and quad @@ -4403,158 +4412,158 @@ Function 529: GetRayCollisionQuad() (5 input parameters) Param[3]: p2 (type: Vector3) Param[4]: p3 (type: Vector3) Param[5]: p4 (type: Vector3) -Function 530: InitAudioDevice() (0 input parameters) +Function 531: InitAudioDevice() (0 input parameters) Name: InitAudioDevice Return type: void Description: Initialize audio device and context No input parameters -Function 531: CloseAudioDevice() (0 input parameters) +Function 532: CloseAudioDevice() (0 input parameters) Name: CloseAudioDevice Return type: void Description: Close the audio device and context No input parameters -Function 532: IsAudioDeviceReady() (0 input parameters) +Function 533: IsAudioDeviceReady() (0 input parameters) Name: IsAudioDeviceReady Return type: bool Description: Check if audio device has been initialized successfully No input parameters -Function 533: SetMasterVolume() (1 input parameters) +Function 534: SetMasterVolume() (1 input parameters) Name: SetMasterVolume Return type: void Description: Set master volume (listener) Param[1]: volume (type: float) -Function 534: GetMasterVolume() (0 input parameters) +Function 535: GetMasterVolume() (0 input parameters) Name: GetMasterVolume Return type: float Description: Get master volume (listener) No input parameters -Function 535: LoadWave() (1 input parameters) +Function 536: LoadWave() (1 input parameters) Name: LoadWave Return type: Wave Description: Load wave data from file Param[1]: fileName (type: const char *) -Function 536: LoadWaveFromMemory() (3 input parameters) +Function 537: LoadWaveFromMemory() (3 input parameters) Name: LoadWaveFromMemory Return type: Wave Description: Load wave from memory buffer, fileType refers to extension: i.e. '.wav' Param[1]: fileType (type: const char *) Param[2]: fileData (type: const unsigned char *) Param[3]: dataSize (type: int) -Function 537: IsWaveValid() (1 input parameters) +Function 538: IsWaveValid() (1 input parameters) Name: IsWaveValid Return type: bool Description: Checks if wave data is valid (data loaded and parameters) Param[1]: wave (type: Wave) -Function 538: LoadSound() (1 input parameters) +Function 539: LoadSound() (1 input parameters) Name: LoadSound Return type: Sound Description: Load sound from file Param[1]: fileName (type: const char *) -Function 539: LoadSoundFromWave() (1 input parameters) +Function 540: LoadSoundFromWave() (1 input parameters) Name: LoadSoundFromWave Return type: Sound Description: Load sound from wave data Param[1]: wave (type: Wave) -Function 540: LoadSoundAlias() (1 input parameters) +Function 541: LoadSoundAlias() (1 input parameters) Name: LoadSoundAlias Return type: Sound Description: Create a new sound that shares the same sample data as the source sound, does not own the sound data Param[1]: source (type: Sound) -Function 541: IsSoundValid() (1 input parameters) +Function 542: IsSoundValid() (1 input parameters) Name: IsSoundValid Return type: bool Description: Checks if a sound is valid (data loaded and buffers initialized) Param[1]: sound (type: Sound) -Function 542: UpdateSound() (3 input parameters) +Function 543: UpdateSound() (3 input parameters) Name: UpdateSound Return type: void Description: Update sound buffer with new data (data and frame count should fit in sound) Param[1]: sound (type: Sound) Param[2]: data (type: const void *) Param[3]: sampleCount (type: int) -Function 543: UnloadWave() (1 input parameters) +Function 544: UnloadWave() (1 input parameters) Name: UnloadWave Return type: void Description: Unload wave data Param[1]: wave (type: Wave) -Function 544: UnloadSound() (1 input parameters) +Function 545: UnloadSound() (1 input parameters) Name: UnloadSound Return type: void Description: Unload sound Param[1]: sound (type: Sound) -Function 545: UnloadSoundAlias() (1 input parameters) +Function 546: UnloadSoundAlias() (1 input parameters) Name: UnloadSoundAlias Return type: void Description: Unload a sound alias (does not deallocate sample data) Param[1]: alias (type: Sound) -Function 546: ExportWave() (2 input parameters) +Function 547: ExportWave() (2 input parameters) Name: ExportWave Return type: bool Description: Export wave data to file, returns true on success Param[1]: wave (type: Wave) Param[2]: fileName (type: const char *) -Function 547: ExportWaveAsCode() (2 input parameters) +Function 548: ExportWaveAsCode() (2 input parameters) Name: ExportWaveAsCode Return type: bool Description: Export wave sample data to code (.h), returns true on success Param[1]: wave (type: Wave) Param[2]: fileName (type: const char *) -Function 548: PlaySound() (1 input parameters) +Function 549: PlaySound() (1 input parameters) Name: PlaySound Return type: void Description: Play a sound Param[1]: sound (type: Sound) -Function 549: StopSound() (1 input parameters) +Function 550: StopSound() (1 input parameters) Name: StopSound Return type: void Description: Stop playing a sound Param[1]: sound (type: Sound) -Function 550: PauseSound() (1 input parameters) +Function 551: PauseSound() (1 input parameters) Name: PauseSound Return type: void Description: Pause a sound Param[1]: sound (type: Sound) -Function 551: ResumeSound() (1 input parameters) +Function 552: ResumeSound() (1 input parameters) Name: ResumeSound Return type: void Description: Resume a paused sound Param[1]: sound (type: Sound) -Function 552: IsSoundPlaying() (1 input parameters) +Function 553: IsSoundPlaying() (1 input parameters) Name: IsSoundPlaying Return type: bool Description: Check if a sound is currently playing Param[1]: sound (type: Sound) -Function 553: SetSoundVolume() (2 input parameters) +Function 554: SetSoundVolume() (2 input parameters) Name: SetSoundVolume Return type: void Description: Set volume for a sound (1.0 is max level) Param[1]: sound (type: Sound) Param[2]: volume (type: float) -Function 554: SetSoundPitch() (2 input parameters) +Function 555: SetSoundPitch() (2 input parameters) Name: SetSoundPitch Return type: void Description: Set pitch for a sound (1.0 is base level) Param[1]: sound (type: Sound) Param[2]: pitch (type: float) -Function 555: SetSoundPan() (2 input parameters) +Function 556: SetSoundPan() (2 input parameters) Name: SetSoundPan Return type: void Description: Set pan for a sound (0.5 is center) Param[1]: sound (type: Sound) Param[2]: pan (type: float) -Function 556: WaveCopy() (1 input parameters) +Function 557: WaveCopy() (1 input parameters) Name: WaveCopy Return type: Wave Description: Copy a wave to a new wave Param[1]: wave (type: Wave) -Function 557: WaveCrop() (3 input parameters) +Function 558: WaveCrop() (3 input parameters) Name: WaveCrop Return type: void Description: Crop a wave to defined frames range Param[1]: wave (type: Wave *) Param[2]: initFrame (type: int) Param[3]: finalFrame (type: int) -Function 558: WaveFormat() (4 input parameters) +Function 559: WaveFormat() (4 input parameters) Name: WaveFormat Return type: void Description: Convert wave data to desired format @@ -4562,203 +4571,203 @@ Function 558: WaveFormat() (4 input parameters) Param[2]: sampleRate (type: int) Param[3]: sampleSize (type: int) Param[4]: channels (type: int) -Function 559: LoadWaveSamples() (1 input parameters) +Function 560: LoadWaveSamples() (1 input parameters) Name: LoadWaveSamples Return type: float * Description: Load samples data from wave as a 32bit float data array Param[1]: wave (type: Wave) -Function 560: UnloadWaveSamples() (1 input parameters) +Function 561: UnloadWaveSamples() (1 input parameters) Name: UnloadWaveSamples Return type: void Description: Unload samples data loaded with LoadWaveSamples() Param[1]: samples (type: float *) -Function 561: LoadMusicStream() (1 input parameters) +Function 562: LoadMusicStream() (1 input parameters) Name: LoadMusicStream Return type: Music Description: Load music stream from file Param[1]: fileName (type: const char *) -Function 562: LoadMusicStreamFromMemory() (3 input parameters) +Function 563: LoadMusicStreamFromMemory() (3 input parameters) Name: LoadMusicStreamFromMemory Return type: Music Description: Load music stream from data Param[1]: fileType (type: const char *) Param[2]: data (type: const unsigned char *) Param[3]: dataSize (type: int) -Function 563: IsMusicValid() (1 input parameters) +Function 564: IsMusicValid() (1 input parameters) Name: IsMusicValid Return type: bool Description: Checks if a music stream is valid (context and buffers initialized) Param[1]: music (type: Music) -Function 564: UnloadMusicStream() (1 input parameters) +Function 565: UnloadMusicStream() (1 input parameters) Name: UnloadMusicStream Return type: void Description: Unload music stream Param[1]: music (type: Music) -Function 565: PlayMusicStream() (1 input parameters) +Function 566: PlayMusicStream() (1 input parameters) Name: PlayMusicStream Return type: void Description: Start music playing Param[1]: music (type: Music) -Function 566: IsMusicStreamPlaying() (1 input parameters) +Function 567: IsMusicStreamPlaying() (1 input parameters) Name: IsMusicStreamPlaying Return type: bool Description: Check if music is playing Param[1]: music (type: Music) -Function 567: UpdateMusicStream() (1 input parameters) +Function 568: UpdateMusicStream() (1 input parameters) Name: UpdateMusicStream Return type: void Description: Updates buffers for music streaming Param[1]: music (type: Music) -Function 568: StopMusicStream() (1 input parameters) +Function 569: StopMusicStream() (1 input parameters) Name: StopMusicStream Return type: void Description: Stop music playing Param[1]: music (type: Music) -Function 569: PauseMusicStream() (1 input parameters) +Function 570: PauseMusicStream() (1 input parameters) Name: PauseMusicStream Return type: void Description: Pause music playing Param[1]: music (type: Music) -Function 570: ResumeMusicStream() (1 input parameters) +Function 571: ResumeMusicStream() (1 input parameters) Name: ResumeMusicStream Return type: void Description: Resume playing paused music Param[1]: music (type: Music) -Function 571: SeekMusicStream() (2 input parameters) +Function 572: SeekMusicStream() (2 input parameters) Name: SeekMusicStream Return type: void Description: Seek music to a position (in seconds) Param[1]: music (type: Music) Param[2]: position (type: float) -Function 572: SetMusicVolume() (2 input parameters) +Function 573: SetMusicVolume() (2 input parameters) Name: SetMusicVolume Return type: void Description: Set volume for music (1.0 is max level) Param[1]: music (type: Music) Param[2]: volume (type: float) -Function 573: SetMusicPitch() (2 input parameters) +Function 574: SetMusicPitch() (2 input parameters) Name: SetMusicPitch Return type: void Description: Set pitch for a music (1.0 is base level) Param[1]: music (type: Music) Param[2]: pitch (type: float) -Function 574: SetMusicPan() (2 input parameters) +Function 575: SetMusicPan() (2 input parameters) Name: SetMusicPan Return type: void Description: Set pan for a music (0.5 is center) Param[1]: music (type: Music) Param[2]: pan (type: float) -Function 575: GetMusicTimeLength() (1 input parameters) +Function 576: GetMusicTimeLength() (1 input parameters) Name: GetMusicTimeLength Return type: float Description: Get music time length (in seconds) Param[1]: music (type: Music) -Function 576: GetMusicTimePlayed() (1 input parameters) +Function 577: GetMusicTimePlayed() (1 input parameters) Name: GetMusicTimePlayed Return type: float Description: Get current music time played (in seconds) Param[1]: music (type: Music) -Function 577: LoadAudioStream() (3 input parameters) +Function 578: LoadAudioStream() (3 input parameters) Name: LoadAudioStream Return type: AudioStream Description: Load audio stream (to stream raw audio pcm data) Param[1]: sampleRate (type: unsigned int) Param[2]: sampleSize (type: unsigned int) Param[3]: channels (type: unsigned int) -Function 578: IsAudioStreamValid() (1 input parameters) +Function 579: IsAudioStreamValid() (1 input parameters) Name: IsAudioStreamValid Return type: bool Description: Checks if an audio stream is valid (buffers initialized) Param[1]: stream (type: AudioStream) -Function 579: UnloadAudioStream() (1 input parameters) +Function 580: UnloadAudioStream() (1 input parameters) Name: UnloadAudioStream Return type: void Description: Unload audio stream and free memory Param[1]: stream (type: AudioStream) -Function 580: UpdateAudioStream() (3 input parameters) +Function 581: UpdateAudioStream() (3 input parameters) Name: UpdateAudioStream Return type: void Description: Update audio stream buffers with data Param[1]: stream (type: AudioStream) Param[2]: data (type: const void *) Param[3]: frameCount (type: int) -Function 581: IsAudioStreamProcessed() (1 input parameters) +Function 582: IsAudioStreamProcessed() (1 input parameters) Name: IsAudioStreamProcessed Return type: bool Description: Check if any audio stream buffers requires refill Param[1]: stream (type: AudioStream) -Function 582: PlayAudioStream() (1 input parameters) +Function 583: PlayAudioStream() (1 input parameters) Name: PlayAudioStream Return type: void Description: Play audio stream Param[1]: stream (type: AudioStream) -Function 583: PauseAudioStream() (1 input parameters) +Function 584: PauseAudioStream() (1 input parameters) Name: PauseAudioStream Return type: void Description: Pause audio stream Param[1]: stream (type: AudioStream) -Function 584: ResumeAudioStream() (1 input parameters) +Function 585: ResumeAudioStream() (1 input parameters) Name: ResumeAudioStream Return type: void Description: Resume audio stream Param[1]: stream (type: AudioStream) -Function 585: IsAudioStreamPlaying() (1 input parameters) +Function 586: IsAudioStreamPlaying() (1 input parameters) Name: IsAudioStreamPlaying Return type: bool Description: Check if audio stream is playing Param[1]: stream (type: AudioStream) -Function 586: StopAudioStream() (1 input parameters) +Function 587: StopAudioStream() (1 input parameters) Name: StopAudioStream Return type: void Description: Stop audio stream Param[1]: stream (type: AudioStream) -Function 587: SetAudioStreamVolume() (2 input parameters) +Function 588: SetAudioStreamVolume() (2 input parameters) Name: SetAudioStreamVolume Return type: void Description: Set volume for audio stream (1.0 is max level) Param[1]: stream (type: AudioStream) Param[2]: volume (type: float) -Function 588: SetAudioStreamPitch() (2 input parameters) +Function 589: SetAudioStreamPitch() (2 input parameters) Name: SetAudioStreamPitch Return type: void Description: Set pitch for audio stream (1.0 is base level) Param[1]: stream (type: AudioStream) Param[2]: pitch (type: float) -Function 589: SetAudioStreamPan() (2 input parameters) +Function 590: SetAudioStreamPan() (2 input parameters) Name: SetAudioStreamPan Return type: void Description: Set pan for audio stream (0.5 is centered) Param[1]: stream (type: AudioStream) Param[2]: pan (type: float) -Function 590: SetAudioStreamBufferSizeDefault() (1 input parameters) +Function 591: SetAudioStreamBufferSizeDefault() (1 input parameters) Name: SetAudioStreamBufferSizeDefault Return type: void Description: Default size for new audio streams Param[1]: size (type: int) -Function 591: SetAudioStreamCallback() (2 input parameters) +Function 592: SetAudioStreamCallback() (2 input parameters) Name: SetAudioStreamCallback Return type: void Description: Audio thread callback to request new data Param[1]: stream (type: AudioStream) Param[2]: callback (type: AudioCallback) -Function 592: AttachAudioStreamProcessor() (2 input parameters) +Function 593: AttachAudioStreamProcessor() (2 input parameters) Name: AttachAudioStreamProcessor Return type: void Description: Attach audio stream processor to stream, receives frames x 2 samples as 'float' (stereo) Param[1]: stream (type: AudioStream) Param[2]: processor (type: AudioCallback) -Function 593: DetachAudioStreamProcessor() (2 input parameters) +Function 594: DetachAudioStreamProcessor() (2 input parameters) Name: DetachAudioStreamProcessor Return type: void Description: Detach audio stream processor from stream Param[1]: stream (type: AudioStream) Param[2]: processor (type: AudioCallback) -Function 594: AttachAudioMixedProcessor() (1 input parameters) +Function 595: AttachAudioMixedProcessor() (1 input parameters) Name: AttachAudioMixedProcessor Return type: void Description: Attach audio stream processor to the entire audio pipeline, receives frames x 2 samples as 'float' (stereo) Param[1]: processor (type: AudioCallback) -Function 595: DetachAudioMixedProcessor() (1 input parameters) +Function 596: DetachAudioMixedProcessor() (1 input parameters) Name: DetachAudioMixedProcessor Return type: void Description: Detach audio stream processor from the entire audio pipeline diff --git a/tools/parser/output/raylib_api.xml b/tools/parser/output/raylib_api.xml index 6ea73d8dc..29546a2a8 100644 --- a/tools/parser/output/raylib_api.xml +++ b/tools/parser/output/raylib_api.xml @@ -679,7 +679,7 @@ - + @@ -1359,6 +1359,13 @@ + + + + + + + From 14a0a4d0c414b3c45b5d339dd1117682e537073c Mon Sep 17 00:00:00 2001 From: Teeto44 <160558926+Teeto44@users.noreply.github.com> Date: Wed, 1 Oct 2025 12:27:28 -0400 Subject: [PATCH 064/167] FIXED: rexm's makefile and default paths (#5224) * FIXED: rexm's makefile and default paths Fixed a windows only backslash in rexm's makefile causing build errors on macOS and linux Added unix paths to rexm for better compatibility * Update rexm.c Readded the fall-through in OP_CREATE Added some safety checks to UpdateRequiredFiles() so it plays nicely outside of the raylib.com context (would segfault previously) --- tools/rexm/Makefile | 5 +- tools/rexm/rexm.c | 111 ++++++++++++++++++++++++++------------------ 2 files changed, 69 insertions(+), 47 deletions(-) diff --git a/tools/rexm/Makefile b/tools/rexm/Makefile index f5e7d1fe4..d7d71f64f 100644 --- a/tools/rexm/Makefile +++ b/tools/rexm/Makefile @@ -35,7 +35,7 @@ PROJECT_BUILD_PATH ?= . PROJECT_SOURCE_FILES ?= rexm.c # raylib library variables -RAYLIB_SRC_PATH ?= ..\..\src +RAYLIB_SRC_PATH ?= ../../src RAYLIB_INCLUDE_PATH ?= $(RAYLIB_SRC_PATH) RAYLIB_LIB_PATH ?= $(RAYLIB_SRC_PATH) @@ -236,7 +236,7 @@ ifeq ($(PLATFORM),PLATFORM_WEB) # --source-map-base # allow debugging in browser with source map # --shell-file shell.html # define a custom shell .html and output extension LDFLAGS += -sUSE_GLFW=3 -sTOTAL_MEMORY=$(BUILD_WEB_HEAP_SIZE) -sSTACK_SIZE=$(BUILD_WEB_STACK_SIZE) -sFORCE_FILESYSTEM=1 -sMINIFY_HTML=0 - + # Build using asyncify ifeq ($(BUILD_WEB_ASYNCIFY),TRUE) LDFLAGS += -sASYNCIFY -sASYNCIFY_STACK_SIZE=$(BUILD_WEB_ASYNCIFY_STACK_SIZE) @@ -363,4 +363,3 @@ ifeq ($(PLATFORM),PLATFORM_WEB) del *.o *.html *.js endif @echo Cleaning done - diff --git a/tools/rexm/rexm.c b/tools/rexm/rexm.c index f6c297769..3306e613a 100644 --- a/tools/rexm/rexm.c +++ b/tools/rexm/rexm.c @@ -205,12 +205,22 @@ int main(int argc, char *argv[]) exCollectionFilePath = getenv("REXM_EXAMPLES_COLLECTION_FILE_PATH"); exVSProjectSolutionFile = getenv("REXM_EXAMPLES_VS2022_SLN_FILE"); +#if defined(_WIN32) if (!exBasePath) exBasePath = "C:/GitHub/raylib/examples"; if (!exWebPath) exWebPath = "C:/GitHub/raylib.com/examples"; if (!exTemplateFilePath) exTemplateFilePath = "C:/GitHub/raylib/examples/examples_template.c"; if (!exTemplateScreenshot) exTemplateScreenshot = "C:/GitHub/raylib/examples/examples_template.png"; if (!exCollectionFilePath) exCollectionFilePath = "C:/GitHub/raylib/examples/examples_list.txt"; if (!exVSProjectSolutionFile) exVSProjectSolutionFile = "C:/GitHub/raylib/projects/VS2022/raylib.sln"; +#else + // Cross-platform relative fallbacks (run from tools/rexm directory) + if (!exBasePath) exBasePath = "../../examples"; + if (!exWebPath) exWebPath = "../../raylib.com/examples"; + if (!exTemplateFilePath) exTemplateFilePath = "../../examples/examples_template.c"; + if (!exTemplateScreenshot) exTemplateScreenshot = "../../examples/examples_template.png"; + if (!exCollectionFilePath) exCollectionFilePath = "../../examples/examples_list.txt"; + if (!exVSProjectSolutionFile) exVSProjectSolutionFile = "../../projects/VS2022/raylib.sln"; +#endif char inFileName[1024] = { 0 }; // Example input filename (to be added) @@ -1660,54 +1670,67 @@ static int UpdateRequiredFiles(void) // NOTE: Entries format: exampleEntry('⭐️☆☆☆' , 'core' , 'basic_window'), //------------------------------------------------------------------------------------------------ char *jsText = LoadFileText(TextFormat("%s/../common/examples.js", exWebPath)); - char *jsTextUpdated = (char *)RL_CALLOC(REXM_MAX_BUFFER_SIZE, 1); // Updated examples.js copy, 2MB - - int jsListStartIndex = TextFindIndex(jsText, "//EXAMPLE_DATA_LIST_START"); - int jsListEndIndex = TextFindIndex(jsText, "//EXAMPLE_DATA_LIST_END"); - - int jsIndex = 0; - memcpy(jsTextUpdated, jsText, jsListStartIndex); - jsIndex = sprintf(jsTextUpdated + jsListStartIndex, "//EXAMPLE_DATA_LIST_START\n"); - jsIndex += sprintf(jsTextUpdated + jsListStartIndex + jsIndex, " var exampleData = [\n"); - - char starsText[16] = { 0 }; - - // NOTE: We avoid "others" category - for (int i = 0; i < REXM_MAX_EXAMPLE_CATEGORIES - 1; i++) + if (!jsText) { - int exCollectionCount = 0; - rlExampleInfo *exCollection = LoadExamplesData(exCollectionFilePath, exCategories[i], false, &exCollectionCount); - for (int x = 0; x < exCollectionCount; x++) - { - for (int s = 0; s < 4; s++) - { - if (s < exCollection[x].stars) strcpy(starsText + 3*s, "⭐️"); // WARNING: Different than '★', more visual - else strcpy(starsText + 3*s, "☆"); - } - - if ((i == 6) && (x == (exCollectionCount - 1))) - { - // NOTE: Last line to add, special case to consider - jsIndex += sprintf(jsTextUpdated + jsListStartIndex + jsIndex, - TextFormat(" exampleEntry('%s', '%s', '%s')];\n", starsText, exCollection[x].category, exCollection[x].name + strlen(exCollection[x].category) + 1)); - } - else - { - jsIndex += sprintf(jsTextUpdated + jsListStartIndex + jsIndex, - TextFormat(" exampleEntry('%s', '%s', '%s'),\n", starsText, exCollection[x].category, exCollection[x].name + strlen(exCollection[x].category) + 1)); - } - } - - UnloadExamplesData(exCollection); + LOG("INFO: examples.js not found, skipping web examples list update\n"); } + else + { + int jsListStartIndex = TextFindIndex(jsText, "//EXAMPLE_DATA_LIST_START"); + int jsListEndIndex = TextFindIndex(jsText, "//EXAMPLE_DATA_LIST_END"); + if ((jsListStartIndex < 0) || (jsListEndIndex < 0)) + { + LOG("WARNING: examples.js markers not found, skipping update\n"); + UnloadFileText(jsText); + } + else + { + char *jsTextUpdated = (char *)RL_CALLOC(REXM_MAX_BUFFER_SIZE, 1); // Updated examples.js copy, 2MB + int jsIndex = 0; + memcpy(jsTextUpdated, jsText, jsListStartIndex); + jsIndex = sprintf(jsTextUpdated + jsListStartIndex, "//EXAMPLE_DATA_LIST_START\n"); + jsIndex += sprintf(jsTextUpdated + jsListStartIndex + jsIndex, " var exampleData = [\n"); - // Add the remaining part of the original file - memcpy(jsTextUpdated + jsListStartIndex + jsIndex, jsText + jsListEndIndex, strlen(jsText) - jsListEndIndex); + char starsText[16] = { 0 }; - // Save updated file - SaveFileText(TextFormat("%s/../common/examples.js", exWebPath), jsTextUpdated); - UnloadFileText(jsText); - RL_FREE(jsTextUpdated); + // NOTE: We avoid "others" category + for (int i = 0; i < REXM_MAX_EXAMPLE_CATEGORIES - 1; i++) + { + int exCollectionCount = 0; + rlExampleInfo *exCollection = LoadExamplesData(exCollectionFilePath, exCategories[i], false, &exCollectionCount); + for (int x = 0; x < exCollectionCount; x++) + { + for (int s = 0; s < 4; s++) + { + if (s < exCollection[x].stars) strcpy(starsText + 3*s, "⭐️"); // WARNING: Different than '★', more visual + else strcpy(starsText + 3*s, "☆"); + } + + if ((i == 6) && (x == (exCollectionCount - 1))) + { + // NOTE: Last line to add, special case to consider + jsIndex += sprintf(jsTextUpdated + jsListStartIndex + jsIndex, + TextFormat(" exampleEntry('%s', '%s', '%s')];\n", starsText, exCollection[x].category, exCollection[x].name + strlen(exCollection[x].category) + 1)); + } + else + { + jsIndex += sprintf(jsTextUpdated + jsListStartIndex + jsIndex, + TextFormat(" exampleEntry('%s', '%s', '%s'),\n", starsText, exCollection[x].category, exCollection[x].name + strlen(exCollection[x].category) + 1)); + } + } + + UnloadExamplesData(exCollection); + } + + // Add the remaining part of the original file + memcpy(jsTextUpdated + jsListStartIndex + jsIndex, jsText + jsListEndIndex, strlen(jsText) - jsListEndIndex); + + // Save updated file + SaveFileText(TextFormat("%s/../common/examples.js", exWebPath), jsTextUpdated); + UnloadFileText(jsText); + RL_FREE(jsTextUpdated); + } + } //------------------------------------------------------------------------------------------------ return result; From 452cac33b86f8ecd87788ba0eb0633d779c155d1 Mon Sep 17 00:00:00 2001 From: Maicon Santana Date: Wed, 1 Oct 2025 17:31:03 +0100 Subject: [PATCH 065/167] [examples] Add `core_monitor_change` (#5215) * Add core monitor change example * Add monitor drawing and more information * Update monitor information every frame * Show info and window position inside the rectangle --- examples/core/core_monitor_change.c | 170 ++++++++++++++++++++++++++ examples/core/core_monitor_change.png | Bin 0 -> 17430 bytes 2 files changed, 170 insertions(+) create mode 100644 examples/core/core_monitor_change.c create mode 100644 examples/core/core_monitor_change.png diff --git a/examples/core/core_monitor_change.c b/examples/core/core_monitor_change.c new file mode 100644 index 000000000..8983556af --- /dev/null +++ b/examples/core/core_monitor_change.c @@ -0,0 +1,170 @@ +/******************************************************************************************* +* +* raylib [core] example - monitor change +* +* Example complexity rating: [★☆☆☆] 1/4 +* +* Example originally created with raylib 5.5, last time updated with raylib 5.6 +* +* Example contributed by Maicon Santana (@maiconpintoabreu) 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 Maicon Santana (@maiconpintoabreu) +* +********************************************************************************************/ + +#include "raylib.h" + +#define MAX_MONITORS 10 + +// Monitor Details +typedef struct Monitor { + Vector2 position; + char *name; + int width; + int height; + int physicalWidth; + int physicalHeight; + int refreshRate; +} Monitor; + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + Monitor monitors[MAX_MONITORS] = { 0 }; + + InitWindow(screenWidth, screenHeight, "raylib [core] example - monitor change"); + + int currentMonitorIndex = GetCurrentMonitor(); + int monitorCount = 0; + + 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 + //---------------------------------------------------------------------------------- + + // Variables to find the max x and Y to calculate the scale + int maxWidth = 1; + int maxHeight = 1; + + // Monitor offset is to fix when monitor position x is negative + int monitorOffsetX = 0; + + // Rebuild monitors array every frame + monitorCount = GetMonitorCount(); + for (int i = 0; i < monitorCount; i++) + { + monitors[i] = (Monitor){ + GetMonitorPosition(i), + GetMonitorName(i), + GetMonitorWidth(i), + GetMonitorHeight(i), + GetMonitorPhysicalWidth(i), + GetMonitorPhysicalHeight(i), + GetMonitorRefreshRate(i) + }; + if (monitors[i].position.x < monitorOffsetX) monitorOffsetX = monitors[i].position.x*-1; + + const int width = monitors[i].position.x + monitors[i].width; + const int height = monitors[i].position.y + monitors[i].height; + + if (maxWidth < width) maxWidth = width; + if (maxHeight < height) maxHeight = height; + } + + if (IsKeyPressed(KEY_ENTER) && monitorCount > 1) + { + currentMonitorIndex += 1; + + // Set index to 0 if the last one + if(currentMonitorIndex == monitorCount) currentMonitorIndex = 0; + + SetWindowMonitor(currentMonitorIndex); // Move window to currentMonitorIndex + } + else + { + // Get currentMonitorIndex if manually moved + currentMonitorIndex = GetCurrentMonitor(); + } + const Monitor currentMonitor = monitors[currentMonitorIndex]; + + float monitorScale = 0.6; + + if(maxHeight > maxWidth + monitorOffsetX) monitorScale *= ((float)screenHeight/(float)maxHeight); + else monitorScale *= ((float)screenWidth/(float)(maxWidth + monitorOffsetX)); + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + DrawText("Press [Enter] to move window to next monitor available", 20, 20, 20, DARKGRAY); + + DrawRectangleLines(20, 60, screenWidth - 40, screenHeight - 100, DARKGRAY); + + // Draw Monitor Rectangles with information inside + for (int i = 0; i < monitorCount; i++) + { + // Calculate retangle position and size using monitorScale + const Rectangle rec = (Rectangle){ + (monitors[i].position.x + monitorOffsetX) * monitorScale + 140, + monitors[i].position.y * monitorScale + 80, + monitors[i].width * monitorScale, + monitors[i].height * monitorScale + }; + + // Draw monitor name and information inside the rectangle + DrawText(TextFormat("[%i] %s", i, monitors[i].name), rec.x + 10, rec.y + (int)(100*monitorScale), (int)(120*monitorScale), BLUE); + DrawText( + TextFormat("Resolution: [%ipx x %ipx]\nRefreshRate: [%ihz]\nPhysical Size: [%imm x %imm]\nPosition: %3.0f x %3.0f", + monitors[i].width, + monitors[i].height, + monitors[i].refreshRate, + monitors[i].physicalWidth, + monitors[i].physicalHeight, + monitors[i].position.x, + monitors[i].position.y + ), rec.x + 10, rec.y + (int)(200*monitorScale), (int)(120*monitorScale), DARKGRAY); + + // Highlight current monitor + if (i == currentMonitorIndex) + { + DrawRectangleLinesEx(rec, 5, RED); + Vector2 windowPosition = (Vector2){ (GetWindowPosition().x + monitorOffsetX)*monitorScale + 140, GetWindowPosition().y*monitorScale + 80 }; + + // Draw window position based on monitors + DrawRectangleV(windowPosition, (Vector2){screenWidth * monitorScale, screenHeight * monitorScale}, Fade(GREEN, 0.5)); + } + else + { + DrawRectangleLinesEx(rec, 5, GRAY); + } + + } + + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} \ No newline at end of file diff --git a/examples/core/core_monitor_change.png b/examples/core/core_monitor_change.png new file mode 100644 index 0000000000000000000000000000000000000000..81f9eed875bf8edf2c11e911cad5265418e054ed GIT binary patch literal 17430 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 Date: Wed, 1 Oct 2025 13:31:53 -0300 Subject: [PATCH 066/167] [examples] Add `models_geometry_textures_cube` (#5221) * ADDED: example: models_geometry_textures_cube * FIXED: example: models_geometry_textures_cube - removed leftover TODO and aligned title with header --- examples/Makefile | 1 + examples/Makefile.Web | 5 + examples/README.md | 5 +- examples/examples_list.txt | 1 + .../models/models_geometry_textures_cube.c | 88 ++++++++++++++++++ .../models/models_geometry_textures_cube.png | Bin 0 -> 49462 bytes 6 files changed, 98 insertions(+), 2 deletions(-) create mode 100644 examples/models/models_geometry_textures_cube.c create mode 100644 examples/models/models_geometry_textures_cube.png diff --git a/examples/Makefile b/examples/Makefile index 9a3f640b7..f594e2867 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -616,6 +616,7 @@ MODELS = \ models/models_cubicmap_rendering \ models/models_first_person_maze \ models/models_geometric_shapes \ + models/models_geometry_textures_cube \ models/models_heightmap_rendering \ models/models_loading \ models/models_loading_gltf \ diff --git a/examples/Makefile.Web b/examples/Makefile.Web index 20d737c38..e5dad0430 100644 --- a/examples/Makefile.Web +++ b/examples/Makefile.Web @@ -616,6 +616,7 @@ MODELS = \ models/models_cubicmap_rendering \ models/models_first_person_maze \ models/models_geometric_shapes \ + models/models_geometry_textures_cube \ models/models_heightmap_rendering \ models/models_loading \ models/models_loading_gltf \ @@ -1085,6 +1086,10 @@ 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 + $(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 diff --git a/examples/README.md b/examples/README.md index a5ee53afd..d52f96280 100644 --- a/examples/README.md +++ b/examples/README.md @@ -17,7 +17,7 @@ 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: 165] +## EXAMPLES COLLECTION [TOTAL: 166] ### category: core [38] @@ -147,7 +147,7 @@ Examples using raylib text functionality, including sprite fonts loading/generat | [text_codepoints_loading](text/text_codepoints_loading.c) | text_codepoints_loading | ⭐⭐⭐☆ | 4.2 | 4.2 | [Ramon Santamaria](https://github.com/raysan5) | | [text_inline_styling](text/text_inline_styling.c) | text_inline_styling | ⭐⭐⭐☆ | 5.6-dev | 5.6-dev | [Wagner Barongello](https://github.com/SultansOfCode) | -### category: models [24] +### category: models [25] Examples using raylib models functionality, including models loading/generation and drawing, provided by raylib [models](../src/rmodels.c) module. @@ -177,6 +177,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) | ### category: shaders [29] diff --git a/examples/examples_list.txt b/examples/examples_list.txt index 10bf09ceb..52104fbd9 100644 --- a/examples/examples_list.txt +++ b/examples/examples_list.txt @@ -131,6 +131,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 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 shaders;shaders_shapes_textures;★★☆☆;1.7;3.7;2015;2025;"Ramon Santamaria";@raysan5 diff --git a/examples/models/models_geometry_textures_cube.c b/examples/models/models_geometry_textures_cube.c new file mode 100644 index 000000000..4608ad951 --- /dev/null +++ b/examples/models/models_geometry_textures_cube.c @@ -0,0 +1,88 @@ +/******************************************************************************************* +* +* raylib [models] example - geometry textures cube +* +* Example complexity rating: [★☆☆☆] 1/4 +* +* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev +* +* Example contributed by Jopestpe (@jopestpe) +* +* 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 Jopestpe (@jopestpe) +* +********************************************************************************************/ + +#include "raylib.h" + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [models] example - geometry textures cube"); + + // Define the camera to look into our 3d world + Camera camera = { 0 }; + camera.position = (Vector3){ 0.0f, 0.0f, 4.0f }; + camera.target = (Vector3){ 0.0f, 0.0f, 0.0f }; + camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; + camera.fovy = 45.0f; + camera.projection = CAMERA_PERSPECTIVE; + + // Load image to create texture for the cube + Model model = LoadModelFromMesh(GenMeshCube(1.0f, 1.0f, 1.0f)); + Image img = LoadImage("resources/cubicmap_atlas.png"); + Image crop = ImageFromImage(img, (Rectangle){0, img.height/2, img.width/2, img.height/2}); + Texture2D texture = LoadTextureFromImage(crop); + UnloadImage(img); + UnloadImage(crop); + + model.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = texture; + + float rotation = 0.0f; + + 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 + //---------------------------------------------------------------------------------- + rotation += 1.0f; + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + BeginMode3D(camera); + + DrawModelEx(model, (Vector3){0,0,0}, (Vector3){0.5f,1,0}, rotation, (Vector3){1,1,1}, WHITE); + + EndMode3D(); + + DrawFPS(10, 10); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + UnloadTexture(texture); // Unload texture + UnloadModel(model); // Unload model + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} diff --git a/examples/models/models_geometry_textures_cube.png b/examples/models/models_geometry_textures_cube.png new file mode 100644 index 0000000000000000000000000000000000000000..4c199bdc4f363f3f714c4bd00a0e2f80072a5f2d GIT binary patch literal 49462 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%0A!s3WfJA7 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 Date: Wed, 1 Oct 2025 12:33:51 -0400 Subject: [PATCH 067/167] removed unneeded include (#5225) --- examples/shapes/shapes_collision_area.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/shapes/shapes_collision_area.c b/examples/shapes/shapes_collision_area.c index f492cf250..426d56536 100644 --- a/examples/shapes/shapes_collision_area.c +++ b/examples/shapes/shapes_collision_area.c @@ -15,8 +15,6 @@ #include "raylib.h" -#include // Required for: abs() - //------------------------------------------------------------------------------------ // Program main entry point //------------------------------------------------------------------------------------ From de20076d36c66aa334fa046055f823f0388fd7d9 Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 2 Oct 2025 13:02:58 +0200 Subject: [PATCH 068/167] Update examples_list.txt --- examples/examples_list.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/examples/examples_list.txt b/examples/examples_list.txt index 52104fbd9..65163caf4 100644 --- a/examples/examples_list.txt +++ b/examples/examples_list.txt @@ -8,6 +8,7 @@ # WARNING: List is not ordered by example name but by the display order on web # core;core_basic_window;★☆☆☆;1.0;1.0;2013;2025;"Ramon Santamaria";@raysan5 +core;core_delta_time;★☆☆☆;5.5;5.6-dev;2025;2025;"Robin";@RobinsAviary core;core_input_keys;★☆☆☆;1.0;1.0;2014;2025;"Ramon Santamaria";@raysan5 core;core_input_mouse;★☆☆☆;1.0;5.5;2014;2025;"Ramon Santamaria";@raysan5 core;core_input_mouse_wheel;★☆☆☆;1.1;1.3;2014;2025;"Ramon Santamaria";@raysan5 @@ -67,6 +68,7 @@ shapes;shapes_splines_drawing;★★★☆;5.0;5.0;2023;2025;"Ramon Santamaria"; shapes;shapes_digital_clock;★★★★;5.5;5.6;2025;2025;"Hamza RAHAL";@hmz-rhl shapes;shapes_double_pendulum;★★☆☆;5.5;5.5;2025;2025;"JoeCheong";@Joecheong2006 shapes;shapes_dashed_line;★☆☆☆;5.5;5.5;2025;2025;"Luís Almeida";@luis605 +shapes;shapes_vector_angle;★★☆☆;1.0;5.0;2025;2025;"Ramon Santamaria";@raysan5 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 @@ -132,6 +134,7 @@ 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 +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 shaders;shaders_shapes_textures;★★☆☆;1.7;3.7;2015;2025;"Ramon Santamaria";@raysan5 @@ -174,4 +177,4 @@ others;rlgl_compute_shader;★★★★;4.0;4.0;2021;2025;"Teddy Astie";@tsnake4 others;easings_testbed;★★★☆;2.5;3.0;2019;2025;"Juan Miguel López";@flashback-fx 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;raymath_vector_angle;★★☆☆;1.0;5.0;2023;2025;"Ramon Santamaria";@raysan5 +others;web_basic_window;☆☆☆☆;5.6-dev;5.6-dev;"Ramon Santamaria";@raysan5 From 5d9c11e16527b09dc7a148a5842a412c7400d408 Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 2 Oct 2025 13:04:34 +0200 Subject: [PATCH 069/167] Updated examples --- examples/shapes/shapes_bouncing_ball.c | 4 +- .../shapes_vector_angle.c} | 7 +- .../shapes_vector_angle.png} | Bin .../VS2022/examples/core_delta_time.vcxproj | 569 ++++++++++++++++++ .../examples/models_basic_voxel.vcxproj | 569 ++++++++++++++++++ .../examples/shapes_bullet_hell.vcxproj | 569 ++++++++++++++++++ .../examples/shapes_vector_angle.vcxproj | 569 ++++++++++++++++++ projects/VS2022/raylib.sln | 108 ++++ 8 files changed, 2390 insertions(+), 5 deletions(-) rename examples/{others/raymath_vector_angle.c => shapes/shapes_vector_angle.c} (96%) rename examples/{others/raymath_vector_angle.png => shapes/shapes_vector_angle.png} (100%) create mode 100644 projects/VS2022/examples/core_delta_time.vcxproj create mode 100644 projects/VS2022/examples/models_basic_voxel.vcxproj create mode 100644 projects/VS2022/examples/shapes_bullet_hell.vcxproj create mode 100644 projects/VS2022/examples/shapes_vector_angle.vcxproj diff --git a/examples/shapes/shapes_bouncing_ball.c b/examples/shapes/shapes_bouncing_ball.c index 73dca0011..5ae699944 100644 --- a/examples/shapes/shapes_bouncing_ball.c +++ b/examples/shapes/shapes_bouncing_ball.c @@ -4,9 +4,9 @@ * * Example complexity rating: [★☆☆☆] 1/4 * -* Example originally created with raylib 2.5, last time updated with raylib 5.6 +* Example originally created with raylib 2.5, last time updated with raylib 2.5 * -* Example contributed by Jopestpe (@jopestpe) +* Example contributed by Ramon Santamaria (@raysan5), reviewed by Jopestpe (@jopestpe) * * Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, * BSD-like license that allows static linking with closed source software diff --git a/examples/others/raymath_vector_angle.c b/examples/shapes/shapes_vector_angle.c similarity index 96% rename from examples/others/raymath_vector_angle.c rename to examples/shapes/shapes_vector_angle.c index cded99e8b..7de296dcb 100644 --- a/examples/others/raymath_vector_angle.c +++ b/examples/shapes/shapes_vector_angle.c @@ -1,6 +1,6 @@ /******************************************************************************************* * -* raylib [others] example - vector angle +* raylib [shapes] example - vector angle * * Example complexity rating: [★★☆☆] 2/4 * @@ -15,7 +15,7 @@ #include "raylib.h" -#include "raymath.h" +#include "raymath.h" // Required for: Vector2LineAngle() //------------------------------------------------------------------------------------ // Program main entry point @@ -25,9 +25,10 @@ int main(void) // Initialization //-------------------------------------------------------------------------------------- const int screenWidth = 800; + const int screenHeight = 450; - InitWindow(screenWidth, screenHeight, "raylib [others] example - vector angle"); + InitWindow(screenWidth, screenHeight, "raylib [shapes] example - vector angle"); Vector2 v0 = { screenWidth/2, screenHeight/2 }; Vector2 v1 = Vector2Add(v0, (Vector2){ 100.0f, 80.0f }); diff --git a/examples/others/raymath_vector_angle.png b/examples/shapes/shapes_vector_angle.png similarity index 100% rename from examples/others/raymath_vector_angle.png rename to examples/shapes/shapes_vector_angle.png diff --git a/projects/VS2022/examples/core_delta_time.vcxproj b/projects/VS2022/examples/core_delta_time.vcxproj new file mode 100644 index 000000000..3d31afa42 --- /dev/null +++ b/projects/VS2022/examples/core_delta_time.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_delta_time + 10.0 + core_delta_time + + + + 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/models_basic_voxel.vcxproj b/projects/VS2022/examples/models_basic_voxel.vcxproj new file mode 100644 index 000000000..f3e541f27 --- /dev/null +++ b/projects/VS2022/examples/models_basic_voxel.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 + + + + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F} + Win32Proj + models_basic_voxel + 10.0 + models_basic_voxel + + + + 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\models + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\models + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\models + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\models + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\models + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\models + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\models + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\models + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\models + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\models + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\models + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\models + 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/shapes_bullet_hell.vcxproj b/projects/VS2022/examples/shapes_bullet_hell.vcxproj new file mode 100644 index 000000000..de74d2f79 --- /dev/null +++ b/projects/VS2022/examples/shapes_bullet_hell.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 + + + + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E} + Win32Proj + shapes_bullet_hell + 10.0 + shapes_bullet_hell + + + + 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\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + 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/shapes_vector_angle.vcxproj b/projects/VS2022/examples/shapes_vector_angle.vcxproj new file mode 100644 index 000000000..c2e0d9426 --- /dev/null +++ b/projects/VS2022/examples/shapes_vector_angle.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 + + + + {9DB1F875-6E65-4195-B23F-ED8095C0B99C} + Win32Proj + shapes_vector_angle + 10.0 + shapes_vector_angle + + + + 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\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + 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 c0295d4c6..5b43235a4 100644 --- a/projects/VS2022/raylib.sln +++ b/projects/VS2022/raylib.sln @@ -347,6 +347,14 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_undo_redo", "examples\ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_input_actions", "examples\core_input_actions.vcxproj", "{718FCBD0-591D-448C-B7D5-9F1CA8544E7B}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_delta_time", "examples\core_delta_time.vcxproj", "{6B1A933E-71B8-4C1F-9E79-02D98830E671}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_bullet_hell", "examples\shapes_bullet_hell.vcxproj", "{2CCCD9E4-9058-4291-BD89-39C979F0CA1E}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_vector_angle", "examples\shapes_vector_angle.vcxproj", "{9DB1F875-6E65-4195-B23F-ED8095C0B99C}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "models_basic_voxel", "examples\models_basic_voxel.vcxproj", "{52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug.DLL|ARM64 = Debug.DLL|ARM64 @@ -4273,6 +4281,102 @@ Global {718FCBD0-591D-448C-B7D5-9F1CA8544E7B}.Release|x64.Build.0 = Release|x64 {718FCBD0-591D-448C-B7D5-9F1CA8544E7B}.Release|x86.ActiveCfg = Release|Win32 {718FCBD0-591D-448C-B7D5-9F1CA8544E7B}.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 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug|ARM64.Build.0 = Debug|ARM64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug|x64.ActiveCfg = Debug|x64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug|x64.Build.0 = Debug|x64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug|x86.ActiveCfg = Debug|Win32 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug|x86.Build.0 = Debug|Win32 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release|ARM64.ActiveCfg = Release|ARM64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release|ARM64.Build.0 = Release|ARM64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release|x64.ActiveCfg = Release|x64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release|x64.Build.0 = Release|x64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release|x86.ActiveCfg = Release|Win32 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release|x86.Build.0 = Release|Win32 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug|ARM64.Build.0 = Debug|ARM64 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug|x64.ActiveCfg = Debug|x64 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug|x64.Build.0 = Debug|x64 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug|x86.ActiveCfg = Debug|Win32 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug|x86.Build.0 = Debug|Win32 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release|ARM64.ActiveCfg = Release|ARM64 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release|ARM64.Build.0 = Release|ARM64 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release|x64.ActiveCfg = Release|x64 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release|x64.Build.0 = Release|x64 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release|x86.ActiveCfg = Release|Win32 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release|x86.Build.0 = Release|Win32 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug|ARM64.Build.0 = Debug|ARM64 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug|x64.ActiveCfg = Debug|x64 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug|x64.Build.0 = Debug|x64 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug|x86.ActiveCfg = Debug|Win32 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug|x86.Build.0 = Debug|Win32 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release|ARM64.ActiveCfg = Release|ARM64 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release|ARM64.Build.0 = Release|ARM64 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release|x64.ActiveCfg = Release|x64 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release|x64.Build.0 = Release|x64 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release|x86.ActiveCfg = Release|Win32 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -4448,6 +4552,10 @@ Global {D496308F-3C3C-40B3-A3ED-EA327D244B3E} = {8D3C83B7-F1E0-4C2E-9E34-EE5F6AB2502A} {3B27F358-2679-4F38-B297-17B536F580BB} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} {718FCBD0-591D-448C-B7D5-9F1CA8544E7B} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} + {6B1A933E-71B8-4C1F-9E79-02D98830E671} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E} = {278D8859-20B1-428F-8448-064F46E1F021} + {9DB1F875-6E65-4195-B23F-ED8095C0B99C} = {278D8859-20B1-428F-8448-064F46E1F021} + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F} = {AF5BEC5C-1F2B-4DA8-B12D-D09FE569237C} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {E926C768-6307-4423-A1EC-57E95B1FAB29} From 8494d76c939eab71ec36b7cd23b329df9508dac1 Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 2 Oct 2025 13:04:43 +0200 Subject: [PATCH 070/167] Update rexm.c --- tools/rexm/rexm.c | 92 +++++++++++++++++++++++++++++------------------ 1 file changed, 58 insertions(+), 34 deletions(-) diff --git a/tools/rexm/rexm.c b/tools/rexm/rexm.c index 3306e613a..6f2b19777 100644 --- a/tools/rexm/rexm.c +++ b/tools/rexm/rexm.c @@ -76,7 +76,7 @@ //---------------------------------------------------------------------------------- // raylib example info struct typedef struct { - char category[16]; // Example category: core, shapes, textures, text, models, shaders, audio, others + char category[16]; // Example category: core, shapes, textures, text, models, shaders, audio, [others] char name[128]; // Example name: _name_part int stars; // Example stars count: ★☆☆☆ char verCreated[12]; // Example raylib creation version @@ -178,6 +178,7 @@ static int RemoveVSProjectFromSolution(const char *slnFile, const char *exName); // Generate unique UUID v4 string // Output format: {9A2F48CC-0DA8-47C0-884E-02E37F9BE6C1} +// TODO: It seems generated UUID is not valid for VS2022 static const char *GenerateUUIDv4(void); // Update source code header and comments metadata @@ -185,6 +186,8 @@ static void UpdateSourceMetadata(const char *exSrcPath, const rlExampleInfo *inf // Update generated Web example .html file metadata static void UpdateWebMetadata(const char *exHtmlPath, const char *exFilePath); +// Check if text string is a list of strings +static bool TextInList(const char *text, const char **list, int listCount); // Get text between two strings //static char *GetTextBetween(const char *text, const char *begin, const char *end); // Replace text between two specific strings @@ -540,14 +543,14 @@ int main(int argc, char *argv[]) // by default add it last in the category list // NOTE: When populating to other files, lists are sorted by name int nextCategoryIndex = 0; - if (strcmp(exCategory, "core") == 0) nextCategoryIndex = 1; - else if (strcmp(exCategory, "shapes") == 0) nextCategoryIndex = 2; - else if (strcmp(exCategory, "textures") == 0) nextCategoryIndex = 3; - else if (strcmp(exCategory, "text") == 0) nextCategoryIndex = 4; - else if (strcmp(exCategory, "models") == 0) nextCategoryIndex = 5; - else if (strcmp(exCategory, "shaders") == 0) nextCategoryIndex = 6; - else if (strcmp(exCategory, "audio") == 0) nextCategoryIndex = 7; - else if (strcmp(exCategory, "others") == 0) nextCategoryIndex = -1; // Add to EOF + if (TextIsEqual(exCategory, "core")) nextCategoryIndex = 1; + else if (TextIsEqual(exCategory, "shapes")) nextCategoryIndex = 2; + else if (TextIsEqual(exCategory, "textures")) nextCategoryIndex = 3; + else if (TextIsEqual(exCategory, "text")) nextCategoryIndex = 4; + else if (TextIsEqual(exCategory, "models")) nextCategoryIndex = 5; + else if (TextIsEqual(exCategory, "shaders")) nextCategoryIndex = 6; + else if (TextIsEqual(exCategory, "audio")) nextCategoryIndex = 7; + else if (TextIsEqual(exCategory, "others")) nextCategoryIndex = -1; // Add to EOF // Get required example info from example file header (if provided) @@ -862,7 +865,7 @@ int main(int argc, char *argv[]) // Scan available example .c files and add to collection missing ones // NOTE: Source of truth is what we have in the examples directories (on validation/update) - FilePathList list = LoadDirectoryFilesEx(exBasePath, ".c", true); + FilePathList clist = LoadDirectoryFilesEx(exBasePath, ".c", true); char *exList = LoadFileText(exCollectionFilePath); char *exListUpdated = (char *)RL_CALLOC(REXM_MAX_BUFFER_SIZE, 1); @@ -887,32 +890,39 @@ int main(int argc, char *argv[]) UnloadTextLines(exListLines, lineCount); - for (unsigned int i = 0; i < list.count; i++) + for (unsigned int i = 0; i < clist.count; i++) { // NOTE: Skipping "examples_template" from checks - if ((strcmp("examples_template", GetFileNameWithoutExt(list.paths[i])) != 0) && - (TextFindIndex(exList, GetFileNameWithoutExt(list.paths[i])) == -1)) + if (!TextIsEqual(GetFileNameWithoutExt(clist.paths[i]), "examples_template") && + (TextFindIndex(exList, GetFileNameWithoutExt(clist.paths[i])) == -1)) { // Add example to the examples collection list // WARNING: Added to the end of the list, order must be set by users and // defines placement on raylib webpage - rlExampleInfo *exInfo = LoadExampleInfo(list.paths[i]); + rlExampleInfo *exInfo = LoadExampleInfo(clist.paths[i]); - // Get example difficulty stars - char starsText[16] = { 0 }; - for (int s = 0; s < 4; s++) + // Validate example category and avoid [others] examples (special category) + if (TextInList(exInfo->category, exCategories, REXM_MAX_EXAMPLE_CATEGORIES) && + !TextIsEqual(exInfo->category, "others")) { - // NOTE: Every UTF-8 star are 3 bytes - if (s < exInfo->stars) strcpy(starsText + 3*s, "★"); - else strcpy(starsText + 3*s, "☆"); + // Get example difficulty stars + char starsText[16] = { 0 }; + for (int s = 0; s < 4; s++) + { + // NOTE: Every UTF-8 star are 3 bytes + if (s < exInfo->stars) strcpy(starsText + 3*s, "★"); + else strcpy(starsText + 3*s, "☆"); + } + + exListLen += sprintf(exListUpdated + exListLen, + TextFormat("%s;%s;%s;%s;%s;%s;%s;\"%s\";@%s\n", + exInfo->category, exInfo->name, starsText, exInfo->verCreated, + exInfo->verUpdated, exInfo->yearCreated, exInfo->yearReviewed, + exInfo->author, exInfo->authorGitHub)); + + listUpdated = true; } - exListLen += sprintf(exListUpdated + exListLen, - TextFormat("%s;%s;%s;%s;%s;\"%s\";@%s\n", - exInfo->category, exInfo->name, starsText, exInfo->verCreated, - exInfo->verUpdated, exInfo->author, exInfo->authorGitHub)); - - listUpdated = true; UnloadExampleInfo(exInfo); } } @@ -922,7 +932,7 @@ int main(int argc, char *argv[]) UnloadFileText(exList); RL_FREE(exListUpdated); - UnloadDirectoryFiles(list); + UnloadDirectoryFiles(clist); // Check all examples in collection [examples_list.txt] -> Source of truth! int exCollectionCount = 0; @@ -1756,12 +1766,12 @@ static rlExampleInfo *LoadExamplesData(const char *fileName, const char *categor { // Basic validation for lines start categories if ((lines[i][0] != '#') && - ((lines[i][0] == 'c') || // core - (lines[i][0] == 's') || // shapes, shaders - (lines[i][0] == 't') || // textures, text - (lines[i][0] == 'm') || // models - (lines[i][0] == 'a') || // audio - (lines[i][0] == 'o'))) // others + ((lines[i][0] == 'c') || // core + (lines[i][0] == 's') || // shapes, shaders + (lines[i][0] == 't') || // textures, text + (lines[i][0] == 'm') || // models + (lines[i][0] == 'a'))) // audio + //(lines[i][0] == 'o'))) // NOTE: others category skipped { rlExampleInfo info = { 0 }; int result = ParseExampleInfoLine(lines[i], &info); @@ -2012,7 +2022,8 @@ static int ParseExampleInfoLine(const char *line, rlExampleInfo *entry) int tokenCount = 0; char **tokens = TextSplit(line, ';', &tokenCount); - if (tokenCount != 9) LOG("REXM: WARNING: Example collection line contains invalid number of tokens: %i\n", tokenCount); + if (tokenCount != 9) + LOG("REXM: WARNING: Example collection line contains invalid number of tokens: %i\n", tokenCount); // Get category and name strcpy(entry->category, tokens[0]); @@ -2491,6 +2502,19 @@ static void UpdateWebMetadata(const char *exHtmlPath, const char *exFilePath) } } +// Check if text string is a list of strings +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; } + } + + return result; +} + /* // Get text between two strings // NOTE: Using static string to return result, MAX: 1024 bytes From a0a0d4d5ad19ca7977b09bc661463b6719cec848 Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 2 Oct 2025 13:05:42 +0200 Subject: [PATCH 071/167] Update rcore_desktop_win32.c --- src/platforms/rcore_desktop_win32.c | 142 +++++++++++++++++++++------- 1 file changed, 107 insertions(+), 35 deletions(-) diff --git a/src/platforms/rcore_desktop_win32.c b/src/platforms/rcore_desktop_win32.c index c7740ba2e..b9acde0e8 100644 --- a/src/platforms/rcore_desktop_win32.c +++ b/src/platforms/rcore_desktop_win32.c @@ -76,8 +76,9 @@ #include #include -#include -//#include +#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE) + #include +#endif //---------------------------------------------------------------------------------- // Types and Structures Definition @@ -87,9 +88,14 @@ // 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; - HDC hdc; - HGLRC glContext; + 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; @@ -251,7 +257,7 @@ static bool DecoratedFromStyle(DWORD style) static Mized MizedFromStyle(DWORD style) { - // minimized takes precedence over maximized + // Minimized takes precedence over maximized if (style & WS_MINIMIZE) return MIZED_MIN; if (style & WS_MAXIMIZE) return MIZED_MAX; return MIZED_NONE; @@ -260,7 +266,7 @@ static Mized MizedFromStyle(DWORD style) static Mized MizedFromFlags(unsigned flags) { // minimized takes precedence over maximized - if (flags & FLAG_WINDOW_MINIMIZED) return MIZED_MIN; + if (FLAG_CHECK(flags, FLAG_WINDOW_MINIMIZED)) return MIZED_MIN; if (flags & FLAG_WINDOW_MAXIMIZED) return MIZED_MAX; return MIZED_NONE; } @@ -287,15 +293,6 @@ static DWORD MakeWindowStyle(unsigned flags) return style; } -static bool IsMinimized2(HWND hwnd) -{ - 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); - - return isIconic; -} - // 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) { @@ -433,6 +430,8 @@ static bool UpdateWindowSize(UpdateWindowKind kind, HWND hwnd, int width, int he info.cbSize = sizeof(info); if (!GetMonitorInfoW(monitor, &info)) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "GetMonitorInfo", GetLastError()); + #define MAX(a,b) (((a)>(b))? (a):(b)) + LONG monitorWidth = info.rcMonitor.right - info.rcMonitor.left; LONG monitorHeight = info.rcMonitor.bottom - info.rcMonitor.top; windowPos = (POINT){ @@ -442,10 +441,16 @@ static bool UpdateWindowSize(UpdateWindowKind kind, HWND hwnd, int width, int he } else swpFlags |= SWP_NOMOVE; - if (!SetWindowPos(hwnd, NULL, windowPos.x, windowPos.y, windowSize.cx, windowSize.cy, swpFlags)) - { - TRACELOG(LOG_ERROR, "%s failed, error=%lu", "SetWindowPos", GetLastError()); - } + // WARNING: This code must be called after swInit() has been called, after InitPlatform() in [rcore] + //RECT rc = {0, 0, desired.cx, desired.cy}; + //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; } @@ -1149,8 +1154,18 @@ void DisableCursor(void) void SwapScreenBuffer(void) { if (!platform.hdc) abort(); + +#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE) + // Update framebuffer + rlCopyFramebuffer(0, 0, CORE.Window.render.width, CORE.Window.render.height, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, platform.pixels); + + // Force redraw + 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()); +#endif } //---------------------------------------------------------------------------------- @@ -1264,7 +1279,6 @@ void PollInputEvents(void) MSG msg = { 0 }; while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) { - if (msg.message == WM_PAINT) return; TranslateMessage(&msg); DispatchMessageW(&msg); } @@ -1432,7 +1446,7 @@ int InitPlatform(void) // NOTE: Title string needs to be converted to WCHAR WCHAR *titleWide = NULL; A_TO_W_ALLOCA(titleWide, CORE.Window.title); - + // Create window and get handle platform.hwnd = CreateWindowExW( WINDOW_STYLE_EX, @@ -1440,7 +1454,7 @@ int InitPlatform(void) titleWide, MakeWindowStyle(CORE.Window.flags), // WS_OVERLAPPEDWINDOW | WS_VISIBLE CW_USEDEFAULT, CW_USEDEFAULT, - 0, 0, // Window size [width, height], needs to be updated + platform.appScreenWidth, platform.appScreenHeight, // TODO: Window size [width, height], needs to be updated? NULL, NULL, GetModuleHandleW(NULL), NULL); @@ -1454,15 +1468,40 @@ int InitPlatform(void) // NOTE: Windows GDI object that represents a drawing surface platform.hdc = GetDC(platform.hwnd); - // TODO: Support software rendering (instead of hardware-accelerated OpenGL context) + if (rlGetVersion() == RL_OPENGL_11_SOFTWARE) // Using software renderer + { + //ShowWindow(platform.hwnd, SW_SHOWDEFAULT); //SW_SHOWNORMAL - // Init OpenGL modern context - platform.glContext = InitOpenGL(platform.hwnd, platform.hdc); + // 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.biCompression = BI_RGB; + + platform.hdcmem = CreateCompatibleDC(platform.hdc); + + platform.hbitmap = CreateDIBSection( + platform.hdcmem, &bmi, DIB_RGB_COLORS, + (void**)&platform.pixels, NULL, 0); + + SelectObject(platform.hdcmem, platform.hbitmap); + + //ReleaseDC(platform.hwnd, platform.hdc); // Required? + } + else + { + // Init hardware-accelerated OpenGL modern context + platform.glContext = InitOpenGL(platform.hwnd, platform.hdc); + } CORE.Window.ready = true; - // TODO: Should this function be called before or after drawing context is created? - UpdateWindowSize(UPDATE_WINDOW_FIRST, platform.hwnd, platform.appScreenWidth, platform.appScreenHeight, platform.desiredFlags); + // 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); CORE.Window.currentFbo.width = CORE.Window.render.width; @@ -1531,11 +1570,29 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara case WM_DESTROY: { // Clean up for window destruction - wglMakeCurrent(platform.hdc, NULL); - if (platform.glContext) + if (rlGetVersion() == RL_OPENGL_11_SOFTWARE) // Using software renderer { - if (!wglDeleteContext(platform.glContext)) abort(); - platform.glContext = NULL; + if (platform.hdcmem) + { + DeleteDC(platform.hdcmem); + platform.hdcmem = NULL; + } + + if (platform.hbitmap) + { + DeleteObject(platform.hbitmap); // Clears platform.pixels data + platform.hbitmap = NULL; + platform.pixels = NULL; // NOTE: Pointer invalid after DeleteObject() + } + } + else // OpenGL hardware renderer + { + wglMakeCurrent(platform.hdc, NULL); + if (platform.glContext) + { + if (!wglDeleteContext(platform.glContext)) abort(); + platform.glContext = NULL; + } } if (platform.hdc) @@ -1544,6 +1601,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara platform.hdc = NULL; } + PostQuitMessage(0); + } break; case WM_CLOSE: CORE.Window.shouldClose = true; break; // Window close button [x], ALT+F4 //case WM_QUIT: // Application closing, not related to window @@ -1711,10 +1770,22 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara result = DefWindowProc(hwnd, msg, wparam, lparam); } break; - //case WM_PAINT + case WM_PAINT: + { + if (rlGetVersion() == RL_OPENGL_11_SOFTWARE) // Using software renderer + { + PAINTSTRUCT ps = { 0 }; + HDC hdc = BeginPaint(hwnd, &ps); + + // Blit from memory DC to window DC + BitBlt(hdc, 0, 0, platform.appScreenWidth, platform.appScreenHeight, platform.hdcmem, 0, 0, SRCCOPY); + + EndPaint(hwnd, &ps); + } + } case WM_INPUT: { - HandleRawInput(lparam); + //HandleRawInput(lparam); } break; case WM_MOUSEMOVE: { @@ -1755,7 +1826,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara case WM_MOUSEHWHEEL: CORE.Input.Mouse.currentWheelMove.x = ((float)GET_WHEEL_DELTA_WPARAM(wparam))/WHEEL_DELTA; break; case WM_APP_UPDATE_WINDOW_SIZE: { - UpdateWindowSize(UPDATE_WINDOW_NORMAL, hwnd, platform.appScreenWidth, platform.appScreenHeight, CORE.Window.flags); + //UpdateWindowSize(UPDATE_WINDOW_NORMAL, hwnd, platform.appScreenWidth, platform.appScreenHeight, CORE.Window.flags); } break; default: result = DefWindowProcW(hwnd, msg, wparam, lparam); // Message passed directly for execution (default behaviour) @@ -1955,6 +2026,7 @@ static void UpdateFlags(HWND hwnd, unsigned desiredFlags, int width, int height) else CORE.Window.flags &= ~FLAG_VSYNC_HINT; } + // TODO: Review all this code... DWORD previousStyle; for (unsigned attempt = 1; ; attempt++) { From 377853bb32016450ae0644bcda85b84b8302dc3a Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 2 Oct 2025 13:16:00 +0200 Subject: [PATCH 072/167] REXM: Updated new examples requried files --- examples/Makefile | 6 +- examples/Makefile.Web | 24 +- examples/README.md | 10 +- examples/core/core_delta_time.c | 4 +- examples/core/core_monitor_change.c | 2 +- examples/examples_list.txt | 3 +- .../models/models_geometry_textures_cube.c | 2 +- examples/shaders/shaders_ascii_rendering.c | 2 +- examples/shapes/shapes_bullet_hell.c | 2 +- examples/shapes/shapes_dashed_line.c | 6 +- .../examples/core_monitor_change.vcxproj | 569 ++++++++++++++++++ .../models_geometry_textures_cube.vcxproj | 569 ++++++++++++++++++ .../examples/shaders_ascii_rendering.vcxproj | 569 ++++++++++++++++++ .../examples/shapes_dashed_line.vcxproj | 569 ++++++++++++++++++ projects/VS2022/raylib.sln | 108 ++++ tools/rexm/examples_report.md | 7 + 16 files changed, 2437 insertions(+), 15 deletions(-) create mode 100644 projects/VS2022/examples/core_monitor_change.vcxproj create mode 100644 projects/VS2022/examples/models_geometry_textures_cube.vcxproj create mode 100644 projects/VS2022/examples/shaders_ascii_rendering.vcxproj create mode 100644 projects/VS2022/examples/shapes_dashed_line.vcxproj diff --git a/examples/Makefile b/examples/Makefile index f594e2867..97e3bbc30 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -514,6 +514,7 @@ CORE = \ core/core_basic_window \ core/core_custom_frame_control \ core/core_custom_logging \ + core/core_delta_time \ core/core_drop_files \ core/core_high_dpi \ core/core_input_actions \ @@ -525,6 +526,7 @@ CORE = \ core/core_input_mouse_wheel \ core/core_input_multitouch \ core/core_input_virtual_controls \ + core/core_monitor_change \ core/core_random_sequence \ core/core_random_values \ core/core_render_texture \ @@ -545,6 +547,7 @@ SHAPES = \ shapes/shapes_circle_sector_drawing \ shapes/shapes_collision_area \ shapes/shapes_colors_palette \ + shapes/shapes_dashed_line \ shapes/shapes_digital_clock \ shapes/shapes_double_pendulum \ shapes/shapes_easings_ball \ @@ -560,7 +563,7 @@ SHAPES = \ shapes/shapes_rounded_rectangle_drawing \ shapes/shapes_splines_drawing \ shapes/shapes_top_down_lights \ - shapes/shapes_dashed_line + shapes/shapes_vector_angle TEXTURES = \ textures/textures_background_scrolling \ @@ -634,6 +637,7 @@ MODELS = \ models/models_yaw_pitch_roll SHADERS = \ + shaders/shaders_ascii_rendering \ shaders/shaders_basic_lighting \ shaders/shaders_basic_pbr \ shaders/shaders_custom_uniform \ diff --git a/examples/Makefile.Web b/examples/Makefile.Web index e5dad0430..0dbefadf2 100644 --- a/examples/Makefile.Web +++ b/examples/Makefile.Web @@ -514,6 +514,7 @@ CORE = \ core/core_basic_window \ core/core_custom_frame_control \ core/core_custom_logging \ + core/core_delta_time \ core/core_drop_files \ core/core_high_dpi \ core/core_input_actions \ @@ -525,6 +526,7 @@ CORE = \ core/core_input_mouse_wheel \ core/core_input_multitouch \ core/core_input_virtual_controls \ + core/core_monitor_change \ core/core_random_sequence \ core/core_random_values \ core/core_render_texture \ @@ -545,6 +547,7 @@ SHAPES = \ shapes/shapes_circle_sector_drawing \ shapes/shapes_collision_area \ shapes/shapes_colors_palette \ + shapes/shapes_dashed_line \ shapes/shapes_digital_clock \ shapes/shapes_double_pendulum \ shapes/shapes_easings_ball \ @@ -560,7 +563,7 @@ SHAPES = \ shapes/shapes_rounded_rectangle_drawing \ shapes/shapes_splines_drawing \ shapes/shapes_top_down_lights \ - shapes/shapes_dashed_line + shapes/shapes_vector_angle TEXTURES = \ textures/textures_background_scrolling \ @@ -634,6 +637,7 @@ MODELS = \ models/models_yaw_pitch_roll SHADERS = \ + shaders/shaders_ascii_rendering \ shaders/shaders_basic_lighting \ shaders/shaders_basic_pbr \ shaders/shaders_custom_uniform \ @@ -731,6 +735,9 @@ core/core_custom_frame_control: core/core_custom_frame_control.c core/core_custom_logging: core/core_custom_logging.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) +core/core_delta_time: core/core_delta_time.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) + core/core_drop_files: core/core_drop_files.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) @@ -766,6 +773,9 @@ 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 + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) + core/core_random_sequence: core/core_random_sequence.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) @@ -822,6 +832,9 @@ shapes/shapes_collision_area: shapes/shapes_collision_area.c shapes/shapes_colors_palette: shapes/shapes_colors_palette.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) +shapes/shapes_dashed_line: shapes/shapes_dashed_line.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) + shapes/shapes_digital_clock: shapes/shapes_digital_clock.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) @@ -867,6 +880,9 @@ shapes/shapes_splines_drawing: shapes/shapes_splines_drawing.c shapes/shapes_top_down_lights: shapes/shapes_top_down_lights.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) +shapes/shapes_vector_angle: shapes/shapes_vector_angle.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) + # Compile TEXTURES examples textures/textures_background_scrolling: textures/textures_background_scrolling.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \ @@ -1158,6 +1174,12 @@ models/models_yaw_pitch_roll: models/models_yaw_pitch_roll.c --preload-file models/resources/models/obj/plane_diffuse.png@resources/models/obj/plane_diffuse.png # Compile SHADERS examples +shaders/shaders_ascii_rendering: shaders/shaders_ascii_rendering.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \ + --preload-file shaders/resources/fudesumi.png@resources/fudesumi.png \ + --preload-file shaders/resources/raysan.png@resources/raysan.png \ + --preload-file shaders/resources/shaders/glsl100/ascii.fs@resources/shaders/glsl100/ascii.fs + shaders/shaders_basic_lighting: shaders/shaders_basic_lighting.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \ --preload-file shaders/resources/shaders/glsl100/lighting.vs@resources/shaders/glsl100/lighting.vs \ diff --git a/examples/README.md b/examples/README.md index d52f96280..0dabc05b4 100644 --- a/examples/README.md +++ b/examples/README.md @@ -19,13 +19,14 @@ You may find it easier to use than other toolchains, especially when it comes to ## EXAMPLES COLLECTION [TOTAL: 166] -### category: core [38] +### category: core [40] Examples using raylib[core](../src/rcore.c) platform functionality like window creation, inputs, drawing modes and system functionality. | example | image | difficulty
level | version
created | last version
updated | original
developer | |-----------|--------|:-------------------:|:------------------:|:-----------------------:|:----------------------| | [core_basic_window](core/core_basic_window.c) | core_basic_window | ⭐☆☆☆ | 1.0 | 1.0 | [Ramon Santamaria](https://github.com/raysan5) | +| [core_delta_time](core/core_delta_time.c) | core_delta_time | ⭐☆☆☆ | 5.5 | 5.6-dev | [Robin](https://github.com/RobinsAviary) | | [core_input_keys](core/core_input_keys.c) | core_input_keys | ⭐☆☆☆ | 1.0 | 1.0 | [Ramon Santamaria](https://github.com/raysan5) | | [core_input_mouse](core/core_input_mouse.c) | core_input_mouse | ⭐☆☆☆ | 1.0 | 5.5 | [Ramon Santamaria](https://github.com/raysan5) | | [core_input_mouse_wheel](core/core_input_mouse_wheel.c) | core_input_mouse_wheel | ⭐☆☆☆ | 1.1 | 1.3 | [Ramon Santamaria](https://github.com/raysan5) | @@ -63,8 +64,9 @@ Examples using raylib[core](../src/rcore.c) platform functionality like window c | [core_render_texture](core/core_render_texture.c) | core_render_texture | ⭐☆☆☆ | 5.6-dev | 5.6-dev | [Ramon Santamaria](https://github.com/raysan5) | | [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_monitor_change](core/core_monitor_change.c) | core_monitor_change | ⭐☆☆☆ | 5.5 | 5.6 | [Maicon Santana](https://github.com/maiconpintoabreu) | -### category: shapes [21] +### category: shapes [23] Examples using raylib shapes drawing functionality, provided by raylib [shapes](../src/rshapes.c) module. @@ -92,6 +94,7 @@ Examples using raylib shapes drawing functionality, provided by raylib [shapes]( | [shapes_digital_clock](shapes/shapes_digital_clock.c) | shapes_digital_clock | ⭐⭐⭐⭐️ | 5.5 | 5.6 | [Hamza RAHAL](https://github.com/hmz-rhl) | | [shapes_double_pendulum](shapes/shapes_double_pendulum.c) | shapes_double_pendulum | ⭐⭐☆☆ | 5.5 | 5.5 | [JoeCheong](https://github.com/Joecheong2006) | | [shapes_dashed_line](shapes/shapes_dashed_line.c) | shapes_dashed_line | ⭐☆☆☆ | 5.5 | 5.5 | [Luís Almeida](https://github.com/luis605) | +| [shapes_vector_angle](shapes/shapes_vector_angle.c) | shapes_vector_angle | ⭐⭐☆☆ | 1.0 | 5.0 | [Ramon Santamaria](https://github.com/raysan5) | ### category: textures [26] @@ -179,12 +182,13 @@ 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_geometry_textures_cube](models/models_geometry_textures_cube.c) | models_geometry_textures_cube | ⭐☆☆☆ | 5.6-dev | 5.6-dev | [Jopestpe](https://github.com/jopestpe) | -### category: shaders [29] +### category: shaders [30] 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. | example | image | difficulty
level | version
created | last version
updated | original
developer | |-----------|--------|:-------------------:|:------------------:|:-----------------------:|:----------------------| +| [shaders_ascii_rendering](shaders/shaders_ascii_rendering.c) | shaders_ascii_rendering | ⭐⭐☆☆ | 5.5 | 5.6 | [Maicon Santana](https://github.com/maiconpintoabreu) | | [shaders_basic_lighting](shaders/shaders_basic_lighting.c) | shaders_basic_lighting | ⭐⭐⭐⭐️ | 3.0 | 4.2 | [Chris Camacho](https://github.com/chriscamacho) | | [shaders_model_shader](shaders/shaders_model_shader.c) | shaders_model_shader | ⭐⭐☆☆ | 1.3 | 3.7 | [Ramon Santamaria](https://github.com/raysan5) | | [shaders_shapes_textures](shaders/shaders_shapes_textures.c) | shaders_shapes_textures | ⭐⭐☆☆ | 1.7 | 3.7 | [Ramon Santamaria](https://github.com/raysan5) | diff --git a/examples/core/core_delta_time.c b/examples/core/core_delta_time.c index 86bc969b3..e52c743da 100644 --- a/examples/core/core_delta_time.c +++ b/examples/core/core_delta_time.c @@ -4,14 +4,14 @@ * * Example complexity rating: [★☆☆☆] 1/4 * -* Example originally created with raylib 5.5 +* Example originally created with raylib 5.5, last time updated with raylib 5.6-dev * * 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) +* Copyright (c) 2025 Robin (@RobinsAviary) * ********************************************************************************************/ diff --git a/examples/core/core_monitor_change.c b/examples/core/core_monitor_change.c index 8983556af..c85b3f633 100644 --- a/examples/core/core_monitor_change.c +++ b/examples/core/core_monitor_change.c @@ -11,7 +11,7 @@ * 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 Maicon Santana (@maiconpintoabreu) +* Copyright (c) 2025 Maicon Santana (@maiconpintoabreu) * ********************************************************************************************/ diff --git a/examples/examples_list.txt b/examples/examples_list.txt index 65163caf4..57602002f 100644 --- a/examples/examples_list.txt +++ b/examples/examples_list.txt @@ -68,7 +68,7 @@ shapes;shapes_splines_drawing;★★★☆;5.0;5.0;2023;2025;"Ramon Santamaria"; shapes;shapes_digital_clock;★★★★;5.5;5.6;2025;2025;"Hamza RAHAL";@hmz-rhl shapes;shapes_double_pendulum;★★☆☆;5.5;5.5;2025;2025;"JoeCheong";@Joecheong2006 shapes;shapes_dashed_line;★☆☆☆;5.5;5.5;2025;2025;"Luís Almeida";@luis605 -shapes;shapes_vector_angle;★★☆☆;1.0;5.0;2025;2025;"Ramon Santamaria";@raysan5 +shapes;shapes_vector_angle;★★☆☆;1.0;5.0;2023;2025;"Ramon Santamaria";@raysan5 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 @@ -178,3 +178,4 @@ 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;"Ramon Santamaria";@raysan5 +core;core_monitor_change;★☆☆☆;5.5;5.6;2025;2025;"Maicon Santana";@maiconpintoabreu diff --git a/examples/models/models_geometry_textures_cube.c b/examples/models/models_geometry_textures_cube.c index 4608ad951..f8236f36d 100644 --- a/examples/models/models_geometry_textures_cube.c +++ b/examples/models/models_geometry_textures_cube.c @@ -11,7 +11,7 @@ * 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 Jopestpe (@jopestpe) +* Copyright (c) 2025 Jopestpe (@jopestpe) * ********************************************************************************************/ diff --git a/examples/shaders/shaders_ascii_rendering.c b/examples/shaders/shaders_ascii_rendering.c index 33fb052f7..523b381b2 100644 --- a/examples/shaders/shaders_ascii_rendering.c +++ b/examples/shaders/shaders_ascii_rendering.c @@ -11,7 +11,7 @@ * 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 Maicon Santana (@maiconpintoabreu) +* Copyright (c) 2025 Maicon Santana (@maiconpintoabreu) * ********************************************************************************************/ diff --git a/examples/shapes/shapes_bullet_hell.c b/examples/shapes/shapes_bullet_hell.c index 2635ee02c..8eaddfbfe 100644 --- a/examples/shapes/shapes_bullet_hell.c +++ b/examples/shapes/shapes_bullet_hell.c @@ -11,7 +11,7 @@ * 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 Zero (@zerohorsepower) +* Copyright (c) 2025 Zero (@zerohorsepower) * ********************************************************************************************/ diff --git a/examples/shapes/shapes_dashed_line.c b/examples/shapes/shapes_dashed_line.c index fd017562f..aa254ab8d 100644 --- a/examples/shapes/shapes_dashed_line.c +++ b/examples/shapes/shapes_dashed_line.c @@ -1,10 +1,10 @@ /******************************************************************************************* * -* raylib [shapes] example - dashed line drawing +* raylib [shapes] example - dashed line * * Example complexity rating: [★☆☆☆] 1/4 * -* Example originally created with raylib 2.5, last time updated with raylib 2.5 +* Example originally created with raylib 5.5, last time updated with raylib 5.5 * * Example contributed by Luís Almeida (@luis605) * @@ -29,7 +29,7 @@ int main(void) const int screenWidth = 800; const int screenHeight = 450; - InitWindow(screenWidth, screenHeight, "raylib [shapes] example - interactive dashed line"); + InitWindow(screenWidth, screenHeight, "raylib [shapes] example - dashed line"); // Line Properties Vector2 lineStartPosition = { 20.0f, 50.0f }; diff --git a/projects/VS2022/examples/core_monitor_change.vcxproj b/projects/VS2022/examples/core_monitor_change.vcxproj new file mode 100644 index 000000000..e372a68d0 --- /dev/null +++ b/projects/VS2022/examples/core_monitor_change.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 + + + + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F} + Win32Proj + core_monitor_change + 10.0 + core_monitor_change + + + + 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/models_geometry_textures_cube.vcxproj b/projects/VS2022/examples/models_geometry_textures_cube.vcxproj new file mode 100644 index 000000000..5c8452472 --- /dev/null +++ b/projects/VS2022/examples/models_geometry_textures_cube.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 + + + + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E} + Win32Proj + models_geometry_textures_cube + 10.0 + models_geometry_textures_cube + + + + 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\models + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\models + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\models + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\models + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\models + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\models + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\models + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\models + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\models + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\models + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\models + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\models + 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/shaders_ascii_rendering.vcxproj b/projects/VS2022/examples/shaders_ascii_rendering.vcxproj new file mode 100644 index 000000000..49ee10790 --- /dev/null +++ b/projects/VS2022/examples/shaders_ascii_rendering.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 + + + + {9DB1F875-6E65-4195-B23F-ED8095C0B99C} + Win32Proj + shaders_ascii_rendering + 10.0 + shaders_ascii_rendering + + + + 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;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/shapes_dashed_line.vcxproj b/projects/VS2022/examples/shapes_dashed_line.vcxproj new file mode 100644 index 000000000..4a4b86ef3 --- /dev/null +++ b/projects/VS2022/examples/shapes_dashed_line.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 + shapes_dashed_line + 10.0 + shapes_dashed_line + + + + 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\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + 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 5b43235a4..9621012c0 100644 --- a/projects/VS2022/raylib.sln +++ b/projects/VS2022/raylib.sln @@ -355,6 +355,14 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_vector_angle", "exam EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "models_basic_voxel", "examples\models_basic_voxel.vcxproj", "{52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_dashed_line", "examples\shapes_dashed_line.vcxproj", "{6B1A933E-71B8-4C1F-9E79-02D98830E671}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "models_geometry_textures_cube", "examples\models_geometry_textures_cube.vcxproj", "{2CCCD9E4-9058-4291-BD89-39C979F0CA1E}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shaders_ascii_rendering", "examples\shaders_ascii_rendering.vcxproj", "{9DB1F875-6E65-4195-B23F-ED8095C0B99C}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_monitor_change", "examples\core_monitor_change.vcxproj", "{52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug.DLL|ARM64 = Debug.DLL|ARM64 @@ -4377,6 +4385,102 @@ Global {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release|x64.Build.0 = Release|x64 {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release|x86.ActiveCfg = Release|Win32 {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.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 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug|ARM64.Build.0 = Debug|ARM64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug|x64.ActiveCfg = Debug|x64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug|x64.Build.0 = Debug|x64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug|x86.ActiveCfg = Debug|Win32 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug|x86.Build.0 = Debug|Win32 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release|ARM64.ActiveCfg = Release|ARM64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release|ARM64.Build.0 = Release|ARM64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release|x64.ActiveCfg = Release|x64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release|x64.Build.0 = Release|x64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release|x86.ActiveCfg = Release|Win32 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release|x86.Build.0 = Release|Win32 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug|ARM64.Build.0 = Debug|ARM64 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug|x64.ActiveCfg = Debug|x64 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug|x64.Build.0 = Debug|x64 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug|x86.ActiveCfg = Debug|Win32 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug|x86.Build.0 = Debug|Win32 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release|ARM64.ActiveCfg = Release|ARM64 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release|ARM64.Build.0 = Release|ARM64 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release|x64.ActiveCfg = Release|x64 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release|x64.Build.0 = Release|x64 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release|x86.ActiveCfg = Release|Win32 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release|x86.Build.0 = Release|Win32 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug|ARM64.Build.0 = Debug|ARM64 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug|x64.ActiveCfg = Debug|x64 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug|x64.Build.0 = Debug|x64 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug|x86.ActiveCfg = Debug|Win32 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug|x86.Build.0 = Debug|Win32 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release|ARM64.ActiveCfg = Release|ARM64 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release|ARM64.Build.0 = Release|ARM64 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release|x64.ActiveCfg = Release|x64 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release|x64.Build.0 = Release|x64 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release|x86.ActiveCfg = Release|Win32 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -4556,6 +4660,10 @@ Global {2CCCD9E4-9058-4291-BD89-39C979F0CA1E} = {278D8859-20B1-428F-8448-064F46E1F021} {9DB1F875-6E65-4195-B23F-ED8095C0B99C} = {278D8859-20B1-428F-8448-064F46E1F021} {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F} = {AF5BEC5C-1F2B-4DA8-B12D-D09FE569237C} + {6B1A933E-71B8-4C1F-9E79-02D98830E671} = {278D8859-20B1-428F-8448-064F46E1F021} + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E} = {AF5BEC5C-1F2B-4DA8-B12D-D09FE569237C} + {9DB1F875-6E65-4195-B23F-ED8095C0B99C} = {5317807F-61D4-4E0F-B6DC-2D9F12621ED9} + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {E926C768-6307-4423-A1EC-57E95B1FAB29} diff --git a/tools/rexm/examples_report.md b/tools/rexm/examples_report.md index 7c9de0b57..d9d8169d0 100644 --- a/tools/rexm/examples_report.md +++ b/tools/rexm/examples_report.md @@ -21,6 +21,7 @@ Example elements validated: | **EXAMPLE NAME** | [C] | [CAT]| [INFO]|[PNG]|[WPNG]| [RES]| [MK] |[MKWEB]| [VCX]| [SOL]|[RDME]|[JS] | [WOUT]|[WMETA]| |:---------------------------------|:---:|:----:|:-----:|:---:|:----:|:----:|:----:|:-----:|:----:|:----:|:----:|:---:|:-----:|:-----:| | core_basic_window | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| core_delta_time | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | core_input_keys | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | core_input_mouse | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | core_input_mouse_wheel | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | @@ -60,6 +61,7 @@ Example elements validated: | core_input_actions | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shapes_basic_shapes | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shapes_bouncing_ball | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| shapes_bullet_hell | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shapes_colors_palette | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shapes_logo_raylib | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shapes_logo_raylib_anim | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | @@ -78,6 +80,8 @@ Example elements validated: | shapes_splines_drawing | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shapes_digital_clock | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shapes_double_pendulum | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| shapes_dashed_line | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| shapes_vector_angle | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | textures_logo_raylib | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | textures_srcrec_dstrec | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | textures_image_drawing | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | @@ -141,6 +145,9 @@ Example elements validated: | models_animation_gpu_skinning | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | models_bone_socket | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | models_tesseract_view | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| models_basic_voxel | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| models_geometry_textures_cube | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| shaders_ascii_rendering | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shaders_basic_lighting | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shaders_model_shader | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shaders_shapes_textures | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | From 36d3c8acfb5db14bf1c1f68afe00c00bb335f470 Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 2 Oct 2025 13:16:29 +0200 Subject: [PATCH 073/167] Update rexm.c --- tools/rexm/rexm.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/rexm/rexm.c b/tools/rexm/rexm.c index 6f2b19777..596fb7852 100644 --- a/tools/rexm/rexm.c +++ b/tools/rexm/rexm.c @@ -901,9 +901,9 @@ int main(int argc, char *argv[]) // defines placement on raylib webpage rlExampleInfo *exInfo = LoadExampleInfo(clist.paths[i]); - // Validate example category and avoid [others] examples (special category) - if (TextInList(exInfo->category, exCategories, REXM_MAX_EXAMPLE_CATEGORIES) && - !TextIsEqual(exInfo->category, "others")) + // Validate example category + // TODO: Should [others] category be considered? + if (TextInList(exInfo->category, exCategories, REXM_MAX_EXAMPLE_CATEGORIES))// && !TextIsEqual(exInfo->category, "others")) { // Get example difficulty stars char starsText[16] = { 0 }; @@ -915,7 +915,7 @@ int main(int argc, char *argv[]) } exListLen += sprintf(exListUpdated + exListLen, - TextFormat("%s;%s;%s;%s;%s;%s;%s;\"%s\";@%s\n", + TextFormat("%s;%s;%s;%s;%s;%i;%i;\"%s\";@%s\n", exInfo->category, exInfo->name, starsText, exInfo->verCreated, exInfo->verUpdated, exInfo->yearCreated, exInfo->yearReviewed, exInfo->author, exInfo->authorGitHub)); From 7e3b7cd349b16b8ea57dbdbf49a3bd4b944ee9d4 Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 2 Oct 2025 13:38:13 +0200 Subject: [PATCH 074/167] REVIEWED: `DrawLineDashed()` --- examples/shapes/shapes_dashed_line.c | 11 +-- src/raylib.h | 2 +- src/rshapes.c | 115 +++++++++++++-------------- 3 files changed, 59 insertions(+), 69 deletions(-) diff --git a/examples/shapes/shapes_dashed_line.c b/examples/shapes/shapes_dashed_line.c index aa254ab8d..7a6bf3eee 100644 --- a/examples/shapes/shapes_dashed_line.c +++ b/examples/shapes/shapes_dashed_line.c @@ -16,8 +16,6 @@ ********************************************************************************************/ #include "raylib.h" -#define RAYGUI_IMPLEMENTATION -#include "raygui.h" // Required for GUI controls //------------------------------------------------------------------------------------ // Program main entry point @@ -42,6 +40,7 @@ int main(void) int colorIndex = 0; SetTargetFPS(60); // Set our game to run at 60 frames-per-second + //-------------------------------------------------------------------------------------- // Main game loop while (!WindowShouldClose()) // Detect window close button or ESC key @@ -50,8 +49,6 @@ int main(void) //---------------------------------------------------------------------------------- lineEndPosition = GetMousePosition(); // Line endpoint follows the mouse - // --- Keyboard Controls --- - // Change Dash Length (UP/DOWN arrows) if (IsKeyDown(KEY_UP)) dashLength += 1.0f; if (IsKeyDown(KEY_DOWN) && dashLength > 1.0f) dashLength -= 1.0f; @@ -61,11 +58,7 @@ int main(void) if (IsKeyDown(KEY_LEFT) && blankLength > 1.0f) blankLength -= 1.0f; // Cycle through colors ('C' key) - if (IsKeyPressed(KEY_C)) - { - colorIndex = (colorIndex + 1) % (sizeof(lineColors)/sizeof(Color)); - } - + if (IsKeyPressed(KEY_C)) colorIndex = (colorIndex + 1)%(sizeof(lineColors)/sizeof(Color)); //---------------------------------------------------------------------------------- // Draw diff --git a/src/raylib.h b/src/raylib.h index b7ccaae22..c57efc2e1 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1258,11 +1258,11 @@ RLAPI Rectangle GetShapesTextureRectangle(void); // Get texture source re RLAPI void DrawPixel(int posX, int posY, Color color); // Draw a pixel using geometry [Can be slow, use with care] RLAPI void DrawPixelV(Vector2 position, Color color); // Draw a pixel using geometry (Vector version) [Can be slow, use with care] RLAPI void DrawLine(int startPosX, int startPosY, int endPosX, int endPosY, Color color); // Draw a line -RLAPI void DrawLineDashed(Vector2 startPos, Vector2 endPos, int dashSize, int whiteSpaceSize, Color color); // Draw a dashed line RLAPI void DrawLineV(Vector2 startPos, Vector2 endPos, Color color); // Draw a line (using gl lines) RLAPI void DrawLineEx(Vector2 startPos, Vector2 endPos, float thick, Color color); // Draw a line (using triangles/quads) RLAPI void DrawLineStrip(const Vector2 *points, int pointCount, Color color); // Draw lines sequence (using gl lines) RLAPI void DrawLineBezier(Vector2 startPos, Vector2 endPos, float thick, Color color); // Draw line segment cubic-bezier in-out interpolation +RLAPI void DrawLineDashed(Vector2 startPos, Vector2 endPos, int dashSize, int spaceSize, Color color); // Draw a dashed line RLAPI void DrawCircle(int centerX, int centerY, float radius, Color color); // Draw a color-filled circle RLAPI void DrawCircleSector(Vector2 center, float radius, float startAngle, float endAngle, int segments, Color color); // Draw a piece of a circle RLAPI void DrawCircleSectorLines(Vector2 center, float radius, float startAngle, float endAngle, int segments, Color color); // Draw circle sector outline diff --git a/src/rshapes.c b/src/rshapes.c index a62b1c5f8..55f7d7fb9 100644 --- a/src/rshapes.c +++ b/src/rshapes.c @@ -182,53 +182,26 @@ void DrawLine(int startPosX, int startPosY, int endPosX, int endPosY, Color colo rlEnd(); } -void DrawLineDashed(Vector2 startPos, Vector2 endPos, int dashSize, int whiteSpaceSize, Color color) +// Draw a line defining thickness +void DrawLineEx(Vector2 startPos, Vector2 endPos, float thick, Color color) { - // Calculate the vector and length of the line - float dx = endPos.x - startPos.x; - float dy = endPos.y - startPos.y; - float lineLength = sqrtf(dx*dx + dy*dy); + Vector2 delta = { endPos.x - startPos.x, endPos.y - startPos.y }; + float length = sqrtf(delta.x*delta.x + delta.y*delta.y); - // If the line is too short for dashing or dash size is invalid, draw a solid thick line - if (lineLength < (dashSize + whiteSpaceSize) || dashSize <= 0) + if ((length > 0) && (thick > 0)) { - DrawLineV(startPos, endPos, color); - return; + float scale = thick/(2*length); + + Vector2 radius = { -scale*delta.y, scale*delta.x }; + Vector2 strip[4] = { + { startPos.x - radius.x, startPos.y - radius.y }, + { startPos.x + radius.x, startPos.y + radius.y }, + { endPos.x - radius.x, endPos.y - radius.y }, + { endPos.x + radius.x, endPos.y + radius.y } + }; + + DrawTriangleStrip(strip, 4, color); } - - // Calculate the normalized direction vector of the line - float invLineLength = 1 / lineLength; - float dirX = dx * invLineLength; - float dirY = dy * invLineLength; - - Vector2 currentPos = startPos; - float distanceTraveled = 0; - - rlBegin(RL_LINES); - rlColor4ub(color.r, color.g, color.b, color.a); - - while (distanceTraveled < lineLength) - { - // Calculate the end of the current dash - float dashEndDist = distanceTraveled + dashSize; - if (dashEndDist > lineLength) - { - dashEndDist = lineLength; - } - - Vector2 dashEndPos = { startPos.x + dashEndDist * dirX, startPos.y + dashEndDist * dirY }; - - // Draw the dash segment - rlVertex2f(currentPos.x, currentPos.y); - rlVertex2f(dashEndPos.x, dashEndPos.y); - - // Update the distance traveled and move the current position for the next dash - distanceTraveled = dashEndDist + whiteSpaceSize; - currentPos.x = startPos.x + distanceTraveled * dirX; - currentPos.y = startPos.y + distanceTraveled * dirY; - } - - rlEnd(); } // Draw a line (using gl lines) @@ -295,26 +268,50 @@ void DrawLineBezier(Vector2 startPos, Vector2 endPos, float thick, Color color) DrawTriangleStrip(points, 2*SPLINE_SEGMENT_DIVISIONS + 2, color); } -// Draw a line defining thickness -void DrawLineEx(Vector2 startPos, Vector2 endPos, float thick, Color color) +// Draw a dashed line +void DrawLineDashed(Vector2 startPos, Vector2 endPos, int dashSize, int spaceSize, Color color) { - Vector2 delta = { endPos.x - startPos.x, endPos.y - startPos.y }; - float length = sqrtf(delta.x*delta.x + delta.y*delta.y); + // Calculate the vector and length of the line + float dx = endPos.x - startPos.x; + float dy = endPos.y - startPos.y; + float lineLength = sqrtf(dx*dx + dy*dy); - if ((length > 0) && (thick > 0)) + // If the line is too short for dashing or dash size is invalid, draw a solid thick line + if ((lineLength < (dashSize + spaceSize)) || (dashSize <= 0)) { - float scale = thick/(2*length); - - Vector2 radius = { -scale*delta.y, scale*delta.x }; - Vector2 strip[4] = { - { startPos.x - radius.x, startPos.y - radius.y }, - { startPos.x + radius.x, startPos.y + radius.y }, - { endPos.x - radius.x, endPos.y - radius.y }, - { endPos.x + radius.x, endPos.y + radius.y } - }; - - DrawTriangleStrip(strip, 4, color); + DrawLineV(startPos, endPos, color); + return; } + + // Calculate the normalized direction vector of the line + float invLineLength = 1.0f/lineLength; + float dirX = dx*invLineLength; + float dirY = dy*invLineLength; + + Vector2 currentPos = startPos; + float distanceTraveled = 0; + + rlBegin(RL_LINES); + rlColor4ub(color.r, color.g, color.b, color.a); + + while (distanceTraveled < lineLength) + { + // Calculate the end of the current dash + float dashEndDist = distanceTraveled + dashSize; + if (dashEndDist > lineLength) dashEndDist = lineLength; + + Vector2 dashEndPos = { startPos.x + dashEndDist*dirX, startPos.y + dashEndDist*dirY }; + + // Draw the dash segment + rlVertex2f(currentPos.x, currentPos.y); + rlVertex2f(dashEndPos.x, dashEndPos.y); + + // Update the distance traveled and move the current position for the next dash + distanceTraveled = dashEndDist + spaceSize; + currentPos.x = startPos.x + distanceTraveled*dirX; + currentPos.y = startPos.y + distanceTraveled*dirY; + } + rlEnd(); } // Draw a color-filled circle From 2ea18f7c88a2056e0f2bbf0557defe906de58302 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 2 Oct 2025 11:38:31 +0000 Subject: [PATCH 075/167] Update raylib_api.* by CI --- tools/parser/output/raylib_api.json | 54 ++++++++++++++--------------- tools/parser/output/raylib_api.lua | 24 ++++++------- tools/parser/output/raylib_api.txt | 26 +++++++------- tools/parser/output/raylib_api.xml | 14 ++++---- 4 files changed, 59 insertions(+), 59 deletions(-) diff --git a/tools/parser/output/raylib_api.json b/tools/parser/output/raylib_api.json index 7b2ffdc9d..9714d5d05 100644 --- a/tools/parser/output/raylib_api.json +++ b/tools/parser/output/raylib_api.json @@ -5508,33 +5508,6 @@ } ] }, - { - "name": "DrawLineDashed", - "description": "Draw a dashed line", - "returnType": "void", - "params": [ - { - "type": "Vector2", - "name": "startPos" - }, - { - "type": "Vector2", - "name": "endPos" - }, - { - "type": "int", - "name": "dashSize" - }, - { - "type": "int", - "name": "whiteSpaceSize" - }, - { - "type": "Color", - "name": "color" - } - ] - }, { "name": "DrawLineV", "description": "Draw a line (using gl lines)", @@ -5619,6 +5592,33 @@ } ] }, + { + "name": "DrawLineDashed", + "description": "Draw a dashed line", + "returnType": "void", + "params": [ + { + "type": "Vector2", + "name": "startPos" + }, + { + "type": "Vector2", + "name": "endPos" + }, + { + "type": "int", + "name": "dashSize" + }, + { + "type": "int", + "name": "spaceSize" + }, + { + "type": "Color", + "name": "color" + } + ] + }, { "name": "DrawCircle", "description": "Draw a color-filled circle", diff --git a/tools/parser/output/raylib_api.lua b/tools/parser/output/raylib_api.lua index 62dc9b25d..75fd06373 100644 --- a/tools/parser/output/raylib_api.lua +++ b/tools/parser/output/raylib_api.lua @@ -4758,18 +4758,6 @@ return { {type = "Color", name = "color"} } }, - { - name = "DrawLineDashed", - description = "Draw a dashed line", - returnType = "void", - params = { - {type = "Vector2", name = "startPos"}, - {type = "Vector2", name = "endPos"}, - {type = "int", name = "dashSize"}, - {type = "int", name = "whiteSpaceSize"}, - {type = "Color", name = "color"} - } - }, { name = "DrawLineV", description = "Draw a line (using gl lines)", @@ -4812,6 +4800,18 @@ return { {type = "Color", name = "color"} } }, + { + name = "DrawLineDashed", + description = "Draw a dashed line", + returnType = "void", + params = { + {type = "Vector2", name = "startPos"}, + {type = "Vector2", name = "endPos"}, + {type = "int", name = "dashSize"}, + {type = "int", name = "spaceSize"}, + {type = "Color", name = "color"} + } + }, { name = "DrawCircle", description = "Draw a color-filled circle", diff --git a/tools/parser/output/raylib_api.txt b/tools/parser/output/raylib_api.txt index ea00fc74e..849a97a56 100644 --- a/tools/parser/output/raylib_api.txt +++ b/tools/parser/output/raylib_api.txt @@ -2190,23 +2190,14 @@ Function 221: DrawLine() (5 input parameters) Param[3]: endPosX (type: int) Param[4]: endPosY (type: int) Param[5]: color (type: Color) -Function 222: DrawLineDashed() (5 input parameters) - Name: DrawLineDashed - Return type: void - Description: Draw a dashed line - Param[1]: startPos (type: Vector2) - Param[2]: endPos (type: Vector2) - Param[3]: dashSize (type: int) - Param[4]: whiteSpaceSize (type: int) - Param[5]: color (type: Color) -Function 223: DrawLineV() (3 input parameters) +Function 222: DrawLineV() (3 input parameters) Name: DrawLineV Return type: void Description: Draw a line (using gl lines) Param[1]: startPos (type: Vector2) Param[2]: endPos (type: Vector2) Param[3]: color (type: Color) -Function 224: DrawLineEx() (4 input parameters) +Function 223: DrawLineEx() (4 input parameters) Name: DrawLineEx Return type: void Description: Draw a line (using triangles/quads) @@ -2214,14 +2205,14 @@ Function 224: DrawLineEx() (4 input parameters) Param[2]: endPos (type: Vector2) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 225: DrawLineStrip() (3 input parameters) +Function 224: DrawLineStrip() (3 input parameters) Name: DrawLineStrip Return type: void Description: Draw lines sequence (using gl lines) Param[1]: points (type: const Vector2 *) Param[2]: pointCount (type: int) Param[3]: color (type: Color) -Function 226: DrawLineBezier() (4 input parameters) +Function 225: DrawLineBezier() (4 input parameters) Name: DrawLineBezier Return type: void Description: Draw line segment cubic-bezier in-out interpolation @@ -2229,6 +2220,15 @@ Function 226: DrawLineBezier() (4 input parameters) Param[2]: endPos (type: Vector2) Param[3]: thick (type: float) Param[4]: color (type: Color) +Function 226: DrawLineDashed() (5 input parameters) + Name: DrawLineDashed + Return type: void + Description: Draw a dashed line + Param[1]: startPos (type: Vector2) + Param[2]: endPos (type: Vector2) + Param[3]: dashSize (type: int) + Param[4]: spaceSize (type: int) + Param[5]: color (type: Color) Function 227: DrawCircle() (4 input parameters) Name: DrawCircle Return type: void diff --git a/tools/parser/output/raylib_api.xml b/tools/parser/output/raylib_api.xml index 29546a2a8..59f2d4a50 100644 --- a/tools/parser/output/raylib_api.xml +++ b/tools/parser/output/raylib_api.xml @@ -1359,13 +1359,6 @@ - - - - - - - @@ -1388,6 +1381,13 @@ + + + + + + + From 78a79a85231ee1a3468b9223295451d529452fe1 Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 2 Oct 2025 13:40:36 +0200 Subject: [PATCH 076/167] Update list --- examples/README.md | 2 +- examples/examples_list.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/README.md b/examples/README.md index 0dabc05b4..327e1bc41 100644 --- a/examples/README.md +++ b/examples/README.md @@ -49,6 +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_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) | @@ -64,7 +65,6 @@ Examples using raylib[core](../src/rcore.c) platform functionality like window c | [core_render_texture](core/core_render_texture.c) | core_render_texture | ⭐☆☆☆ | 5.6-dev | 5.6-dev | [Ramon Santamaria](https://github.com/raysan5) | | [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_monitor_change](core/core_monitor_change.c) | core_monitor_change | ⭐☆☆☆ | 5.5 | 5.6 | [Maicon Santana](https://github.com/maiconpintoabreu) | ### category: shapes [23] diff --git a/examples/examples_list.txt b/examples/examples_list.txt index 57602002f..56c8ee2d6 100644 --- a/examples/examples_list.txt +++ b/examples/examples_list.txt @@ -31,6 +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_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 @@ -178,4 +179,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;"Ramon Santamaria";@raysan5 -core;core_monitor_change;★☆☆☆;5.5;5.6;2025;2025;"Maicon Santana";@maiconpintoabreu From 301df440bdcaa6acf95a3d6f9f987aad3fea744b Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 2 Oct 2025 13:41:40 +0200 Subject: [PATCH 077/167] Merge branch 'master' of https://github.com/raysan5/raylib From 29a7996402c9548a5aee6030dc0cf5a13fbb23fe Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 2 Oct 2025 13:45:06 +0200 Subject: [PATCH 078/167] REXM: Remove dead code of functions already moved to raylib --- tools/rexm/rexm.c | 174 ---------------------------------------------- 1 file changed, 174 deletions(-) diff --git a/tools/rexm/rexm.c b/tools/rexm/rexm.c index 596fb7852..493ca258a 100644 --- a/tools/rexm/rexm.c +++ b/tools/rexm/rexm.c @@ -137,13 +137,6 @@ static const char *exVSProjectSolutionFile = NULL; // Env REXM_EXAMPLES_VS2022_S //---------------------------------------------------------------------------------- // Module Internal Functions Declaration //---------------------------------------------------------------------------------- -//static int FileTextFind(const char *fileName, const char *find); -//static int FileTextReplace(const char *fileName, const char *find, const char *replace); -//static int FileCopy(const char *srcPath, const char *dstPath); -//static int FileRename(const char *fileName, const char *fileRename); -//static int FileMove(const char *srcPath, const char *dstPath); -//static int FileRemove(const char *fileName); - // Update required files from examples collection // UPDATES: Makefile, Makefile.Web, README.md, examples.js static int UpdateRequiredFiles(void); @@ -188,10 +181,6 @@ static void UpdateWebMetadata(const char *exHtmlPath, const char *exFilePath); // Check if text string is a list of strings static bool TextInList(const char *text, const char **list, int listCount); -// Get text between two strings -//static char *GetTextBetween(const char *text, const char *begin, const char *end); -// Replace text between two specific strings -//static char *TextReplaceBetween(const char *text, const char *begin, const char *end, const char *replace); //------------------------------------------------------------------------------------ // Program main entry point @@ -1810,110 +1799,6 @@ static void UnloadExamplesData(rlExampleInfo *exInfo) RL_FREE(exInfo); } -/* -// Find text in existing file -static int FileTextFind(const char *fileName, const char *find) -{ - int result = -1; - - if (FileExists(fileName)) - { - char *fileText = LoadFileText(fileName); - result = TextFindIndex(fileText, find); - UnloadFileText(fileText); - } - - return result; -} - -// Replace text in an existing file -static int FileTextReplace(const char *fileName, const char *textLookUp, const char *textReplace) -{ - int result = 0; - char *fileText = NULL; - char *fileTextUpdated = { 0 }; - - if (FileExists(fileName)) - { - fileText = LoadFileText(fileName); - fileTextUpdated = TextReplace(fileText, textLookUp, textReplace); - result = SaveFileText(fileName, fileTextUpdated); - MemFree(fileTextUpdated); - UnloadFileText(fileText); - } - - return result; -} - -// Copy file from one path to another -// NOTE: If destination path does not exist, it is created! -static int FileCopy(const char *srcPath, const char *dstPath) -{ - int result = 0; - int srcDataSize = 0; - unsigned char *srcFileData = LoadFileData(srcPath, &srcDataSize); - - // Create required paths if they do not exist - if (!DirectoryExists(GetDirectoryPath(dstPath))) - result = MakeDirectory(GetDirectoryPath(dstPath)); - - if (result == 0) // Directory created successfully (or already exists) - { - if ((srcFileData != NULL) && (srcDataSize > 0)) - result = SaveFileData(dstPath, srcFileData, srcDataSize); - } - - UnloadFileData(srcFileData); - - return result; -} - -// Rename file (if exists) -// NOTE: Only rename file name required, not full path -static int FileRename(const char *fileName, const char *fileRename) -{ - int result = 0; - - if (FileExists(fileName)) - { - result = rename(fileName, fileRename); - } - else result = -1; - - return result; -} - -// Remove file (if exists) -static int FileRemove(const char *fileName) -{ - int result = 0; - - if (FileExists(fileName)) - { - result = remove(fileName); - } - else result = -1; - - return result; -} - -// Move file from one directory to another -// NOTE: If dst directories do not exists they are created -static int FileMove(const char *srcPath, const char *dstPath) -{ - int result = 0; - - if (FileExists(srcPath)) - { - FileCopy(srcPath, dstPath); - remove(srcPath); - } - else result = -1; - - return result; -} -*/ - // Get example info from example file header // WARNING: Expecting the example to follow raylib_example_template.c static rlExampleInfo *LoadExampleInfo(const char *exFileName) @@ -2515,62 +2400,3 @@ static bool TextInList(const char *text, const char **list, int listCount) return result; } -/* -// Get text between two strings -// NOTE: Using static string to return result, MAX: 1024 bytes -static char *GetTextBetween(const char *text, const char *begin, const char *end) -{ - #define MAX_TEXT_BETWEEN_SIZE 1024 - - static char between[MAX_TEXT_BETWEEN_SIZE] = { 0 }; - memset(between, 0, MAX_TEXT_BETWEEN_SIZE); - - int beginIndex = TextFindIndex(text, begin); - - if (beginIndex > -1) - { - int beginLen = strlen(begin); - int endIndex = TextFindIndex(text + beginIndex + beginLen, end); - - if (endIndex > -1) - { - endIndex += (beginIndex + beginLen); - int len = (endIndex - beginIndex - beginLen); - if (len < (MAX_TEXT_BETWEEN_SIZE - 1)) strncpy(between, text + beginIndex + beginLen, len); - else strncpy(between, text + beginIndex + beginLen, MAX_TEXT_BETWEEN_SIZE - 1); - } - } - - return between; -} - -// Replace text between two specific strings -// WARNING: Returned string must be freed by user -static char *TextReplaceBetween(const char *text, const char *begin, const char *end, const char *replace) -{ - char *result = NULL; - int beginIndex = TextFindIndex(text, begin); - - if (beginIndex > -1) - { - int beginLen = strlen(begin); - int endIndex = TextFindIndex(text + beginIndex + beginLen, end); - - if (endIndex > -1) - { - endIndex += (beginIndex + beginLen); - - int textLen = strlen(text); - int replaceLen = strlen(replace); - int toreplaceLen = endIndex - beginIndex - beginLen; - result = (char *)RL_CALLOC(textLen + replaceLen - toreplaceLen + 1, sizeof(char)); - - strncpy(result, text, beginIndex + beginLen); // Copy first text part - strncpy(result + beginIndex + beginLen, replace, replaceLen); // Copy replace - strncpy(result + beginIndex + beginLen + replaceLen, text + endIndex, textLen - endIndex); // Copy end text part - } - } - - return result; -} -*/ From 8670e6e1b986a136c3f9fe826249c9ef954c858c Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 2 Oct 2025 13:45:25 +0200 Subject: [PATCH 079/167] REXM: FIX: Get others category --- tools/rexm/rexm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/rexm/rexm.c b/tools/rexm/rexm.c index 493ca258a..745a5ba80 100644 --- a/tools/rexm/rexm.c +++ b/tools/rexm/rexm.c @@ -1759,8 +1759,8 @@ static rlExampleInfo *LoadExamplesData(const char *fileName, const char *categor (lines[i][0] == 's') || // shapes, shaders (lines[i][0] == 't') || // textures, text (lines[i][0] == 'm') || // models - (lines[i][0] == 'a'))) // audio - //(lines[i][0] == 'o'))) // NOTE: others category skipped + (lines[i][0] == 'a') || // audio + (lines[i][0] == 'o'))) // TODO: Get others category? { rlExampleInfo info = { 0 }; int result = ParseExampleInfoLine(lines[i], &info); From 718a841cfba2c1739b979ee068aafe018c03aa95 Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 2 Oct 2025 13:54:11 +0200 Subject: [PATCH 080/167] REXM: Update examples --- examples/Makefile | 4 +- examples/README.md | 4 +- examples/examples_list.txt | 2 +- examples/others/web_basic_window.c | 17 +- .../VS2022/examples/web_basic_window.vcxproj | 569 ++++++++++++++++++ projects/VS2022/raylib.sln | 26 + tools/rexm/examples_report.md | 3 +- tools/rexm/examples_report_issues.md | 2 +- 8 files changed, 613 insertions(+), 14 deletions(-) create mode 100644 projects/VS2022/examples/web_basic_window.vcxproj diff --git a/examples/Makefile b/examples/Makefile index 97e3bbc30..fb33b4894 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -682,9 +682,9 @@ OTHERS = \ others/easings_testbed \ others/embedded_files_loading \ others/raylib_opengl_interop \ - others/raymath_vector_angle \ others/rlgl_compute_shader \ - others/rlgl_standalone + others/rlgl_standalone \ + others/web_basic_window #EXAMPLES_LIST_END # Define processes to execute diff --git a/examples/README.md b/examples/README.md index 327e1bc41..70e07df2b 100644 --- a/examples/README.md +++ b/examples/README.md @@ -17,7 +17,7 @@ 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: 166] +## EXAMPLES COLLECTION [TOTAL: 172] ### category: core [40] @@ -245,7 +245,7 @@ Examples showing raylib misc functionality that does not fit in other categories | [easings_testbed](others/easings_testbed.c) | easings_testbed | ⭐⭐⭐☆ | 2.5 | 3.0 | [Juan Miguel López](https://github.com/flashback-fx) | | [raylib_opengl_interop](others/raylib_opengl_interop.c) | raylib_opengl_interop | ⭐⭐⭐⭐️ | 3.8 | 4.0 | [Stephan Soller](https://github.com/arkanis) | | [embedded_files_loading](others/embedded_files_loading.c) | embedded_files_loading | ⭐⭐☆☆ | 3.0 | 3.5 | [Kristian Holmgren](https://github.com/defutura) | -| [raymath_vector_angle](others/raymath_vector_angle.c) | raymath_vector_angle | ⭐⭐☆☆ | 1.0 | 5.0 | [Ramon Santamaria](https://github.com/raysan5) | +| [web_basic_window](others/web_basic_window.c) | web_basic_window | ⭐☆☆☆ | 5.6-dev | 5.6-dev | [Ramon Santamaria](https://github.com/raysan5) | Some example missing? As always, contributions are welcome, feel free to send new examples! Here is an[examples template](examples_template.c) with instructions to start with! diff --git a/examples/examples_list.txt b/examples/examples_list.txt index 56c8ee2d6..50643bf2b 100644 --- a/examples/examples_list.txt +++ b/examples/examples_list.txt @@ -178,4 +178,4 @@ others;rlgl_compute_shader;★★★★;4.0;4.0;2021;2025;"Teddy Astie";@tsnake4 others;easings_testbed;★★★☆;2.5;3.0;2019;2025;"Juan Miguel López";@flashback-fx 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;"Ramon Santamaria";@raysan5 +others;web_basic_window;★☆☆☆;5.6-dev;5.6-dev;2014;2025;"Ramon Santamaria";@raysan5 diff --git a/examples/others/web_basic_window.c b/examples/others/web_basic_window.c index 8aeebf414..f85c6e4f6 100644 --- a/examples/others/web_basic_window.c +++ b/examples/others/web_basic_window.c @@ -1,15 +1,18 @@ /******************************************************************************************* * -* raylib [others] example - Basic window (adapted for HTML5 platform) +* raylib [others] example - basic window * -* This example is prepared to compile for PLATFORM_WEB and PLATFORM_DESKTOP -* As you will notice, code structure is slightly different to the other examples... -* To compile it for PLATFORM_WEB just uncomment #define PLATFORM_WEB at beginning +* This example has been adapted to compile for PLATFORM_WEB and PLATFORM_DESKTOP +* As you will notice, code structure is slightly different to the other examples * -* This example has been created using raylib 1.3 (www.raylib.com) -* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* Example complexity rating: [★☆☆☆] 1/4 * -* Copyright (c) 2015 Ramon Santamaria (@raysan5) +* Example originally created with raylib 1.3, last time updated with raylib 5.5 +* +* 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) 2015-2025 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/projects/VS2022/examples/web_basic_window.vcxproj b/projects/VS2022/examples/web_basic_window.vcxproj new file mode 100644 index 000000000..e36012ac6 --- /dev/null +++ b/projects/VS2022/examples/web_basic_window.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 + web_basic_window + 10.0 + web_basic_window + + + + 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\others + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\others + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\others + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\others + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\others + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\others + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\others + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\others + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\others + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\others + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\others + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\others + 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 9621012c0..0d7019b61 100644 --- a/projects/VS2022/raylib.sln +++ b/projects/VS2022/raylib.sln @@ -363,6 +363,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shaders_ascii_rendering", " EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_monitor_change", "examples\core_monitor_change.vcxproj", "{52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "web_basic_window", "examples\web_basic_window.vcxproj", "{6B1A933E-71B8-4C1F-9E79-02D98830E671}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug.DLL|ARM64 = Debug.DLL|ARM64 @@ -4481,6 +4483,30 @@ Global {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release|x64.Build.0 = Release|x64 {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release|x86.ActiveCfg = Release|Win32 {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.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 diff --git a/tools/rexm/examples_report.md b/tools/rexm/examples_report.md index d9d8169d0..bf2dbde8b 100644 --- a/tools/rexm/examples_report.md +++ b/tools/rexm/examples_report.md @@ -44,6 +44,7 @@ Example elements validated: | core_window_flags | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | core_window_letterbox | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | core_window_should_close | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| core_monitor_change | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | core_custom_logging | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | core_drop_files | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | core_random_values | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | @@ -190,4 +191,4 @@ Example elements validated: | easings_testbed | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | raylib_opengl_interop | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | | embedded_files_loading | ✔ | ❌ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | -| raymath_vector_angle | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | +| web_basic_window | ✔ | ❌ | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | diff --git a/tools/rexm/examples_report_issues.md b/tools/rexm/examples_report_issues.md index 5c4df4202..5178dabdd 100644 --- a/tools/rexm/examples_report_issues.md +++ b/tools/rexm/examples_report_issues.md @@ -25,4 +25,4 @@ Example elements validated: | easings_testbed | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | raylib_opengl_interop | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | | embedded_files_loading | ✔ | ❌ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | -| raymath_vector_angle | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | +| web_basic_window | ✔ | ❌ | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | From 02b3e44f88abb99c5ee329324f7a0b6745ce5016 Mon Sep 17 00:00:00 2001 From: JohnnyCena123 Date: Thu, 2 Oct 2025 15:13:07 +0300 Subject: [PATCH 081/167] swap TraceLog to TRACELOG (#5226) --- src/rcore.c | 2 +- src/rmodels.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rcore.c b/src/rcore.c index 7a17d7f6f..b9098db02 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -1332,7 +1332,7 @@ Shader LoadShader(const char *vsFileName, const char *fsFileName) if (vsFileName != NULL) vShaderStr = LoadFileText(vsFileName); if (fsFileName != NULL) fShaderStr = LoadFileText(fsFileName); - if ((vShaderStr == NULL) && (fShaderStr == NULL)) TraceLog(LOG_WARNING, "SHADER: Shader files provided are not valid, using default shader"); + if ((vShaderStr == NULL) && (fShaderStr == NULL)) TRACELOG(LOG_WARNING, "SHADER: Shader files provided are not valid, using default shader"); shader = LoadShaderFromMemory(vShaderStr, fShaderStr); diff --git a/src/rmodels.c b/src/rmodels.c index 9ded580c3..1e7599004 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -5023,7 +5023,7 @@ static ModelAnimation *LoadModelAnimationsIQM(const char *fileName, int *animCou animations[a].bones = (BoneInfo *)RL_MALLOC(iqmHeader->num_poses*sizeof(BoneInfo)); animations[a].framePoses = (Transform **)RL_MALLOC(anim[a].num_frames*sizeof(Transform *)); memcpy(animations[a].name, fileDataPtr + iqmHeader->ofs_text + anim[a].name, 32); // I don't like this 32 here - TraceLog(LOG_INFO, "IQM Anim %s", animations[a].name); + TRACELOG(LOG_INFO, "IQM Anim %s", animations[a].name); // animations[a].framerate = anim.framerate; // TODO: Use animation framerate data? for (unsigned int j = 0; j < iqmHeader->num_poses; j++) From 7b5c597da5b66ff11a5bf97301a62d5e21f5e6fc Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 2 Oct 2025 19:25:45 +0200 Subject: [PATCH 082/167] Update rexm.c --- tools/rexm/rexm.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tools/rexm/rexm.c b/tools/rexm/rexm.c index 745a5ba80..1928f462b 100644 --- a/tools/rexm/rexm.c +++ b/tools/rexm/rexm.c @@ -222,6 +222,7 @@ int main(int argc, char *argv[]) char exRename[64] = { 0 }; // Example re-name, without extension int opCode = OP_NONE; // Operation code: 0-None(Help), 1-Create, 2-Add, 3-Rename, 4-Remove + bool verbose = false; // Flag for verbose log info /* // Testing code for UpdateSourceMetadata() @@ -416,6 +417,12 @@ int main(int argc, char *argv[]) UnloadFileText(exColInfo); } } + + // Check for verbose log mode request + for (int i = 1; i < argc; i++) + { + if ((strcmp(argv[i], "-v") == 0) || (strcmp(argv[i], "--verbose") == 0)) verbose = true; + } } switch (opCode) @@ -1907,8 +1914,7 @@ static int ParseExampleInfoLine(const char *line, rlExampleInfo *entry) int tokenCount = 0; char **tokens = TextSplit(line, ';', &tokenCount); - if (tokenCount != 9) - LOG("REXM: WARNING: Example collection line contains invalid number of tokens: %i\n", tokenCount); + if (tokenCount != 9) LOG("REXM: WARNING: Example collection line contains invalid number of tokens: %i\n", tokenCount); // Get category and name strcpy(entry->category, tokens[0]); From e7d27e5b80194c10f3c95aee2a04a3c5e3417c9f Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 2 Oct 2025 19:26:27 +0200 Subject: [PATCH 083/167] REXM: Remove test code --- tools/rexm/rexm.c | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/tools/rexm/rexm.c b/tools/rexm/rexm.c index 1928f462b..fd6d52109 100644 --- a/tools/rexm/rexm.c +++ b/tools/rexm/rexm.c @@ -224,24 +224,6 @@ int main(int argc, char *argv[]) int opCode = OP_NONE; // Operation code: 0-None(Help), 1-Create, 2-Add, 3-Rename, 4-Remove bool verbose = false; // Flag for verbose log info - /* - // Testing code for UpdateSourceMetadata() - rlExampleInfo test = { 0 }; - strcpy(test.category, "core"); - strcpy(test.name, "core_boring_window"); - test.stars = 4; - strcpy(test.verCreated, "2.9"); - strcpy(test.verUpdated, "6.0"); - test.yearCreated = 2010; - test.yearReviewed = 2026; - strcpy(test.author, "John W. Smith"); - strcpy(test.authorGitHub, "littlejohnny"); - - char exSourcePath[512] = { 0 }; - strcpy(exSourcePath, TextFormat("%s/core/core_basic_window.c", exBasePath)); // WARNING: Cache path for saving - UpdateSourceMetadata(exSourcePath, &test); - */ - // Command-line usage mode //-------------------------------------------------------------------------------------- if (argc > 1) From f0ffdb33f46028366e6ebd91962cddd438735351 Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 2 Oct 2025 20:04:41 +0200 Subject: [PATCH 084/167] REXM: Support building full example collection and categories ADDED: Some log info --- tools/rexm/rexm.c | 148 +++++++++++++++++++++++++++++----------------- 1 file changed, 95 insertions(+), 53 deletions(-) diff --git a/tools/rexm/rexm.c b/tools/rexm/rexm.c index fd6d52109..2dc295f37 100644 --- a/tools/rexm/rexm.c +++ b/tools/rexm/rexm.c @@ -56,7 +56,7 @@ #define SUPPORT_LOG_INFO #if defined(SUPPORT_LOG_INFO) && defined(_DEBUG) - #define LOG(...) printf(__VA_ARGS__) + #define LOG(...) printf("REXM: "__VA_ARGS__) #else #define LOG(...) #endif @@ -221,10 +221,12 @@ int main(int argc, char *argv[]) char exRecategory[32] = { 0 }; // Example re-name category: shapes char exRename[64] = { 0 }; // Example re-name, without extension + 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 verbose = false; // Flag for verbose log info - // Command-line usage mode + // Command-line usage mode: command args processing //-------------------------------------------------------------------------------------- if (argc > 1) { @@ -387,16 +389,25 @@ int main(int argc, char *argv[]) else if (argc > 3) LOG("WARNING: Too many arguments provided\n"); else { - // Verify example exists in collection to be removed - char *exColInfo = LoadFileText(exCollectionFilePath); - if (TextFindIndex(exColInfo, argv[2]) != -1) // Example in the collection - { - strcpy(exName, argv[2]); // Register example name for removal - strncpy(exCategory, exName, TextFindIndex(exName, "_")); - opCode = OP_BUILD; + // 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 + strcpy(exRebuildRequested, argv[2]); + } + else + { + // Verify example exists in collection to be removed + char *exColInfo = LoadFileText(exCollectionFilePath); + if (TextFindIndex(exColInfo, argv[2]) != -1) // Example in the collection + { + strcpy(exName, argv[2]); // Register example name for removal + strncpy(exCategory, exName, TextFindIndex(exName, "_")); + opCode = OP_BUILD; + } + else LOG("WARNING: BUILD: Example requested not available in the collection\n"); + UnloadFileText(exColInfo); } - else LOG("WARNING: BUILD: Example not available in the collection\n"); - UnloadFileText(exColInfo); } } @@ -407,10 +418,14 @@ int main(int argc, char *argv[]) } } + // Command-line usage mode: command execution switch (opCode) { case OP_CREATE: // Create: New example from template { + LOG("INFO: Command requested: CREATE\n"); + LOG("INFO: Example to create: %s\n", exName); + // Create: raylib/examples//_example_name.c char *exText = LoadFileText(exTemplateFilePath); char *exTextUpdated[6] = { 0 }; @@ -430,6 +445,9 @@ int main(int argc, char *argv[]) } case OP_ADD: // Add: Example from command-line input filename { + if (opCode != OP_CREATE) LOG("INFO: Command requested: ADD\n"); + LOG("INFO: Example file to be added: %s\n", inFileName); + // Add: raylib/examples//_example_name.c if (opCode != OP_CREATE) FileCopy(inFileName, TextFormat("%s/%s/%s.c", exBasePath, exCategory, exName)); @@ -629,6 +647,9 @@ int main(int argc, char *argv[]) } break; case OP_RENAME: // Rename { + LOG("INFO: Command requested: RENAME\n"); + LOG("INFO: Example to be renamed: %s --> %s\n", exName, exRename); + // NOTE: At this point provided values have been validated: // exName, exCategory, exRename, exRecategory if (strcmp(exCategory, exRecategory) == 0) @@ -740,6 +761,9 @@ int main(int argc, char *argv[]) } break; case OP_REMOVE: // Remove { + LOG("INFO: Command requested: REMOVE\n"); + LOG("INFO: Example to be removed: %s\n", exName); + // Remove example from collection for files update //------------------------------------------------------------------------------------------------ char *exCollectionList = LoadFileText(exCollectionFilePath); @@ -818,10 +842,70 @@ int main(int argc, char *argv[]) FileRemove(TextFormat("%s/%s/%s.wasm", exWebPath, exCategory, exName)); FileRemove(TextFormat("%s/%s/%s.js", exWebPath, exCategory, exName)); + } break; + case OP_BUILD: + { + LOG("INFO: Command requested: BUILD\n"); + LOG("INFO: Example to be built: %s\n", exRebuildRequested); + + if ((strcmp(exRebuildRequested, "others") != 0) && + (strcmp(exCategory, "others") != 0)) // Skipping "others" category for rebuild: Special needs + { + int exRebuildCount = 0; + rlExampleInfo *exRebuildList = LoadExamplesData(exCollectionFilePath, exRebuildRequested, false, &exRebuildCount); + + // Build: raylib.com/examples//_example_name.html + // Build: raylib.com/examples//_example_name.data + // Build: raylib.com/examples//_example_name.wasm + // Build: raylib.com/examples//_example_name.js + +#if defined(_WIN32) + // Set required environment variables + //putenv(TextFormat("RAYLIB_DIR=%s\\..", exBasePath)); + putenv("PATH=%PATH%;C:\\raylib\\w64devkit\\bin"); + //putenv("MAKE=mingw32-make"); + //ChangeDirectory(exBasePath); +#endif + for (int i = 0; i < exRebuildCount; i++) + { + // Build example for PLATFORM_DESKTOP +#if defined(_WIN32) + system(TextFormat("mingw32-make -C %s %s/%s PLATFORM=PLATFORM_DESKTOP -B", exBasePath, exRebuildList[i].category, exRebuildList[i].name)); +#else + system(TextFormat("make -C %s %s/%s PLATFORM=PLATFORM_DESKTOP -B", exBasePath, exRebuildList[i].category, exRebuildList[i].name)); +#endif + + // Build example for PLATFORM_WEB +#if defined(_WIN32) + system(TextFormat("mingw32-make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exRebuildList[i].category, exRebuildList[i].name)); +#else + system(TextFormat("make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exRebuildList[i].category, exRebuildList[i].name)); +#endif + // Update generated .html metadata + UpdateWebMetadata(TextFormat("%s/%s/%s.html", exBasePath, exRebuildList[i].category, exRebuildList[i].name), + TextFormat("%s/%s/%s.c", exBasePath, exRebuildList[i].category, exRebuildList[i].name)); + + // Copy results to web side + FileCopy(TextFormat("%s/%s/%s.html", exBasePath, exRebuildList[i].category, exRebuildList[i].name), + TextFormat("%s/%s/%s.html", exWebPath, exRebuildList[i].category, exRebuildList[i].name)); + FileCopy(TextFormat("%s/%s/%s.data", exBasePath, exRebuildList[i].category, exRebuildList[i].name), + TextFormat("%s/%s/%s.data", exWebPath, exRebuildList[i].category, exRebuildList[i].name)); + FileCopy(TextFormat("%s/%s/%s.wasm", exBasePath, exRebuildList[i].category, exRebuildList[i].name), + TextFormat("%s/%s/%s.wasm", exWebPath, exRebuildList[i].category, exRebuildList[i].name)); + FileCopy(TextFormat("%s/%s/%s.js", exBasePath, exRebuildList[i].category, exRebuildList[i].name), + TextFormat("%s/%s/%s.js", exWebPath, exRebuildList[i].category, exRebuildList[i].name)); + } + + UnloadExamplesData(exRebuildList); + } + else LOG("WARNING: [others] category examples should be build manually, they could have specific build requirements\n"); + } break; case OP_VALIDATE: // Validate: report and actions case OP_UPDATE: { + LOG("INFO: Command requested: %s\n", (opCode == OP_VALIDATE)? "VALIDATE" : "UPDATE"); + LOG("INFO: Example collection is being %s\n", (opCode == OP_VALIDATE)? "validated" : "validated and updated"); /* // Validation flags available: VALID_MISSING_C @@ -1285,48 +1369,6 @@ int main(int argc, char *argv[]) //------------------------------------------------------------------------------------------------ } break; - case OP_BUILD: - { - // Build: raylib.com/examples//_example_name.html - // Build: raylib.com/examples//_example_name.data - // Build: raylib.com/examples//_example_name.wasm - // Build: raylib.com/examples//_example_name.js - if (strcmp(exCategory, "others") != 0) // Skipping "others" category - { - // Build example for PLATFORM_DESKTOP - #if defined(_WIN32) - //putenv(TextFormat("RAYLIB_DIR=%s\\..", exBasePath)); - putenv("PATH=%PATH%;C:\\raylib\\w64devkit\\bin"); - //putenv("MAKE=mingw32-make"); - //ChangeDirectory(exBasePath); - system(TextFormat("mingw32-make -C %s %s/%s PLATFORM=PLATFORM_DESKTOP -B", exBasePath, exCategory, exName)); - #else - system(TextFormat("make -C %s %s/%s PLATFORM=PLATFORM_DESKTOP -B", exBasePath, exCategory, exName)); - #endif - - // Build example for PLATFORM_WEB - #if defined(_WIN32) - putenv("PATH=%PATH%;C:\\raylib\\w64devkit\\bin"); - system(TextFormat("mingw32-make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exCategory, exName)); - #else - system(TextFormat("make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exCategory, exName)); - #endif - - // Update generated .html metadata - UpdateWebMetadata(TextFormat("%s/%s/%s.html", exBasePath, exCategory, exName), - TextFormat("%s/%s/%s.c", exBasePath, exCategory, exName)); - - // Copy results to web side - FileCopy(TextFormat("%s/%s/%s.html", exBasePath, exCategory, exName), - TextFormat("%s/%s/%s.html", exWebPath, exCategory, exName)); - FileCopy(TextFormat("%s/%s/%s.data", exBasePath, exCategory, exName), - TextFormat("%s/%s/%s.data", exWebPath, exCategory, exName)); - FileCopy(TextFormat("%s/%s/%s.wasm", exBasePath, exCategory, exName), - TextFormat("%s/%s/%s.wasm", exWebPath, exCategory, exName)); - FileCopy(TextFormat("%s/%s/%s.js", exBasePath, exCategory, exName), - TextFormat("%s/%s/%s.js", exWebPath, exCategory, exName)); - } - } break; default: // Help { // Supported commands: From d7a83a1111ece79bf226950ede66417876809173 Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 4 Oct 2025 19:39:25 +0200 Subject: [PATCH 085/167] REVIEWED: RENAMED: Renamed tool `raylib_parser` to `rlparser` The tool can work with other libraries following `raylib.h` structure, keeping the `raylib_parser` name could be missleading. Also added an icon an reviewed Makefile an CI. --- .github/workflows/parse_api.yml | 4 +- tools/parser/Makefile | 44 ------- tools/{parser => rlparser}/LICENSE | 0 tools/rlparser/Makefile | 118 ++++++++++++++++++ tools/{parser => rlparser}/README.md | 24 ++-- .../output/raylib_api.json | 0 .../output/raylib_api.lua | 0 .../output/raylib_api.txt | 0 .../output/raylib_api.xml | 0 .../raylib_parser.c => rlparser/rlparser.c} | 14 +-- tools/rlparser/rlparser.ico | Bin 0 -> 2922 bytes tools/rlparser/rlparser.rc | 24 ++++ tools/rlparser/rlparser.rc.data | Bin 0 -> 4486 bytes 13 files changed, 163 insertions(+), 65 deletions(-) delete mode 100644 tools/parser/Makefile rename tools/{parser => rlparser}/LICENSE (100%) create mode 100644 tools/rlparser/Makefile rename tools/{parser => rlparser}/README.md (83%) rename tools/{parser => rlparser}/output/raylib_api.json (100%) rename tools/{parser => rlparser}/output/raylib_api.lua (100%) rename tools/{parser => rlparser}/output/raylib_api.txt (100%) rename tools/{parser => rlparser}/output/raylib_api.xml (100%) rename tools/{parser/raylib_parser.c => rlparser/rlparser.c} (99%) create mode 100644 tools/rlparser/rlparser.ico create mode 100644 tools/rlparser/rlparser.rc create mode 100644 tools/rlparser/rlparser.rc.data diff --git a/.github/workflows/parse_api.yml b/.github/workflows/parse_api.yml index c8665e1d4..ce7cb9f9a 100644 --- a/.github/workflows/parse_api.yml +++ b/.github/workflows/parse_api.yml @@ -32,6 +32,6 @@ jobs: set -x git config user.name "github-actions[bot]" git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add tools/parser - git commit -m "Update raylib_api.* by CI" + git add tools/rlparser + git commit -m "rlparser: update raylib_api.* by CI" git push diff --git a/tools/parser/Makefile b/tools/parser/Makefile deleted file mode 100644 index ecfdb44ba..000000000 --- a/tools/parser/Makefile +++ /dev/null @@ -1,44 +0,0 @@ -EXTENSION?=txt -FORMAT?=DEFAULT -.PHONY: all parse clean raylib_api - - -raylib_parser: raylib_parser.c - cc raylib_parser.c -o raylib_parser - -raylib_api: ../../src/raylib.h raylib_parser - FORMAT=DEFAULT EXTENSION=txt $(MAKE) raylib_api.txt - FORMAT=JSON EXTENSION=json $(MAKE) raylib_api.json - FORMAT=XML EXTENSION=xml $(MAKE) raylib_api.xml - FORMAT=LUA EXTENSION=lua $(MAKE) raylib_api.lua - -raylib_api.$(EXTENSION): ../../src/raylib.h raylib_parser - ./raylib_parser -i ../../src/raylib.h -o raylib_api.$(EXTENSION) -f $(FORMAT) -d RLAPI - -raymath_api.$(EXTENSION): ../../src/raymath.h raylib_parser - ./raylib_parser -i ../../src/raymath.h -o raymath_api.$(EXTENSION) -f $(FORMAT) -d RMAPI - -rlgl_api.$(EXTENSION): ../../src/rlgl.h raylib_parser - ./raylib_parser -i ../../src/rlgl.h -o rlgl_api.$(EXTENSION) -f $(FORMAT) -d RLAPI -t "RLGL IMPLEMENTATION" - -reasings_api.$(EXTENSION): ../../examples/others/reasings.h raylib_parser - ./raylib_parser -i ../../examples/others/reasings.h -o reasings_api.$(EXTENSION) -f $(FORMAT) -d EASEDEF - -raygui_api.$(EXTENSION): ../raygui.h raylib_parser - ./raylib_parser -i ../raygui.h -o raygui_api.$(EXTENSION) -f $(FORMAT) -d RAYGUIAPI -t "RAYGUI IMPLEMENTATION" - -parse: raylib_api.$(EXTENSION) raymath_api.$(EXTENSION) rlgl_api.$(EXTENSION) raygui_api.$(EXTENSION) - - -# `make parse` (and therefore `make all) requires -# rmem.h, physac.h and raygui.h to exist in the correct directory -# API files for individual headers can be created likeso, provided the relevant header exists: -# FORMAT=JSON EXTENSION=json make raygui_api.json -all: raylib_parser - FORMAT=DEFAULT EXTENSION=txt $(MAKE) parse - FORMAT=JSON EXTENSION=json $(MAKE) parse - FORMAT=XML EXTENSION=xml $(MAKE) parse - FORMAT=LUA EXTENSION=lua $(MAKE) parse - -clean: - rm -f raylib_parser *.json *.txt *.xml *.lua diff --git a/tools/parser/LICENSE b/tools/rlparser/LICENSE similarity index 100% rename from tools/parser/LICENSE rename to tools/rlparser/LICENSE diff --git a/tools/rlparser/Makefile b/tools/rlparser/Makefile new file mode 100644 index 000000000..a645f7f41 --- /dev/null +++ b/tools/rlparser/Makefile @@ -0,0 +1,118 @@ +EXTENSION?=txt +FORMAT?=DEFAULT +.PHONY: all parse clean raylib_api + +# Determine PLATFORM_OS +# No uname.exe on MinGW!, but OS=Windows_NT on Windows! +# ifeq ($(UNAME),Msys) -> Windows +ifeq ($(OS),Windows_NT) + PLATFORM_OS = WINDOWS +else + UNAMEOS = $(shell uname) + ifeq ($(UNAMEOS),Linux) + PLATFORM_OS = LINUX + endif + ifeq ($(UNAMEOS),FreeBSD) + PLATFORM_OS = BSD + endif + ifeq ($(UNAMEOS),OpenBSD) + PLATFORM_OS = BSD + endif + ifeq ($(UNAMEOS),NetBSD) + PLATFORM_OS = BSD + endif + ifeq ($(UNAMEOS),DragonFly) + PLATFORM_OS = BSD + endif + ifeq ($(UNAMEOS),Darwin) + PLATFORM_OS = OSX + endif +endif + +# Define default C compiler: CC +#------------------------------------------------------------------------------------------------ +CC = gcc +ifeq ($(PLATFORM_OS),OSX) + # OSX default compiler + CC = clang +endif +ifeq ($(PLATFORM_OS),BSD) + # FreeBSD, OpenBSD, NetBSD, DragonFly default compiler + CC = clang +endif + +# Define default make program: MAKE +#------------------------------------------------------------------------------------------------ +MAKE ?= make +ifeq ($(PLATFORM_OS),WINDOWS) + MAKE = mingw32-make +endif + +# Define compiler flags: CFLAGS +#------------------------------------------------------------------------------------------------ +CFLAGS = -Wall -std=c99 +#CFLAGS += -Wextra -Wmissing-prototypes -Wstrict-prototypes + +ifeq ($(BUILD_MODE),DEBUG) + CFLAGS += -g -D_DEBUG +else + ifeq ($(PLATFORM_OS),OSX) + CFLAGS += -O2 + else + CFLAGS += -s -O2 + endif +endif +ifeq ($(PLATFORM_OS),WINDOWS) + # NOTE: The resource .rc file contains windows executable icon and properties + CFLAGS += rlparser.rc.data +endif + +# Define processes to execute +#------------------------------------------------------------------------------------------------ +# rlparser compilation +rlparser: rlparser.c + $(CC) rlparser.c -o rlparser $(CFLAGS) + +# rlparser execution: [raylib.h] parse, generating some output files +raylib_api: ../../src/raylib.h rlparser + FORMAT=DEFAULT EXTENSION=txt $(MAKE) raylib_api.txt + FORMAT=JSON EXTENSION=json $(MAKE) raylib_api.json + FORMAT=XML EXTENSION=xml $(MAKE) raylib_api.xml + FORMAT=LUA EXTENSION=lua $(MAKE) raylib_api.lua + +# rlparser execution: [raylib.h] parse, generating some output files +raylib_api.$(EXTENSION): ../../src/raylib.h rlparser + ./rlparser -i ../../src/raylib.h -o raylib_api.$(EXTENSION) -f $(FORMAT) -d RLAPI + +# rlparser execution: [rlgl.h] parse, generating some output files +rlgl_api.$(EXTENSION): ../../src/rlgl.h rlparser + ./rlparser -i ../../src/rlgl.h -o rlgl_api.$(EXTENSION) -f $(FORMAT) -d RLAPI -t "RLGL IMPLEMENTATION" + +# rlparser execution: [raymath.h] parse, generating some output files +raymath_api.$(EXTENSION): ../../src/raymath.h rlparser + ./rlparser -i ../../src/raymath.h -o raymath_api.$(EXTENSION) -f $(FORMAT) -d RMAPI + +# rlparser execution: [reasings.h] parse, generating some output files +reasings_api.$(EXTENSION): ../../examples/others/reasings.h rlparser + ./rlparser -i ../../examples/others/reasings.h -o reasings_api.$(EXTENSION) -f $(FORMAT) -d EASEDEF + +# rlparser execution: [raygui.h] parse, generating some output files +raygui_api.$(EXTENSION): ../raygui.h rlparser + ./rlparser -i ../raygui.h -o raygui_api.$(EXTENSION) -f $(FORMAT) -d RAYGUIAPI -t "RAYGUI IMPLEMENTATION" + +# Target to generate required APIs output files +parse: raylib_api.$(EXTENSION) raymath_api.$(EXTENSION) rlgl_api.$(EXTENSION) raygui_api.$(EXTENSION) + +# "make parse" (and therefore "make all") requires +# raygui.h and reasings_api.h to exist in the correct directory +# API files for individual headers can be created likeso, provided the relevant header exists: +# FORMAT=JSON EXTENSION=json make raygui_api.json +all: rlparser + FORMAT=DEFAULT EXTENSION=txt $(MAKE) parse + FORMAT=JSON EXTENSION=json $(MAKE) parse + FORMAT=XML EXTENSION=xml $(MAKE) parse + FORMAT=LUA EXTENSION=lua $(MAKE) parse + +# Clean rlparser and generated output files +clean: + rm -f rlparser *.json *.txt *.xml *.lua diff --git a/tools/parser/README.md b/tools/rlparser/README.md similarity index 83% rename from tools/parser/README.md rename to tools/rlparser/README.md index 86cdfdd5b..0e4f9b739 100644 --- a/tools/parser/README.md +++ b/tools/rlparser/README.md @@ -1,4 +1,4 @@ -# raylib parser +# rlparser - raylib parser This parser scans [`raylib.h`](../src/raylib.h) to get information about `defines`, `structs`, `enums` and `functions`. All data is separated into parts, usually as strings. The following types are used for data: @@ -8,16 +8,16 @@ All data is separated into parts, usually as strings. The following types are us - `struct StructInfo` - `struct EnumInfo` -Check `raylib_parser.c` for details about those structs. +Check `rlparser.c` for details about those structs. ## Command Line ``` ////////////////////////////////////////////////////////////////////////////////// // // -// raylib API parser // +// rlparser - raylib header API parser // // // -// more info and bugs-report: github.com/raysan5/raylib/parser // +// more info and bugs-report: github.com/raysan5/raylib/tools/rlparser // // // // Copyright (c) 2021-2025 Ramon Santamaria (@raysan5) // // // @@ -25,7 +25,7 @@ Check `raylib_parser.c` for details about those structs. USAGE: - > raylib_parser [--help] [--input ] [--output ] [--format ] + > rlparser [--help] [--input ] [--output ] [--format ] OPTIONS: @@ -50,19 +50,19 @@ OPTIONS: EXAMPLES: - > raylib_parser --input raylib.h --output api.json + > rlparser --input raylib.h --output api.json Process to generate - > raylib_parser --output raylib_data.info --format XML + > rlparser --output raylib_data.info --format XML Process to generate as XML text data - > raylib_parser --input raymath.h --output raymath_data.info --format XML --define RMAPI + > rlparser --input raymath.h --output raymath_data.info --format XML --define RMAPI Process to generate as XML text data ``` ## Constraints -This parser is specifically designed to work with raylib.h, so, it has some constraints: +`rlparser` is specifically designed to work with `raylib.h`, so, it has some constraints: - Functions are expected as a single line with the following structure: ``` @@ -91,7 +91,7 @@ This parser is specifically designed to work with raylib.h, so, it has some cons ``` _NOTE: For enums, multiple options are supported:_ - + - If value is not provided, ( + 1) is assigned - Value description can be provided or not @@ -103,5 +103,7 @@ This parser **does not require `` library**, all data is parsed direct ### LICENSE: zlib/libpng -raylib-parser is licensed under an unmodified zlib/libpng license, which is an OSI-certified, BSD-like license that allows static linking with closed source software. Check [LICENSE](LICENSE) for further details. +raylib-parser is licensed under an unmodified zlib/libpng license, which is an OSI-certified, BSD-like license that allows static linking with closed source software. + +Check [LICENSE](LICENSE) for further details. diff --git a/tools/parser/output/raylib_api.json b/tools/rlparser/output/raylib_api.json similarity index 100% rename from tools/parser/output/raylib_api.json rename to tools/rlparser/output/raylib_api.json diff --git a/tools/parser/output/raylib_api.lua b/tools/rlparser/output/raylib_api.lua similarity index 100% rename from tools/parser/output/raylib_api.lua rename to tools/rlparser/output/raylib_api.lua diff --git a/tools/parser/output/raylib_api.txt b/tools/rlparser/output/raylib_api.txt similarity index 100% rename from tools/parser/output/raylib_api.txt rename to tools/rlparser/output/raylib_api.txt diff --git a/tools/parser/output/raylib_api.xml b/tools/rlparser/output/raylib_api.xml similarity index 100% rename from tools/parser/output/raylib_api.xml rename to tools/rlparser/output/raylib_api.xml diff --git a/tools/parser/raylib_parser.c b/tools/rlparser/rlparser.c similarity index 99% rename from tools/parser/raylib_parser.c rename to tools/rlparser/rlparser.c index 4b5fe1625..2432af4af 100644 --- a/tools/parser/raylib_parser.c +++ b/tools/rlparser/rlparser.c @@ -1,28 +1,28 @@ /********************************************************************************************** - raylib API parser + rlparser - raylib header API parser, extracts API information as separate tokens This parser scans raylib.h to get API information about defines, structs, aliases, enums, callbacks and functions. All data is divided into pieces, usually as strings. The following types are used for data: - - struct DefineInfo - struct StructInfo - struct AliasInfo - struct EnumInfo - struct FunctionInfo + + WARNING: This parser is specifically designed to work with raylib.h, and has some contraints + in that regards. Still, it can also work with other header files that follow same file structure + conventions as raylib.h: rlgl.h, raymath.h, raygui.h, reasings.h CONSTRAINTS: - This parser is specifically designed to work with raylib.h, so, it has some constraints: - Functions are expected as a single line with the following structure: - ( , ); - Be careful with functions broken into several lines, it breaks the process! + WARNING: Be careful with functions broken into several lines, it breaks the process! - Structures are expected as several lines with the following form: - typedef struct { ; @@ -31,7 +31,6 @@ } ; - Enums are expected as several lines with the following form: - typedef enum { = , @@ -45,7 +44,6 @@ - Value description can be provided or not OTHER NOTES: - - This parser could work with other C header files if mentioned constraints are followed. - This parser does not require library, all data is parsed directly from char buffers. diff --git a/tools/rlparser/rlparser.ico b/tools/rlparser/rlparser.ico new file mode 100644 index 0000000000000000000000000000000000000000..37f2af6b65b7ad4ad7a2c6c35b6db7d447d17b69 GIT binary patch literal 2922 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 X_yVq Date: Sun, 5 Oct 2025 04:10:53 +1030 Subject: [PATCH 086/167] Updated miniaudio.h - v0.11.23 (#5234) Co-authored-by: pyrokn8 <202429796+pyrokn8@users.noreply.github.com> --- src/external/miniaudio.h | 6089 ++++++++++++++++++++++++++------------ 1 file changed, 4135 insertions(+), 1954 deletions(-) diff --git a/src/external/miniaudio.h b/src/external/miniaudio.h index c74bebeb3..b7e7a54dd 100644 --- a/src/external/miniaudio.h +++ b/src/external/miniaudio.h @@ -1,6 +1,6 @@ /* Audio playback and capture library. Choice of public domain or MIT-0. See license statements at the end of this file. -miniaudio - v0.11.22 - 2025-02-24 +miniaudio - v0.11.23 - 2025-09-11 David Reid - mackron@gmail.com @@ -12,18 +12,10 @@ GitHub: https://github.com/mackron/miniaudio /* 1. Introduction =============== -To use miniaudio, include "miniaudio.h": - - ```c - #include "miniaudio.h" - ``` - -The implementation is contained in "miniaudio.c". Just compile this like any other source file. You -can include miniaudio.c if you want to compile your project as a single translation unit: - - ```c - #include "miniaudio.c" - ``` +To use miniaudio, just include "miniaudio.h" like any other header and add "miniaudio.c" to your +source tree. If you don't want to add it to your source tree you can compile and link to it like +any other library. Note that ABI compatibility is not guaranteed between versions, even with bug +fix releases, so take care if compiling as a shared object. miniaudio includes both low level and high level APIs. The low level API is good for those who want to do all of their mixing themselves and only require a light weight interface to the underlying @@ -303,7 +295,7 @@ The engine encapsulates both the resource manager and the node graph to create a use high level API. The resource manager and node graph APIs are covered in more later sections of this manual. -The code below shows how you can initialize an engine using it's default configuration. +The code below shows how you can initialize an engine using its default configuration. ```c ma_result result; @@ -391,7 +383,7 @@ Sounds are not started by default. Start a sound with `ma_sound_start()` and sto `ma_sound_stop()`. When a sound is stopped, it is not rewound to the start. Use `ma_sound_seek_to_pcm_frame(&sound, 0)` to seek back to the start of a sound. By default, starting and stopping sounds happens immediately, but sometimes it might be convenient to schedule the sound -the be started and/or stopped at a specific time. This can be done with the following functions: +to be started and/or stopped at a specific time. This can be done with the following functions: ```c ma_sound_set_start_time_in_pcm_frames() @@ -463,6 +455,11 @@ is at the end, use `ma_sound_at_end()`. Looping of a sound can be controlled wit miniaudio should work cleanly out of the box without the need to download or install any dependencies. See below for platform-specific details. +This library has been designed to be added directly to your source tree which is the preferred way +of using it, but you can compile it as a normal library if that's your preference. Be careful if +compiling as a shared object because miniaudio is not ABI compatible between any release, including +bug fix releases. It's recommended you link statically. + Note that GCC and Clang require `-msse2`, `-mavx2`, etc. for SIMD optimizations. If you get errors about undefined references to `__sync_val_compare_and_swap_8`, `__atomic_load_8`, @@ -532,7 +529,7 @@ you'll need to disable run-time linking with `MA_NO_RUNTIME_LINKING` and link wi The Emscripten build emits Web Audio JavaScript directly and should compile cleanly out of the box. You cannot use `-std=c*` compiler flags, nor `-ansi`. -You can enable the use of AudioWorkets by defining `MA_ENABLE_AUDIO_WORKLETS` and then compiling +You can enable the use of AudioWorklets by defining `MA_ENABLE_AUDIO_WORKLETS` and then compiling with the following options: -sAUDIO_WORKLET=1 -sWASM_WORKERS=1 -sASYNCIFY @@ -881,7 +878,7 @@ read data within a certain range of the underlying data. To do this you can use This is useful if you have a sound bank where many sounds are stored in the same file and you want the data source to only play one of those sub-sounds. Note that once the range is set, everything -that takes a position, such as cursors and loop points, should always be relatvie to the start of +that takes a position, such as cursors and loop points, should always be relative to the start of the range. When the range is set, any previously defined loop point will be reset. Custom loop points can also be used with data sources. By default, data sources will loop after @@ -889,7 +886,7 @@ they reach the end of the data source, but if you need to loop at a specific loc the following: ```c - result = ma_data_set_loop_point_in_pcm_frames(pDataSource, loopBegInFrames, loopEndInFrames); + result = ma_data_source_set_loop_point_in_pcm_frames(pDataSource, loopBegInFrames, loopEndInFrames); if (result != MA_SUCCESS) { return result; // Failed to set the loop point. } @@ -3750,7 +3747,7 @@ extern "C" { #define MA_VERSION_MAJOR 0 #define MA_VERSION_MINOR 11 -#define MA_VERSION_REVISION 22 +#define MA_VERSION_REVISION 23 #define MA_VERSION_STRING MA_XSTRINGIFY(MA_VERSION_MAJOR) "." MA_XSTRINGIFY(MA_VERSION_MINOR) "." MA_XSTRINGIFY(MA_VERSION_REVISION) #if defined(_MSC_VER) && !defined(__clang__) @@ -3857,6 +3854,8 @@ typedef ma_uint16 wchar_t; #define MA_SIZE_MAX 0xFFFFFFFF /* When SIZE_MAX is not defined by the standard library just default to the maximum 32-bit unsigned integer. */ #endif +#define MA_UINT64_MAX (((ma_uint64)0xFFFFFFFF << 32) | (ma_uint64)0xFFFFFFFF) /* Weird shifting syntax is for VC6 compatibility. */ + /* Platform/backend detection. */ #if defined(_WIN32) || defined(__COSMOPOLITAN__) @@ -3865,29 +3864,55 @@ typedef ma_uint16 wchar_t; #define MA_WIN32_UWP #elif defined(WINAPI_FAMILY) && (defined(WINAPI_FAMILY_GAMES) && WINAPI_FAMILY == WINAPI_FAMILY_GAMES) #define MA_WIN32_GDK + #elif defined(NXDK) + #define MA_WIN32_NXDK #else #define MA_WIN32_DESKTOP #endif + + /* The original Xbox. */ + #if defined(NXDK) /* <-- Add other Xbox compiler toolchains here, and then add a toolchain-specific define in case we need to discriminate between them later. */ + #define MA_XBOX + + #if defined(NXDK) + #define MA_XBOX_NXDK + #endif + #endif #endif -#if !defined(_WIN32) /* If it's not Win32, assume POSIX. */ +#if defined(__MSDOS__) || defined(MSDOS) || defined(_MSDOS) || defined(__DOS__) + #define MA_DOS + + /* No threading allowed on DOS. */ + #ifndef MA_NO_THREADING + #define MA_NO_THREADING + #endif + + /* No runtime linking allowed on DOS. */ + #ifndef MA_NO_RUNTIME_LINKING + #define MA_NO_RUNTIME_LINKING + #endif +#endif +#if !defined(MA_WIN32) && !defined(MA_DOS) /* If it's not Win32, assume POSIX. */ #define MA_POSIX - /* - Use the MA_NO_PTHREAD_IN_HEADER option at your own risk. This is intentionally undocumented. - You can use this to avoid including pthread.h in the header section. The downside is that it - results in some fixed sized structures being declared for the various types that are used in - miniaudio. The risk here is that these types might be too small for a given platform. This - risk is yours to take and no support will be offered if you enable this option. - */ - #ifndef MA_NO_PTHREAD_IN_HEADER - #include /* Unfortunate #include, but needed for pthread_t, pthread_mutex_t and pthread_cond_t types. */ - typedef pthread_t ma_pthread_t; - typedef pthread_mutex_t ma_pthread_mutex_t; - typedef pthread_cond_t ma_pthread_cond_t; - #else - typedef ma_uintptr ma_pthread_t; - typedef union ma_pthread_mutex_t { char __data[40]; ma_uint64 __alignment; } ma_pthread_mutex_t; - typedef union ma_pthread_cond_t { char __data[48]; ma_uint64 __alignment; } ma_pthread_cond_t; + #if !defined(MA_NO_THREADING) + /* + Use the MA_NO_PTHREAD_IN_HEADER option at your own risk. This is intentionally undocumented. + You can use this to avoid including pthread.h in the header section. The downside is that it + results in some fixed sized structures being declared for the various types that are used in + miniaudio. The risk here is that these types might be too small for a given platform. This + risk is yours to take and no support will be offered if you enable this option. + */ + #ifndef MA_NO_PTHREAD_IN_HEADER + #include /* Unfortunate #include, but needed for pthread_t, pthread_mutex_t and pthread_cond_t types. */ + typedef pthread_t ma_pthread_t; + typedef pthread_mutex_t ma_pthread_mutex_t; + typedef pthread_cond_t ma_pthread_cond_t; + #else + typedef ma_uintptr ma_pthread_t; + typedef union ma_pthread_mutex_t { char __data[40]; ma_uint64 __alignment; } ma_pthread_mutex_t; + typedef union ma_pthread_cond_t { char __data[48]; ma_uint64 __alignment; } ma_pthread_cond_t; + #endif #endif #if defined(__unix__) @@ -3914,8 +3939,11 @@ typedef ma_uint16 wchar_t; #if defined(__PROSPERO__) #define MA_PROSPERO #endif - #if defined(__NX__) - #define MA_NX + #if defined(__3DS__) + #define MA_3DS + #endif + #if defined(__SWITCH__) || defined(__NX__) + #define MA_SWITCH #endif #if defined(__BEOS__) || defined(__HAIKU__) #define MA_BEOS @@ -3925,12 +3953,13 @@ typedef ma_uint16 wchar_t; #endif #endif -#if defined(__has_c_attribute) - #if __has_c_attribute(fallthrough) - #define MA_FALLTHROUGH [[fallthrough]] - #endif +#if !defined(MA_FALLTHROUGH) && defined(__cplusplus) && __cplusplus >= 201703L + #define MA_FALLTHROUGH [[fallthrough]] #endif -#if !defined(MA_FALLTHROUGH) && defined(__has_attribute) && (defined(__clang__) || defined(__GNUC__)) +#if !defined(MA_FALLTHROUGH) && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202000L + #define MA_FALLTHROUGH [[fallthrough]] +#endif +#if !defined(MA_FALLTHROUGH) && defined(__has_attribute) #if __has_attribute(fallthrough) #define MA_FALLTHROUGH __attribute__((fallthrough)) #endif @@ -3967,7 +3996,7 @@ typedef ma_uint16 wchar_t; #define MA_NO_INLINE __attribute__((noinline)) #else #define MA_INLINE MA_GNUC_INLINE_HINT - #define MA_NO_INLINE __attribute__((noinline)) + #define MA_NO_INLINE #endif #elif defined(__WATCOMC__) #define MA_INLINE __inline @@ -4350,7 +4379,7 @@ typedef struct typedef struct { - ma_int32 state; + ma_uint32 state; } ma_lcg; @@ -6569,7 +6598,7 @@ This section contains the APIs for device playback and capture. Here is where yo ************************************************************************************************************************************************************/ #ifndef MA_NO_DEVICE_IO /* Some backends are only supported on certain platforms. */ -#if defined(MA_WIN32) +#if defined(MA_WIN32) && !defined(MA_XBOX) #define MA_SUPPORT_WASAPI #if defined(MA_WIN32_DESKTOP) /* DirectSound and WinMM backends are only supported on desktops. */ @@ -7426,6 +7455,7 @@ struct ma_context ma_proc snd_pcm_hw_params_set_rate_resample; ma_proc snd_pcm_hw_params_set_rate; ma_proc snd_pcm_hw_params_set_rate_near; + ma_proc snd_pcm_hw_params_set_rate_minmax; ma_proc snd_pcm_hw_params_set_buffer_size_near; ma_proc snd_pcm_hw_params_set_periods_near; ma_proc snd_pcm_hw_params_set_access; @@ -7986,6 +8016,7 @@ struct ma_device /*AAudioStream**/ ma_ptr pStreamPlayback; /*AAudioStream**/ ma_ptr pStreamCapture; ma_mutex rerouteLock; + ma_atomic_bool32 isTearingDown; ma_aaudio_usage usage; ma_aaudio_content_type contentType; ma_aaudio_input_preset inputPreset; @@ -11255,7 +11286,7 @@ typedef struct ma_log* pLog; /* When set to NULL, will use the context's log. */ ma_uint32 listenerCount; /* Must be between 1 and MA_ENGINE_MAX_LISTENERS. */ ma_uint32 channels; /* The number of channels to use when mixing and spatializing. When set to 0, will use the native channel count of the device. */ - ma_uint32 sampleRate; /* The sample rate. When set to 0 will use the native channel count of the device. */ + ma_uint32 sampleRate; /* The sample rate. When set to 0 will use the native sample rate of the device. */ ma_uint32 periodSizeInFrames; /* If set to something other than 0, updates will always be exactly this size. The underlying device may be a different size, but from the perspective of the mixer that won't matter.*/ ma_uint32 periodSizeInMilliseconds; /* Used if periodSizeInFrames is unset. */ ma_uint32 gainSmoothTimeInFrames; /* The number of frames to interpolate the gain of spatialized sounds across. If set to 0, will use gainSmoothTimeInMilliseconds. */ @@ -11419,11 +11450,11 @@ MA_API ma_bool32 ma_sound_is_looping(const ma_sound* pSound); MA_API ma_bool32 ma_sound_at_end(const ma_sound* pSound); MA_API ma_result ma_sound_seek_to_pcm_frame(ma_sound* pSound, ma_uint64 frameIndex); /* Just a wrapper around ma_data_source_seek_to_pcm_frame(). */ MA_API ma_result ma_sound_seek_to_second(ma_sound* pSound, float seekPointInSeconds); /* Abstraction to ma_sound_seek_to_pcm_frame() */ -MA_API ma_result ma_sound_get_data_format(ma_sound* pSound, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap); -MA_API ma_result ma_sound_get_cursor_in_pcm_frames(ma_sound* pSound, ma_uint64* pCursor); -MA_API ma_result ma_sound_get_length_in_pcm_frames(ma_sound* pSound, ma_uint64* pLength); -MA_API ma_result ma_sound_get_cursor_in_seconds(ma_sound* pSound, float* pCursor); -MA_API ma_result ma_sound_get_length_in_seconds(ma_sound* pSound, float* pLength); +MA_API ma_result ma_sound_get_data_format(const ma_sound* pSound, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap); +MA_API ma_result ma_sound_get_cursor_in_pcm_frames(const ma_sound* pSound, ma_uint64* pCursor); +MA_API ma_result ma_sound_get_length_in_pcm_frames(const ma_sound* pSound, ma_uint64* pLength); +MA_API ma_result ma_sound_get_cursor_in_seconds(const ma_sound* pSound, float* pCursor); +MA_API ma_result ma_sound_get_length_in_seconds(const ma_sound* pSound, float* pLength); MA_API ma_result ma_sound_set_end_callback(ma_sound* pSound, ma_sound_end_proc callback, void* pUserData); MA_API ma_result ma_sound_group_init(ma_engine* pEngine, ma_uint32 flags, ma_sound_group* pParentGroup, ma_sound_group* pGroup); @@ -11544,17 +11575,23 @@ IMPLEMENTATION #endif #if !defined(MA_WIN32) -#include -#include /* select() (used for ma_sleep()). */ -#include + #if !defined(MA_NO_THREADING) + #include + #include /* For pthreads. */ + #endif + + #include /* select() (used for ma_sleep()). */ + #include /* For nanosleep() */ + #include #endif -#ifdef MA_NX -#include /* For nanosleep() */ +/* For fstat(), etc. */ +#if defined(MA_XBOX_NXDK) + #include /* Suggestion for NXDK: Add a sys/stat.h wrapper for compatibility. */ +#else + #include #endif -#include /* For fstat(), etc. */ - #ifdef MA_EMSCRIPTEN #include #endif @@ -11861,7 +11898,7 @@ static MA_INLINE ma_bool32 ma_has_neon(void) #endif #ifndef MA_RESTRICT - #if defined(__clang__) || defined(__GNUC__) || defined(_MSC_VER) + #if defined(__clang__) || defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95))) #define MA_RESTRICT __restrict #else #define MA_RESTRICT @@ -11955,7 +11992,7 @@ static void ma_sleep__posix(ma_uint32 milliseconds) (void)milliseconds; MA_ASSERT(MA_FALSE); /* The Emscripten build should never sleep. */ #else - #if (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309L) || defined(MA_NX) + #if (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309L) || defined(MA_SWITCH) struct timespec ts; ts.tv_sec = milliseconds / 1000; ts.tv_nsec = milliseconds % 1000 * 1000000; @@ -11997,7 +12034,7 @@ static MA_INLINE void ma_yield(void) #endif #endif #else - __asm__ __volatile__ ("pause"); + __asm__ __volatile__ ("rep; nop"); #endif #elif (defined(__arm__) && defined(__ARM_ARCH) && __ARM_ARCH >= 7) || defined(_M_ARM64) || (defined(_M_ARM) && _M_ARM >= 7) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6T2__) /* ARM */ @@ -12020,7 +12057,7 @@ static MA_INLINE unsigned int ma_disable_denormals(void) { unsigned int prevState; - #if defined(_MSC_VER) + #if defined(_MSC_VER) && !defined(MA_XBOX_NXDK) { /* Older versions of Visual Studio don't support the "safe" versions of _controlfp_s(). I don't @@ -12043,7 +12080,7 @@ static MA_INLINE unsigned int ma_disable_denormals(void) } #elif defined(MA_X86) || defined(MA_X64) { - #if defined(__SSE2__) && !(defined(__TINYC__) || defined(__WATCOMC__) || defined(__COSMOPOLITAN__)) /* <-- Add compilers that lack support for _mm_getcsr() and _mm_setcsr() to this list. */ + #if defined(MA_SUPPORT_SSE2) && defined(__SSE2__) && !(defined(__TINYC__) || defined(__WATCOMC__) || defined(__COSMOPOLITAN__)) /* <-- Add compilers that lack support for _mm_getcsr() and _mm_setcsr() to this list. */ { prevState = _mm_getcsr(); _mm_setcsr(prevState | MA_MM_DENORMALS_ZERO_MASK | MA_MM_FLUSH_ZERO_MASK); @@ -12067,7 +12104,7 @@ static MA_INLINE unsigned int ma_disable_denormals(void) static MA_INLINE void ma_restore_denormals(unsigned int prevState) { - #if defined(_MSC_VER) + #if defined(_MSC_VER) && !defined(MA_XBOX_NXDK) { /* Older versions of Visual Studio do not support _controlfp_s(). See ma_disable_denormals(). */ #if _MSC_VER <= 1200 @@ -12083,7 +12120,7 @@ static MA_INLINE void ma_restore_denormals(unsigned int prevState) } #elif defined(MA_X86) || defined(MA_X64) { - #if defined(__SSE2__) && !(defined(__TINYC__) || defined(__WATCOMC__) || defined(__COSMOPOLITAN__)) /* <-- Add compilers that lack support for _mm_getcsr() and _mm_setcsr() to this list. */ + #if defined(MA_SUPPORT_SSE2) && defined(__SSE2__) && !(defined(__TINYC__) || defined(__WATCOMC__) || defined(__COSMOPOLITAN__)) /* <-- Add compilers that lack support for _mm_getcsr() and _mm_setcsr() to this list. */ { _mm_setcsr(prevState); } @@ -12719,6 +12756,29 @@ MA_API MA_NO_INLINE int ma_strcmp(const char* str1, const char* str2) return ((unsigned char*)str1)[0] - ((unsigned char*)str2)[0]; } +MA_API MA_NO_INLINE int ma_wcscmp(const wchar_t* str1, const wchar_t* str2) +{ + if (str1 == str2) return 0; + + /* These checks differ from the standard implementation. It's not important, but I prefer it just for sanity. */ + if (str1 == NULL) return -1; + if (str2 == NULL) return 1; + + for (;;) { + if (str1[0] == L'\0') { + break; + } + if (str1[0] != str2[0]) { + break; + } + + str1 += 1; + str2 += 1; + } + + return ((unsigned short*)str1)[0] - ((unsigned short*)str2)[0]; +} + MA_API MA_NO_INLINE int ma_strappend(char* dst, size_t dstSize, const char* srcA, const char* srcB) { int result; @@ -12736,6 +12796,22 @@ MA_API MA_NO_INLINE int ma_strappend(char* dst, size_t dstSize, const char* srcA return result; } +MA_API MA_NO_INLINE size_t ma_wcslen(const wchar_t* str) +{ + const wchar_t* end; + + if (str == NULL) { + return 0; + } + + end = str; + while (end[0] != '\0') { + end += 1; + } + + return end - str; +} + MA_API MA_NO_INLINE char* ma_copy_string(const char* src, const ma_allocation_callbacks* pAllocationCallbacks) { size_t sz; @@ -12758,7 +12834,7 @@ MA_API MA_NO_INLINE char* ma_copy_string(const char* src, const ma_allocation_ca MA_API MA_NO_INLINE wchar_t* ma_copy_string_w(const wchar_t* src, const ma_allocation_callbacks* pAllocationCallbacks) { - size_t sz = wcslen(src)+1; + size_t sz = ma_wcslen(src)+1; wchar_t* dst = (wchar_t*)ma_malloc(sz * sizeof(*dst), pAllocationCallbacks); if (dst == NULL) { return NULL; @@ -13189,7 +13265,7 @@ MA_API ma_result ma_fopen(FILE** ppFile, const char* pFilePath, const char* pOpe return MA_INVALID_ARGS; } -#if defined(_MSC_VER) && _MSC_VER >= 1400 +#if (defined(_MSC_VER) && _MSC_VER >= 1400) && !defined(MA_XBOX_NXDK) err = fopen_s(ppFile, pFilePath, pOpenMode); if (err != 0) { return ma_result_from_errno(err); @@ -13231,7 +13307,7 @@ _wfopen() isn't always available in all compilation environments. This can be reviewed as compatibility issues arise. The preference is to use _wfopen_s() and _wfopen() as opposed to the wcsrtombs() fallback, so if you notice your compiler not detecting this properly I'm happy to look at adding support. */ -#if defined(_WIN32) +#if defined(_WIN32) && !defined(MA_XBOX_NXDK) #if defined(_MSC_VER) || defined(__MINGW64__) || (!defined(__STRICT_ANSI__) && !defined(_NO_EXT_KEYS)) #define MA_HAS_WFOPEN #endif @@ -13247,29 +13323,34 @@ MA_API ma_result ma_wfopen(FILE** ppFile, const wchar_t* pFilePath, const wchar_ return MA_INVALID_ARGS; } -#if defined(MA_HAS_WFOPEN) + #if defined(MA_HAS_WFOPEN) { /* Use _wfopen() on Windows. */ - #if defined(_MSC_VER) && _MSC_VER >= 1400 - errno_t err = _wfopen_s(ppFile, pFilePath, pOpenMode); - if (err != 0) { - return ma_result_from_errno(err); + #if defined(_MSC_VER) && _MSC_VER >= 1400 + { + errno_t err = _wfopen_s(ppFile, pFilePath, pOpenMode); + if (err != 0) { + return ma_result_from_errno(err); + } } - #else - *ppFile = _wfopen(pFilePath, pOpenMode); - if (*ppFile == NULL) { - return ma_result_from_errno(errno); + #else + { + *ppFile = _wfopen(pFilePath, pOpenMode); + if (*ppFile == NULL) { + return ma_result_from_errno(errno); + } } - #endif + #endif + (void)pAllocationCallbacks; } -#else - /* - Use fopen() on anything other than Windows. Requires a conversion. This is annoying because fopen() is locale specific. The only real way I can - think of to do this is with wcsrtombs(). Note that wcstombs() is apparently not thread-safe because it uses a static global mbstate_t object for - maintaining state. I've checked this with -std=c89 and it works, but if somebody get's a compiler error I'll look into improving compatibility. - */ + #elif !defined(MA_XBOX_NXDK) && !defined(MA_DOS) /* If your compiler does not support wcsrtombs(), add it here. */ { + /* + Use fopen() on anything other than Windows. Requires a conversion. This is annoying because fopen() is locale specific. The only real way I can + think of to do this is with wcsrtombs(). Note that wcstombs() is apparently not thread-safe because it uses a static global mbstate_t object for + maintaining state. I've checked this with -std=c89 and it works, but if somebody get's a compiler error I'll look into improving compatibility. + */ mbstate_t mbs; size_t lenMB; const wchar_t* pFilePathTemp = pFilePath; @@ -13310,11 +13391,16 @@ MA_API ma_result ma_wfopen(FILE** ppFile, const wchar_t* pFilePath, const wchar_ ma_free(pFilePathMB, pAllocationCallbacks); } + #else + { + /* Getting here means there is no way to open the file with a wide character string. */ + *ppFile = NULL; + } + #endif if (*ppFile == NULL) { return MA_ERROR; } -#endif return MA_SUCCESS; } @@ -13323,7 +13409,7 @@ MA_API ma_result ma_wfopen(FILE** ppFile, const wchar_t* pFilePath, const wchar_ static MA_INLINE void ma_copy_memory_64(void* dst, const void* src, ma_uint64 sizeInBytes) { -#if 0xFFFFFFFFFFFFFFFF <= MA_SIZE_MAX +#if MA_SIZE_MAX > 0xFFFFFFFF MA_COPY_MEMORY(dst, src, (size_t)sizeInBytes); #else while (sizeInBytes > 0) { @@ -13343,7 +13429,7 @@ static MA_INLINE void ma_copy_memory_64(void* dst, const void* src, ma_uint64 si static MA_INLINE void ma_zero_memory_64(void* dst, ma_uint64 sizeInBytes) { -#if 0xFFFFFFFFFFFFFFFF <= MA_SIZE_MAX +#if MA_SIZE_MAX > 0xFFFFFFFF MA_ZERO_MEMORY(dst, (size_t)sizeInBytes); #else while (sizeInBytes > 0) { @@ -13472,6 +13558,18 @@ static ma_result ma_allocation_callbacks_init_copy(ma_allocation_callbacks* pDst Logging **************************************************************************************************************************************************************/ +#ifndef ma_va_copy + #if !defined(_MSC_VER) || _MSC_VER >= 1800 + #if (defined(__GNUC__) && __GNUC__ < 3) + #define ma_va_copy(dst, src) ((dst) = (src)) /* This is untested. Not sure if this is correct for old GCC. */ + #else + #define ma_va_copy(dst, src) va_copy((dst), (src)) + #endif + #else + #define ma_va_copy(dst, src) ((dst) = (src)) + #endif +#endif + MA_API const char* ma_log_level_to_string(ma_uint32 logLevel) { switch (logLevel) @@ -13712,9 +13810,15 @@ MA_API ma_result ma_log_postv(ma_log* pLog, ma_uint32 level, const char* pFormat int length; char pFormattedMessageStack[1024]; char* pFormattedMessageHeap = NULL; + va_list args2; /* First try formatting into our fixed sized stack allocated buffer. If this is too small we'll fallback to a heap allocation. */ - length = vsnprintf(pFormattedMessageStack, sizeof(pFormattedMessageStack), pFormat, args); + ma_va_copy(args2, args); + { + length = vsnprintf(pFormattedMessageStack, sizeof(pFormattedMessageStack), pFormat, args2); + } + va_end(args2); + if (length < 0) { return MA_INVALID_OPERATION; /* An error occurred when trying to convert the buffer. */ } @@ -13755,17 +13859,10 @@ MA_API ma_result ma_log_postv(ma_log* pLog, ma_uint32 level, const char* pFormat char* pFormattedMessage = NULL; va_list args2; - #if _MSC_VER >= 1800 + ma_va_copy(args2, args); { - va_copy(args2, args); + formattedLen = ma_vscprintf(&pLog->allocationCallbacks, pFormat, args2); } - #else - { - args2 = args; - } - #endif - - formattedLen = ma_vscprintf(&pLog->allocationCallbacks, pFormat, args2); va_end(args2); if (formattedLen <= 0) { @@ -13964,7 +14061,7 @@ miniaudio's purposes. #define MA_LCG_A 48271 #define MA_LCG_C 0 -static ma_lcg g_maLCG = {MA_DEFAULT_LCG_SEED}; /* Non-zero initial seed. Use ma_seed() to use an explicit seed. */ +static ma_lcg g_maLCG = {MA_DEFAULT_LCG_SEED}; /* Non-zero initial seed. Use ma_lcg_seed() to use an explicit seed. */ static MA_INLINE void ma_lcg_seed(ma_lcg* pLCG, ma_int32 seed) { @@ -14013,7 +14110,7 @@ static MA_INLINE ma_int32 ma_lcg_rand_range_s32(ma_lcg* pLCG, ma_int32 lo, ma_in } - +#if 0 /* Currently unused. */ static MA_INLINE void ma_seed(ma_int32 seed) { ma_lcg_seed(&g_maLCG, seed); @@ -14038,6 +14135,7 @@ static MA_INLINE float ma_rand_f32(void) { return ma_lcg_rand_f32(&g_maLCG); } +#endif static MA_INLINE float ma_rand_range_f32(float lo, float hi) { @@ -14097,6 +14195,7 @@ Atomics **************************************************************************************************************************************************************/ /* c89atomic.h begin */ #ifndef ma_atomic_h +#define ma_atomic_h #if defined(__cplusplus) extern "C" { #endif @@ -14108,11 +14207,40 @@ extern "C" { #endif #endif typedef int ma_atomic_memory_order; -#define MA_ATOMIC_HAS_8 -#define MA_ATOMIC_HAS_16 -#define MA_ATOMIC_HAS_32 -#define MA_ATOMIC_HAS_64 -#if (defined(_MSC_VER) ) || defined(__WATCOMC__) || defined(__DMC__) +#if !defined(MA_ATOMIC_MODERN_MSVC) && \ + !defined(MA_ATOMIC_LEGACY_MSVC) && \ + !defined(MA_ATOMIC_LEGACY_MSVC_ASM) && \ + !defined(MA_ATOMIC_MODERN_GCC) && \ + !defined(MA_ATOMIC_LEGACY_GCC) && \ + !defined(MA_ATOMIC_LEGACY_GCC_ASM) + #if defined(_MSC_VER) || defined(__WATCOMC__) || defined(__DMC__) || defined(__BORLANDC__) + #if (defined(_MSC_VER) && _MSC_VER > 1600) + #define MA_ATOMIC_MODERN_MSVC + #else + #if defined(MA_X64) + #define MA_ATOMIC_LEGACY_MSVC + #else + #define MA_ATOMIC_LEGACY_MSVC_ASM + #endif + #endif + #elif (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))) || defined(__clang__) + #define MA_ATOMIC_MODERN_GCC + #else + #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) + #define MA_ATOMIC_LEGACY_GCC + #else + #define MA_ATOMIC_LEGACY_GCC_ASM + #endif + #endif +#endif +#if defined(MA_ATOMIC_MODERN_MSVC) || defined(MA_ATOMIC_LEGACY_MSVC) + #include + #define ma_atomic_memory_order_relaxed 1 + #define ma_atomic_memory_order_consume 2 + #define ma_atomic_memory_order_acquire 3 + #define ma_atomic_memory_order_release 4 + #define ma_atomic_memory_order_acq_rel 5 + #define ma_atomic_memory_order_seq_cst 6 #define MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, intrin, ma_atomicType, msvcType) \ ma_atomicType result; \ switch (order) \ @@ -14138,720 +14266,1501 @@ typedef int ma_atomic_memory_order; } break; \ } \ return result; - #define MA_ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, expected, desired, order, intrin, ma_atomicType, msvcType) \ + typedef ma_uint32 ma_atomic_flag; + static MA_INLINE ma_atomic_flag ma_atomic_flag_test_and_set_explicit(volatile ma_atomic_flag* dst, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, 1, order, _InterlockedExchange, ma_atomic_flag, long); + } + #else + { + (void)order; + return (ma_atomic_flag)_InterlockedExchange((volatile long*)dst, (long)1); + } + #endif + } + static MA_INLINE void ma_atomic_flag_clear_explicit(volatile ma_atomic_flag* dst, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, 0, order, _InterlockedExchange, ma_atomic_flag, long); + } + #else + { + (void)order; + _InterlockedExchange((volatile long*)dst, (long)0); + } + #endif + } + static MA_INLINE ma_atomic_flag ma_atomic_flag_load_explicit(volatile const ma_atomic_flag* dst, ma_atomic_memory_order order) + { + (void)order; + return (ma_uint32)_InterlockedCompareExchange((volatile long*)dst, 0, 0); + } +#endif +#if defined(MA_ATOMIC_LEGACY_MSVC_ASM) + #define ma_atomic_memory_order_relaxed 1 + #define ma_atomic_memory_order_consume 2 + #define ma_atomic_memory_order_acquire 3 + #define ma_atomic_memory_order_release 4 + #define ma_atomic_memory_order_acq_rel 5 + #define ma_atomic_memory_order_seq_cst 6 + typedef ma_uint32 ma_atomic_flag; + static MA_INLINE ma_atomic_flag ma_atomic_flag_test_and_set_explicit(volatile ma_atomic_flag* dst, ma_atomic_memory_order order) + { + ma_atomic_flag result = 0; + (void)order; + __asm { + mov ecx, dst + mov eax, 1 + xchg [ecx], eax + mov result, eax + } + return result; + } + static MA_INLINE void ma_atomic_flag_clear_explicit(volatile ma_atomic_flag* dst, ma_atomic_memory_order order) + { + if (order == ma_atomic_memory_order_relaxed) { + __asm { + mov esi, dst + mov dword ptr [esi], 0 + } + } else { + __asm { + mov esi, dst + mov eax, 0 + xchg [esi], eax + } + } + } + static MA_INLINE ma_atomic_flag ma_atomic_flag_load_explicit(volatile const ma_atomic_flag* dst, ma_atomic_memory_order order) + { + ma_atomic_flag result = 0; + if (order == ma_atomic_memory_order_relaxed) { + __asm { + mov esi, dst + mov eax, [esi] + mov result, eax + } + } else if (order <= ma_atomic_memory_order_release) { + __asm { + mov esi, dst + mov eax, [esi] + lock add dword ptr [esp], 0 + mov result, eax + } + } else { + __asm { + lock add dword ptr [esp], 0 + mov esi, dst + mov eax, [esi] + mov result, eax + lock add dword ptr [esp], 0 + } + } + return result; + } +#endif +#if defined(MA_ATOMIC_MODERN_GCC) + #define ma_atomic_memory_order_relaxed __ATOMIC_RELAXED + #define ma_atomic_memory_order_consume __ATOMIC_CONSUME + #define ma_atomic_memory_order_acquire __ATOMIC_ACQUIRE + #define ma_atomic_memory_order_release __ATOMIC_RELEASE + #define ma_atomic_memory_order_acq_rel __ATOMIC_ACQ_REL + #define ma_atomic_memory_order_seq_cst __ATOMIC_SEQ_CST + typedef ma_uint32 ma_atomic_flag; + #define ma_atomic_flag_test_and_set_explicit(dst, order) __atomic_exchange_n(dst, 1, order) + #define ma_atomic_flag_clear_explicit(dst, order) __atomic_store_n(dst, 0, order) + #define ma_atomic_flag_load_explicit(dst, order) __atomic_load_n(dst, order) +#endif +#if defined(MA_ATOMIC_LEGACY_GCC) + #define ma_atomic_memory_order_relaxed 1 + #define ma_atomic_memory_order_consume 2 + #define ma_atomic_memory_order_acquire 3 + #define ma_atomic_memory_order_release 4 + #define ma_atomic_memory_order_acq_rel 5 + #define ma_atomic_memory_order_seq_cst 6 + typedef ma_uint32 ma_atomic_flag; + static MA_INLINE ma_atomic_flag ma_atomic_flag_test_and_set_explicit(volatile ma_atomic_flag* dst, ma_atomic_memory_order order) + { + if (order > ma_atomic_memory_order_acquire) { + __sync_synchronize(); + } + return __sync_lock_test_and_set(dst, 1); + } + static MA_INLINE void ma_atomic_flag_clear_explicit(volatile ma_atomic_flag* dst, ma_atomic_memory_order order) + { + if (order > ma_atomic_memory_order_release) { + __sync_synchronize(); + } + __sync_lock_release(dst); + } + static MA_INLINE ma_atomic_flag ma_atomic_flag_load_explicit(volatile const ma_atomic_flag* dst, ma_atomic_memory_order order) + { + (void)order; + return __sync_val_compare_and_swap((ma_atomic_flag*)dst, 0, 0); + } +#endif +#if defined(MA_ATOMIC_LEGACY_GCC_ASM) + #define ma_atomic_memory_order_relaxed 1 + #define ma_atomic_memory_order_consume 2 + #define ma_atomic_memory_order_acquire 3 + #define ma_atomic_memory_order_release 4 + #define ma_atomic_memory_order_acq_rel 5 + #define ma_atomic_memory_order_seq_cst 6 + #if defined(MA_X86) + #define ma_atomic_thread_fence(order) __asm__ __volatile__("lock; addl $0, (%%esp)" ::: "memory") + #elif defined(MA_X64) + #define ma_atomic_thread_fence(order) __asm__ __volatile__("lock; addq $0, (%%rsp)" ::: "memory") + #else + #error Unsupported architecture. + #endif + #define MA_ATOMIC_XCHG_GCC_X86(instructionSizeSuffix, result, dst, src) \ + __asm__ __volatile__( \ + "xchg"instructionSizeSuffix" %0, %1" \ + : "=r"(result), \ + "=m"(*dst) \ + : "0"(src), \ + "m"(*dst) \ + : "memory" \ + ) + #define MA_ATOMIC_LOAD_RELAXED_GCC_X86(instructionSizeSuffix, result, dst) \ + __asm__ __volatile__( \ + "mov"instructionSizeSuffix" %1, %0" \ + : "=r"(result) \ + : "m"(*dst) \ + ) + #define MA_ATOMIC_LOAD_RELEASE_GCC_X86(instructionSizeSuffix, result, dst) \ + ma_atomic_thread_fence(ma_atomic_memory_order_release); \ + __asm__ __volatile__( \ + "mov"instructionSizeSuffix" %1, %0" \ + : "=r"(result) \ + : "m"(*dst) \ + : "memory" \ + ) + #define MA_ATOMIC_LOAD_SEQ_CST_GCC_X86(instructionSizeSuffix, result, dst) \ + ma_atomic_thread_fence(ma_atomic_memory_order_seq_cst); \ + __asm__ __volatile__( \ + "mov"instructionSizeSuffix" %1, %0" \ + : "=r"(result) \ + : "m"(*dst) \ + : "memory" \ + ); \ + ma_atomic_thread_fence(ma_atomic_memory_order_seq_cst) + typedef ma_uint32 ma_atomic_flag; + static MA_INLINE ma_atomic_flag ma_atomic_flag_test_and_set_explicit(volatile ma_atomic_flag* dst, ma_atomic_memory_order order) + { + ma_atomic_flag result; + #if defined(MA_X86) || defined(MA_X64) + { + (void)order; + MA_ATOMIC_XCHG_GCC_X86("l", result, dst, 1); + } + #else + { + #error Unsupported architecture. + } + #endif + return result; + } + static MA_INLINE void ma_atomic_flag_clear_explicit(volatile ma_atomic_flag* dst, ma_atomic_memory_order order) + { + #if defined(MA_X86) || defined(MA_X64) + { + if (order == ma_atomic_memory_order_relaxed) { + __asm__ __volatile__( + "movl $0, %0" + : "=m"(*dst) + ); + } else if (order == ma_atomic_memory_order_release) { + __asm__ __volatile__( + "movl $0, %0" + : "=m"(*dst) + : + : "memory" + ); + } else { + ma_atomic_flag tmp = 0; + __asm__ __volatile__( + "xchgl %0, %1" + : "=r"(tmp), + "=m"(*dst) + : "0"(tmp), + "m"(*dst) + : "memory" + ); + } + } + #else + { + #error Unsupported architecture. + } + #endif + } + static MA_INLINE ma_atomic_flag ma_atomic_flag_load_explicit(volatile const ma_atomic_flag* dst, ma_atomic_memory_order order) + { + #if defined(MA_X86) || defined(MA_X64) + { + ma_atomic_flag result; + if (order == ma_atomic_memory_order_relaxed) { + MA_ATOMIC_LOAD_RELAXED_GCC_X86("l", result, dst); + } else if (order <= ma_atomic_memory_order_release) { + MA_ATOMIC_LOAD_RELEASE_GCC_X86("l", result, dst); + } else { + MA_ATOMIC_LOAD_SEQ_CST_GCC_X86("l", result, dst); + } + return result; + } + #else + { + #error Unsupported architecture. + } + #endif + } +#endif +#define ma_atomic_flag_test_and_set(dst) ma_atomic_flag_test_and_set_explicit(dst, ma_atomic_memory_order_acquire) +#define ma_atomic_flag_clear(dst) ma_atomic_flag_clear_explicit(dst, ma_atomic_memory_order_release) +typedef ma_atomic_flag ma_atomic_spinlock; +static MA_INLINE void ma_atomic_spinlock_lock(volatile ma_atomic_spinlock* pSpinlock) +{ + for (;;) { + if (ma_atomic_flag_test_and_set_explicit(pSpinlock, ma_atomic_memory_order_acquire) == 0) { + break; + } + while (ma_atomic_flag_load_explicit(pSpinlock, ma_atomic_memory_order_relaxed) == 1) { + } + } +} +static MA_INLINE void ma_atomic_spinlock_unlock(volatile ma_atomic_spinlock* pSpinlock) +{ + ma_atomic_flag_clear_explicit(pSpinlock, ma_atomic_memory_order_release); +} +ma_atomic_spinlock ma_atomic_global_lock; +#if defined(MA_ATOMIC_MODERN_MSVC) || defined(MA_ATOMIC_LEGACY_MSVC) || defined(MA_ATOMIC_LEGACY_MSVC_ASM) || defined(MA_ATOMIC_LEGACY_GCC) || defined(MA_ATOMIC_LEGACY_GCC_ASM) + #if defined(MA_X64) || (defined(MA_X86) && ((defined(__GNUC__) && defined(__i486__)) || (defined(_M_IX86) && _M_IX86 >= 400))) + #if defined(MA_ATOMIC_LEGACY_MSVC) && defined(MA_X64) + #else + #define MA_ATOMIC_IS_LOCK_FREE_8 1 + #define MA_ATOMIC_IS_LOCK_FREE_16 1 + #endif + #define MA_ATOMIC_IS_LOCK_FREE_32 1 + #if defined(MA_X64) || (defined(MA_X86) && ((defined(__GNUC__) && defined(__i586__)) || (defined(_M_IX86) && _M_IX86 >= 500))) + #define MA_ATOMIC_IS_LOCK_FREE_64 1 + #else + #endif + #else + #endif + #if defined(MA_ARM32) || defined(MA_ARM64) + #define MA_ATOMIC_IS_LOCK_FREE_8 1 + #define MA_ATOMIC_IS_LOCK_FREE_16 1 + #define MA_ATOMIC_IS_LOCK_FREE_32 1 + #if defined(MA_ARM64) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) + #define MA_ATOMIC_IS_LOCK_FREE_64 1 + #endif + #endif + #if defined(MA_ATOMIC_PPC32) || defined(MA_ATOMIC_PPC64) + #if (defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 7))) && !defined(__clang__) + #else + #define MA_ATOMIC_IS_LOCK_FREE_8 1 + #define MA_ATOMIC_IS_LOCK_FREE_16 1 + #endif + #define MA_ATOMIC_IS_LOCK_FREE_32 1 + #if defined(MA_ATOMIC_PPC64) + #define MA_ATOMIC_IS_LOCK_FREE_64 1 + #endif + #endif + static MA_INLINE ma_bool32 ma_atomic_is_lock_free_8(volatile void* ptr) + { + (void)ptr; + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) + return 1; + #else + return 0; + #endif + } + static MA_INLINE ma_bool32 ma_atomic_is_lock_free_16(volatile void* ptr) + { + (void)ptr; + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) + return 1; + #else + return 0; + #endif + } + static MA_INLINE ma_bool32 ma_atomic_is_lock_free_32(volatile void* ptr) + { + (void)ptr; + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + return 1; + #else + return 0; + #endif + } + static MA_INLINE ma_bool32 ma_atomic_is_lock_free_64(volatile void* ptr) + { + (void)ptr; + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) + return 1; + #else + return 0; + #endif + } +#endif +#define MA_ATOMIC_COMPARE_AND_SWAP_LOCK(sizeInBits, dst, expected, replacement) \ + ma_uint##sizeInBits result; \ + ma_atomic_spinlock_lock(&ma_atomic_global_lock); \ + { \ + result = *dst; \ + if (result == expected) { \ + *dst = replacement; \ + } \ + } \ + ma_atomic_spinlock_unlock(&ma_atomic_global_lock); \ + return result +#define MA_ATOMIC_LOAD_EXPLICIT_LOCK(sizeInBits, ptr, order) \ + ma_uint##sizeInBits result; \ + ma_atomic_spinlock_lock(&ma_atomic_global_lock); \ + { \ + result = *ptr; \ + (void)order; \ + } \ + ma_atomic_spinlock_unlock(&ma_atomic_global_lock); \ + return result +#define MA_ATOMIC_STORE_EXPLICIT_LOCK(sizeInBits, dst, src, order) \ + ma_atomic_spinlock_lock(&ma_atomic_global_lock); \ + { \ + *dst = src; \ + (void)order; \ + } \ + ma_atomic_spinlock_unlock(&ma_atomic_global_lock) +#define MA_ATOMIC_STORE_EXPLICIT_CAS(sizeInBits, dst, src, order) \ + ma_uint##sizeInBits oldValue; \ + do { \ + oldValue = ma_atomic_load_explicit_##sizeInBits(dst, ma_atomic_memory_order_relaxed); \ + } while (ma_atomic_compare_and_swap_##sizeInBits(dst, oldValue, src) != oldValue); \ + (void)order +#define MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(sizeInBits, dst, src, order) \ + ma_uint##sizeInBits result; \ + ma_atomic_spinlock_lock(&ma_atomic_global_lock); \ + { \ + result = *dst; \ + *dst = src; \ + (void)order; \ + } \ + ma_atomic_spinlock_unlock(&ma_atomic_global_lock); \ + return result +#define MA_ATOMIC_EXCHANGE_EXPLICIT_CAS(sizeInBits, dst, src, order) \ + ma_uint##sizeInBits oldValue; \ + do { \ + oldValue = ma_atomic_load_explicit_##sizeInBits(dst, ma_atomic_memory_order_relaxed); \ + } while (ma_atomic_compare_and_swap_##sizeInBits(dst, oldValue, src) != oldValue); \ + (void)order; \ + return oldValue +#define MA_ATOMIC_FETCH_ADD_LOCK(sizeInBits, dst, src, order) \ + ma_uint##sizeInBits result; \ + ma_atomic_spinlock_lock(&ma_atomic_global_lock); \ + { \ + result = *dst; \ + *dst += src; \ + (void)order; \ + } \ + ma_atomic_spinlock_unlock(&ma_atomic_global_lock); \ + return result +#define MA_ATOMIC_FETCH_ADD_CAS(sizeInBits, dst, src, order) \ + ma_uint##sizeInBits oldValue; \ + ma_uint##sizeInBits newValue; \ + do { \ + oldValue = ma_atomic_load_explicit_##sizeInBits(dst, ma_atomic_memory_order_relaxed); \ + newValue = oldValue + src; \ + } while (ma_atomic_compare_and_swap_##sizeInBits(dst, oldValue, newValue) != oldValue); \ + (void)order; \ + return oldValue +#define MA_ATOMIC_FETCH_AND_CAS(sizeInBits, dst, src, order) \ + ma_uint##sizeInBits oldValue; \ + ma_uint##sizeInBits newValue; \ + do { \ + oldValue = ma_atomic_load_explicit_##sizeInBits(dst, ma_atomic_memory_order_relaxed); \ + newValue = (ma_uint##sizeInBits)(oldValue & src); \ + } while (ma_atomic_compare_and_swap_##sizeInBits(dst, oldValue, newValue) != oldValue); \ + (void)order; \ + return oldValue +#define MA_ATOMIC_FETCH_OR_CAS(sizeInBits, dst, src, order) \ + ma_uint##sizeInBits oldValue; \ + ma_uint##sizeInBits newValue; \ + do { \ + oldValue = ma_atomic_load_explicit_##sizeInBits(dst, ma_atomic_memory_order_relaxed); \ + newValue = (ma_uint##sizeInBits)(oldValue | src); \ + } while (ma_atomic_compare_and_swap_##sizeInBits(dst, oldValue, newValue) != oldValue); \ + (void)order; \ + return oldValue +#define MA_ATOMIC_FETCH_XOR_CAS(sizeInBits, dst, src, order) \ + ma_uint##sizeInBits oldValue; \ + ma_uint##sizeInBits newValue; \ + do { \ + oldValue = ma_atomic_load_explicit_##sizeInBits(dst, ma_atomic_memory_order_relaxed); \ + newValue = (ma_uint##sizeInBits)(oldValue ^ src); \ + } while (ma_atomic_compare_and_swap_##sizeInBits(dst, oldValue, newValue) != oldValue); \ + (void)order; \ + return oldValue +#if defined(MA_ATOMIC_MODERN_MSVC) || defined(MA_ATOMIC_LEGACY_MSVC) + #define MA_ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, expected, replacement, order, intrin, ma_atomicType, msvcType) \ ma_atomicType result; \ switch (order) \ { \ case ma_atomic_memory_order_relaxed: \ { \ - result = (ma_atomicType)intrin##_nf((volatile msvcType*)ptr, (msvcType)expected, (msvcType)desired); \ + result = (ma_atomicType)intrin##_nf((volatile msvcType*)ptr, (msvcType)expected, (msvcType)replacement); \ } break; \ case ma_atomic_memory_order_consume: \ case ma_atomic_memory_order_acquire: \ { \ - result = (ma_atomicType)intrin##_acq((volatile msvcType*)ptr, (msvcType)expected, (msvcType)desired); \ + result = (ma_atomicType)intrin##_acq((volatile msvcType*)ptr, (msvcType)expected, (msvcType)replacement); \ } break; \ case ma_atomic_memory_order_release: \ { \ - result = (ma_atomicType)intrin##_rel((volatile msvcType*)ptr, (msvcType)expected, (msvcType)desired); \ + result = (ma_atomicType)intrin##_rel((volatile msvcType*)ptr, (msvcType)expected, (msvcType)replacement); \ } break; \ case ma_atomic_memory_order_acq_rel: \ case ma_atomic_memory_order_seq_cst: \ default: \ { \ - result = (ma_atomicType)intrin((volatile msvcType*)ptr, (msvcType)expected, (msvcType)desired); \ + result = (ma_atomicType)intrin((volatile msvcType*)ptr, (msvcType)expected, (msvcType)replacement); \ } break; \ } \ return result; - #define ma_atomic_memory_order_relaxed 0 - #define ma_atomic_memory_order_consume 1 - #define ma_atomic_memory_order_acquire 2 - #define ma_atomic_memory_order_release 3 - #define ma_atomic_memory_order_acq_rel 4 - #define ma_atomic_memory_order_seq_cst 5 - #if _MSC_VER < 1600 && defined(MA_X86) - #define MA_ATOMIC_MSVC_USE_INLINED_ASSEMBLY - #endif - #if _MSC_VER < 1600 - #undef MA_ATOMIC_HAS_8 - #undef MA_ATOMIC_HAS_16 - #endif - #if !defined(MA_ATOMIC_MSVC_USE_INLINED_ASSEMBLY) - #include - #endif - #if defined(MA_ATOMIC_MSVC_USE_INLINED_ASSEMBLY) - #if defined(MA_ATOMIC_HAS_8) - static MA_INLINE ma_uint8 __stdcall ma_atomic_compare_and_swap_8(volatile ma_uint8* dst, ma_uint8 expected, ma_uint8 desired) - { - ma_uint8 result = 0; - __asm { - mov ecx, dst - mov al, expected - mov dl, desired - lock cmpxchg [ecx], dl - mov result, al - } - return result; - } - #endif - #if defined(MA_ATOMIC_HAS_16) - static MA_INLINE ma_uint16 __stdcall ma_atomic_compare_and_swap_16(volatile ma_uint16* dst, ma_uint16 expected, ma_uint16 desired) - { - ma_uint16 result = 0; - __asm { - mov ecx, dst - mov ax, expected - mov dx, desired - lock cmpxchg [ecx], dx - mov result, ax - } - return result; - } - #endif - #if defined(MA_ATOMIC_HAS_32) - static MA_INLINE ma_uint32 __stdcall ma_atomic_compare_and_swap_32(volatile ma_uint32* dst, ma_uint32 expected, ma_uint32 desired) - { - ma_uint32 result = 0; - __asm { - mov ecx, dst - mov eax, expected - mov edx, desired - lock cmpxchg [ecx], edx - mov result, eax - } - return result; - } - #endif - #if defined(MA_ATOMIC_HAS_64) - static MA_INLINE ma_uint64 __stdcall ma_atomic_compare_and_swap_64(volatile ma_uint64* dst, ma_uint64 expected, ma_uint64 desired) - { - ma_uint32 resultEAX = 0; - ma_uint32 resultEDX = 0; - __asm { - mov esi, dst - mov eax, dword ptr expected - mov edx, dword ptr expected + 4 - mov ebx, dword ptr desired - mov ecx, dword ptr desired + 4 - lock cmpxchg8b qword ptr [esi] - mov resultEAX, eax - mov resultEDX, edx - } - return ((ma_uint64)resultEDX << 32) | resultEAX; - } - #endif + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) + #define ma_atomic_compare_and_swap_8( dst, expected, replacement) (ma_uint8 )_InterlockedCompareExchange8((volatile char*)dst, (char)replacement, (char)expected) #else - #if defined(MA_ATOMIC_HAS_8) - #define ma_atomic_compare_and_swap_8( dst, expected, desired) (ma_uint8 )_InterlockedCompareExchange8((volatile char*)dst, (char)desired, (char)expected) - #endif - #if defined(MA_ATOMIC_HAS_16) - #define ma_atomic_compare_and_swap_16(dst, expected, desired) (ma_uint16)_InterlockedCompareExchange16((volatile short*)dst, (short)desired, (short)expected) - #endif - #if defined(MA_ATOMIC_HAS_32) - #define ma_atomic_compare_and_swap_32(dst, expected, desired) (ma_uint32)_InterlockedCompareExchange((volatile long*)dst, (long)desired, (long)expected) - #endif - #if defined(MA_ATOMIC_HAS_64) - #define ma_atomic_compare_and_swap_64(dst, expected, desired) (ma_uint64)_InterlockedCompareExchange64((volatile ma_int64*)dst, (ma_int64)desired, (ma_int64)expected) - #endif + static MA_INLINE ma_uint8 __stdcall ma_atomic_compare_and_swap_8(volatile ma_uint8* dst, ma_uint8 expected, ma_uint8 replacement) + { + MA_ATOMIC_COMPARE_AND_SWAP_LOCK(8, dst, expected, replacement); + } #endif - #if defined(MA_ATOMIC_MSVC_USE_INLINED_ASSEMBLY) - #if defined(MA_ATOMIC_HAS_8) - static MA_INLINE ma_uint8 __stdcall ma_atomic_exchange_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) - { - ma_uint8 result = 0; - (void)order; - __asm { - mov ecx, dst - mov al, src - lock xchg [ecx], al - mov result, al - } - return result; - } - #endif - #if defined(MA_ATOMIC_HAS_16) - static MA_INLINE ma_uint16 __stdcall ma_atomic_exchange_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) - { - ma_uint16 result = 0; - (void)order; - __asm { - mov ecx, dst - mov ax, src - lock xchg [ecx], ax - mov result, ax - } - return result; - } - #endif - #if defined(MA_ATOMIC_HAS_32) - static MA_INLINE ma_uint32 __stdcall ma_atomic_exchange_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) - { - ma_uint32 result = 0; - (void)order; - __asm { - mov ecx, dst - mov eax, src - lock xchg [ecx], eax - mov result, eax - } - return result; - } - #endif + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) + #define ma_atomic_compare_and_swap_16(dst, expected, replacement) (ma_uint16)_InterlockedCompareExchange16((volatile short*)dst, (short)replacement, (short)expected) #else - #if defined(MA_ATOMIC_HAS_8) - static MA_INLINE ma_uint8 __stdcall ma_atomic_exchange_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) - { + static MA_INLINE ma_uint16 __stdcall ma_atomic_compare_and_swap_16(volatile ma_uint16* dst, ma_uint16 expected, ma_uint16 replacement) + { + MA_ATOMIC_COMPARE_AND_SWAP_LOCK(16, dst, expected, replacement); + } + #endif + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + #define ma_atomic_compare_and_swap_32(dst, expected, replacement) (ma_uint32)_InterlockedCompareExchange((volatile long*)dst, (long)replacement, (long)expected) + #else + static MA_INLINE ma_uint32 __stdcall ma_atomic_compare_and_swap_32(volatile ma_uint32* dst, ma_uint32 expected, ma_uint32 replacement) + { + MA_ATOMIC_COMPARE_AND_SWAP_LOCK(32, dst, expected, replacement); + } + #endif + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + #define ma_atomic_compare_and_swap_64(dst, expected, replacement) (ma_uint64)_InterlockedCompareExchange64((volatile ma_int64*)dst, (ma_int64)replacement, (ma_int64)expected) + #else + static MA_INLINE ma_uint64 __stdcall ma_atomic_compare_and_swap_64(volatile ma_uint64* dst, ma_uint64 expected, ma_uint64 replacement) + { + MA_ATOMIC_COMPARE_AND_SWAP_LOCK(64, dst, expected, replacement); + } + #endif + static MA_INLINE ma_uint8 ma_atomic_load_explicit_8(volatile const ma_uint8* ptr, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) + { #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchange8, ma_uint8, char); + { + MA_ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, 0, 0, order, _InterlockedCompareExchange8, ma_uint8, char); + } #else + { + (void)order; + return ma_atomic_compare_and_swap_8((volatile ma_uint8*)ptr, 0, 0); + } + #endif + } + #else + { + MA_ATOMIC_LOAD_EXPLICIT_LOCK(8, ptr, order); + } + #endif + } + static MA_INLINE ma_uint16 ma_atomic_load_explicit_16(volatile const ma_uint16* ptr, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, 0, 0, order, _InterlockedCompareExchange16, ma_uint16, short); + } + #else + { + (void)order; + return ma_atomic_compare_and_swap_16((volatile ma_uint16*)ptr, 0, 0); + } + #endif + } + #else + { + MA_ATOMIC_LOAD_EXPLICIT_LOCK(16, ptr, order); + } + #endif + } + static MA_INLINE ma_uint32 ma_atomic_load_explicit_32(volatile const ma_uint32* ptr, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, 0, 0, order, _InterlockedCompareExchange, ma_uint32, long); + } + #else + { + (void)order; + return ma_atomic_compare_and_swap_32((volatile ma_uint32*)ptr, 0, 0); + } + #endif + } + #else + { + MA_ATOMIC_LOAD_EXPLICIT_LOCK(32, ptr, order); + } + #endif + } + static MA_INLINE ma_uint64 ma_atomic_load_explicit_64(volatile const ma_uint64* ptr, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, 0, 0, order, _InterlockedCompareExchange64, ma_uint64, long long); + } + #else + { + (void)order; + return ma_atomic_compare_and_swap_64((volatile ma_uint64*)ptr, 0, 0); + } + #endif + } + #else + { + MA_ATOMIC_LOAD_EXPLICIT_LOCK(64, ptr, order); + } + #endif + } + static MA_INLINE ma_uint8 __stdcall ma_atomic_exchange_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchange8, ma_uint8, char); + } + #else + { (void)order; return (ma_uint8)_InterlockedExchange8((volatile char*)dst, (char)src); - #endif } + #endif + } + #else + { + MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(8, dst, src, order); + } #endif - #if defined(MA_ATOMIC_HAS_16) - static MA_INLINE ma_uint16 __stdcall ma_atomic_exchange_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) - { + } + static MA_INLINE ma_uint16 __stdcall ma_atomic_exchange_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) + { #if defined(MA_ARM) + { MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchange16, ma_uint16, short); + } #else + { (void)order; return (ma_uint16)_InterlockedExchange16((volatile short*)dst, (short)src); - #endif } + #endif + } + #else + { + MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(16, dst, src, order); + } #endif - #if defined(MA_ATOMIC_HAS_32) - static MA_INLINE ma_uint32 __stdcall ma_atomic_exchange_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) - { + } + static MA_INLINE ma_uint32 __stdcall ma_atomic_exchange_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + { #if defined(MA_ARM) + { MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchange, ma_uint32, long); + } #else + { (void)order; return (ma_uint32)_InterlockedExchange((volatile long*)dst, (long)src); - #endif } - #endif - #if defined(MA_ATOMIC_HAS_64) && defined(MA_64BIT) - static MA_INLINE ma_uint64 __stdcall ma_atomic_exchange_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) - { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchange64, ma_uint64, long long); - #else - (void)order; - return (ma_uint64)_InterlockedExchange64((volatile long long*)dst, (long long)src); #endif - } - #else - #endif - #endif - #if defined(MA_ATOMIC_HAS_64) && !defined(MA_64BIT) - static MA_INLINE ma_uint64 __stdcall ma_atomic_exchange_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) - { - ma_uint64 oldValue; - do { - oldValue = *dst; - } while (ma_atomic_compare_and_swap_64(dst, oldValue, src) != oldValue); - (void)order; - return oldValue; } - #endif - #if defined(MA_ATOMIC_MSVC_USE_INLINED_ASSEMBLY) - #if defined(MA_ATOMIC_HAS_8) - static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_add_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) - { - ma_uint8 result = 0; - (void)order; - __asm { - mov ecx, dst - mov al, src - lock xadd [ecx], al - mov result, al - } - return result; - } + #else + { + MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(32, dst, src, order); + } #endif - #if defined(MA_ATOMIC_HAS_16) - static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_add_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + } + static MA_INLINE ma_uint64 __stdcall ma_atomic_exchange_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) + { + #if defined(MA_32BIT) { - ma_uint16 result = 0; - (void)order; - __asm { - mov ecx, dst - mov ax, src - lock xadd [ecx], ax - mov result, ax - } - return result; + MA_ATOMIC_EXCHANGE_EXPLICIT_CAS(64, dst, src, order); } - #endif - #if defined(MA_ATOMIC_HAS_32) - static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_add_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) - { - ma_uint32 result = 0; - (void)order; - __asm { - mov ecx, dst - mov eax, src - lock xadd [ecx], eax - mov result, eax - } - return result; - } - #endif - #else - #if defined(MA_ATOMIC_HAS_8) - static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_add_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) - { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchangeAdd8, ma_uint8, char); #else + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchange64, ma_uint64, long long); + } + #else + { + (void)order; + return (ma_uint64)_InterlockedExchange64((volatile long long*)dst, (long long)src); + } + #endif + } + #endif + } + #else + { + MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(64, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_add_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchangeAdd8, ma_uint8, char); + } + #else + { (void)order; return (ma_uint8)_InterlockedExchangeAdd8((volatile char*)dst, (char)src); - #endif } + #endif + } + #else + { + MA_ATOMIC_FETCH_ADD_LOCK(8, dst, src, order); + } #endif - #if defined(MA_ATOMIC_HAS_16) - static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_add_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) - { + } + static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_add_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) + { #if defined(MA_ARM) + { MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchangeAdd16, ma_uint16, short); + } #else + { (void)order; return (ma_uint16)_InterlockedExchangeAdd16((volatile short*)dst, (short)src); - #endif } + #endif + } + #else + { + MA_ATOMIC_FETCH_ADD_LOCK(16, dst, src, order); + } #endif - #if defined(MA_ATOMIC_HAS_32) - static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_add_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) - { + } + static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_add_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + { #if defined(MA_ARM) + { MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchangeAdd, ma_uint32, long); + } #else + { (void)order; return (ma_uint32)_InterlockedExchangeAdd((volatile long*)dst, (long)src); - #endif } - #endif - #if defined(MA_ATOMIC_HAS_64) && defined(MA_64BIT) - static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_add_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) - { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchangeAdd64, ma_uint64, long long); - #else - (void)order; - return (ma_uint64)_InterlockedExchangeAdd64((volatile long long*)dst, (long long)src); #endif - } + } #else - #endif - #endif - #if defined(MA_ATOMIC_HAS_64) && !defined(MA_64BIT) - static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_add_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) { - ma_uint64 oldValue; - ma_uint64 newValue; - do { - oldValue = *dst; - newValue = oldValue + src; - } while (ma_atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; + MA_ATOMIC_FETCH_ADD_LOCK(32, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_add_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) + { + #if defined(MA_32BIT) + { + MA_ATOMIC_FETCH_ADD_CAS(64, dst, src, order); + } + #else + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchangeAdd64, ma_uint64, long long); + } + #else + { + (void)order; + return (ma_uint64)_InterlockedExchangeAdd64((volatile long long*)dst, (long long)src); + } + #endif + } + #endif + } + #else + { + MA_ATOMIC_FETCH_ADD_LOCK(64, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_sub_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + return ma_atomic_fetch_add_explicit_8(dst, (ma_uint8)(-(ma_int8)src), order); + } + static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_sub_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + return ma_atomic_fetch_add_explicit_16(dst, (ma_uint16)(-(ma_int16)src), order); + } + static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_sub_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + return ma_atomic_fetch_add_explicit_32(dst, (ma_uint32)(-(ma_int32)src), order); + } + static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_sub_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + return ma_atomic_fetch_add_explicit_64(dst, (ma_uint64)(-(ma_int64)src), order); + } + static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_and_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedAnd8, ma_uint8, char); + } + #else + { + MA_ATOMIC_FETCH_AND_CAS(8, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_and_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedAnd16, ma_uint16, short); + } + #else + { + MA_ATOMIC_FETCH_AND_CAS(16, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_and_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedAnd, ma_uint32, long); + } + #else + { + MA_ATOMIC_FETCH_AND_CAS(32, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_and_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedAnd64, ma_uint64, long long); + } + #else + { + MA_ATOMIC_FETCH_AND_CAS(64, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_or_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedOr8, ma_uint8, char); + } + #else + { + MA_ATOMIC_FETCH_OR_CAS(8, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_or_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedOr16, ma_uint16, short); + } + #else + { + MA_ATOMIC_FETCH_OR_CAS(16, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_or_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedOr, ma_uint32, long); + } + #else + { + MA_ATOMIC_FETCH_OR_CAS(32, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_or_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedOr64, ma_uint64, long long); + } + #else + { + MA_ATOMIC_FETCH_OR_CAS(64, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_xor_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedXor8, ma_uint8, char); + } + #else + { + MA_ATOMIC_FETCH_XOR_CAS(8, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_xor_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedXor16, ma_uint16, short); + } + #else + { + MA_ATOMIC_FETCH_XOR_CAS(16, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_xor_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedXor, ma_uint32, long); + } + #else + { + MA_ATOMIC_FETCH_XOR_CAS(32, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_xor_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + #if defined(MA_ARM) + { + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedXor64, ma_uint64, long long); + } + #else + { + MA_ATOMIC_FETCH_XOR_CAS(64, dst, src, order); + } + #endif + } + #define ma_atomic_store_explicit_8( dst, src, order) (void)ma_atomic_exchange_explicit_8 (dst, src, order) + #define ma_atomic_store_explicit_16(dst, src, order) (void)ma_atomic_exchange_explicit_16(dst, src, order) + #define ma_atomic_store_explicit_32(dst, src, order) (void)ma_atomic_exchange_explicit_32(dst, src, order) + #define ma_atomic_store_explicit_64(dst, src, order) (void)ma_atomic_exchange_explicit_64(dst, src, order) + #if defined(MA_X64) + #define ma_atomic_thread_fence(order) __faststorefence(), (void)order + #elif defined(MA_ARM64) + #define ma_atomic_thread_fence(order) __dmb(_ARM64_BARRIER_ISH), (void)order + #else + static MA_INLINE void ma_atomic_thread_fence(ma_atomic_memory_order order) + { + volatile ma_uint32 barrier = 0; + ma_atomic_fetch_add_explicit_32(&barrier, 0, order); } #endif - #if defined(MA_ATOMIC_MSVC_USE_INLINED_ASSEMBLY) - static MA_INLINE void __stdcall ma_atomic_thread_fence(ma_atomic_memory_order order) + #define ma_atomic_signal_fence(order) _ReadWriteBarrier(), (void)order +#endif +#if defined(MA_ATOMIC_LEGACY_MSVC_ASM) + static MA_INLINE ma_uint8 __stdcall ma_atomic_compare_and_swap_8(volatile ma_uint8* dst, ma_uint8 expected, ma_uint8 replacement) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) { + ma_uint8 result = 0; + __asm { + mov ecx, dst + mov al, expected + mov dl, replacement + lock cmpxchg [ecx], dl + mov result, al + } + return result; + } + #else + { + MA_ATOMIC_COMPARE_AND_SWAP_LOCK(8, dst, expected, replacement); + } + #endif + } + static MA_INLINE ma_uint16 __stdcall ma_atomic_compare_and_swap_16(volatile ma_uint16* dst, ma_uint16 expected, ma_uint16 replacement) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) + { + ma_uint16 result = 0; + __asm { + mov ecx, dst + mov ax, expected + mov dx, replacement + lock cmpxchg [ecx], dx + mov result, ax + } + return result; + } + #else + { + MA_ATOMIC_COMPARE_AND_SWAP_LOCK(16, dst, expected, replacement); + } + #endif + } + static MA_INLINE ma_uint32 __stdcall ma_atomic_compare_and_swap_32(volatile ma_uint32* dst, ma_uint32 expected, ma_uint32 replacement) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + { + ma_uint32 result = 0; + __asm { + mov ecx, dst + mov eax, expected + mov edx, replacement + lock cmpxchg [ecx], edx + mov result, eax + } + return result; + } + #else + { + MA_ATOMIC_COMPARE_AND_SWAP_LOCK(32, dst, expected, replacement); + } + #endif + } + static MA_INLINE ma_uint64 __stdcall ma_atomic_compare_and_swap_64(volatile ma_uint64* dst, ma_uint64 expected, ma_uint64 replacement) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) + { + ma_uint32 resultEAX = 0; + ma_uint32 resultEDX = 0; + __asm { + mov esi, dst + mov eax, dword ptr expected + mov edx, dword ptr expected + 4 + mov ebx, dword ptr replacement + mov ecx, dword ptr replacement + 4 + lock cmpxchg8b qword ptr [esi] + mov resultEAX, eax + mov resultEDX, edx + } + return ((ma_uint64)resultEDX << 32) | resultEAX; + } + #else + { + MA_ATOMIC_COMPARE_AND_SWAP_LOCK(64, dst, expected, replacement); + } + #endif + } + static MA_INLINE ma_uint8 ma_atomic_load_explicit_8(volatile const ma_uint8* dst, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) + { + ma_uint8 result = 0; + if (order == ma_atomic_memory_order_relaxed) { + __asm { + mov esi, dst + mov al, [esi] + mov result, al + } + } else if (order <= ma_atomic_memory_order_release) { + __asm { + mov esi, dst + mov al, [esi] + lock add dword ptr [esp], 0 + mov result, al + } + } else { + __asm { + lock add dword ptr [esp], 0 + mov esi, dst + mov al, [esi] + mov result, al + lock add dword ptr [esp], 0 + } + } + return result; + } + #else + { + MA_ATOMIC_LOAD_EXPLICIT_LOCK(8, dst, order); + } + #endif + } + static MA_INLINE ma_uint16 ma_atomic_load_explicit_16(volatile const ma_uint16* dst, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) + { + ma_uint16 result = 0; + if (order == ma_atomic_memory_order_relaxed) { + __asm { + mov esi, dst + mov ax, [esi] + mov result, ax + } + } else if (order <= ma_atomic_memory_order_release) { + __asm { + mov esi, dst + mov ax, [esi] + lock add dword ptr [esp], 0 + mov result, ax + } + } else { + __asm { + lock add dword ptr [esp], 0 + mov esi, dst + mov ax, [esi] + mov result, ax + lock add dword ptr [esp], 0 + } + } + return result; + } + #else + { + MA_ATOMIC_LOAD_EXPLICIT_LOCK(16, dst, order); + } + #endif + } + static MA_INLINE ma_uint32 ma_atomic_load_explicit_32(volatile const ma_uint32* dst, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + { + ma_uint32 result = 0; + if (order == ma_atomic_memory_order_relaxed) { + __asm { + mov esi, dst + mov eax, [esi] + mov result, eax + } + } else if (order <= ma_atomic_memory_order_release) { + __asm { + mov esi, dst + mov eax, [esi] + lock add dword ptr [esp], 0 + mov result, eax + } + } else { + __asm { + lock add dword ptr [esp], 0 + mov esi, dst + mov eax, [esi] + mov result, eax + lock add dword ptr [esp], 0 + } + } + return result; + } + #else + { + MA_ATOMIC_LOAD_EXPLICIT_LOCK(32, dst, order); + } + #endif + } + static MA_INLINE ma_uint64 ma_atomic_load_explicit_64(volatile const ma_uint64* dst, ma_atomic_memory_order order) + { + (void)order; + return ma_atomic_compare_and_swap_64((volatile ma_uint64*)dst, 0, 0); + } + static MA_INLINE void __stdcall ma_atomic_store_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + if (order == ma_atomic_memory_order_relaxed) { + __asm { + mov esi, dst + mov al, src + mov [esi], al + } + } else { + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) + { + __asm { + mov esi, dst + mov al, src + xchg [esi], al + } + } + #else + { + MA_ATOMIC_STORE_EXPLICIT_LOCK(8, dst, src, order); + } + #endif + } + } + static MA_INLINE void __stdcall ma_atomic_store_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + if (order == ma_atomic_memory_order_relaxed) { + __asm { + mov esi, dst + mov ax, src + mov [esi], ax + } + } else { + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) + { + __asm { + mov esi, dst + mov ax, src + xchg [esi], ax + } + } + #else + { + MA_ATOMIC_STORE_EXPLICIT_LOCK(16, dst, src, order); + } + #endif + } + } + static MA_INLINE void __stdcall ma_atomic_store_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + if (order == ma_atomic_memory_order_relaxed) { + __asm { + mov esi, dst + mov eax, src + mov [esi], eax + } + } else { + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + { + __asm { + mov esi, dst + mov eax, src + xchg [esi], eax + } + } + #else + { + MA_ATOMIC_STORE_EXPLICIT_LOCK(32, dst, src, order); + } + #endif + } + } + static MA_INLINE void __stdcall ma_atomic_store_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) + { + MA_ATOMIC_STORE_EXPLICIT_CAS(64, dst, src, order); + } + #else + { + MA_ATOMIC_STORE_EXPLICIT_LOCK(64, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint8 __stdcall ma_atomic_exchange_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) + { + ma_uint8 result = 0; (void)order; __asm { - lock add [esp], 0 + mov ecx, dst + mov al, src + lock xchg [ecx], al + mov result, al } + return result; } - #else - #if defined(MA_X64) - #define ma_atomic_thread_fence(order) __faststorefence(), (void)order - #elif defined(MA_ARM64) - #define ma_atomic_thread_fence(order) __dmb(_ARM64_BARRIER_ISH), (void)order #else - static MA_INLINE void ma_atomic_thread_fence(ma_atomic_memory_order order) - { - volatile ma_uint32 barrier = 0; - ma_atomic_fetch_add_explicit_32(&barrier, 0, order); + { + MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(8, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint16 __stdcall ma_atomic_exchange_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) + { + ma_uint16 result = 0; + (void)order; + __asm { + mov ecx, dst + mov ax, src + lock xchg [ecx], ax + mov result, ax } - #endif - #endif - #define ma_atomic_compiler_fence() ma_atomic_thread_fence(ma_atomic_memory_order_seq_cst) - #define ma_atomic_signal_fence(order) ma_atomic_thread_fence(order) - #if defined(MA_ATOMIC_HAS_8) - static MA_INLINE ma_uint8 ma_atomic_load_explicit_8(volatile const ma_uint8* ptr, ma_atomic_memory_order order) - { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, 0, 0, order, _InterlockedCompareExchange8, ma_uint8, char); + return result; + } #else - (void)order; - return ma_atomic_compare_and_swap_8((volatile ma_uint8*)ptr, 0, 0); - #endif - } - #endif - #if defined(MA_ATOMIC_HAS_16) - static MA_INLINE ma_uint16 ma_atomic_load_explicit_16(volatile const ma_uint16* ptr, ma_atomic_memory_order order) { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, 0, 0, order, _InterlockedCompareExchange16, ma_uint16, short); + MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(16, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint32 __stdcall ma_atomic_exchange_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + { + ma_uint32 result = 0; + (void)order; + __asm { + mov ecx, dst + mov eax, src + xchg [ecx], eax + mov result, eax + } + return result; + } #else - (void)order; - return ma_atomic_compare_and_swap_16((volatile ma_uint16*)ptr, 0, 0); - #endif - } - #endif - #if defined(MA_ATOMIC_HAS_32) - static MA_INLINE ma_uint32 ma_atomic_load_explicit_32(volatile const ma_uint32* ptr, ma_atomic_memory_order order) { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, 0, 0, order, _InterlockedCompareExchange, ma_uint32, long); + MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(32, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint64 __stdcall ma_atomic_exchange_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) + { + MA_ATOMIC_EXCHANGE_EXPLICIT_CAS(64, dst, src, order); + } #else - (void)order; - return ma_atomic_compare_and_swap_32((volatile ma_uint32*)ptr, 0, 0); - #endif - } - #endif - #if defined(MA_ATOMIC_HAS_64) - static MA_INLINE ma_uint64 ma_atomic_load_explicit_64(volatile const ma_uint64* ptr, ma_atomic_memory_order order) { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, 0, 0, order, _InterlockedCompareExchange64, ma_uint64, long long); + MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(64, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_add_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) + { + ma_uint8 result = 0; + (void)order; + __asm { + mov ecx, dst + mov al, src + lock xadd [ecx], al + mov result, al + } + return result; + } #else - (void)order; - return ma_atomic_compare_and_swap_64((volatile ma_uint64*)ptr, 0, 0); + { + MA_ATOMIC_FETCH_ADD_LOCK(8, dst, src, order); + } #endif - } - #endif - #if defined(MA_ATOMIC_HAS_8) - #define ma_atomic_store_explicit_8( dst, src, order) (void)ma_atomic_exchange_explicit_8 (dst, src, order) - #endif - #if defined(MA_ATOMIC_HAS_16) - #define ma_atomic_store_explicit_16(dst, src, order) (void)ma_atomic_exchange_explicit_16(dst, src, order) - #endif - #if defined(MA_ATOMIC_HAS_32) - #define ma_atomic_store_explicit_32(dst, src, order) (void)ma_atomic_exchange_explicit_32(dst, src, order) - #endif - #if defined(MA_ATOMIC_HAS_64) - #define ma_atomic_store_explicit_64(dst, src, order) (void)ma_atomic_exchange_explicit_64(dst, src, order) - #endif - #if defined(MA_ATOMIC_HAS_8) - static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_sub_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + } + static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_add_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) { - ma_uint8 oldValue; - ma_uint8 newValue; - do { - oldValue = *dst; - newValue = (ma_uint8)(oldValue - src); - } while (ma_atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); + ma_uint16 result = 0; (void)order; - return oldValue; + __asm { + mov ecx, dst + mov ax, src + lock xadd [ecx], ax + mov result, ax + } + return result; } - #endif - #if defined(MA_ATOMIC_HAS_16) - static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_sub_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) - { - ma_uint16 oldValue; - ma_uint16 newValue; - do { - oldValue = *dst; - newValue = (ma_uint16)(oldValue - src); - } while (ma_atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; - } - #endif - #if defined(MA_ATOMIC_HAS_32) - static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_sub_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) - { - ma_uint32 oldValue; - ma_uint32 newValue; - do { - oldValue = *dst; - newValue = oldValue - src; - } while (ma_atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; - } - #endif - #if defined(MA_ATOMIC_HAS_64) - static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_sub_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) - { - ma_uint64 oldValue; - ma_uint64 newValue; - do { - oldValue = *dst; - newValue = oldValue - src; - } while (ma_atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; - } - #endif - #if defined(MA_ATOMIC_HAS_8) - static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_and_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) - { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedAnd8, ma_uint8, char); #else - ma_uint8 oldValue; - ma_uint8 newValue; - do { - oldValue = *dst; - newValue = (ma_uint8)(oldValue & src); - } while (ma_atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; - #endif - } - #endif - #if defined(MA_ATOMIC_HAS_16) - static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_and_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedAnd16, ma_uint16, short); - #else - ma_uint16 oldValue; - ma_uint16 newValue; - do { - oldValue = *dst; - newValue = (ma_uint16)(oldValue & src); - } while (ma_atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; - #endif + MA_ATOMIC_FETCH_ADD_LOCK(16, dst, src, order); } - #endif - #if defined(MA_ATOMIC_HAS_32) - static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_and_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + #endif + } + static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_add_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedAnd, ma_uint32, long); - #else - ma_uint32 oldValue; - ma_uint32 newValue; - do { - oldValue = *dst; - newValue = oldValue & src; - } while (ma_atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); + ma_uint32 result = 0; (void)order; - return oldValue; - #endif + __asm { + mov ecx, dst + mov eax, src + lock xadd [ecx], eax + mov result, eax + } + return result; } - #endif - #if defined(MA_ATOMIC_HAS_64) - static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_and_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + #else { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedAnd64, ma_uint64, long long); - #else - ma_uint64 oldValue; - ma_uint64 newValue; - do { - oldValue = *dst; - newValue = oldValue & src; - } while (ma_atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; - #endif + MA_ATOMIC_FETCH_ADD_LOCK(32, dst, src, order); } - #endif - #if defined(MA_ATOMIC_HAS_8) - static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_xor_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + #endif + } + static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_add_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedXor8, ma_uint8, char); - #else - ma_uint8 oldValue; - ma_uint8 newValue; - do { - oldValue = *dst; - newValue = (ma_uint8)(oldValue ^ src); - } while (ma_atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; - #endif + MA_ATOMIC_FETCH_ADD_CAS(64, dst, src, order); } - #endif - #if defined(MA_ATOMIC_HAS_16) - static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_xor_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + #else { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedXor16, ma_uint16, short); - #else - ma_uint16 oldValue; - ma_uint16 newValue; - do { - oldValue = *dst; - newValue = (ma_uint16)(oldValue ^ src); - } while (ma_atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; - #endif + MA_ATOMIC_FETCH_ADD_LOCK(64, dst, src, order); } - #endif - #if defined(MA_ATOMIC_HAS_32) - static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_xor_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + #endif + } + static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_sub_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedXor, ma_uint32, long); - #else - ma_uint32 oldValue; - ma_uint32 newValue; - do { - oldValue = *dst; - newValue = oldValue ^ src; - } while (ma_atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); + ma_uint8 result = 0; (void)order; - return oldValue; - #endif + __asm { + mov ecx, dst + mov al, src + neg al + lock xadd [ecx], al + mov result, al + } + return result; } - #endif - #if defined(MA_ATOMIC_HAS_64) - static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_xor_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + #else { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedXor64, ma_uint64, long long); - #else - ma_uint64 oldValue; - ma_uint64 newValue; - do { - oldValue = *dst; - newValue = oldValue ^ src; - } while (ma_atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; - #endif + MA_ATOMIC_FETCH_ADD_LOCK(8, dst, (ma_uint8)(-(ma_int8)src), order); } - #endif - #if defined(MA_ATOMIC_HAS_8) - static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_or_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + #endif + } + static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_sub_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedOr8, ma_uint8, char); - #else - ma_uint8 oldValue; - ma_uint8 newValue; - do { - oldValue = *dst; - newValue = (ma_uint8)(oldValue | src); - } while (ma_atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); + ma_uint16 result = 0; (void)order; - return oldValue; - #endif + __asm { + mov ecx, dst + mov ax, src + neg ax + lock xadd [ecx], ax + mov result, ax + } + return result; } - #endif - #if defined(MA_ATOMIC_HAS_16) - static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_or_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + #else { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedOr16, ma_uint16, short); - #else - ma_uint16 oldValue; - ma_uint16 newValue; - do { - oldValue = *dst; - newValue = (ma_uint16)(oldValue | src); - } while (ma_atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; - #endif + MA_ATOMIC_FETCH_ADD_LOCK(16, dst, (ma_uint16)(-(ma_int16)src), order); } - #endif - #if defined(MA_ATOMIC_HAS_32) - static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_or_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + #endif + } + static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_sub_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedOr, ma_uint32, long); - #else - ma_uint32 oldValue; - ma_uint32 newValue; - do { - oldValue = *dst; - newValue = oldValue | src; - } while (ma_atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); + ma_uint32 result = 0; (void)order; - return oldValue; - #endif + __asm { + mov ecx, dst + mov eax, src + neg eax + lock xadd [ecx], eax + mov result, eax + } + return result; } - #endif - #if defined(MA_ATOMIC_HAS_64) - static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_or_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + #else { - #if defined(MA_ARM) - MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedOr64, ma_uint64, long long); - #else - ma_uint64 oldValue; - ma_uint64 newValue; - do { - oldValue = *dst; - newValue = oldValue | src; - } while (ma_atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; - #endif + MA_ATOMIC_FETCH_ADD_LOCK(32, dst, (ma_uint32)(-(ma_int32)src), order); } - #endif - #if defined(MA_ATOMIC_HAS_8) - #define ma_atomic_test_and_set_explicit_8( dst, order) ma_atomic_exchange_explicit_8 (dst, 1, order) - #endif - #if defined(MA_ATOMIC_HAS_16) - #define ma_atomic_test_and_set_explicit_16(dst, order) ma_atomic_exchange_explicit_16(dst, 1, order) - #endif - #if defined(MA_ATOMIC_HAS_32) - #define ma_atomic_test_and_set_explicit_32(dst, order) ma_atomic_exchange_explicit_32(dst, 1, order) - #endif - #if defined(MA_ATOMIC_HAS_64) - #define ma_atomic_test_and_set_explicit_64(dst, order) ma_atomic_exchange_explicit_64(dst, 1, order) - #endif - #if defined(MA_ATOMIC_HAS_8) - #define ma_atomic_clear_explicit_8( dst, order) ma_atomic_store_explicit_8 (dst, 0, order) - #endif - #if defined(MA_ATOMIC_HAS_16) - #define ma_atomic_clear_explicit_16(dst, order) ma_atomic_store_explicit_16(dst, 0, order) - #endif - #if defined(MA_ATOMIC_HAS_32) - #define ma_atomic_clear_explicit_32(dst, order) ma_atomic_store_explicit_32(dst, 0, order) - #endif - #if defined(MA_ATOMIC_HAS_64) - #define ma_atomic_clear_explicit_64(dst, order) ma_atomic_store_explicit_64(dst, 0, order) - #endif - #if defined(MA_ATOMIC_HAS_8) - typedef ma_uint8 ma_atomic_flag; - #define ma_atomic_flag_test_and_set_explicit(ptr, order) (ma_bool32)ma_atomic_test_and_set_explicit_8(ptr, order) - #define ma_atomic_flag_clear_explicit(ptr, order) ma_atomic_clear_explicit_8(ptr, order) - #define ma_atomic_flag_load_explicit(ptr, order) ma_atomic_load_explicit_8(ptr, order) - #else - typedef ma_uint32 ma_atomic_flag; - #define ma_atomic_flag_test_and_set_explicit(ptr, order) (ma_bool32)ma_atomic_test_and_set_explicit_32(ptr, order) - #define ma_atomic_flag_clear_explicit(ptr, order) ma_atomic_clear_explicit_32(ptr, order) - #define ma_atomic_flag_load_explicit(ptr, order) ma_atomic_load_explicit_32(ptr, order) - #endif -#elif defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))) + #endif + } + static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_sub_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_ADD_CAS(64, dst, (ma_uint64)(-(ma_int64)src), order); + } + static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_and_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_AND_CAS(8, dst, src, order); + } + static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_and_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_AND_CAS(16, dst, src, order); + } + static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_and_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_AND_CAS(32, dst, src, order); + } + static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_and_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_AND_CAS(64, dst, src, order); + } + static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_or_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_OR_CAS(8, dst, src, order); + } + static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_or_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_OR_CAS(16, dst, src, order); + } + static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_or_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_OR_CAS(32, dst, src, order); + } + static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_or_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_OR_CAS(64, dst, src, order); + } + static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_xor_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_XOR_CAS(8, dst, src, order); + } + static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_xor_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_XOR_CAS(16, dst, src, order); + } + static MA_INLINE ma_uint32 __stdcall ma_atomic_fetch_xor_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_XOR_CAS(32, dst, src, order); + } + static MA_INLINE ma_uint64 __stdcall ma_atomic_fetch_xor_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_XOR_CAS(64, dst, src, order); + } + static MA_INLINE void __stdcall ma_atomic_thread_fence(ma_atomic_memory_order order) + { + (void)order; + __asm { + lock add dword ptr [esp], 0 + } + } + #define ma_atomic_signal_fence(order) __asm {}; (void)order +#endif +#if defined(MA_ATOMIC_MODERN_GCC) #define MA_ATOMIC_HAS_NATIVE_COMPARE_EXCHANGE - #define MA_ATOMIC_HAS_NATIVE_IS_LOCK_FREE - #define ma_atomic_memory_order_relaxed __ATOMIC_RELAXED - #define ma_atomic_memory_order_consume __ATOMIC_CONSUME - #define ma_atomic_memory_order_acquire __ATOMIC_ACQUIRE - #define ma_atomic_memory_order_release __ATOMIC_RELEASE - #define ma_atomic_memory_order_acq_rel __ATOMIC_ACQ_REL - #define ma_atomic_memory_order_seq_cst __ATOMIC_SEQ_CST - #define ma_atomic_compiler_fence() __asm__ __volatile__("":::"memory") #define ma_atomic_thread_fence(order) __atomic_thread_fence(order) #define ma_atomic_signal_fence(order) __atomic_signal_fence(order) #define ma_atomic_is_lock_free_8(ptr) __atomic_is_lock_free(1, ptr) #define ma_atomic_is_lock_free_16(ptr) __atomic_is_lock_free(2, ptr) #define ma_atomic_is_lock_free_32(ptr) __atomic_is_lock_free(4, ptr) #define ma_atomic_is_lock_free_64(ptr) __atomic_is_lock_free(8, ptr) - #define ma_atomic_test_and_set_explicit_8( dst, order) __atomic_exchange_n(dst, 1, order) - #define ma_atomic_test_and_set_explicit_16(dst, order) __atomic_exchange_n(dst, 1, order) - #define ma_atomic_test_and_set_explicit_32(dst, order) __atomic_exchange_n(dst, 1, order) - #define ma_atomic_test_and_set_explicit_64(dst, order) __atomic_exchange_n(dst, 1, order) - #define ma_atomic_clear_explicit_8( dst, order) __atomic_store_n(dst, 0, order) - #define ma_atomic_clear_explicit_16(dst, order) __atomic_store_n(dst, 0, order) - #define ma_atomic_clear_explicit_32(dst, order) __atomic_store_n(dst, 0, order) - #define ma_atomic_clear_explicit_64(dst, order) __atomic_store_n(dst, 0, order) #define ma_atomic_store_explicit_8( dst, src, order) __atomic_store_n(dst, src, order) #define ma_atomic_store_explicit_16(dst, src, order) __atomic_store_n(dst, src, order) #define ma_atomic_store_explicit_32(dst, src, order) __atomic_store_n(dst, src, order) @@ -14864,14 +15773,14 @@ typedef int ma_atomic_memory_order; #define ma_atomic_exchange_explicit_16(dst, src, order) __atomic_exchange_n(dst, src, order) #define ma_atomic_exchange_explicit_32(dst, src, order) __atomic_exchange_n(dst, src, order) #define ma_atomic_exchange_explicit_64(dst, src, order) __atomic_exchange_n(dst, src, order) - #define ma_atomic_compare_exchange_strong_explicit_8( dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 0, successOrder, failureOrder) - #define ma_atomic_compare_exchange_strong_explicit_16(dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 0, successOrder, failureOrder) - #define ma_atomic_compare_exchange_strong_explicit_32(dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 0, successOrder, failureOrder) - #define ma_atomic_compare_exchange_strong_explicit_64(dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 0, successOrder, failureOrder) - #define ma_atomic_compare_exchange_weak_explicit_8( dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 1, successOrder, failureOrder) - #define ma_atomic_compare_exchange_weak_explicit_16(dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 1, successOrder, failureOrder) - #define ma_atomic_compare_exchange_weak_explicit_32(dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 1, successOrder, failureOrder) - #define ma_atomic_compare_exchange_weak_explicit_64(dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 1, successOrder, failureOrder) + #define ma_atomic_compare_exchange_strong_explicit_8( dst, expected, replacement, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, replacement, 0, successOrder, failureOrder) + #define ma_atomic_compare_exchange_strong_explicit_16(dst, expected, replacement, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, replacement, 0, successOrder, failureOrder) + #define ma_atomic_compare_exchange_strong_explicit_32(dst, expected, replacement, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, replacement, 0, successOrder, failureOrder) + #define ma_atomic_compare_exchange_strong_explicit_64(dst, expected, replacement, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, replacement, 0, successOrder, failureOrder) + #define ma_atomic_compare_exchange_weak_explicit_8( dst, expected, replacement, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, replacement, 1, successOrder, failureOrder) + #define ma_atomic_compare_exchange_weak_explicit_16(dst, expected, replacement, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, replacement, 1, successOrder, failureOrder) + #define ma_atomic_compare_exchange_weak_explicit_32(dst, expected, replacement, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, replacement, 1, successOrder, failureOrder) + #define ma_atomic_compare_exchange_weak_explicit_64(dst, expected, replacement, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, replacement, 1, successOrder, failureOrder) #define ma_atomic_fetch_add_explicit_8( dst, src, order) __atomic_fetch_add(dst, src, order) #define ma_atomic_fetch_add_explicit_16(dst, src, order) __atomic_fetch_add(dst, src, order) #define ma_atomic_fetch_add_explicit_32(dst, src, order) __atomic_fetch_add(dst, src, order) @@ -14892,19 +15801,19 @@ typedef int ma_atomic_memory_order; #define ma_atomic_fetch_and_explicit_16(dst, src, order) __atomic_fetch_and(dst, src, order) #define ma_atomic_fetch_and_explicit_32(dst, src, order) __atomic_fetch_and(dst, src, order) #define ma_atomic_fetch_and_explicit_64(dst, src, order) __atomic_fetch_and(dst, src, order) - static MA_INLINE ma_uint8 ma_atomic_compare_and_swap_8(volatile ma_uint8* dst, ma_uint8 expected, ma_uint8 desired) + static MA_INLINE ma_uint8 ma_atomic_compare_and_swap_8(volatile ma_uint8* dst, ma_uint8 expected, ma_uint8 replacement) { - __atomic_compare_exchange_n(dst, &expected, desired, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); + __atomic_compare_exchange_n(dst, &expected, replacement, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); return expected; } - static MA_INLINE ma_uint16 ma_atomic_compare_and_swap_16(volatile ma_uint16* dst, ma_uint16 expected, ma_uint16 desired) + static MA_INLINE ma_uint16 ma_atomic_compare_and_swap_16(volatile ma_uint16* dst, ma_uint16 expected, ma_uint16 replacement) { - __atomic_compare_exchange_n(dst, &expected, desired, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); + __atomic_compare_exchange_n(dst, &expected, replacement, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); return expected; } - static MA_INLINE ma_uint32 ma_atomic_compare_and_swap_32(volatile ma_uint32* dst, ma_uint32 expected, ma_uint32 desired) + static MA_INLINE ma_uint32 ma_atomic_compare_and_swap_32(volatile ma_uint32* dst, ma_uint32 expected, ma_uint32 replacement) { - __atomic_compare_exchange_n(dst, &expected, desired, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); + __atomic_compare_exchange_n(dst, &expected, replacement, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); return expected; } #if defined(__clang__) @@ -14913,636 +15822,1134 @@ typedef int ma_atomic_memory_order; #pragma clang diagnostic ignored "-Watomic-alignment" #endif #endif - static MA_INLINE ma_uint64 ma_atomic_compare_and_swap_64(volatile ma_uint64* dst, ma_uint64 expected, ma_uint64 desired) + static MA_INLINE ma_uint64 ma_atomic_compare_and_swap_64(volatile ma_uint64* dst, ma_uint64 expected, ma_uint64 replacement) { - __atomic_compare_exchange_n(dst, &expected, desired, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); + __atomic_compare_exchange_n(dst, &expected, replacement, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); return expected; } #if defined(__clang__) #pragma clang diagnostic pop #endif - typedef ma_uint8 ma_atomic_flag; - #define ma_atomic_flag_test_and_set_explicit(dst, order) (ma_bool32)__atomic_test_and_set(dst, order) - #define ma_atomic_flag_clear_explicit(dst, order) __atomic_clear(dst, order) - #define ma_atomic_flag_load_explicit(ptr, order) ma_atomic_load_explicit_8(ptr, order) -#else - #define ma_atomic_memory_order_relaxed 1 - #define ma_atomic_memory_order_consume 2 - #define ma_atomic_memory_order_acquire 3 - #define ma_atomic_memory_order_release 4 - #define ma_atomic_memory_order_acq_rel 5 - #define ma_atomic_memory_order_seq_cst 6 - #define ma_atomic_compiler_fence() __asm__ __volatile__("":::"memory") - #if defined(__GNUC__) +#endif +#if defined(MA_ATOMIC_LEGACY_GCC) || defined(MA_ATOMIC_LEGACY_GCC_ASM) + #define ma_atomic_signal_fence(order) __asm__ __volatile__("":::"memory") + #if defined(MA_ATOMIC_LEGACY_GCC) #define ma_atomic_thread_fence(order) __sync_synchronize(), (void)order - static MA_INLINE ma_uint8 ma_atomic_exchange_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + static MA_INLINE ma_uint8 ma_atomic_compare_and_swap_8(volatile ma_uint8* dst, ma_uint8 expected, ma_uint8 replacement) { - if (order > ma_atomic_memory_order_acquire) { - __sync_synchronize(); + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) + { + return __sync_val_compare_and_swap(dst, expected, replacement); } - return __sync_lock_test_and_set(dst, src); + #else + { + MA_ATOMIC_COMPARE_AND_SWAP_LOCK(8, dst, expected, replacement); + } + #endif } - static MA_INLINE ma_uint16 ma_atomic_exchange_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + static MA_INLINE ma_uint16 ma_atomic_compare_and_swap_16(volatile ma_uint16* dst, ma_uint16 expected, ma_uint16 replacement) { - ma_uint16 oldValue; - do { - oldValue = *dst; - } while (__sync_val_compare_and_swap(dst, oldValue, src) != oldValue); - (void)order; - return oldValue; + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) + { + return __sync_val_compare_and_swap(dst, expected, replacement); + } + #else + { + MA_ATOMIC_COMPARE_AND_SWAP_LOCK(16, dst, expected, replacement); + } + #endif } - static MA_INLINE ma_uint32 ma_atomic_exchange_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + static MA_INLINE ma_uint32 ma_atomic_compare_and_swap_32(volatile ma_uint32* dst, ma_uint32 expected, ma_uint32 replacement) { - ma_uint32 oldValue; - do { - oldValue = *dst; - } while (__sync_val_compare_and_swap(dst, oldValue, src) != oldValue); - (void)order; - return oldValue; + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + { + return __sync_val_compare_and_swap(dst, expected, replacement); + } + #else + { + MA_ATOMIC_COMPARE_AND_SWAP_LOCK(32, dst, expected, replacement); + } + #endif } - static MA_INLINE ma_uint64 ma_atomic_exchange_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + static MA_INLINE ma_uint64 ma_atomic_compare_and_swap_64(volatile ma_uint64* dst, ma_uint64 expected, ma_uint64 replacement) { - ma_uint64 oldValue; - do { - oldValue = *dst; - } while (__sync_val_compare_and_swap(dst, oldValue, src) != oldValue); - (void)order; - return oldValue; + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) + { + return __sync_val_compare_and_swap(dst, expected, replacement); + } + #else + { + MA_ATOMIC_COMPARE_AND_SWAP_LOCK(64, dst, expected, replacement); + } + #endif } - static MA_INLINE ma_uint8 ma_atomic_fetch_add_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + static MA_INLINE ma_uint8 ma_atomic_load_explicit_8(volatile const ma_uint8* ptr, ma_atomic_memory_order order) { - (void)order; - return __sync_fetch_and_add(dst, src); + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) + { + (void)order; + return ma_atomic_compare_and_swap_8((ma_uint8*)ptr, 0, 0); + } + #else + { + MA_ATOMIC_LOAD_EXPLICIT_LOCK(8, ptr, order); + } + #endif } - static MA_INLINE ma_uint16 ma_atomic_fetch_add_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + static MA_INLINE ma_uint16 ma_atomic_load_explicit_16(volatile const ma_uint16* ptr, ma_atomic_memory_order order) { - (void)order; - return __sync_fetch_and_add(dst, src); + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) + { + (void)order; + return ma_atomic_compare_and_swap_16((ma_uint16*)ptr, 0, 0); + } + #else + { + MA_ATOMIC_LOAD_EXPLICIT_LOCK(16, ptr, order); + } + #endif } - static MA_INLINE ma_uint32 ma_atomic_fetch_add_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + static MA_INLINE ma_uint32 ma_atomic_load_explicit_32(volatile const ma_uint32* ptr, ma_atomic_memory_order order) { - (void)order; - return __sync_fetch_and_add(dst, src); + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + { + (void)order; + return ma_atomic_compare_and_swap_32((ma_uint32*)ptr, 0, 0); + } + #else + { + MA_ATOMIC_LOAD_EXPLICIT_LOCK(32, ptr, order); + } + #endif } - static MA_INLINE ma_uint64 ma_atomic_fetch_add_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + static MA_INLINE ma_uint64 ma_atomic_load_explicit_64(volatile const ma_uint64* ptr, ma_atomic_memory_order order) { - (void)order; - return __sync_fetch_and_add(dst, src); - } - static MA_INLINE ma_uint8 ma_atomic_fetch_sub_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) - { - (void)order; - return __sync_fetch_and_sub(dst, src); - } - static MA_INLINE ma_uint16 ma_atomic_fetch_sub_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) - { - (void)order; - return __sync_fetch_and_sub(dst, src); - } - static MA_INLINE ma_uint32 ma_atomic_fetch_sub_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) - { - (void)order; - return __sync_fetch_and_sub(dst, src); - } - static MA_INLINE ma_uint64 ma_atomic_fetch_sub_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) - { - (void)order; - return __sync_fetch_and_sub(dst, src); - } - static MA_INLINE ma_uint8 ma_atomic_fetch_or_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) - { - (void)order; - return __sync_fetch_and_or(dst, src); - } - static MA_INLINE ma_uint16 ma_atomic_fetch_or_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) - { - (void)order; - return __sync_fetch_and_or(dst, src); - } - static MA_INLINE ma_uint32 ma_atomic_fetch_or_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) - { - (void)order; - return __sync_fetch_and_or(dst, src); - } - static MA_INLINE ma_uint64 ma_atomic_fetch_or_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) - { - (void)order; - return __sync_fetch_and_or(dst, src); - } - static MA_INLINE ma_uint8 ma_atomic_fetch_xor_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) - { - (void)order; - return __sync_fetch_and_xor(dst, src); - } - static MA_INLINE ma_uint16 ma_atomic_fetch_xor_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) - { - (void)order; - return __sync_fetch_and_xor(dst, src); - } - static MA_INLINE ma_uint32 ma_atomic_fetch_xor_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) - { - (void)order; - return __sync_fetch_and_xor(dst, src); - } - static MA_INLINE ma_uint64 ma_atomic_fetch_xor_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) - { - (void)order; - return __sync_fetch_and_xor(dst, src); - } - static MA_INLINE ma_uint8 ma_atomic_fetch_and_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) - { - (void)order; - return __sync_fetch_and_and(dst, src); - } - static MA_INLINE ma_uint16 ma_atomic_fetch_and_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) - { - (void)order; - return __sync_fetch_and_and(dst, src); - } - static MA_INLINE ma_uint32 ma_atomic_fetch_and_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) - { - (void)order; - return __sync_fetch_and_and(dst, src); - } - static MA_INLINE ma_uint64 ma_atomic_fetch_and_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) - { - (void)order; - return __sync_fetch_and_and(dst, src); - } - #define ma_atomic_compare_and_swap_8( dst, expected, desired) __sync_val_compare_and_swap(dst, expected, desired) - #define ma_atomic_compare_and_swap_16(dst, expected, desired) __sync_val_compare_and_swap(dst, expected, desired) - #define ma_atomic_compare_and_swap_32(dst, expected, desired) __sync_val_compare_and_swap(dst, expected, desired) - #define ma_atomic_compare_and_swap_64(dst, expected, desired) __sync_val_compare_and_swap(dst, expected, desired) - #else - #if defined(MA_X86) - #define ma_atomic_thread_fence(order) __asm__ __volatile__("lock; addl $0, (%%esp)" ::: "memory", "cc") - #elif defined(MA_X64) - #define ma_atomic_thread_fence(order) __asm__ __volatile__("lock; addq $0, (%%rsp)" ::: "memory", "cc") - #else - #error Unsupported architecture. Please submit a feature request. - #endif - static MA_INLINE ma_uint8 ma_atomic_compare_and_swap_8(volatile ma_uint8* dst, ma_uint8 expected, ma_uint8 desired) - { - ma_uint8 result; - #if defined(MA_X86) || defined(MA_X64) - __asm__ __volatile__("lock; cmpxchg %3, %0" : "+m"(*dst), "=a"(result) : "a"(expected), "d"(desired) : "cc"); - #else - #error Unsupported architecture. Please submit a feature request. - #endif - return result; - } - static MA_INLINE ma_uint16 ma_atomic_compare_and_swap_16(volatile ma_uint16* dst, ma_uint16 expected, ma_uint16 desired) - { - ma_uint16 result; - #if defined(MA_X86) || defined(MA_X64) - __asm__ __volatile__("lock; cmpxchg %3, %0" : "+m"(*dst), "=a"(result) : "a"(expected), "d"(desired) : "cc"); - #else - #error Unsupported architecture. Please submit a feature request. - #endif - return result; - } - static MA_INLINE ma_uint32 ma_atomic_compare_and_swap_32(volatile ma_uint32* dst, ma_uint32 expected, ma_uint32 desired) - { - ma_uint32 result; - #if defined(MA_X86) || defined(MA_X64) - __asm__ __volatile__("lock; cmpxchg %3, %0" : "+m"(*dst), "=a"(result) : "a"(expected), "d"(desired) : "cc"); - #else - #error Unsupported architecture. Please submit a feature request. - #endif - return result; - } - static MA_INLINE ma_uint64 ma_atomic_compare_and_swap_64(volatile ma_uint64* dst, ma_uint64 expected, ma_uint64 desired) - { - volatile ma_uint64 result; - #if defined(MA_X86) - ma_uint32 resultEAX; - ma_uint32 resultEDX; - __asm__ __volatile__("push %%ebx; xchg %5, %%ebx; lock; cmpxchg8b %0; pop %%ebx" : "+m"(*dst), "=a"(resultEAX), "=d"(resultEDX) : "a"(expected & 0xFFFFFFFF), "d"(expected >> 32), "r"(desired & 0xFFFFFFFF), "c"(desired >> 32) : "cc"); - result = ((ma_uint64)resultEDX << 32) | resultEAX; - #elif defined(MA_X64) - __asm__ __volatile__("lock; cmpxchg %3, %0" : "+m"(*dst), "=a"(result) : "a"(expected), "d"(desired) : "cc"); - #else - #error Unsupported architecture. Please submit a feature request. - #endif - return result; + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) + { + (void)order; + return ma_atomic_compare_and_swap_64((ma_uint64*)ptr, 0, 0); + } + #else + { + MA_ATOMIC_LOAD_EXPLICIT_LOCK(64, ptr, order); + } + #endif } static MA_INLINE ma_uint8 ma_atomic_exchange_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) { - ma_uint8 result = 0; - (void)order; - #if defined(MA_X86) || defined(MA_X64) - __asm__ __volatile__("lock; xchg %1, %0" : "+m"(*dst), "=a"(result) : "a"(src)); - #else - #error Unsupported architecture. Please submit a feature request. - #endif - return result; + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) + { + if (order > ma_atomic_memory_order_acquire) { + __sync_synchronize(); + } + return __sync_lock_test_and_set(dst, src); + } + #else + { + MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(8, dst, src, order); + } + #endif } static MA_INLINE ma_uint16 ma_atomic_exchange_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) { - ma_uint16 result = 0; - (void)order; - #if defined(MA_X86) || defined(MA_X64) - __asm__ __volatile__("lock; xchg %1, %0" : "+m"(*dst), "=a"(result) : "a"(src)); - #else - #error Unsupported architecture. Please submit a feature request. - #endif - return result; + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) + { + if (order > ma_atomic_memory_order_acquire) { + __sync_synchronize(); + } + return __sync_lock_test_and_set(dst, src); + } + #else + { + MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(16, dst, src, order); + } + #endif } static MA_INLINE ma_uint32 ma_atomic_exchange_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) { - ma_uint32 result; - (void)order; - #if defined(MA_X86) || defined(MA_X64) - __asm__ __volatile__("lock; xchg %1, %0" : "+m"(*dst), "=a"(result) : "a"(src)); - #else - #error Unsupported architecture. Please submit a feature request. - #endif - return result; + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + { + if (order > ma_atomic_memory_order_acquire) { + __sync_synchronize(); + } + return __sync_lock_test_and_set(dst, src); + } + #else + { + MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(32, dst, src, order); + } + #endif } static MA_INLINE ma_uint64 ma_atomic_exchange_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) { - ma_uint64 result; - (void)order; - #if defined(MA_X86) - do { - result = *dst; - } while (ma_atomic_compare_and_swap_64(dst, result, src) != result); - #elif defined(MA_X64) - __asm__ __volatile__("lock; xchg %1, %0" : "+m"(*dst), "=a"(result) : "a"(src)); - #else - #error Unsupported architecture. Please submit a feature request. - #endif - return result; + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) + { + if (order > ma_atomic_memory_order_acquire) { + __sync_synchronize(); + } + return __sync_lock_test_and_set(dst, src); + } + #else + { + MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(64, dst, src, order); + } + #endif } + #define ma_atomic_store_explicit_8( dst, src, order) (void)ma_atomic_exchange_explicit_8 (dst, src, order) + #define ma_atomic_store_explicit_16(dst, src, order) (void)ma_atomic_exchange_explicit_16(dst, src, order) + #define ma_atomic_store_explicit_32(dst, src, order) (void)ma_atomic_exchange_explicit_32(dst, src, order) + #define ma_atomic_store_explicit_64(dst, src, order) (void)ma_atomic_exchange_explicit_64(dst, src, order) static MA_INLINE ma_uint8 ma_atomic_fetch_add_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) { - ma_uint8 result; - (void)order; - #if defined(MA_X86) || defined(MA_X64) - __asm__ __volatile__("lock; xadd %1, %0" : "+m"(*dst), "=a"(result) : "a"(src) : "cc"); - #else - #error Unsupported architecture. Please submit a feature request. - #endif - return result; + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) + { + (void)order; + return __sync_fetch_and_add(dst, src); + } + #else + { + MA_ATOMIC_FETCH_ADD_LOCK(8, dst, src, order); + } + #endif } static MA_INLINE ma_uint16 ma_atomic_fetch_add_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) { - ma_uint16 result; - (void)order; - #if defined(MA_X86) || defined(MA_X64) - __asm__ __volatile__("lock; xadd %1, %0" : "+m"(*dst), "=a"(result) : "a"(src) : "cc"); - #else - #error Unsupported architecture. Please submit a feature request. - #endif - return result; + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) + { + (void)order; + return __sync_fetch_and_add(dst, src); + } + #else + { + MA_ATOMIC_FETCH_ADD_LOCK(16, dst, src, order); + } + #endif } static MA_INLINE ma_uint32 ma_atomic_fetch_add_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) { - ma_uint32 result; - (void)order; - #if defined(MA_X86) || defined(MA_X64) - __asm__ __volatile__("lock; xadd %1, %0" : "+m"(*dst), "=a"(result) : "a"(src) : "cc"); - #else - #error Unsupported architecture. Please submit a feature request. - #endif - return result; + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + { + (void)order; + return __sync_fetch_and_add(dst, src); + } + #else + { + MA_ATOMIC_FETCH_ADD_LOCK(32, dst, src, order); + } + #endif } static MA_INLINE ma_uint64 ma_atomic_fetch_add_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) { - #if defined(MA_X86) - ma_uint64 oldValue; - ma_uint64 newValue; - (void)order; - do { - oldValue = *dst; - newValue = oldValue + src; - } while (ma_atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); - return oldValue; - #elif defined(MA_X64) - ma_uint64 result; - (void)order; - __asm__ __volatile__("lock; xadd %1, %0" : "+m"(*dst), "=a"(result) : "a"(src) : "cc"); - return result; - #endif + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) + { + (void)order; + return __sync_fetch_and_add(dst, src); + } + #else + { + MA_ATOMIC_FETCH_ADD_LOCK(64, dst, src, order); + } + #endif } static MA_INLINE ma_uint8 ma_atomic_fetch_sub_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) { - ma_uint8 oldValue; - ma_uint8 newValue; - do { - oldValue = *dst; - newValue = (ma_uint8)(oldValue - src); - } while (ma_atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) + { + (void)order; + return __sync_fetch_and_sub(dst, src); + } + #else + { + MA_ATOMIC_FETCH_ADD_LOCK(8, dst, (ma_uint8)(-(ma_int8)src), order); + } + #endif } static MA_INLINE ma_uint16 ma_atomic_fetch_sub_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) { - ma_uint16 oldValue; - ma_uint16 newValue; - do { - oldValue = *dst; - newValue = (ma_uint16)(oldValue - src); - } while (ma_atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) + { + (void)order; + return __sync_fetch_and_sub(dst, src); + } + #else + { + MA_ATOMIC_FETCH_ADD_LOCK(16, dst, (ma_uint16)(-(ma_int16)src), order); + } + #endif } static MA_INLINE ma_uint32 ma_atomic_fetch_sub_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) { - ma_uint32 oldValue; - ma_uint32 newValue; - do { - oldValue = *dst; - newValue = oldValue - src; - } while (ma_atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + { + (void)order; + return __sync_fetch_and_sub(dst, src); + } + #else + { + MA_ATOMIC_FETCH_ADD_LOCK(32, dst, (ma_uint32)(-(ma_int32)src), order); + } + #endif } static MA_INLINE ma_uint64 ma_atomic_fetch_sub_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) { - ma_uint64 oldValue; - ma_uint64 newValue; - do { - oldValue = *dst; - newValue = oldValue - src; - } while (ma_atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) + { + (void)order; + return __sync_fetch_and_sub(dst, src); + } + #else + { + MA_ATOMIC_FETCH_ADD_LOCK(64, dst, (ma_uint64)(-(ma_int64)src), order); + } + #endif } static MA_INLINE ma_uint8 ma_atomic_fetch_and_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) { - ma_uint8 oldValue; - ma_uint8 newValue; - do { - oldValue = *dst; - newValue = (ma_uint8)(oldValue & src); - } while (ma_atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) + { + (void)order; + return __sync_fetch_and_and(dst, src); + } + #else + { + MA_ATOMIC_FETCH_AND_CAS(8, dst, src, order); + } + #endif } static MA_INLINE ma_uint16 ma_atomic_fetch_and_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) { - ma_uint16 oldValue; - ma_uint16 newValue; - do { - oldValue = *dst; - newValue = (ma_uint16)(oldValue & src); - } while (ma_atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) + { + (void)order; + return __sync_fetch_and_and(dst, src); + } + #else + { + MA_ATOMIC_FETCH_AND_CAS(16, dst, src, order); + } + #endif } static MA_INLINE ma_uint32 ma_atomic_fetch_and_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) { - ma_uint32 oldValue; - ma_uint32 newValue; - do { - oldValue = *dst; - newValue = oldValue & src; - } while (ma_atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + { + (void)order; + return __sync_fetch_and_and(dst, src); + } + #else + { + MA_ATOMIC_FETCH_AND_CAS(32, dst, src, order); + } + #endif } static MA_INLINE ma_uint64 ma_atomic_fetch_and_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) { - ma_uint64 oldValue; - ma_uint64 newValue; - do { - oldValue = *dst; - newValue = oldValue & src; - } while (ma_atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; - } - static MA_INLINE ma_uint8 ma_atomic_fetch_xor_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) - { - ma_uint8 oldValue; - ma_uint8 newValue; - do { - oldValue = *dst; - newValue = (ma_uint8)(oldValue ^ src); - } while (ma_atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; - } - static MA_INLINE ma_uint16 ma_atomic_fetch_xor_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) - { - ma_uint16 oldValue; - ma_uint16 newValue; - do { - oldValue = *dst; - newValue = (ma_uint16)(oldValue ^ src); - } while (ma_atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; - } - static MA_INLINE ma_uint32 ma_atomic_fetch_xor_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) - { - ma_uint32 oldValue; - ma_uint32 newValue; - do { - oldValue = *dst; - newValue = oldValue ^ src; - } while (ma_atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; - } - static MA_INLINE ma_uint64 ma_atomic_fetch_xor_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) - { - ma_uint64 oldValue; - ma_uint64 newValue; - do { - oldValue = *dst; - newValue = oldValue ^ src; - } while (ma_atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) + { + (void)order; + return __sync_fetch_and_and(dst, src); + } + #else + { + MA_ATOMIC_FETCH_AND_CAS(64, dst, src, order); + } + #endif } static MA_INLINE ma_uint8 ma_atomic_fetch_or_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) { - ma_uint8 oldValue; - ma_uint8 newValue; - do { - oldValue = *dst; - newValue = (ma_uint8)(oldValue | src); - } while (ma_atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) + { + (void)order; + return __sync_fetch_and_or(dst, src); + } + #else + { + MA_ATOMIC_FETCH_OR_CAS(8, dst, src, order); + } + #endif } static MA_INLINE ma_uint16 ma_atomic_fetch_or_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) { - ma_uint16 oldValue; - ma_uint16 newValue; - do { - oldValue = *dst; - newValue = (ma_uint16)(oldValue | src); - } while (ma_atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) + { + (void)order; + return __sync_fetch_and_or(dst, src); + } + #else + { + MA_ATOMIC_FETCH_OR_CAS(16, dst, src, order); + } + #endif } static MA_INLINE ma_uint32 ma_atomic_fetch_or_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) { - ma_uint32 oldValue; - ma_uint32 newValue; - do { - oldValue = *dst; - newValue = oldValue | src; - } while (ma_atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + { + (void)order; + return __sync_fetch_and_or(dst, src); + } + #else + { + MA_ATOMIC_FETCH_OR_CAS(32, dst, src, order); + } + #endif } static MA_INLINE ma_uint64 ma_atomic_fetch_or_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) { - ma_uint64 oldValue; - ma_uint64 newValue; - do { - oldValue = *dst; - newValue = oldValue | src; - } while (ma_atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); - (void)order; - return oldValue; + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) + { + (void)order; + return __sync_fetch_and_or(dst, src); + } + #else + { + MA_ATOMIC_FETCH_OR_CAS(64, dst, src, order); + } + #endif } + static MA_INLINE ma_uint8 ma_atomic_fetch_xor_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) + { + (void)order; + return __sync_fetch_and_xor(dst, src); + } + #else + { + MA_ATOMIC_FETCH_XOR_CAS(8, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint16 ma_atomic_fetch_xor_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) + { + (void)order; + return __sync_fetch_and_xor(dst, src); + } + #else + { + MA_ATOMIC_FETCH_XOR_CAS(16, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint32 ma_atomic_fetch_xor_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) + { + (void)order; + return __sync_fetch_and_xor(dst, src); + } + #else + { + MA_ATOMIC_FETCH_XOR_CAS(32, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint64 ma_atomic_fetch_xor_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) + { + (void)order; + return __sync_fetch_and_xor(dst, src); + } + #else + { + MA_ATOMIC_FETCH_XOR_CAS(64, dst, src, order); + } + #endif + } + #elif defined(MA_ATOMIC_LEGACY_GCC_ASM) + #define MA_ATOMIC_CMPXCHG_GCC_X86(instructionSizeSuffix, result, dst, expected, replacement) \ + __asm__ __volatile__( \ + "lock; cmpxchg"instructionSizeSuffix" %2, %1" \ + : "=a"(result), \ + "=m"(*dst) \ + : "r"(replacement), \ + "0"(expected), \ + "m"(*dst) \ + : "cc", "memory") + #define MA_ATOMIC_XADD_GCC_X86(instructionSizeSuffix, result, dst, src) \ + __asm__ __volatile__( \ + "lock; xadd"instructionSizeSuffix" %0, %1" \ + : "=a"(result), \ + "=m"(*dst) \ + : "0"(src), \ + "m"(*dst) \ + : "cc", "memory") + static MA_INLINE ma_uint8 ma_atomic_compare_and_swap_8(volatile ma_uint8* dst, ma_uint8 expected, ma_uint8 replacement) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) && (defined(MA_X86) || defined(MA_X64)) + { + ma_uint8 result; + #if defined(MA_X86) || defined(MA_X64) + { + MA_ATOMIC_CMPXCHG_GCC_X86("b", result, dst, expected, replacement); + } + #else + { + #error Unsupported architecture. + } + #endif + return result; + } + #else + { + MA_ATOMIC_COMPARE_AND_SWAP_LOCK(8, dst, expected, replacement); + } + #endif + } + static MA_INLINE ma_uint16 ma_atomic_compare_and_swap_16(volatile ma_uint16* dst, ma_uint16 expected, ma_uint16 replacement) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) && (defined(MA_X86) || defined(MA_X64)) + { + ma_uint16 result; + #if defined(MA_X86) || defined(MA_X64) + { + MA_ATOMIC_CMPXCHG_GCC_X86("w", result, dst, expected, replacement); + } + #else + { + #error Unsupported architecture. + } + #endif + return result; + } + #else + { + MA_ATOMIC_COMPARE_AND_SWAP_LOCK(16, dst, expected, replacement); + } + #endif + } + static MA_INLINE ma_uint32 ma_atomic_compare_and_swap_32(volatile ma_uint32* dst, ma_uint32 expected, ma_uint32 replacement) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) && (defined(MA_X86) || defined(MA_X64)) + { + ma_uint32 result; + #if defined(MA_X86) || defined(MA_X64) + { + MA_ATOMIC_CMPXCHG_GCC_X86("l", result, dst, expected, replacement); + } + #else + { + #error Unsupported architecture. + } + #endif + return result; + } + #else + { + MA_ATOMIC_COMPARE_AND_SWAP_LOCK(32, dst, expected, replacement); + } + #endif + } + static MA_INLINE ma_uint64 ma_atomic_compare_and_swap_64(volatile ma_uint64* dst, ma_uint64 expected, ma_uint64 replacement) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) && (defined(MA_X86) || defined(MA_X64)) + { + ma_uint64 result; + #if defined(MA_X86) + { + ma_uint32 resultEAX; + ma_uint32 resultEDX; + __asm__ __volatile__( + "pushl %%ebx\n" + "movl %4, %%ebx\n" + "lock cmpxchg8b (%%edi)\n" + "popl %%ebx\n" + : "=a"(resultEAX), + "=d"(resultEDX) + : "a"((ma_uint32)(expected & 0xFFFFFFFF)), + "d"((ma_uint32)(expected >> 32)), + "r"((ma_uint32)(replacement & 0xFFFFFFFF)), + "c"((ma_uint32)(replacement >> 32)), + "D"(dst) + : "memory", "cc"); + result = ((ma_uint64)resultEDX << 32) | resultEAX; + } + #elif defined(MA_X64) + { + MA_ATOMIC_CMPXCHG_GCC_X86("q", result, dst, expected, replacement); + } + #else + { + #error Unsupported architecture. + } + #endif + return result; + } + #else + { + MA_ATOMIC_COMPARE_AND_SWAP_LOCK(64, dst, expected, replacement); + } + #endif + } + static MA_INLINE ma_uint8 ma_atomic_load_explicit_8(volatile const ma_uint8* dst, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) && (defined(MA_X86) || defined(MA_X64)) + { + ma_uint8 result; + #if defined(MA_X86) || defined(MA_X64) + { + if (order == ma_atomic_memory_order_relaxed) { + MA_ATOMIC_LOAD_RELAXED_GCC_X86("b", result, dst); + } else if (order <= ma_atomic_memory_order_release) { + MA_ATOMIC_LOAD_RELEASE_GCC_X86("b", result, dst); + } else { + MA_ATOMIC_LOAD_SEQ_CST_GCC_X86("b", result, dst); + } + } + #else + { + #error Unsupported architecture. + } + #endif + return result; + } + #else + { + MA_ATOMIC_LOAD_EXPLICIT_LOCK(8, dst, order); + } + #endif + } + static MA_INLINE ma_uint16 ma_atomic_load_explicit_16(volatile const ma_uint16* dst, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) && (defined(MA_X86) || defined(MA_X64)) + { + ma_uint16 result; + #if defined(MA_X86) || defined(MA_X64) + { + if (order == ma_atomic_memory_order_relaxed) { + MA_ATOMIC_LOAD_RELAXED_GCC_X86("w", result, dst); + } else if (order <= ma_atomic_memory_order_release) { + MA_ATOMIC_LOAD_RELEASE_GCC_X86("w", result, dst); + } else { + MA_ATOMIC_LOAD_SEQ_CST_GCC_X86("w", result, dst); + } + } + #else + { + #error Unsupported architecture. + } + #endif + return result; + } + #else + { + MA_ATOMIC_LOAD_EXPLICIT_LOCK(16, dst, order); + } + #endif + } + static MA_INLINE ma_uint32 ma_atomic_load_explicit_32(volatile const ma_uint32* dst, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) && (defined(MA_X86) || defined(MA_X64)) + { + ma_uint32 result; + #if defined(MA_X86) || defined(MA_X64) + { + if (order == ma_atomic_memory_order_relaxed) { + MA_ATOMIC_LOAD_RELAXED_GCC_X86("l", result, dst); + } else if (order <= ma_atomic_memory_order_release) { + MA_ATOMIC_LOAD_RELEASE_GCC_X86("l", result, dst); + } else { + MA_ATOMIC_LOAD_SEQ_CST_GCC_X86("l", result, dst); + } + } + #else + { + #error Unsupported architecture. + } + #endif + return result; + } + #else + { + MA_ATOMIC_LOAD_EXPLICIT_LOCK(32, dst, order); + } + #endif + } + static MA_INLINE ma_uint64 ma_atomic_load_explicit_64(volatile const ma_uint64* dst, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) && (defined(MA_X86) || defined(MA_X64)) + { + ma_uint64 result; + #if defined(MA_X64) + { + if (order == ma_atomic_memory_order_relaxed) { + MA_ATOMIC_LOAD_RELAXED_GCC_X86("q", result, dst); + } else if (order <= ma_atomic_memory_order_release) { + MA_ATOMIC_LOAD_RELEASE_GCC_X86("q", result, dst); + } else { + MA_ATOMIC_LOAD_SEQ_CST_GCC_X86("q", result, dst); + } + } + #elif defined(MA_X86) + { + (void)order; + return ma_atomic_compare_and_swap_64((volatile ma_uint64*)dst, 0, 0); + } + #else + { + #error Unsupported architecture. + } + #endif + return result; + } + #else + { + MA_ATOMIC_LOAD_EXPLICIT_LOCK(64, dst, order); + } + #endif + } + static MA_INLINE ma_uint8 ma_atomic_exchange_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) && (defined(MA_X86) || defined(MA_X64)) + { + ma_uint8 result; + (void)order; + #if defined(MA_X86) || defined(MA_X64) + { + MA_ATOMIC_XCHG_GCC_X86("b", result, dst, src); + } + #else + { + #error Unsupported architecture. + } + #endif + return result; + } + #else + { + MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(8, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint16 ma_atomic_exchange_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) && (defined(MA_X86) || defined(MA_X64)) + { + ma_uint16 result; + (void)order; + #if defined(MA_X86) || defined(MA_X64) + { + MA_ATOMIC_XCHG_GCC_X86("w", result, dst, src); + } + #else + { + #error Unsupported architecture. + } + #endif + return result; + } + #else + { + MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(16, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint32 ma_atomic_exchange_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) && (defined(MA_X86) || defined(MA_X64)) + { + ma_uint32 result; + (void)order; + #if defined(MA_X86) || defined(MA_X64) + { + MA_ATOMIC_XCHG_GCC_X86("l", result, dst, src); + } + #else + { + #error Unsupported architecture. + } + #endif + return result; + } + #else + { + MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(32, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint64 ma_atomic_exchange_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) && (defined(MA_X86) || defined(MA_X64)) + { + ma_uint64 result; + (void)order; + #if defined(MA_X86) + { + MA_ATOMIC_EXCHANGE_EXPLICIT_CAS(64, dst, src, order); + } + #elif defined(MA_X64) + { + MA_ATOMIC_XCHG_GCC_X86("q", result, dst, src); + } + #else + { + #error Unsupported architecture. + } + #endif + return result; + } + #else + { + MA_ATOMIC_EXCHANGE_EXPLICIT_LOCK(64, dst, src, order); + } + #endif + } + static MA_INLINE void ma_atomic_store_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) && (defined(MA_X86) || defined(MA_X64)) + { + #if defined(MA_X86) || defined(MA_X64) + { + if (order == ma_atomic_memory_order_relaxed) { + __asm__ __volatile__ ( + "movb %1, %0" + : "=m"(*dst) + : "r"(src) + ); + } else { + __asm__ __volatile__ ( + "xchgb %1, %0" + : "=m"(*dst) + : "r"(src) + : "memory" + ); + } + } + #else + { + #error Unsupported architecture. + } + #endif + } + #else + { + MA_ATOMIC_STORE_EXPLICIT_LOCK(8, dst, src, order); + } + #endif + } + static MA_INLINE void ma_atomic_store_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) && (defined(MA_X86) || defined(MA_X64)) + { + #if defined(MA_X86) || defined(MA_X64) + { + if (order == ma_atomic_memory_order_relaxed) { + __asm__ __volatile__ ( + "movw %1, %0" + : "=m"(*dst) + : "r"(src) + ); + } else { + __asm__ __volatile__ ( + "xchgw %1, %0" + : "=m"(*dst) + : "r"(src) + : "memory" + ); + } + } + #else + { + #error Unsupported architecture. + } + #endif + } + #else + { + MA_ATOMIC_STORE_EXPLICIT_LOCK(16, dst, src, order); + } + #endif + } + static MA_INLINE void ma_atomic_store_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) && (defined(MA_X86) || defined(MA_X64)) + { + #if defined(MA_X86) || defined(MA_X64) + { + if (order == ma_atomic_memory_order_relaxed) { + __asm__ __volatile__ ( + "movl %1, %0" + : "=m"(*dst) + : "r"(src) + ); + } else { + __asm__ __volatile__ ( + "xchgl %1, %0" + : "=m"(*dst) + : "r"(src) + : "memory" + ); + } + } + #else + { + #error Unsupported architecture. + } + #endif + } + #else + { + MA_ATOMIC_STORE_EXPLICIT_LOCK(32, dst, src, order); + } + #endif + } + static MA_INLINE void ma_atomic_store_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) && (defined(MA_X86) || defined(MA_X64)) + { + #if defined(MA_X64) + { + if (order == ma_atomic_memory_order_relaxed) { + __asm__ __volatile__ ( + "movq %1, %0" + : "=m"(*dst) + : "r"(src) + ); + } else { + __asm__ __volatile__ ( + "xchgq %1, %0" + : "=m"(*dst) + : "r"(src) + : "memory" + ); + } + } + #else + { + MA_ATOMIC_STORE_EXPLICIT_CAS(64, dst, src, order); + } + #endif + } + #else + { + MA_ATOMIC_STORE_EXPLICIT_LOCK(64, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint8 ma_atomic_fetch_add_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_8) && (defined(MA_X86) || defined(MA_X64)) + { + #if defined(MA_X86) || defined(MA_X64) + { + ma_uint8 result; + (void)order; + MA_ATOMIC_XADD_GCC_X86("b", result, dst, src); + return result; + } + #else + { + #error Unsupported architecture. + } + #endif + } + #else + { + MA_ATOMIC_FETCH_ADD_LOCK(8, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint16 ma_atomic_fetch_add_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_16) && (defined(MA_X86) || defined(MA_X64)) + { + #if defined(MA_X86) || defined(MA_X64) + { + ma_uint16 result; + (void)order; + MA_ATOMIC_XADD_GCC_X86("w", result, dst, src); + return result; + } + #else + { + #error Unsupported architecture. + } + #endif + } + #else + { + MA_ATOMIC_FETCH_ADD_LOCK(16, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint32 ma_atomic_fetch_add_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_32) && (defined(MA_X86) || defined(MA_X64)) + { + #if defined(MA_X86) || defined(MA_X64) + { + ma_uint32 result; + (void)order; + MA_ATOMIC_XADD_GCC_X86("l", result, dst, src); + return result; + } + #else + { + #error Unsupported architecture. + } + #endif + } + #else + { + MA_ATOMIC_FETCH_ADD_LOCK(32, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint64 ma_atomic_fetch_add_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + #if defined(MA_ATOMIC_IS_LOCK_FREE_64) && (defined(MA_X86) || defined(MA_X64)) + { + #if defined(MA_X86) + { + MA_ATOMIC_FETCH_ADD_CAS(64, dst, src, order); + } + #elif defined(MA_X64) + { + ma_uint64 result; + MA_ATOMIC_XADD_GCC_X86("q", result, dst, src); + (void)order; + return result; + } + #else + { + #error Unsupported architecture. + } + #endif + } + #else + { + MA_ATOMIC_FETCH_ADD_LOCK(64, dst, src, order); + } + #endif + } + static MA_INLINE ma_uint8 ma_atomic_fetch_sub_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + return ma_atomic_fetch_add_explicit_8(dst, (ma_uint8)(-(ma_int8)src), order); + } + static MA_INLINE ma_uint16 ma_atomic_fetch_sub_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + return ma_atomic_fetch_add_explicit_16(dst, (ma_uint16)(-(ma_int16)src), order); + } + static MA_INLINE ma_uint32 ma_atomic_fetch_sub_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + return ma_atomic_fetch_add_explicit_32(dst, (ma_uint32)(-(ma_int32)src), order); + } + static MA_INLINE ma_uint64 ma_atomic_fetch_sub_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + return ma_atomic_fetch_add_explicit_64(dst, (ma_uint64)(-(ma_int64)src), order); + } + static MA_INLINE ma_uint8 ma_atomic_fetch_and_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_AND_CAS(8, dst, src, order); + } + static MA_INLINE ma_uint16 ma_atomic_fetch_and_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_AND_CAS(16, dst, src, order); + } + static MA_INLINE ma_uint32 ma_atomic_fetch_and_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_AND_CAS(32, dst, src, order); + } + static MA_INLINE ma_uint64 ma_atomic_fetch_and_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_AND_CAS(64, dst, src, order); + } + static MA_INLINE ma_uint8 ma_atomic_fetch_or_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_OR_CAS(8, dst, src, order); + } + static MA_INLINE ma_uint16 ma_atomic_fetch_or_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_OR_CAS(16, dst, src, order); + } + static MA_INLINE ma_uint32 ma_atomic_fetch_or_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_OR_CAS(32, dst, src, order); + } + static MA_INLINE ma_uint64 ma_atomic_fetch_or_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_OR_CAS(64, dst, src, order); + } + static MA_INLINE ma_uint8 ma_atomic_fetch_xor_explicit_8(volatile ma_uint8* dst, ma_uint8 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_XOR_CAS(8, dst, src, order); + } + static MA_INLINE ma_uint16 ma_atomic_fetch_xor_explicit_16(volatile ma_uint16* dst, ma_uint16 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_XOR_CAS(16, dst, src, order); + } + static MA_INLINE ma_uint32 ma_atomic_fetch_xor_explicit_32(volatile ma_uint32* dst, ma_uint32 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_XOR_CAS(32, dst, src, order); + } + static MA_INLINE ma_uint64 ma_atomic_fetch_xor_explicit_64(volatile ma_uint64* dst, ma_uint64 src, ma_atomic_memory_order order) + { + MA_ATOMIC_FETCH_XOR_CAS(64, dst, src, order); + } + #else + #error Unsupported compiler. #endif - #define ma_atomic_signal_fence(order) ma_atomic_thread_fence(order) - static MA_INLINE ma_uint8 ma_atomic_load_explicit_8(volatile const ma_uint8* ptr, ma_atomic_memory_order order) - { - (void)order; - return ma_atomic_compare_and_swap_8((ma_uint8*)ptr, 0, 0); - } - static MA_INLINE ma_uint16 ma_atomic_load_explicit_16(volatile const ma_uint16* ptr, ma_atomic_memory_order order) - { - (void)order; - return ma_atomic_compare_and_swap_16((ma_uint16*)ptr, 0, 0); - } - static MA_INLINE ma_uint32 ma_atomic_load_explicit_32(volatile const ma_uint32* ptr, ma_atomic_memory_order order) - { - (void)order; - return ma_atomic_compare_and_swap_32((ma_uint32*)ptr, 0, 0); - } - static MA_INLINE ma_uint64 ma_atomic_load_explicit_64(volatile const ma_uint64* ptr, ma_atomic_memory_order order) - { - (void)order; - return ma_atomic_compare_and_swap_64((ma_uint64*)ptr, 0, 0); - } - #define ma_atomic_store_explicit_8( dst, src, order) (void)ma_atomic_exchange_explicit_8 (dst, src, order) - #define ma_atomic_store_explicit_16(dst, src, order) (void)ma_atomic_exchange_explicit_16(dst, src, order) - #define ma_atomic_store_explicit_32(dst, src, order) (void)ma_atomic_exchange_explicit_32(dst, src, order) - #define ma_atomic_store_explicit_64(dst, src, order) (void)ma_atomic_exchange_explicit_64(dst, src, order) - #define ma_atomic_test_and_set_explicit_8( dst, order) ma_atomic_exchange_explicit_8 (dst, 1, order) - #define ma_atomic_test_and_set_explicit_16(dst, order) ma_atomic_exchange_explicit_16(dst, 1, order) - #define ma_atomic_test_and_set_explicit_32(dst, order) ma_atomic_exchange_explicit_32(dst, 1, order) - #define ma_atomic_test_and_set_explicit_64(dst, order) ma_atomic_exchange_explicit_64(dst, 1, order) - #define ma_atomic_clear_explicit_8( dst, order) ma_atomic_store_explicit_8 (dst, 0, order) - #define ma_atomic_clear_explicit_16(dst, order) ma_atomic_store_explicit_16(dst, 0, order) - #define ma_atomic_clear_explicit_32(dst, order) ma_atomic_store_explicit_32(dst, 0, order) - #define ma_atomic_clear_explicit_64(dst, order) ma_atomic_store_explicit_64(dst, 0, order) - typedef ma_uint8 ma_atomic_flag; - #define ma_atomic_flag_test_and_set_explicit(ptr, order) (ma_bool32)ma_atomic_test_and_set_explicit_8(ptr, order) - #define ma_atomic_flag_clear_explicit(ptr, order) ma_atomic_clear_explicit_8(ptr, order) - #define ma_atomic_flag_load_explicit(ptr, order) ma_atomic_load_explicit_8(ptr, order) #endif #if !defined(MA_ATOMIC_HAS_NATIVE_COMPARE_EXCHANGE) - #if defined(MA_ATOMIC_HAS_8) - static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_8(volatile ma_uint8* dst, ma_uint8* expected, ma_uint8 desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) - { - ma_uint8 expectedValue; - ma_uint8 result; - (void)successOrder; - (void)failureOrder; - expectedValue = ma_atomic_load_explicit_8(expected, ma_atomic_memory_order_seq_cst); - result = ma_atomic_compare_and_swap_8(dst, expectedValue, desired); - if (result == expectedValue) { - return 1; - } else { - ma_atomic_store_explicit_8(expected, result, failureOrder); - return 0; - } - } - #endif - #if defined(MA_ATOMIC_HAS_16) - static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_16(volatile ma_uint16* dst, ma_uint16* expected, ma_uint16 desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) - { - ma_uint16 expectedValue; - ma_uint16 result; - (void)successOrder; - (void)failureOrder; - expectedValue = ma_atomic_load_explicit_16(expected, ma_atomic_memory_order_seq_cst); - result = ma_atomic_compare_and_swap_16(dst, expectedValue, desired); - if (result == expectedValue) { - return 1; - } else { - ma_atomic_store_explicit_16(expected, result, failureOrder); - return 0; - } - } - #endif - #if defined(MA_ATOMIC_HAS_32) - static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_32(volatile ma_uint32* dst, ma_uint32* expected, ma_uint32 desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) - { - ma_uint32 expectedValue; - ma_uint32 result; - (void)successOrder; - (void)failureOrder; - expectedValue = ma_atomic_load_explicit_32(expected, ma_atomic_memory_order_seq_cst); - result = ma_atomic_compare_and_swap_32(dst, expectedValue, desired); - if (result == expectedValue) { - return 1; - } else { - ma_atomic_store_explicit_32(expected, result, failureOrder); - return 0; - } - } - #endif - #if defined(MA_ATOMIC_HAS_64) - static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_64(volatile ma_uint64* dst, volatile ma_uint64* expected, ma_uint64 desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) - { - ma_uint64 expectedValue; - ma_uint64 result; - (void)successOrder; - (void)failureOrder; - expectedValue = ma_atomic_load_explicit_64(expected, ma_atomic_memory_order_seq_cst); - result = ma_atomic_compare_and_swap_64(dst, expectedValue, desired); - if (result == expectedValue) { - return 1; - } else { - ma_atomic_store_explicit_64(expected, result, failureOrder); - return 0; - } - } - #endif - #define ma_atomic_compare_exchange_weak_explicit_8( dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_8 (dst, expected, desired, successOrder, failureOrder) - #define ma_atomic_compare_exchange_weak_explicit_16(dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_16(dst, expected, desired, successOrder, failureOrder) - #define ma_atomic_compare_exchange_weak_explicit_32(dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_32(dst, expected, desired, successOrder, failureOrder) - #define ma_atomic_compare_exchange_weak_explicit_64(dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_64(dst, expected, desired, successOrder, failureOrder) -#endif -#if !defined(MA_ATOMIC_HAS_NATIVE_IS_LOCK_FREE) - static MA_INLINE ma_bool32 ma_atomic_is_lock_free_8(volatile void* ptr) + static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_8(volatile ma_uint8* dst, ma_uint8* expected, ma_uint8 replacement, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) { - (void)ptr; - return 1; - } - static MA_INLINE ma_bool32 ma_atomic_is_lock_free_16(volatile void* ptr) - { - (void)ptr; - return 1; - } - static MA_INLINE ma_bool32 ma_atomic_is_lock_free_32(volatile void* ptr) - { - (void)ptr; - return 1; - } - static MA_INLINE ma_bool32 ma_atomic_is_lock_free_64(volatile void* ptr) - { - (void)ptr; - #if defined(MA_64BIT) - return 1; - #else - #if defined(MA_X86) || defined(MA_X64) + ma_uint8 result; + (void)successOrder; + (void)failureOrder; + result = ma_atomic_compare_and_swap_8(dst, *expected, replacement); + if (result == *expected) { return 1; - #else + } else { + *expected = result; return 0; - #endif - #endif + } } + static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_16(volatile ma_uint16* dst, ma_uint16* expected, ma_uint16 replacement, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) + { + ma_uint16 result; + (void)successOrder; + (void)failureOrder; + result = ma_atomic_compare_and_swap_16(dst, *expected, replacement); + if (result == *expected) { + return 1; + } else { + *expected = result; + return 0; + } + } + static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_32(volatile ma_uint32* dst, ma_uint32* expected, ma_uint32 replacement, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) + { + ma_uint32 result; + (void)successOrder; + (void)failureOrder; + result = ma_atomic_compare_and_swap_32(dst, *expected, replacement); + if (result == *expected) { + return 1; + } else { + *expected = result; + return 0; + } + } + static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_64(volatile ma_uint64* dst, volatile ma_uint64* expected, ma_uint64 replacement, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) + { + ma_uint64 result; + (void)successOrder; + (void)failureOrder; + result = ma_atomic_compare_and_swap_64(dst, *expected, replacement); + if (result == *expected) { + return 1; + } else { + *expected = result; + return 0; + } + } + #define ma_atomic_compare_exchange_weak_explicit_8( dst, expected, replacement, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_8 (dst, expected, replacement, successOrder, failureOrder) + #define ma_atomic_compare_exchange_weak_explicit_16(dst, expected, replacement, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_16(dst, expected, replacement, successOrder, failureOrder) + #define ma_atomic_compare_exchange_weak_explicit_32(dst, expected, replacement, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_32(dst, expected, replacement, successOrder, failureOrder) + #define ma_atomic_compare_exchange_weak_explicit_64(dst, expected, replacement, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_64(dst, expected, replacement, successOrder, failureOrder) #endif #if defined(MA_64BIT) static MA_INLINE ma_bool32 ma_atomic_is_lock_free_ptr(volatile void** ptr) @@ -15561,17 +16968,17 @@ typedef int ma_atomic_memory_order; { return (void*)ma_atomic_exchange_explicit_64((volatile ma_uint64*)dst, (ma_uint64)src, order); } - static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_ptr(volatile void** dst, void** expected, void* desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) + static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_ptr(volatile void** dst, void** expected, void* replacement, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) { - return ma_atomic_compare_exchange_strong_explicit_64((volatile ma_uint64*)dst, (ma_uint64*)expected, (ma_uint64)desired, successOrder, failureOrder); + return ma_atomic_compare_exchange_strong_explicit_64((volatile ma_uint64*)dst, (ma_uint64*)expected, (ma_uint64)replacement, successOrder, failureOrder); } - static MA_INLINE ma_bool32 ma_atomic_compare_exchange_weak_explicit_ptr(volatile void** dst, void** expected, void* desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) + static MA_INLINE ma_bool32 ma_atomic_compare_exchange_weak_explicit_ptr(volatile void** dst, void** expected, void* replacement, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) { - return ma_atomic_compare_exchange_weak_explicit_64((volatile ma_uint64*)dst, (ma_uint64*)expected, (ma_uint64)desired, successOrder, failureOrder); + return ma_atomic_compare_exchange_weak_explicit_64((volatile ma_uint64*)dst, (ma_uint64*)expected, (ma_uint64)replacement, successOrder, failureOrder); } - static MA_INLINE void* ma_atomic_compare_and_swap_ptr(volatile void** dst, void* expected, void* desired) + static MA_INLINE void* ma_atomic_compare_and_swap_ptr(volatile void** dst, void* expected, void* replacement) { - return (void*)ma_atomic_compare_and_swap_64((volatile ma_uint64*)dst, (ma_uint64)expected, (ma_uint64)desired); + return (void*)ma_atomic_compare_and_swap_64((volatile ma_uint64*)dst, (ma_uint64)expected, (ma_uint64)replacement); } #elif defined(MA_32BIT) static MA_INLINE ma_bool32 ma_atomic_is_lock_free_ptr(volatile void** ptr) @@ -15590,36 +16997,26 @@ typedef int ma_atomic_memory_order; { return (void*)ma_atomic_exchange_explicit_32((volatile ma_uint32*)dst, (ma_uint32)src, order); } - static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_ptr(volatile void** dst, void** expected, void* desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) + static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_ptr(volatile void** dst, void** expected, void* replacement, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) { - return ma_atomic_compare_exchange_strong_explicit_32((volatile ma_uint32*)dst, (ma_uint32*)expected, (ma_uint32)desired, successOrder, failureOrder); + return ma_atomic_compare_exchange_strong_explicit_32((volatile ma_uint32*)dst, (ma_uint32*)expected, (ma_uint32)replacement, successOrder, failureOrder); } - static MA_INLINE ma_bool32 ma_atomic_compare_exchange_weak_explicit_ptr(volatile void** dst, void** expected, void* desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) + static MA_INLINE ma_bool32 ma_atomic_compare_exchange_weak_explicit_ptr(volatile void** dst, void** expected, void* replacement, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) { - return ma_atomic_compare_exchange_weak_explicit_32((volatile ma_uint32*)dst, (ma_uint32*)expected, (ma_uint32)desired, successOrder, failureOrder); + return ma_atomic_compare_exchange_weak_explicit_32((volatile ma_uint32*)dst, (ma_uint32*)expected, (ma_uint32)replacement, successOrder, failureOrder); } - static MA_INLINE void* ma_atomic_compare_and_swap_ptr(volatile void** dst, void* expected, void* desired) + static MA_INLINE void* ma_atomic_compare_and_swap_ptr(volatile void** dst, void* expected, void* replacement) { - return (void*)ma_atomic_compare_and_swap_32((volatile ma_uint32*)dst, (ma_uint32)expected, (ma_uint32)desired); + return (void*)ma_atomic_compare_and_swap_32((volatile ma_uint32*)dst, (ma_uint32)expected, (ma_uint32)replacement); } #else #error Unsupported architecture. #endif -#define ma_atomic_flag_test_and_set(ptr) ma_atomic_flag_test_and_set_explicit(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_flag_clear(ptr) ma_atomic_flag_clear_explicit(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_store_ptr(dst, src) ma_atomic_store_explicit_ptr((volatile void**)dst, (void*)src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_load_ptr(ptr) ma_atomic_load_explicit_ptr((volatile void**)ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_exchange_ptr(dst, src) ma_atomic_exchange_explicit_ptr((volatile void**)dst, (void*)src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_ptr(dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_ptr((volatile void**)dst, (void**)expected, (void*)desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_ptr(dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_ptr((volatile void**)dst, (void**)expected, (void*)desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_test_and_set_8( ptr) ma_atomic_test_and_set_explicit_8( ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_test_and_set_16(ptr) ma_atomic_test_and_set_explicit_16(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_test_and_set_32(ptr) ma_atomic_test_and_set_explicit_32(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_test_and_set_64(ptr) ma_atomic_test_and_set_explicit_64(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_clear_8( ptr) ma_atomic_clear_explicit_8( ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_clear_16(ptr) ma_atomic_clear_explicit_16(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_clear_32(ptr) ma_atomic_clear_explicit_32(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_clear_64(ptr) ma_atomic_clear_explicit_64(ptr, ma_atomic_memory_order_seq_cst) +#define ma_atomic_store_ptr(dst, src) ma_atomic_store_explicit_ptr((volatile void**)dst, (void*)src, ma_atomic_memory_order_seq_cst) +#define ma_atomic_load_ptr(ptr) ma_atomic_load_explicit_ptr((volatile void**)ptr, ma_atomic_memory_order_seq_cst) +#define ma_atomic_exchange_ptr(dst, src) ma_atomic_exchange_explicit_ptr((volatile void**)dst, (void*)src, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_strong_ptr(dst, expected, replacement) ma_atomic_compare_exchange_strong_explicit_ptr((volatile void**)dst, (void**)expected, (void*)replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_weak_ptr(dst, expected, replacement) ma_atomic_compare_exchange_weak_explicit_ptr((volatile void**)dst, (void**)expected, (void*)replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) #define ma_atomic_store_8( dst, src) ma_atomic_store_explicit_8( dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_store_16(dst, src) ma_atomic_store_explicit_16(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_store_32(dst, src) ma_atomic_store_explicit_32(dst, src, ma_atomic_memory_order_seq_cst) @@ -15632,14 +17029,14 @@ typedef int ma_atomic_memory_order; #define ma_atomic_exchange_16(dst, src) ma_atomic_exchange_explicit_16(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_exchange_32(dst, src) ma_atomic_exchange_explicit_32(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_exchange_64(dst, src) ma_atomic_exchange_explicit_64(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_8( dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_8( dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_16(dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_16(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_32(dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_32(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_64(dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_64(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_8( dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_8( dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_16( dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_16(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_32( dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_32(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_64( dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_64(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_strong_8( dst, expected, replacement) ma_atomic_compare_exchange_strong_explicit_8( dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_strong_16(dst, expected, replacement) ma_atomic_compare_exchange_strong_explicit_16(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_strong_32(dst, expected, replacement) ma_atomic_compare_exchange_strong_explicit_32(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_strong_64(dst, expected, replacement) ma_atomic_compare_exchange_strong_explicit_64(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_weak_8( dst, expected, replacement) ma_atomic_compare_exchange_weak_explicit_8( dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_weak_16( dst, expected, replacement) ma_atomic_compare_exchange_weak_explicit_16(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_weak_32( dst, expected, replacement) ma_atomic_compare_exchange_weak_explicit_32(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_weak_64( dst, expected, replacement) ma_atomic_compare_exchange_weak_explicit_64(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) #define ma_atomic_fetch_add_8( dst, src) ma_atomic_fetch_add_explicit_8( dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_fetch_add_16(dst, src) ma_atomic_fetch_add_explicit_16(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_fetch_add_32(dst, src) ma_atomic_fetch_add_explicit_32(dst, src, ma_atomic_memory_order_seq_cst) @@ -15660,14 +17057,6 @@ typedef int ma_atomic_memory_order; #define ma_atomic_fetch_and_16(dst, src) ma_atomic_fetch_and_explicit_16(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_fetch_and_32(dst, src) ma_atomic_fetch_and_explicit_32(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_fetch_and_64(dst, src) ma_atomic_fetch_and_explicit_64(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_test_and_set_explicit_i8( ptr, order) (ma_int8 )ma_atomic_test_and_set_explicit_8( (ma_uint8* )ptr, order) -#define ma_atomic_test_and_set_explicit_i16(ptr, order) (ma_int16)ma_atomic_test_and_set_explicit_16((ma_uint16*)ptr, order) -#define ma_atomic_test_and_set_explicit_i32(ptr, order) (ma_int32)ma_atomic_test_and_set_explicit_32((ma_uint32*)ptr, order) -#define ma_atomic_test_and_set_explicit_i64(ptr, order) (ma_int64)ma_atomic_test_and_set_explicit_64((ma_uint64*)ptr, order) -#define ma_atomic_clear_explicit_i8( ptr, order) ma_atomic_clear_explicit_8( (ma_uint8* )ptr, order) -#define ma_atomic_clear_explicit_i16(ptr, order) ma_atomic_clear_explicit_16((ma_uint16*)ptr, order) -#define ma_atomic_clear_explicit_i32(ptr, order) ma_atomic_clear_explicit_32((ma_uint32*)ptr, order) -#define ma_atomic_clear_explicit_i64(ptr, order) ma_atomic_clear_explicit_64((ma_uint64*)ptr, order) #define ma_atomic_store_explicit_i8( dst, src, order) ma_atomic_store_explicit_8( (ma_uint8* )dst, (ma_uint8 )src, order) #define ma_atomic_store_explicit_i16(dst, src, order) ma_atomic_store_explicit_16((ma_uint16*)dst, (ma_uint16)src, order) #define ma_atomic_store_explicit_i32(dst, src, order) ma_atomic_store_explicit_32((ma_uint32*)dst, (ma_uint32)src, order) @@ -15680,14 +17069,14 @@ typedef int ma_atomic_memory_order; #define ma_atomic_exchange_explicit_i16(dst, src, order) (ma_int16)ma_atomic_exchange_explicit_16((ma_uint16*)dst, (ma_uint16)src, order) #define ma_atomic_exchange_explicit_i32(dst, src, order) (ma_int32)ma_atomic_exchange_explicit_32((ma_uint32*)dst, (ma_uint32)src, order) #define ma_atomic_exchange_explicit_i64(dst, src, order) (ma_int64)ma_atomic_exchange_explicit_64((ma_uint64*)dst, (ma_uint64)src, order) -#define ma_atomic_compare_exchange_strong_explicit_i8( dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_8( (ma_uint8* )dst, (ma_uint8* )expected, (ma_uint8 )desired, successOrder, failureOrder) -#define ma_atomic_compare_exchange_strong_explicit_i16(dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_16((ma_uint16*)dst, (ma_uint16*)expected, (ma_uint16)desired, successOrder, failureOrder) -#define ma_atomic_compare_exchange_strong_explicit_i32(dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_32((ma_uint32*)dst, (ma_uint32*)expected, (ma_uint32)desired, successOrder, failureOrder) -#define ma_atomic_compare_exchange_strong_explicit_i64(dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_64((ma_uint64*)dst, (ma_uint64*)expected, (ma_uint64)desired, successOrder, failureOrder) -#define ma_atomic_compare_exchange_weak_explicit_i8( dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_weak_explicit_8( (ma_uint8* )dst, (ma_uint8* )expected, (ma_uint8 )desired, successOrder, failureOrder) -#define ma_atomic_compare_exchange_weak_explicit_i16(dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_weak_explicit_16((ma_uint16*)dst, (ma_uint16*)expected, (ma_uint16)desired, successOrder, failureOrder) -#define ma_atomic_compare_exchange_weak_explicit_i32(dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_weak_explicit_32((ma_uint32*)dst, (ma_uint32*)expected, (ma_uint32)desired, successOrder, failureOrder) -#define ma_atomic_compare_exchange_weak_explicit_i64(dst, expected, desired, successOrder, failureOrder) ma_atomic_compare_exchange_weak_explicit_64((ma_uint64*)dst, (ma_uint64*)expected, (ma_uint64)desired, successOrder, failureOrder) +#define ma_atomic_compare_exchange_strong_explicit_i8( dst, expected, replacement, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_8( (ma_uint8* )dst, (ma_uint8* )expected, (ma_uint8 )replacement, successOrder, failureOrder) +#define ma_atomic_compare_exchange_strong_explicit_i16(dst, expected, replacement, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_16((ma_uint16*)dst, (ma_uint16*)expected, (ma_uint16)replacement, successOrder, failureOrder) +#define ma_atomic_compare_exchange_strong_explicit_i32(dst, expected, replacement, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_32((ma_uint32*)dst, (ma_uint32*)expected, (ma_uint32)replacement, successOrder, failureOrder) +#define ma_atomic_compare_exchange_strong_explicit_i64(dst, expected, replacement, successOrder, failureOrder) ma_atomic_compare_exchange_strong_explicit_64((ma_uint64*)dst, (ma_uint64*)expected, (ma_uint64)replacement, successOrder, failureOrder) +#define ma_atomic_compare_exchange_weak_explicit_i8( dst, expected, replacement, successOrder, failureOrder) ma_atomic_compare_exchange_weak_explicit_8( (ma_uint8* )dst, (ma_uint8* )expected, (ma_uint8 )replacement, successOrder, failureOrder) +#define ma_atomic_compare_exchange_weak_explicit_i16(dst, expected, replacement, successOrder, failureOrder) ma_atomic_compare_exchange_weak_explicit_16((ma_uint16*)dst, (ma_uint16*)expected, (ma_uint16)replacement, successOrder, failureOrder) +#define ma_atomic_compare_exchange_weak_explicit_i32(dst, expected, replacement, successOrder, failureOrder) ma_atomic_compare_exchange_weak_explicit_32((ma_uint32*)dst, (ma_uint32*)expected, (ma_uint32)replacement, successOrder, failureOrder) +#define ma_atomic_compare_exchange_weak_explicit_i64(dst, expected, replacement, successOrder, failureOrder) ma_atomic_compare_exchange_weak_explicit_64((ma_uint64*)dst, (ma_uint64*)expected, (ma_uint64)replacement, successOrder, failureOrder) #define ma_atomic_fetch_add_explicit_i8( dst, src, order) (ma_int8 )ma_atomic_fetch_add_explicit_8( (ma_uint8* )dst, (ma_uint8 )src, order) #define ma_atomic_fetch_add_explicit_i16(dst, src, order) (ma_int16)ma_atomic_fetch_add_explicit_16((ma_uint16*)dst, (ma_uint16)src, order) #define ma_atomic_fetch_add_explicit_i32(dst, src, order) (ma_int32)ma_atomic_fetch_add_explicit_32((ma_uint32*)dst, (ma_uint32)src, order) @@ -15708,14 +17097,6 @@ typedef int ma_atomic_memory_order; #define ma_atomic_fetch_and_explicit_i16(dst, src, order) (ma_int16)ma_atomic_fetch_and_explicit_16((ma_uint16*)dst, (ma_uint16)src, order) #define ma_atomic_fetch_and_explicit_i32(dst, src, order) (ma_int32)ma_atomic_fetch_and_explicit_32((ma_uint32*)dst, (ma_uint32)src, order) #define ma_atomic_fetch_and_explicit_i64(dst, src, order) (ma_int64)ma_atomic_fetch_and_explicit_64((ma_uint64*)dst, (ma_uint64)src, order) -#define ma_atomic_test_and_set_i8( ptr) ma_atomic_test_and_set_explicit_i8( ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_test_and_set_i16(ptr) ma_atomic_test_and_set_explicit_i16(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_test_and_set_i32(ptr) ma_atomic_test_and_set_explicit_i32(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_test_and_set_i64(ptr) ma_atomic_test_and_set_explicit_i64(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_clear_i8( ptr) ma_atomic_clear_explicit_i8( ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_clear_i16(ptr) ma_atomic_clear_explicit_i16(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_clear_i32(ptr) ma_atomic_clear_explicit_i32(ptr, ma_atomic_memory_order_seq_cst) -#define ma_atomic_clear_i64(ptr) ma_atomic_clear_explicit_i64(ptr, ma_atomic_memory_order_seq_cst) #define ma_atomic_store_i8( dst, src) ma_atomic_store_explicit_i8( dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_store_i16(dst, src) ma_atomic_store_explicit_i16(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_store_i32(dst, src) ma_atomic_store_explicit_i32(dst, src, ma_atomic_memory_order_seq_cst) @@ -15728,14 +17109,14 @@ typedef int ma_atomic_memory_order; #define ma_atomic_exchange_i16(dst, src) ma_atomic_exchange_explicit_i16(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_exchange_i32(dst, src) ma_atomic_exchange_explicit_i32(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_exchange_i64(dst, src) ma_atomic_exchange_explicit_i64(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_i8( dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_i8( dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_i16(dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_i16(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_i32(dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_i32(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_i64(dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_i64(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_i8( dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_i8( dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_i16(dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_i16(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_i32(dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_i32(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_i64(dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_i64(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_strong_i8( dst, expected, replacement) ma_atomic_compare_exchange_strong_explicit_i8( dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_strong_i16(dst, expected, replacement) ma_atomic_compare_exchange_strong_explicit_i16(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_strong_i32(dst, expected, replacement) ma_atomic_compare_exchange_strong_explicit_i32(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_strong_i64(dst, expected, replacement) ma_atomic_compare_exchange_strong_explicit_i64(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_weak_i8( dst, expected, replacement) ma_atomic_compare_exchange_weak_explicit_i8( dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_weak_i16(dst, expected, replacement) ma_atomic_compare_exchange_weak_explicit_i16(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_weak_i32(dst, expected, replacement) ma_atomic_compare_exchange_weak_explicit_i32(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_weak_i64(dst, expected, replacement) ma_atomic_compare_exchange_weak_explicit_i64(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) #define ma_atomic_fetch_add_i8( dst, src) ma_atomic_fetch_add_explicit_i8( dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_fetch_add_i16(dst, src) ma_atomic_fetch_add_explicit_i16(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_fetch_add_i32(dst, src) ma_atomic_fetch_add_explicit_i32(dst, src, ma_atomic_memory_order_seq_cst) @@ -15812,28 +17193,28 @@ static MA_INLINE double ma_atomic_exchange_explicit_f64(volatile double* dst, do r.i = ma_atomic_exchange_explicit_64((volatile ma_uint64*)dst, x.i, order); return r.f; } -static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_f32(volatile float* dst, float* expected, float desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) +static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_f32(volatile float* dst, float* expected, float replacement, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) { ma_atomic_if32 d; - d.f = desired; + d.f = replacement; return ma_atomic_compare_exchange_strong_explicit_32((volatile ma_uint32*)dst, (ma_uint32*)expected, d.i, successOrder, failureOrder); } -static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_f64(volatile double* dst, double* expected, double desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) +static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_f64(volatile double* dst, double* expected, double replacement, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) { ma_atomic_if64 d; - d.f = desired; + d.f = replacement; return ma_atomic_compare_exchange_strong_explicit_64((volatile ma_uint64*)dst, (ma_uint64*)expected, d.i, successOrder, failureOrder); } -static MA_INLINE ma_bool32 ma_atomic_compare_exchange_weak_explicit_f32(volatile float* dst, float* expected, float desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) +static MA_INLINE ma_bool32 ma_atomic_compare_exchange_weak_explicit_f32(volatile float* dst, float* expected, float replacement, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) { ma_atomic_if32 d; - d.f = desired; + d.f = replacement; return ma_atomic_compare_exchange_weak_explicit_32((volatile ma_uint32*)dst, (ma_uint32*)expected, d.i, successOrder, failureOrder); } -static MA_INLINE ma_bool32 ma_atomic_compare_exchange_weak_explicit_f64(volatile double* dst, double* expected, double desired, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) +static MA_INLINE ma_bool32 ma_atomic_compare_exchange_weak_explicit_f64(volatile double* dst, double* expected, double replacement, ma_atomic_memory_order successOrder, ma_atomic_memory_order failureOrder) { ma_atomic_if64 d; - d.f = desired; + d.f = replacement; return ma_atomic_compare_exchange_weak_explicit_64((volatile ma_uint64*)dst, (ma_uint64*)expected, d.i, successOrder, failureOrder); } static MA_INLINE float ma_atomic_fetch_add_explicit_f32(volatile float* dst, float src, ma_atomic_memory_order order) @@ -15924,10 +17305,10 @@ static MA_INLINE double ma_atomic_fetch_and_explicit_f64(volatile double* dst, d #define ma_atomic_load_f64(ptr) (double)ma_atomic_load_explicit_f64(ptr, ma_atomic_memory_order_seq_cst) #define ma_atomic_exchange_f32(dst, src) (float )ma_atomic_exchange_explicit_f32(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_exchange_f64(dst, src) (double)ma_atomic_exchange_explicit_f64(dst, src, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_f32(dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_f32(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_strong_f64(dst, expected, desired) ma_atomic_compare_exchange_strong_explicit_f64(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_f32(dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_f32(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) -#define ma_atomic_compare_exchange_weak_f64(dst, expected, desired) ma_atomic_compare_exchange_weak_explicit_f64(dst, expected, desired, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_strong_f32(dst, expected, replacement) ma_atomic_compare_exchange_strong_explicit_f32(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_strong_f64(dst, expected, replacement) ma_atomic_compare_exchange_strong_explicit_f64(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_weak_f32(dst, expected, replacement) ma_atomic_compare_exchange_weak_explicit_f32(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) +#define ma_atomic_compare_exchange_weak_f64(dst, expected, replacement) ma_atomic_compare_exchange_weak_explicit_f64(dst, expected, replacement, ma_atomic_memory_order_seq_cst, ma_atomic_memory_order_seq_cst) #define ma_atomic_fetch_add_f32(dst, src) ma_atomic_fetch_add_explicit_f32(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_fetch_add_f64(dst, src) ma_atomic_fetch_add_explicit_f64(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_fetch_sub_f32(dst, src) ma_atomic_fetch_sub_explicit_f32(dst, src, ma_atomic_memory_order_seq_cst) @@ -15938,39 +17319,24 @@ static MA_INLINE double ma_atomic_fetch_and_explicit_f64(volatile double* dst, d #define ma_atomic_fetch_xor_f64(dst, src) ma_atomic_fetch_xor_explicit_f64(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_fetch_and_f32(dst, src) ma_atomic_fetch_and_explicit_f32(dst, src, ma_atomic_memory_order_seq_cst) #define ma_atomic_fetch_and_f64(dst, src) ma_atomic_fetch_and_explicit_f64(dst, src, ma_atomic_memory_order_seq_cst) -static MA_INLINE float ma_atomic_compare_and_swap_f32(volatile float* dst, float expected, float desired) +static MA_INLINE float ma_atomic_compare_and_swap_f32(volatile float* dst, float expected, float replacement) { ma_atomic_if32 r; ma_atomic_if32 e, d; e.f = expected; - d.f = desired; + d.f = replacement; r.i = ma_atomic_compare_and_swap_32((volatile ma_uint32*)dst, e.i, d.i); return r.f; } -static MA_INLINE double ma_atomic_compare_and_swap_f64(volatile double* dst, double expected, double desired) +static MA_INLINE double ma_atomic_compare_and_swap_f64(volatile double* dst, double expected, double replacement) { ma_atomic_if64 r; ma_atomic_if64 e, d; e.f = expected; - d.f = desired; + d.f = replacement; r.i = ma_atomic_compare_and_swap_64((volatile ma_uint64*)dst, e.i, d.i); return r.f; } -typedef ma_atomic_flag ma_atomic_spinlock; -static MA_INLINE void ma_atomic_spinlock_lock(volatile ma_atomic_spinlock* pSpinlock) -{ - for (;;) { - if (ma_atomic_flag_test_and_set_explicit(pSpinlock, ma_atomic_memory_order_acquire) == 0) { - break; - } - while (ma_atomic_flag_load_explicit(pSpinlock, ma_atomic_memory_order_relaxed) == 1) { - } - } -} -static MA_INLINE void ma_atomic_spinlock_unlock(volatile ma_atomic_spinlock* pSpinlock) -{ - ma_atomic_flag_clear_explicit(pSpinlock, ma_atomic_memory_order_release); -} #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) #pragma GCC diagnostic pop #endif @@ -16176,7 +17542,7 @@ static ma_result ma_thread_create__posix(ma_thread* pThread, ma_thread_priority int result; pthread_attr_t* pAttr = NULL; -#if !defined(__EMSCRIPTEN__) && !defined(__3DS__) +#if !defined(MA_EMSCRIPTEN) && !defined(MA_3DS) && !defined(MA_SWITCH) /* Try setting the thread priority. It's not critical if anything fails here. */ pthread_attr_t attr; if (pthread_attr_init(&attr) == 0) { @@ -16208,9 +17574,18 @@ static ma_result ma_thread_create__posix(ma_thread* pThread, ma_thread_priority } #endif - if (stackSize > 0) { - pthread_attr_setstacksize(&attr, stackSize); + #if defined(_POSIX_THREAD_ATTR_STACKSIZE) && _POSIX_THREAD_ATTR_STACKSIZE >= 0 + { + if (stackSize > 0) { + pthread_attr_setstacksize(&attr, stackSize); + } } + #else + { + (void)stackSize; /* Suppress unused parameter warning. */ + } + #endif + if (scheduler != -1) { int priorityMin = sched_get_priority_min(scheduler); @@ -16267,6 +17642,21 @@ static ma_result ma_thread_create__posix(ma_thread* pThread, ma_thread_priority } if (result != 0) { + /* + There have been reports that attempting to create a realtime thread can sometimes fail. In this case, + fall back to a normal priority thread. + + I'm including a compile-time option here to disable this functionality for those who have a hard + requirement on realtime threads and would rather an explicit failure. + */ + #ifndef MA_NO_PTHREAD_REALTIME_PRIORITY_FALLBACK + { + if(result == EPERM && priority == ma_thread_priority_realtime) { + return ma_thread_create__posix(pThread, ma_thread_priority_normal, stackSize, entryProc, pData); + } + } + #endif + return ma_result_from_errno(result); } @@ -16538,7 +17928,7 @@ static ma_result ma_event_signal__win32(ma_event* pEvent) static ma_result ma_semaphore_init__win32(int initialValue, ma_semaphore* pSemaphore) { - *pSemaphore = CreateSemaphoreW(NULL, (LONG)initialValue, LONG_MAX, NULL); + *pSemaphore = CreateSemaphore(NULL, (LONG)initialValue, LONG_MAX, NULL); if (*pSemaphore == NULL) { return ma_result_from_GetLastError(GetLastError()); } @@ -17432,10 +18822,12 @@ static MA_INLINE ma_uint16 ma_job_extract_slot(ma_uint64 toc) return (ma_uint16)(toc & 0x0000FFFF); } +#if 0 /* Currently unused, but might make use of this later. */ static MA_INLINE ma_uint16 ma_job_extract_code(ma_uint64 toc) { return (ma_uint16)((toc & 0xFFFF0000) >> 16); } +#endif static MA_INLINE ma_uint64 ma_job_toc_to_allocation(ma_uint64 toc) { @@ -17900,6 +19292,13 @@ MA_API ma_result ma_job_queue_next(ma_job_queue* pQueue, ma_job* pJob) Dynamic Linking *******************************************************************************/ +/* Disable run-time linking on certain backends and platforms. */ +#ifndef MA_NO_RUNTIME_LINKING + #if defined(MA_EMSCRIPTEN) || defined(MA_ORBIS) || defined(MA_PROSPERO) || defined(MA_SWITCH) || defined(MA_DOS) + #define MA_NO_RUNTIME_LINKING + #endif +#endif + #ifdef MA_POSIX /* No need for dlfcn.h if we're not using runtime linking. */ #ifndef MA_NO_RUNTIME_LINKING @@ -17909,104 +19308,124 @@ Dynamic Linking MA_API ma_handle ma_dlopen(ma_log* pLog, const char* filename) { -#ifndef MA_NO_RUNTIME_LINKING - ma_handle handle; + #ifndef MA_NO_RUNTIME_LINKING + { + ma_handle handle; - ma_log_postf(pLog, MA_LOG_LEVEL_DEBUG, "Loading library: %s\n", filename); + ma_log_postf(pLog, MA_LOG_LEVEL_DEBUG, "Loading library: %s\n", filename); - #ifdef MA_WIN32 - /* From MSDN: Desktop applications cannot use LoadPackagedLibrary; if a desktop application calls this function it fails with APPMODEL_ERROR_NO_PACKAGE.*/ - #if !defined(MA_WIN32_UWP) || !(defined(WINAPI_FAMILY) && ((defined(WINAPI_FAMILY_PHONE_APP) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP))) - handle = (ma_handle)LoadLibraryA(filename); + #ifdef MA_WIN32 + /* From MSDN: Desktop applications cannot use LoadPackagedLibrary; if a desktop application calls this function it fails with APPMODEL_ERROR_NO_PACKAGE.*/ + #if !defined(MA_WIN32_UWP) || !(defined(WINAPI_FAMILY) && ((defined(WINAPI_FAMILY_PHONE_APP) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP))) + handle = (ma_handle)LoadLibraryA(filename); + #else + /* *sigh* It appears there is no ANSI version of LoadPackagedLibrary()... */ + WCHAR filenameW[4096]; + if (MultiByteToWideChar(CP_UTF8, 0, filename, -1, filenameW, sizeof(filenameW)) == 0) { + handle = NULL; + } else { + handle = (ma_handle)LoadPackagedLibrary(filenameW, 0); + } + #endif #else - /* *sigh* It appears there is no ANSI version of LoadPackagedLibrary()... */ - WCHAR filenameW[4096]; - if (MultiByteToWideChar(CP_UTF8, 0, filename, -1, filenameW, sizeof(filenameW)) == 0) { - handle = NULL; - } else { - handle = (ma_handle)LoadPackagedLibrary(filenameW, 0); - } + handle = (ma_handle)dlopen(filename, RTLD_NOW); #endif - #else - handle = (ma_handle)dlopen(filename, RTLD_NOW); - #endif - /* - I'm not considering failure to load a library an error nor a warning because seamlessly falling through to a lower-priority - backend is a deliberate design choice. Instead I'm logging it as an informational message. - */ - if (handle == NULL) { - ma_log_postf(pLog, MA_LOG_LEVEL_INFO, "Failed to load library: %s\n", filename); + /* + I'm not considering failure to load a library an error nor a warning because seamlessly falling through to a lower-priority + backend is a deliberate design choice. Instead I'm logging it as an informational message. + */ + if (handle == NULL) { + ma_log_postf(pLog, MA_LOG_LEVEL_INFO, "Failed to load library: %s\n", filename); + } + + return handle; } - - return handle; -#else - /* Runtime linking is disabled. */ - (void)pLog; - (void)filename; - return NULL; -#endif + #else + { + /* Runtime linking is disabled. */ + (void)pLog; + (void)filename; + return NULL; + } + #endif } MA_API void ma_dlclose(ma_log* pLog, ma_handle handle) { -#ifndef MA_NO_RUNTIME_LINKING - #ifdef MA_WIN32 - FreeLibrary((HMODULE)handle); - #else - /* Hack for Android bug (see https://github.com/android/ndk/issues/360). Calling dlclose() pre-API 28 may segfault. */ - #if !defined(MA_ANDROID) || (defined(__ANDROID_API__) && __ANDROID_API__ >= 28) + #ifndef MA_NO_RUNTIME_LINKING + { + #ifdef MA_WIN32 { - dlclose((void*)handle); + FreeLibrary((HMODULE)handle); } #else { - (void)handle; + /* Hack for Android bug (see https://github.com/android/ndk/issues/360). Calling dlclose() pre-API 28 may segfault. */ + #if !defined(MA_ANDROID) || (defined(__ANDROID_API__) && __ANDROID_API__ >= 28) + { + dlclose((void*)handle); + } + #else + { + (void)handle; + } + #endif } #endif - #endif - (void)pLog; -#else - /* Runtime linking is disabled. */ - (void)pLog; - (void)handle; -#endif + (void)pLog; + } + #else + { + /* Runtime linking is disabled. */ + (void)pLog; + (void)handle; + } + #endif } MA_API ma_proc ma_dlsym(ma_log* pLog, ma_handle handle, const char* symbol) { -#ifndef MA_NO_RUNTIME_LINKING - ma_proc proc; + #ifndef MA_NO_RUNTIME_LINKING + { + ma_proc proc; - ma_log_postf(pLog, MA_LOG_LEVEL_DEBUG, "Loading symbol: %s\n", symbol); + ma_log_postf(pLog, MA_LOG_LEVEL_DEBUG, "Loading symbol: %s\n", symbol); -#ifdef _WIN32 - proc = (ma_proc)GetProcAddress((HMODULE)handle, symbol); -#else -#if (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) || defined(__clang__) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wpedantic" -#endif - proc = (ma_proc)dlsym((void*)handle, symbol); -#if (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) || defined(__clang__) - #pragma GCC diagnostic pop -#endif -#endif + #ifdef _WIN32 + { + proc = (ma_proc)GetProcAddress((HMODULE)handle, symbol); + } + #else + { + #if (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) || defined(__clang__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wpedantic" + #endif + proc = (ma_proc)dlsym((void*)handle, symbol); + #if (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) || defined(__clang__) + #pragma GCC diagnostic pop + #endif + } + #endif - if (proc == NULL) { - ma_log_postf(pLog, MA_LOG_LEVEL_WARNING, "Failed to load symbol: %s\n", symbol); + if (proc == NULL) { + ma_log_postf(pLog, MA_LOG_LEVEL_WARNING, "Failed to load symbol: %s\n", symbol); + } + + (void)pLog; /* It's possible for pContext to be unused. */ + return proc; } - - (void)pLog; /* It's possible for pContext to be unused. */ - return proc; -#else - /* Runtime linking is disabled. */ - (void)pLog; - (void)handle; - (void)symbol; - return NULL; -#endif + #else + { + /* Runtime linking is disabled. */ + (void)pLog; + (void)handle; + (void)symbol; + return NULL; + } + #endif } @@ -18020,13 +19439,6 @@ DEVICE I/O ************************************************************************************************************************************************************* ************************************************************************************************************************************************************/ -/* Disable run-time linking on certain backends and platforms. */ -#ifndef MA_NO_RUNTIME_LINKING - #if defined(MA_EMSCRIPTEN) || defined(MA_ORBIS) || defined(MA_PROSPERO) - #define MA_NO_RUNTIME_LINKING - #endif -#endif - #ifdef MA_APPLE #include #endif @@ -18039,12 +19451,6 @@ DEVICE I/O #ifdef MA_POSIX #include - #include - - /* No need for dlfcn.h if we're not using runtime linking. */ - #ifndef MA_NO_RUNTIME_LINKING - #include - #endif #endif /* This must be set to at least 26. */ @@ -18299,7 +19705,7 @@ MA_API ma_bool32 ma_is_loopback_supported(ma_backend backend) -#if defined(MA_WIN32) +#if defined(MA_WIN32) && !defined(MA_XBOX) /* WASAPI error codes. */ #define MA_AUDCLNT_E_NOT_INITIALIZED ((HRESULT)0x88890001) #define MA_AUDCLNT_E_ALREADY_INITIALIZED ((HRESULT)0x88890002) @@ -18514,6 +19920,11 @@ typedef LONG (WINAPI * MA_PFN_RegCloseKey)(HKEY hKey); typedef LONG (WINAPI * MA_PFN_RegQueryValueExA)(HKEY hKey, const char* lpValueName, DWORD* lpReserved, DWORD* lpType, BYTE* lpData, DWORD* lpcbData); #endif /* MA_WIN32_DESKTOP */ +static GUID MA_GUID_KSDATAFORMAT_SUBTYPE_PCM = {0x00000001, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; +static GUID MA_GUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = {0x00000003, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; +/*static GUID MA_GUID_KSDATAFORMAT_SUBTYPE_ALAW = {0x00000006, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};*/ +/*static GUID MA_GUID_KSDATAFORMAT_SUBTYPE_MULAW = {0x00000007, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};*/ + MA_API size_t ma_strlen_WCHAR(const WCHAR* str) { size_t len = 0; @@ -18577,7 +19988,7 @@ Timing *******************************************************************************/ #if defined(MA_WIN32) && !defined(MA_POSIX) static LARGE_INTEGER g_ma_TimerFrequency; /* <-- Initialized to zero since it's static. */ - static void ma_timer_init(ma_timer* pTimer) + static MA_INLINE void ma_timer_init(ma_timer* pTimer) { LARGE_INTEGER counter; @@ -18589,7 +20000,7 @@ Timing pTimer->counter = counter.QuadPart; } - static double ma_timer_get_time_in_seconds(ma_timer* pTimer) + static MA_INLINE double ma_timer_get_time_in_seconds(ma_timer* pTimer) { LARGE_INTEGER counter; if (!QueryPerformanceCounter(&counter)) { @@ -18600,7 +20011,7 @@ Timing } #elif defined(MA_APPLE) && (MAC_OS_X_VERSION_MIN_REQUIRED < 101200) static ma_uint64 g_ma_TimerFrequency = 0; - static void ma_timer_init(ma_timer* pTimer) + static MA_INLINE void ma_timer_init(ma_timer* pTimer) { mach_timebase_info_data_t baseTime; mach_timebase_info(&baseTime); @@ -18609,7 +20020,7 @@ Timing pTimer->counter = mach_absolute_time(); } - static double ma_timer_get_time_in_seconds(ma_timer* pTimer) + static MA_INLINE double ma_timer_get_time_in_seconds(ma_timer* pTimer) { ma_uint64 newTimeCounter = mach_absolute_time(); ma_uint64 oldTimeCounter = pTimer->counter; @@ -18634,7 +20045,7 @@ Timing #define MA_CLOCK_ID CLOCK_REALTIME #endif - static void ma_timer_init(ma_timer* pTimer) + static MA_INLINE void ma_timer_init(ma_timer* pTimer) { struct timespec newTime; clock_gettime(MA_CLOCK_ID, &newTime); @@ -18642,7 +20053,7 @@ Timing pTimer->counter = (newTime.tv_sec * 1000000000) + newTime.tv_nsec; } - static double ma_timer_get_time_in_seconds(ma_timer* pTimer) + static MA_INLINE double ma_timer_get_time_in_seconds(ma_timer* pTimer) { ma_uint64 newTimeCounter; ma_uint64 oldTimeCounter; @@ -18656,7 +20067,7 @@ Timing return (newTimeCounter - oldTimeCounter) / 1000000000.0; } #else - static void ma_timer_init(ma_timer* pTimer) + static MA_INLINE void ma_timer_init(ma_timer* pTimer) { struct timeval newTime; gettimeofday(&newTime, NULL); @@ -18664,7 +20075,7 @@ Timing pTimer->counter = (newTime.tv_sec * 1000000) + newTime.tv_usec; } - static double ma_timer_get_time_in_seconds(ma_timer* pTimer) + static MA_INLINE double ma_timer_get_time_in_seconds(ma_timer* pTimer) { ma_uint64 newTimeCounter; ma_uint64 oldTimeCounter; @@ -19248,14 +20659,6 @@ static MA_INLINE void ma_device__set_state(ma_device* pDevice, ma_device_state n } -#if defined(MA_WIN32) - static GUID MA_GUID_KSDATAFORMAT_SUBTYPE_PCM = {0x00000001, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; - static GUID MA_GUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = {0x00000003, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; - /*static GUID MA_GUID_KSDATAFORMAT_SUBTYPE_ALAW = {0x00000006, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};*/ - /*static GUID MA_GUID_KSDATAFORMAT_SUBTYPE_MULAW = {0x00000007, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};*/ -#endif - - MA_API ma_uint32 ma_get_format_priority_index(ma_format format) /* Lower = better. */ { @@ -19967,7 +21370,7 @@ static ma_result ma_context_init__null(ma_context* pContext, const ma_context_co WIN32 COMMON *******************************************************************************/ -#if defined(MA_WIN32) +#if defined(MA_WIN32) && !defined(MA_XBOX) #if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) #define ma_CoInitializeEx(pContext, pvReserved, dwCoInit) ((pContext->win32.CoInitializeEx) ? ((MA_PFN_CoInitializeEx)pContext->win32.CoInitializeEx)(pvReserved, dwCoInit) : ((MA_PFN_CoInitialize)pContext->win32.CoInitialize)(pvReserved)) #define ma_CoUninitialize(pContext) ((MA_PFN_CoUninitialize)pContext->win32.CoUninitialize)() @@ -19982,7 +21385,7 @@ WIN32 COMMON #define ma_PropVariantClear(pContext, pvar) PropVariantClear(pvar) #endif -#if !defined(MAXULONG_PTR) && !defined(__WATCOMC__) +#if !defined(MAXULONG_PTR) && !defined(__WATCOMC__) && !defined(MA_XBOX_NXDK) typedef size_t DWORD_PTR; #endif @@ -20409,11 +21812,21 @@ typedef enum MA_AudioCategory_Other = 0 /* <-- miniaudio is only caring about Other. */ } MA_AUDIO_STREAM_CATEGORY; +typedef enum +{ + MA_AUDCLNT_STREAMOPTIONS_NONE, + MA_AUDCLNT_STREAMOPTIONS_RAW, + MA_AUDCLNT_STREAMOPTIONS_MATCH_FORMAT, + MA_AUDCLNT_STREAMOPTIONS_AMBISONICS, + MA_AUDCLNT_STREAMOPTIONS_POST_VOLUME_LOOPBACK +} MA_AUDCLNT_STREAMOPTIONS; + typedef struct { ma_uint32 cbSize; BOOL bIsOffload; MA_AUDIO_STREAM_CATEGORY eCategory; + MA_AUDCLNT_STREAMOPTIONS Options; } ma_AudioClientProperties; /* IUnknown */ @@ -21588,6 +23001,7 @@ static ma_result ma_context_get_MMDevice__wasapi(ma_context* pContext, ma_device { ma_IMMDeviceEnumerator* pDeviceEnumerator; HRESULT hr; + HRESULT CoInitializeResult; MA_ASSERT(pContext != NULL); MA_ASSERT(ppMMDevice != NULL); @@ -21601,12 +23015,17 @@ static ma_result ma_context_get_MMDevice__wasapi(ma_context* pContext, ma_device The community has reported that this seems to fix the crash. There are future plans to move all WASAPI operation over to a single thread to make everything safer, but in the meantime while we wait for that to come online I'm happy enough to use this hack instead. + + CoUninitialize should only be called if we successfully initialized. S_OK and S_FALSE both mean that we need to + call CoUninitialize since the internal ref count was increased. RPC_E_CHANGED_MODE means that CoInitializeEx was + called with a different COINIT value, and we don't call CoUninitialize in that case. Other errors are possible, + so we check for S_OK and S_FALSE specifically. */ - ma_CoInitializeEx(pContext, NULL, MA_COINIT_VALUE); + CoInitializeResult = ma_CoInitializeEx(pContext, NULL, MA_COINIT_VALUE); { hr = ma_CoCreateInstance(pContext, &MA_CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, &MA_IID_IMMDeviceEnumerator, (void**)&pDeviceEnumerator); - } - ma_CoUninitialize(pContext); + } + if (CoInitializeResult == S_OK || CoInitializeResult == S_FALSE) { ma_CoUninitialize(pContext); } if (FAILED(hr)) { /* <-- This is checking the call above to ma_CoCreateInstance(). */ ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create IMMDeviceEnumerator.\n"); @@ -21950,7 +23369,7 @@ static ma_result ma_context_get_IAudioClient__wasapi(ma_context* pContext, ma_de pActivationParams = &activationParams; /* When requesting a specific device ID we need to use a special device ID. */ - MA_COPY_MEMORY(virtualDeviceID.wasapi, MA_VIRTUAL_AUDIO_DEVICE_PROCESS_LOOPBACK, (wcslen(MA_VIRTUAL_AUDIO_DEVICE_PROCESS_LOOPBACK) + 1) * sizeof(wchar_t)); /* +1 for the null terminator. */ + MA_COPY_MEMORY(virtualDeviceID.wasapi, MA_VIRTUAL_AUDIO_DEVICE_PROCESS_LOOPBACK, (ma_wcslen(MA_VIRTUAL_AUDIO_DEVICE_PROCESS_LOOPBACK) + 1) * sizeof(wchar_t)); /* +1 for the null terminator. */ pDeviceID = &virtualDeviceID; } else { pActivationParams = NULL; /* No activation parameters required. */ @@ -26679,6 +28098,9 @@ typedef snd_pcm_channel_area_t ma_snd_pcm_channel_area_t; typedef snd_pcm_chmap_t ma_snd_pcm_chmap_t; typedef snd_pcm_state_t ma_snd_pcm_state_t; +/* snd_pcm_state_t */ +#define MA_SND_PCM_STATE_XRUN SND_PCM_STATE_XRUN + /* snd_pcm_stream_t */ #define MA_SND_PCM_STREAM_PLAYBACK SND_PCM_STREAM_PLAYBACK #define MA_SND_PCM_STREAM_CAPTURE SND_PCM_STREAM_CAPTURE @@ -26874,6 +28296,7 @@ typedef int (* ma_snd_pcm_hw_params_set_channels_minmax_proc) ( typedef int (* ma_snd_pcm_hw_params_set_rate_resample_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, unsigned int val); typedef int (* ma_snd_pcm_hw_params_set_rate_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, unsigned int val, int dir); typedef int (* ma_snd_pcm_hw_params_set_rate_near_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +typedef int (* ma_snd_pcm_hw_params_set_rate_minmax_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, unsigned int *min, int *mindir, unsigned int *max, int *maxdir); typedef int (* ma_snd_pcm_hw_params_set_buffer_size_near_proc)(ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, ma_snd_pcm_uframes_t *val); typedef int (* ma_snd_pcm_hw_params_set_periods_near_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, unsigned int *val, int *dir); typedef int (* ma_snd_pcm_hw_params_set_access_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, ma_snd_pcm_access_t _access); @@ -28640,8 +30063,9 @@ static ma_result ma_context_init__alsa(ma_context* pContext, const ma_context_co ma_snd_pcm_hw_params_get_format_mask_proc _snd_pcm_hw_params_get_format_mask = snd_pcm_hw_params_get_format_mask; ma_snd_pcm_hw_params_set_channels_proc _snd_pcm_hw_params_set_channels = snd_pcm_hw_params_set_channels; ma_snd_pcm_hw_params_set_channels_near_proc _snd_pcm_hw_params_set_channels_near = snd_pcm_hw_params_set_channels_near; + ma_snd_pcm_hw_params_set_channels_minmax_proc _snd_pcm_hw_params_set_channels_minmax = snd_pcm_hw_params_set_channels_minmax; ma_snd_pcm_hw_params_set_rate_resample_proc _snd_pcm_hw_params_set_rate_resample = snd_pcm_hw_params_set_rate_resample; - ma_snd_pcm_hw_params_set_rate_near _snd_pcm_hw_params_set_rate = snd_pcm_hw_params_set_rate; + ma_snd_pcm_hw_params_set_rate_proc _snd_pcm_hw_params_set_rate = snd_pcm_hw_params_set_rate; ma_snd_pcm_hw_params_set_rate_near_proc _snd_pcm_hw_params_set_rate_near = snd_pcm_hw_params_set_rate_near; ma_snd_pcm_hw_params_set_rate_minmax_proc _snd_pcm_hw_params_set_rate_minmax = snd_pcm_hw_params_set_rate_minmax; ma_snd_pcm_hw_params_set_buffer_size_near_proc _snd_pcm_hw_params_set_buffer_size_near = snd_pcm_hw_params_set_buffer_size_near; @@ -28693,9 +30117,9 @@ static ma_result ma_context_init__alsa(ma_context* pContext, const ma_context_co ma_snd_pcm_info_proc _snd_pcm_info = snd_pcm_info; ma_snd_pcm_info_sizeof_proc _snd_pcm_info_sizeof = snd_pcm_info_sizeof; ma_snd_pcm_info_get_name_proc _snd_pcm_info_get_name = snd_pcm_info_get_name; - ma_snd_pcm_poll_descriptors _snd_pcm_poll_descriptors = snd_pcm_poll_descriptors; - ma_snd_pcm_poll_descriptors_count _snd_pcm_poll_descriptors_count = snd_pcm_poll_descriptors_count; - ma_snd_pcm_poll_descriptors_revents _snd_pcm_poll_descriptors_revents = snd_pcm_poll_descriptors_revents; + ma_snd_pcm_poll_descriptors_proc _snd_pcm_poll_descriptors = snd_pcm_poll_descriptors; + ma_snd_pcm_poll_descriptors_count_proc _snd_pcm_poll_descriptors_count = snd_pcm_poll_descriptors_count; + ma_snd_pcm_poll_descriptors_revents_proc _snd_pcm_poll_descriptors_revents = snd_pcm_poll_descriptors_revents; ma_snd_config_update_free_global_proc _snd_config_update_free_global = snd_config_update_free_global; pContext->alsa.snd_pcm_open = (ma_proc)_snd_pcm_open; @@ -28711,6 +30135,7 @@ static ma_result ma_context_init__alsa(ma_context* pContext, const ma_context_co pContext->alsa.snd_pcm_hw_params_set_rate_resample = (ma_proc)_snd_pcm_hw_params_set_rate_resample; pContext->alsa.snd_pcm_hw_params_set_rate = (ma_proc)_snd_pcm_hw_params_set_rate; pContext->alsa.snd_pcm_hw_params_set_rate_near = (ma_proc)_snd_pcm_hw_params_set_rate_near; + pContext->alsa.snd_pcm_hw_params_set_rate_minmax = (ma_proc)_snd_pcm_hw_params_set_rate_minmax; pContext->alsa.snd_pcm_hw_params_set_buffer_size_near = (ma_proc)_snd_pcm_hw_params_set_buffer_size_near; pContext->alsa.snd_pcm_hw_params_set_periods_near = (ma_proc)_snd_pcm_hw_params_set_periods_near; pContext->alsa.snd_pcm_hw_params_set_access = (ma_proc)_snd_pcm_hw_params_set_access; @@ -29436,7 +30861,7 @@ typedef void (* ma_pa_threaded_mainloop_unlock_proc) ( typedef void (* ma_pa_threaded_mainloop_wait_proc) (ma_pa_threaded_mainloop* m); typedef void (* ma_pa_threaded_mainloop_signal_proc) (ma_pa_threaded_mainloop* m, int wait_for_accept); typedef void (* ma_pa_threaded_mainloop_accept_proc) (ma_pa_threaded_mainloop* m); -typedef int (* ma_pa_threaded_mainloop_get_retval_proc) (ma_pa_threaded_mainloop* m); +typedef int (* ma_pa_threaded_mainloop_get_retval_proc) (const ma_pa_threaded_mainloop* m); typedef ma_pa_mainloop_api* (* ma_pa_threaded_mainloop_get_api_proc) (ma_pa_threaded_mainloop* m); typedef int (* ma_pa_threaded_mainloop_in_thread_proc) (ma_pa_threaded_mainloop* m); typedef void (* ma_pa_threaded_mainloop_set_name_proc) (ma_pa_threaded_mainloop* m, const char* name); @@ -29445,13 +30870,13 @@ typedef void (* ma_pa_context_unref_proc) ( typedef int (* ma_pa_context_connect_proc) (ma_pa_context* c, const char* server, ma_pa_context_flags_t flags, const ma_pa_spawn_api* api); typedef void (* ma_pa_context_disconnect_proc) (ma_pa_context* c); typedef void (* ma_pa_context_set_state_callback_proc) (ma_pa_context* c, ma_pa_context_notify_cb_t cb, void* userdata); -typedef ma_pa_context_state_t (* ma_pa_context_get_state_proc) (ma_pa_context* c); +typedef ma_pa_context_state_t (* ma_pa_context_get_state_proc) (const ma_pa_context* c); typedef ma_pa_operation* (* ma_pa_context_get_sink_info_list_proc) (ma_pa_context* c, ma_pa_sink_info_cb_t cb, void* userdata); typedef ma_pa_operation* (* ma_pa_context_get_source_info_list_proc) (ma_pa_context* c, ma_pa_source_info_cb_t cb, void* userdata); typedef ma_pa_operation* (* ma_pa_context_get_sink_info_by_name_proc) (ma_pa_context* c, const char* name, ma_pa_sink_info_cb_t cb, void* userdata); typedef ma_pa_operation* (* ma_pa_context_get_source_info_by_name_proc)(ma_pa_context* c, const char* name, ma_pa_source_info_cb_t cb, void* userdata); typedef void (* ma_pa_operation_unref_proc) (ma_pa_operation* o); -typedef ma_pa_operation_state_t (* ma_pa_operation_get_state_proc) (ma_pa_operation* o); +typedef ma_pa_operation_state_t (* ma_pa_operation_get_state_proc) (const ma_pa_operation* o); typedef ma_pa_channel_map* (* ma_pa_channel_map_init_extend_proc) (ma_pa_channel_map* m, unsigned channels, ma_pa_channel_map_def_t def); typedef int (* ma_pa_channel_map_valid_proc) (const ma_pa_channel_map* m); typedef int (* ma_pa_channel_map_compatible_proc) (const ma_pa_channel_map* m, const ma_pa_sample_spec* ss); @@ -29460,12 +30885,12 @@ typedef void (* ma_pa_stream_unref_proc) ( typedef int (* ma_pa_stream_connect_playback_proc) (ma_pa_stream* s, const char* dev, const ma_pa_buffer_attr* attr, ma_pa_stream_flags_t flags, const ma_pa_cvolume* volume, ma_pa_stream* sync_stream); typedef int (* ma_pa_stream_connect_record_proc) (ma_pa_stream* s, const char* dev, const ma_pa_buffer_attr* attr, ma_pa_stream_flags_t flags); typedef int (* ma_pa_stream_disconnect_proc) (ma_pa_stream* s); -typedef ma_pa_stream_state_t (* ma_pa_stream_get_state_proc) (ma_pa_stream* s); +typedef ma_pa_stream_state_t (* ma_pa_stream_get_state_proc) (const ma_pa_stream* s); typedef const ma_pa_sample_spec* (* ma_pa_stream_get_sample_spec_proc) (ma_pa_stream* s); typedef const ma_pa_channel_map* (* ma_pa_stream_get_channel_map_proc) (ma_pa_stream* s); typedef const ma_pa_buffer_attr* (* ma_pa_stream_get_buffer_attr_proc) (ma_pa_stream* s); typedef ma_pa_operation* (* ma_pa_stream_set_buffer_attr_proc) (ma_pa_stream* s, const ma_pa_buffer_attr* attr, ma_pa_stream_success_cb_t cb, void* userdata); -typedef const char* (* ma_pa_stream_get_device_name_proc) (ma_pa_stream* s); +typedef const char* (* ma_pa_stream_get_device_name_proc) (const ma_pa_stream* s); typedef void (* ma_pa_stream_set_write_callback_proc) (ma_pa_stream* s, ma_pa_stream_request_cb_t cb, void* userdata); typedef void (* ma_pa_stream_set_read_callback_proc) (ma_pa_stream* s, ma_pa_stream_request_cb_t cb, void* userdata); typedef void (* ma_pa_stream_set_suspended_callback_proc) (ma_pa_stream* s, ma_pa_stream_notify_cb_t cb, void* userdata); @@ -29473,15 +30898,15 @@ typedef void (* ma_pa_stream_set_moved_callback_proc) ( typedef int (* ma_pa_stream_is_suspended_proc) (const ma_pa_stream* s); typedef ma_pa_operation* (* ma_pa_stream_flush_proc) (ma_pa_stream* s, ma_pa_stream_success_cb_t cb, void* userdata); typedef ma_pa_operation* (* ma_pa_stream_drain_proc) (ma_pa_stream* s, ma_pa_stream_success_cb_t cb, void* userdata); -typedef int (* ma_pa_stream_is_corked_proc) (ma_pa_stream* s); +typedef int (* ma_pa_stream_is_corked_proc) (const ma_pa_stream* s); typedef ma_pa_operation* (* ma_pa_stream_cork_proc) (ma_pa_stream* s, int b, ma_pa_stream_success_cb_t cb, void* userdata); typedef ma_pa_operation* (* ma_pa_stream_trigger_proc) (ma_pa_stream* s, ma_pa_stream_success_cb_t cb, void* userdata); typedef int (* ma_pa_stream_begin_write_proc) (ma_pa_stream* s, void** data, size_t* nbytes); typedef int (* ma_pa_stream_write_proc) (ma_pa_stream* s, const void* data, size_t nbytes, ma_pa_free_cb_t free_cb, int64_t offset, ma_pa_seek_mode_t seek); typedef int (* ma_pa_stream_peek_proc) (ma_pa_stream* s, const void** data, size_t* nbytes); typedef int (* ma_pa_stream_drop_proc) (ma_pa_stream* s); -typedef size_t (* ma_pa_stream_writable_size_proc) (ma_pa_stream* s); -typedef size_t (* ma_pa_stream_readable_size_proc) (ma_pa_stream* s); +typedef size_t (* ma_pa_stream_writable_size_proc) (const ma_pa_stream* s); +typedef size_t (* ma_pa_stream_readable_size_proc) (const ma_pa_stream* s); typedef struct { @@ -29777,7 +31202,7 @@ static ma_result ma_init_pa_mainloop_and_pa_context__pulse(ma_context* pContext, } /* Now we need to connect to the context. Everything is asynchronous so we need to wait for it to connect before returning. */ - result = ma_result_from_pulse(((ma_pa_context_connect_proc)pContext->pulse.pa_context_connect)((ma_pa_context*)pPulseContext, pServerName, (tryAutoSpawn) ? 0 : MA_PA_CONTEXT_NOAUTOSPAWN, NULL)); + result = ma_result_from_pulse(((ma_pa_context_connect_proc)pContext->pulse.pa_context_connect)((ma_pa_context*)pPulseContext, pServerName, (tryAutoSpawn) ? MA_PA_CONTEXT_NOFLAGS : MA_PA_CONTEXT_NOAUTOSPAWN, NULL)); if (result != MA_SUCCESS) { ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to connect PulseAudio context."); ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)((ma_pa_mainloop*)(pMainLoop)); @@ -30510,7 +31935,7 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi const ma_pa_buffer_attr* pActualAttr = NULL; const ma_pa_channel_map* pActualChannelMap = NULL; ma_uint32 iChannel; - ma_pa_stream_flags_t streamFlags; + int streamFlags; MA_ASSERT(pDevice != NULL); MA_ZERO_OBJECT(&pDevice->pulse); @@ -30568,8 +31993,13 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi ss.channels = pDescriptorCapture->channels; } + /* PulseAudio has a maximum channel count of 32. We'll get a crash if this is exceeded. */ + if (ss.channels > 32) { + ss.channels = 32; + } + /* Use a default channel map. */ - ((ma_pa_channel_map_init_extend_proc)pDevice->pContext->pulse.pa_channel_map_init_extend)(&cmap, ss.channels, pConfig->pulse.channelMap); + ((ma_pa_channel_map_init_extend_proc)pDevice->pContext->pulse.pa_channel_map_init_extend)(&cmap, ss.channels, (ma_pa_channel_map_def_t)pConfig->pulse.channelMap); /* Use the requested sample rate if one was specified. */ if (pDescriptorCapture->sampleRate != 0) { @@ -30626,7 +32056,7 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi streamFlags |= MA_PA_STREAM_DONT_MOVE; } - error = ((ma_pa_stream_connect_record_proc)pDevice->pContext->pulse.pa_stream_connect_record)((ma_pa_stream*)pDevice->pulse.pStreamCapture, devCapture, &attr, streamFlags); + error = ((ma_pa_stream_connect_record_proc)pDevice->pContext->pulse.pa_stream_connect_record)((ma_pa_stream*)pDevice->pulse.pStreamCapture, devCapture, &attr, (ma_pa_stream_flags_t)streamFlags); if (error != MA_PA_OK) { ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to connect PulseAudio capture stream."); result = ma_result_from_pulse(error); @@ -30720,8 +32150,13 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi ss.channels = pDescriptorPlayback->channels; } + /* PulseAudio has a maximum channel count of 32. We'll get a crash if this is exceeded. */ + if (ss.channels > 32) { + ss.channels = 32; + } + /* Use a default channel map. */ - ((ma_pa_channel_map_init_extend_proc)pDevice->pContext->pulse.pa_channel_map_init_extend)(&cmap, ss.channels, pConfig->pulse.channelMap); + ((ma_pa_channel_map_init_extend_proc)pDevice->pContext->pulse.pa_channel_map_init_extend)(&cmap, ss.channels, (ma_pa_channel_map_def_t)pConfig->pulse.channelMap); /* Use the requested sample rate if one was specified. */ @@ -30783,7 +32218,7 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi streamFlags |= MA_PA_STREAM_DONT_MOVE; } - error = ((ma_pa_stream_connect_playback_proc)pDevice->pContext->pulse.pa_stream_connect_playback)((ma_pa_stream*)pDevice->pulse.pStreamPlayback, devPlayback, &attr, streamFlags, NULL, NULL); + error = ((ma_pa_stream_connect_playback_proc)pDevice->pContext->pulse.pa_stream_connect_playback)((ma_pa_stream*)pDevice->pulse.pStreamPlayback, devPlayback, &attr, (ma_pa_stream_flags_t)streamFlags, NULL, NULL); if (error != MA_PA_OK) { ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to connect PulseAudio playback stream."); result = ma_result_from_pulse(error); @@ -31338,6 +32773,7 @@ typedef JackProcessCallback ma_JackProcessCallback; typedef JackBufferSizeCallback ma_JackBufferSizeCallback; typedef JackShutdownCallback ma_JackShutdownCallback; #define MA_JACK_DEFAULT_AUDIO_TYPE JACK_DEFAULT_AUDIO_TYPE +#define ma_JackNullOption JackNullOption #define ma_JackNoStartServer JackNoStartServer #define ma_JackPortIsInput JackPortIsInput #define ma_JackPortIsOutput JackPortIsOutput @@ -31352,6 +32788,7 @@ typedef int (* ma_JackProcessCallback) (ma_jack_nframes_t nframes, void* arg) typedef int (* ma_JackBufferSizeCallback)(ma_jack_nframes_t nframes, void* arg); typedef void (* ma_JackShutdownCallback) (void* arg); #define MA_JACK_DEFAULT_AUDIO_TYPE "32 bit float mono audio" +#define ma_JackNullOption 0 #define ma_JackNoStartServer 1 #define ma_JackPortIsInput 1 #define ma_JackPortIsOutput 2 @@ -31392,7 +32829,7 @@ static ma_result ma_context_open_client__jack(ma_context* pContext, ma_jack_clie maxClientNameSize = ((ma_jack_client_name_size_proc)pContext->jack.jack_client_name_size)(); /* Includes null terminator. */ ma_strncpy_s(clientName, ma_min(sizeof(clientName), maxClientNameSize), (pContext->jack.pClientName != NULL) ? pContext->jack.pClientName : "miniaudio", (size_t)-1); - pClient = ((ma_jack_client_open_proc)pContext->jack.jack_client_open)(clientName, (pContext->jack.tryStartServer) ? 0 : ma_JackNoStartServer, &status, NULL); + pClient = ((ma_jack_client_open_proc)pContext->jack.jack_client_open)(clientName, (pContext->jack.tryStartServer) ? ma_JackNullOption : ma_JackNoStartServer, &status, NULL); if (pClient == NULL) { return MA_FAILED_TO_OPEN_BACKEND_DEVICE; } @@ -36994,7 +38431,7 @@ OSS Backend #define MA_OSS_DEFAULT_DEVICE_NAME "/dev/dsp" -static int ma_open_temp_device__oss() +static int ma_open_temp_device__oss(void) { /* The OSS sample code uses "/dev/mixer" as the device for getting system properties so I'm going to do the same. */ int fd = open("/dev/mixer", O_RDONLY, 0); @@ -37834,25 +39271,30 @@ static void ma_stream_error_callback__aaudio(ma_AAudioStream* pStream, void* pUs (void)error; ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[AAudio] ERROR CALLBACK: error=%d, AAudioStream_getState()=%d\n", error, ((MA_PFN_AAudioStream_getState)pDevice->pContext->aaudio.AAudioStream_getState)(pStream)); + /* When we get an error, we'll assume that the stream is in an erroneous state and needs to be restarted. From the documentation, we cannot do this from the error callback. Therefore we are going to use an event thread for the AAudio backend to do this cleanly and safely. */ - job = ma_job_init(MA_JOB_TYPE_DEVICE_AAUDIO_REROUTE); - job.data.device.aaudio.reroute.pDevice = pDevice; - - if (pStream == pDevice->aaudio.pStreamCapture) { - job.data.device.aaudio.reroute.deviceType = ma_device_type_capture; + if (ma_atomic_bool32_get(&pDevice->aaudio.isTearingDown)) { + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[AAudio] Device Disconnected. Tearing down device.\n"); } else { - job.data.device.aaudio.reroute.deviceType = ma_device_type_playback; - } - - result = ma_device_job_thread_post(&pDevice->pContext->aaudio.jobThread, &job); - if (result != MA_SUCCESS) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[AAudio] Device Disconnected. Failed to post job for rerouting.\n"); - return; + job = ma_job_init(MA_JOB_TYPE_DEVICE_AAUDIO_REROUTE); + job.data.device.aaudio.reroute.pDevice = pDevice; + + if (pStream == pDevice->aaudio.pStreamCapture) { + job.data.device.aaudio.reroute.deviceType = ma_device_type_capture; + } else { + job.data.device.aaudio.reroute.deviceType = ma_device_type_playback; + } + + result = ma_device_job_thread_post(&pDevice->pContext->aaudio.jobThread, &job); + if (result != MA_SUCCESS) { + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[AAudio] Device Disconnected. Failed to post job for rerouting.\n"); + return; + } } } @@ -38169,7 +39611,7 @@ static ma_result ma_close_streams__aaudio(ma_device* pDevice) { MA_ASSERT(pDevice != NULL); - /* When re-routing, streams may have been closed and never re-opened. Hence the extra checks below. */ + /* When rerouting, streams may have been closed and never re-opened. Hence the extra checks below. */ if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { ma_close_stream__aaudio(pDevice->pContext, (ma_AAudioStream*)pDevice->aaudio.pStreamCapture); pDevice->aaudio.pStreamCapture = NULL; @@ -38186,6 +39628,12 @@ static ma_result ma_device_uninit__aaudio(ma_device* pDevice) { MA_ASSERT(pDevice != NULL); + /* + Note: Closing the streams may cause a timeout error, which would then trigger rerouting in our error callback. + We must not schedule a reroute when device is getting destroyed. + */ + ma_atomic_bool32_set(&pDevice->aaudio.isTearingDown, MA_TRUE); + /* Wait for any rerouting to finish before attempting to close the streams. */ ma_mutex_lock(&pDevice->aaudio.rerouteLock); { @@ -38193,7 +39641,7 @@ static ma_result ma_device_uninit__aaudio(ma_device* pDevice) } ma_mutex_unlock(&pDevice->aaudio.rerouteLock); - /* Destroy re-routing lock. */ + /* Destroy rerouting lock. */ ma_mutex_uninit(&pDevice->aaudio.rerouteLock); return MA_SUCCESS; @@ -38429,17 +39877,22 @@ static ma_result ma_device_stop__aaudio(ma_device* pDevice) static ma_result ma_device_reinit__aaudio(ma_device* pDevice, ma_device_type deviceType) { + const ma_int32 maxAttempts = 4; /* Reasonable retry limit. */ + ma_result result; - int32_t retries = 0; + ma_int32 iAttempt; MA_ASSERT(pDevice != NULL); - /* - TODO: Stop retrying if main thread is about to uninit device. - */ - ma_mutex_lock(&pDevice->aaudio.rerouteLock); - { -error_disconnected: + /* We got disconnected! Retry a few times, until we find a connected device! */ + iAttempt = 0; + while (iAttempt++ < maxAttempts) { + /* Device tearing down? No need to reroute! */ + if (ma_atomic_bool32_get(&pDevice->aaudio.isTearingDown)) { + result = MA_SUCCESS; /* Caller should continue as normal. */ + break; + } + /* The first thing to do is close the streams. */ ma_close_streams__aaudio(pDevice); @@ -38495,14 +39948,16 @@ error_disconnected: result = ma_device_init_streams__aaudio(pDevice, &deviceConfig, &descriptorPlayback, &descriptorCapture); if (result != MA_SUCCESS) { ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_WARNING, "[AAudio] Failed to create stream after route change."); - goto done; + /* Reroute failed! */ + break; } result = ma_device_post_init(pDevice, deviceType, &descriptorPlayback, &descriptorCapture); if (result != MA_SUCCESS) { ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_WARNING, "[AAudio] Failed to initialize device after route change."); ma_close_streams__aaudio(pDevice); - goto done; + /* Reroute failed! */ + break; } /* We'll only ever do this in response to a reroute. */ @@ -38513,26 +39968,23 @@ error_disconnected: if (pDevice->aaudio.noAutoStartAfterReroute == MA_FALSE) { result = ma_device_start__aaudio(pDevice); if (result != MA_SUCCESS) { - /* We got disconnected! Retry a few times, until we find a connected device! */ - retries += 1; - if (retries <= 3) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[AAudio] Failed to start stream after route change, retrying(%d)", retries); - goto error_disconnected; + if (iAttempt < maxAttempts) { + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[AAudio] Failed to start stream after route change, retrying(%d)", iAttempt); + } else { + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[AAudio] Failed to start stream after route change, giving up."); } - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[AAudio] Failed to start stream after route change."); - goto done; } } else { - ma_device_stop(pDevice); /* Do a full device stop so we set internal state correctly. */ + ma_device_stop(pDevice); /* Do a full device stop so we set internal state correctly. */ } } - - result = MA_SUCCESS; - } -done: - /* Re-routing done */ - ma_mutex_unlock(&pDevice->aaudio.rerouteLock); + if (result == MA_SUCCESS) { + /* Reroute successful! */ + break; + } + } + return result; } @@ -38698,7 +40150,7 @@ static ma_result ma_context_init__aaudio(ma_context* pContext, const ma_context_ static ma_result ma_job_process__device__aaudio_reroute(ma_job* pJob) { - ma_result result; + ma_result result = MA_SUCCESS; ma_device* pDevice; MA_ASSERT(pJob != NULL); @@ -38706,19 +40158,22 @@ static ma_result ma_job_process__device__aaudio_reroute(ma_job* pJob) pDevice = (ma_device*)pJob->data.device.aaudio.reroute.pDevice; MA_ASSERT(pDevice != NULL); - /* Here is where we need to reroute the device. To do this we need to uninitialize the stream and reinitialize it. */ - result = ma_device_reinit__aaudio(pDevice, (ma_device_type)pJob->data.device.aaudio.reroute.deviceType); - if (result != MA_SUCCESS) { - /* - Getting here means we failed to reroute the device. The best thing I can think of here is to - just stop the device. - */ - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[AAudio] Stopping device due to reroute failure."); - ma_device_stop(pDevice); - return result; + ma_mutex_lock(&pDevice->aaudio.rerouteLock); + { + /* Here is where we need to reroute the device. To do this we need to uninitialize the stream and reinitialize it. */ + result = ma_device_reinit__aaudio(pDevice, (ma_device_type)pJob->data.device.aaudio.reroute.deviceType); + if (result != MA_SUCCESS) { + /* + Getting here means we failed to reroute the device. The best thing I can think of here is to + just stop the device. + */ + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[AAudio] Stopping device due to reroute failure."); + ma_device_stop(pDevice); + } } + ma_mutex_unlock(&pDevice->aaudio.rerouteLock); - return MA_SUCCESS; + return result; } #else /* Getting here means there is no AAudio backend so we need a no-op job implementation. */ @@ -41236,13 +42691,13 @@ MA_API ma_result ma_device_post_init(ma_device* pDevice, ma_device_type deviceTy static ma_thread_result MA_THREADCALL ma_worker_thread(void* pData) { ma_device* pDevice = (ma_device*)pData; -#ifdef MA_WIN32 +#if defined(MA_WIN32) && !defined(MA_XBOX) HRESULT CoInitializeResult; #endif MA_ASSERT(pDevice != NULL); -#ifdef MA_WIN32 +#if defined(MA_WIN32) && !defined(MA_XBOX) CoInitializeResult = ma_CoInitializeEx(pDevice->pContext, NULL, MA_COINIT_VALUE); #endif @@ -41333,8 +42788,8 @@ static ma_thread_result MA_THREADCALL ma_worker_thread(void* pData) ma_event_signal(&pDevice->stopEvent); } -#ifdef MA_WIN32 - if (CoInitializeResult == S_OK) { +#if defined(MA_WIN32) && !defined(MA_XBOX) + if (CoInitializeResult == S_OK || CoInitializeResult == S_FALSE) { ma_CoUninitialize(pDevice->pContext); } #endif @@ -41358,67 +42813,92 @@ static ma_bool32 ma_device__is_initialized(ma_device* pDevice) static ma_result ma_context_uninit_backend_apis__win32(ma_context* pContext) { /* For some reason UWP complains when CoUninitialize() is called. I'm just not going to call it on UWP. */ -#if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) - if (pContext->win32.CoInitializeResult == S_OK) { - ma_CoUninitialize(pContext); + #if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) + { + /* TODO: Remove this once the new single threaded backend system is in place in 0.12. */ + #if !defined(MA_XBOX) + { + if (pContext->win32.CoInitializeResult == S_OK || pContext->win32.CoInitializeResult == S_FALSE) { + ma_CoUninitialize(pContext); /* TODO: Remove this once the new single threaded backend system is in place in 0.12. */ + } + } + #endif + + #if defined(MA_WIN32_DESKTOP) + ma_dlclose(ma_context_get_log(pContext), pContext->win32.hUser32DLL); + ma_dlclose(ma_context_get_log(pContext), pContext->win32.hAdvapi32DLL); + #endif + + ma_dlclose(ma_context_get_log(pContext), pContext->win32.hOle32DLL); + } + #else + { + (void)pContext; } - - #if defined(MA_WIN32_DESKTOP) - ma_dlclose(ma_context_get_log(pContext), pContext->win32.hUser32DLL); - ma_dlclose(ma_context_get_log(pContext), pContext->win32.hAdvapi32DLL); #endif - ma_dlclose(ma_context_get_log(pContext), pContext->win32.hOle32DLL); -#else - (void)pContext; -#endif - return MA_SUCCESS; } static ma_result ma_context_init_backend_apis__win32(ma_context* pContext) { -#if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) - #if defined(MA_WIN32_DESKTOP) - /* User32.dll */ - pContext->win32.hUser32DLL = ma_dlopen(ma_context_get_log(pContext), "user32.dll"); - if (pContext->win32.hUser32DLL == NULL) { + /* + TODO: Reassess all of this stuff and move everything to the relevant backends. For example, I think + GetForegroundWindow() and GetDesktopWindow() are only used by the DirectSound backend. + */ + #if (defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK)) && !defined(MA_XBOX) + { + #if defined(MA_WIN32_DESKTOP) + { + /* User32.dll */ + pContext->win32.hUser32DLL = ma_dlopen(ma_context_get_log(pContext), "user32.dll"); + if (pContext->win32.hUser32DLL == NULL) { + return MA_FAILED_TO_INIT_BACKEND; + } + + pContext->win32.GetForegroundWindow = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hUser32DLL, "GetForegroundWindow"); + pContext->win32.GetDesktopWindow = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hUser32DLL, "GetDesktopWindow"); + + + /* Advapi32.dll */ + pContext->win32.hAdvapi32DLL = ma_dlopen(ma_context_get_log(pContext), "advapi32.dll"); + if (pContext->win32.hAdvapi32DLL == NULL) { + return MA_FAILED_TO_INIT_BACKEND; + } + + pContext->win32.RegOpenKeyExA = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hAdvapi32DLL, "RegOpenKeyExA"); + pContext->win32.RegCloseKey = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hAdvapi32DLL, "RegCloseKey"); + pContext->win32.RegQueryValueExA = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hAdvapi32DLL, "RegQueryValueExA"); + } + #endif + + /* Ole32.dll */ + pContext->win32.hOle32DLL = ma_dlopen(ma_context_get_log(pContext), "ole32.dll"); + if (pContext->win32.hOle32DLL == NULL) { return MA_FAILED_TO_INIT_BACKEND; } - pContext->win32.GetForegroundWindow = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hUser32DLL, "GetForegroundWindow"); - pContext->win32.GetDesktopWindow = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hUser32DLL, "GetDesktopWindow"); - - - /* Advapi32.dll */ - pContext->win32.hAdvapi32DLL = ma_dlopen(ma_context_get_log(pContext), "advapi32.dll"); - if (pContext->win32.hAdvapi32DLL == NULL) { - return MA_FAILED_TO_INIT_BACKEND; - } - - pContext->win32.RegOpenKeyExA = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hAdvapi32DLL, "RegOpenKeyExA"); - pContext->win32.RegCloseKey = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hAdvapi32DLL, "RegCloseKey"); - pContext->win32.RegQueryValueExA = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hAdvapi32DLL, "RegQueryValueExA"); + pContext->win32.CoInitialize = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "CoInitialize"); + pContext->win32.CoInitializeEx = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "CoInitializeEx"); + pContext->win32.CoUninitialize = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "CoUninitialize"); + pContext->win32.CoCreateInstance = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "CoCreateInstance"); + pContext->win32.CoTaskMemFree = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "CoTaskMemFree"); + pContext->win32.PropVariantClear = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "PropVariantClear"); + pContext->win32.StringFromGUID2 = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "StringFromGUID2"); + } + #else + { + (void)pContext; /* Unused. */ + } #endif - /* Ole32.dll */ - pContext->win32.hOle32DLL = ma_dlopen(ma_context_get_log(pContext), "ole32.dll"); - if (pContext->win32.hOle32DLL == NULL) { - return MA_FAILED_TO_INIT_BACKEND; + /* TODO: Remove this once the new single threaded backend system is in place in 0.12. */ + #if !defined(MA_XBOX) + { + pContext->win32.CoInitializeResult = ma_CoInitializeEx(pContext, NULL, MA_COINIT_VALUE); } + #endif - pContext->win32.CoInitialize = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "CoInitialize"); - pContext->win32.CoInitializeEx = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "CoInitializeEx"); - pContext->win32.CoUninitialize = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "CoUninitialize"); - pContext->win32.CoCreateInstance = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "CoCreateInstance"); - pContext->win32.CoTaskMemFree = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "CoTaskMemFree"); - pContext->win32.PropVariantClear = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "PropVariantClear"); - pContext->win32.StringFromGUID2 = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->win32.hOle32DLL, "StringFromGUID2"); -#else - (void)pContext; /* Unused. */ -#endif - - pContext->win32.CoInitializeResult = ma_CoInitializeEx(pContext, NULL, MA_COINIT_VALUE); return MA_SUCCESS; } #else @@ -44016,7 +45496,7 @@ static MA_INLINE void ma_pcm_s16_to_s32__reference(void* dst, const void* src, m ma_uint64 i; for (i = 0; i < count; i += 1) { - dst_s32[i] = src_s16[i] << 16; + dst_s32[i] = (ma_int32)src_s16[i] << 16; } (void)ditherMode; @@ -56408,8 +57888,12 @@ MA_API size_t ma_channel_map_to_string(const ma_channel* pChannelMap, ma_uint32 } /* Null terminate. Don't increment the length here. */ - if (pBufferOut != NULL && bufferCap > len + 1) { - pBufferOut[len] = '\0'; + if (pBufferOut != NULL) { + if (bufferCap > len) { + pBufferOut[len] = '\0'; + } else if (bufferCap > 0) { + pBufferOut[bufferCap - 1] = '\0'; + } } return len; @@ -56620,7 +58104,7 @@ MA_API ma_result ma_rb_init_ex(size_t subbufferSizeInBytes, size_t subbufferCoun Here is where we allocate our own buffer. We always want to align this to MA_SIMD_ALIGNMENT for future SIMD optimization opportunity. To do this we need to make sure the stride is a multiple of MA_SIMD_ALIGNMENT. */ - pRB->subbufferStrideInBytes = (pRB->subbufferSizeInBytes + (MA_SIMD_ALIGNMENT-1)) & ~MA_SIMD_ALIGNMENT; + pRB->subbufferStrideInBytes = ma_align(pRB->subbufferSizeInBytes, MA_SIMD_ALIGNMENT); bufferSizeInBytes = (size_t)pRB->subbufferCount*pRB->subbufferStrideInBytes; pRB->pBuffer = ma_aligned_malloc(bufferSizeInBytes, MA_SIMD_ALIGNMENT, &pRB->allocationCallbacks); @@ -59515,7 +60999,7 @@ MA_API ma_result ma_vfs_info(ma_vfs* pVFS, ma_vfs_file file, ma_file_info* pInfo } -#if !defined(MA_USE_WIN32_FILEIO) && (defined(MA_WIN32) && defined(MA_WIN32_DESKTOP) && !defined(MA_NO_WIN32_FILEIO) && !defined(MA_POSIX)) +#if !defined(MA_USE_WIN32_FILEIO) && (defined(MA_WIN32) && (defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_NXDK)) && !defined(MA_NO_WIN32_FILEIO) && !defined(MA_POSIX)) #define MA_USE_WIN32_FILEIO #endif @@ -59592,25 +61076,34 @@ static ma_result ma_default_vfs_open__win32(ma_vfs* pVFS, const char* pFilePath, static ma_result ma_default_vfs_open_w__win32(ma_vfs* pVFS, const wchar_t* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile) { - HANDLE hFile; - DWORD dwDesiredAccess; - DWORD dwShareMode; - DWORD dwCreationDisposition; + #if !defined(MA_XBOX_NXDK) + { + HANDLE hFile; + DWORD dwDesiredAccess; + DWORD dwShareMode; + DWORD dwCreationDisposition; - (void)pVFS; + (void)pVFS; - /* Load some Win32 symbols dynamically so we can dynamically check for the existence of SetFilePointerEx. */ - ma_win32_fileio_init(); + /* Load some Win32 symbols dynamically so we can dynamically check for the existence of SetFilePointerEx. */ + ma_win32_fileio_init(); - ma_default_vfs__get_open_settings_win32(openMode, &dwDesiredAccess, &dwShareMode, &dwCreationDisposition); + ma_default_vfs__get_open_settings_win32(openMode, &dwDesiredAccess, &dwShareMode, &dwCreationDisposition); - hFile = CreateFileW(pFilePath, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL); - if (hFile == INVALID_HANDLE_VALUE) { - return ma_result_from_GetLastError(GetLastError()); + hFile = CreateFileW(pFilePath, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) { + return ma_result_from_GetLastError(GetLastError()); + } + + *pFile = hFile; + return MA_SUCCESS; } - - *pFile = hFile; - return MA_SUCCESS; + #else + { + /* No CreateFileW() available. */ + return MA_NOT_IMPLEMENTED; + } + #endif } static ma_result ma_default_vfs_close__win32(ma_vfs* pVFS, ma_vfs_file file) @@ -59781,19 +61274,28 @@ static ma_result ma_default_vfs_tell__win32(ma_vfs* pVFS, ma_vfs_file file, ma_i static ma_result ma_default_vfs_info__win32(ma_vfs* pVFS, ma_vfs_file file, ma_file_info* pInfo) { - BY_HANDLE_FILE_INFORMATION fi; - BOOL result; - (void)pVFS; - result = GetFileInformationByHandle((HANDLE)file, &fi); - if (result == 0) { - return ma_result_from_GetLastError(GetLastError()); + #if !defined(MA_XBOX_NXDK) + { + BY_HANDLE_FILE_INFORMATION fi; + BOOL result; + + result = GetFileInformationByHandle((HANDLE)file, &fi); + if (result == 0) { + return ma_result_from_GetLastError(GetLastError()); + } + + pInfo->sizeInBytes = ((ma_uint64)fi.nFileSizeHigh << 32) | ((ma_uint64)fi.nFileSizeLow); + + return MA_SUCCESS; } - - pInfo->sizeInBytes = ((ma_uint64)fi.nFileSizeHigh << 32) | ((ma_uint64)fi.nFileSizeLow); - - return MA_SUCCESS; + #else + { + /* GetFileInformationByHandle() is unavailable. */ + return MA_NOT_IMPLEMENTED; + } + #endif } #else static ma_result ma_default_vfs_open__stdio(ma_vfs* pVFS, const char* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile) @@ -60131,6 +61633,8 @@ static ma_result ma_default_vfs_tell(ma_vfs* pVFS, ma_vfs_file file, ma_int64* p static ma_result ma_default_vfs_info(ma_vfs* pVFS, ma_vfs_file file, ma_file_info* pInfo) { + ma_result result; + if (pInfo == NULL) { return MA_INVALID_ARGS; } @@ -60142,10 +61646,43 @@ static ma_result ma_default_vfs_info(ma_vfs* pVFS, ma_vfs_file file, ma_file_inf } #if defined(MA_USE_WIN32_FILEIO) - return ma_default_vfs_info__win32(pVFS, file, pInfo); + result = ma_default_vfs_info__win32(pVFS, file, pInfo); #else - return ma_default_vfs_info__stdio(pVFS, file, pInfo); + result = ma_default_vfs_info__stdio(pVFS, file, pInfo); #endif + + if (result == MA_NOT_IMPLEMENTED) { + /* Not implemented. Fall back to seek/tell/seek. */ + ma_result result; + ma_int64 cursor; + ma_int64 sizeInBytes; + + result = ma_default_vfs_tell(pVFS, file, &cursor); + if (result != MA_SUCCESS) { + return result; + } + + result = ma_default_vfs_seek(pVFS, file, 0, ma_seek_origin_end); + if (result != MA_SUCCESS) { + return result; + } + + result = ma_default_vfs_tell(pVFS, file, &sizeInBytes); + if (result != MA_SUCCESS) { + return result; + } + + pInfo->sizeInBytes = sizeInBytes; + + result = ma_default_vfs_seek(pVFS, file, cursor, ma_seek_origin_start); + if (result != MA_SUCCESS) { + return result; + } + + MA_ASSERT(result == MA_SUCCESS); + } + + return result; } @@ -60333,8 +61870,8 @@ extern "C" { #define MA_DR_WAV_STRINGIFY(x) #x #define MA_DR_WAV_XSTRINGIFY(x) MA_DR_WAV_STRINGIFY(x) #define MA_DR_WAV_VERSION_MAJOR 0 -#define MA_DR_WAV_VERSION_MINOR 13 -#define MA_DR_WAV_VERSION_REVISION 18 +#define MA_DR_WAV_VERSION_MINOR 14 +#define MA_DR_WAV_VERSION_REVISION 1 #define MA_DR_WAV_VERSION_STRING MA_DR_WAV_XSTRINGIFY(MA_DR_WAV_VERSION_MAJOR) "." MA_DR_WAV_XSTRINGIFY(MA_DR_WAV_VERSION_MINOR) "." MA_DR_WAV_XSTRINGIFY(MA_DR_WAV_VERSION_REVISION) #include #define MA_DR_WAVE_FORMAT_PCM 0x1 @@ -60350,8 +61887,9 @@ MA_API void ma_dr_wav_version(ma_uint32* pMajor, ma_uint32* pMinor, ma_uint32* p MA_API const char* ma_dr_wav_version_string(void); typedef enum { - ma_dr_wav_seek_origin_start, - ma_dr_wav_seek_origin_current + MA_DR_WAV_SEEK_SET, + MA_DR_WAV_SEEK_CUR, + MA_DR_WAV_SEEK_END } ma_dr_wav_seek_origin; typedef enum { @@ -60388,6 +61926,7 @@ MA_API ma_uint16 ma_dr_wav_fmt_get_format(const ma_dr_wav_fmt* pFMT); typedef size_t (* ma_dr_wav_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead); typedef size_t (* ma_dr_wav_write_proc)(void* pUserData, const void* pData, size_t bytesToWrite); typedef ma_bool32 (* ma_dr_wav_seek_proc)(void* pUserData, int offset, ma_dr_wav_seek_origin origin); +typedef ma_bool32 (* ma_dr_wav_tell_proc)(void* pUserData, ma_int64* pCursor); typedef ma_uint64 (* ma_dr_wav_chunk_proc)(void* pChunkUserData, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pReadSeekUserData, const ma_dr_wav_chunk_header* pChunkHeader, ma_dr_wav_container container, const ma_dr_wav_fmt* pFMT); typedef struct { @@ -60432,6 +61971,11 @@ typedef enum ma_dr_wav_metadata_type_list_info_genre = 1 << 15, ma_dr_wav_metadata_type_list_info_album = 1 << 16, ma_dr_wav_metadata_type_list_info_tracknumber = 1 << 17, + ma_dr_wav_metadata_type_list_info_location = 1 << 18, + ma_dr_wav_metadata_type_list_info_organization = 1 << 19, + ma_dr_wav_metadata_type_list_info_keywords = 1 << 20, + ma_dr_wav_metadata_type_list_info_medium = 1 << 21, + ma_dr_wav_metadata_type_list_info_description = 1 << 22, ma_dr_wav_metadata_type_list_all_info_strings = ma_dr_wav_metadata_type_list_info_software | ma_dr_wav_metadata_type_list_info_copyright | ma_dr_wav_metadata_type_list_info_title @@ -60440,7 +61984,12 @@ typedef enum | ma_dr_wav_metadata_type_list_info_date | ma_dr_wav_metadata_type_list_info_genre | ma_dr_wav_metadata_type_list_info_album - | ma_dr_wav_metadata_type_list_info_tracknumber, + | ma_dr_wav_metadata_type_list_info_tracknumber + | ma_dr_wav_metadata_type_list_info_location + | ma_dr_wav_metadata_type_list_info_organization + | ma_dr_wav_metadata_type_list_info_keywords + | ma_dr_wav_metadata_type_list_info_medium + | ma_dr_wav_metadata_type_list_info_description, ma_dr_wav_metadata_type_list_all_adtl = ma_dr_wav_metadata_type_list_label | ma_dr_wav_metadata_type_list_note | ma_dr_wav_metadata_type_list_labelled_cue_region, @@ -60457,8 +62006,8 @@ typedef struct { ma_uint32 cuePointId; ma_uint32 type; - ma_uint32 firstSampleByteOffset; - ma_uint32 lastSampleByteOffset; + ma_uint32 firstSampleOffset; + ma_uint32 lastSampleOffset; ma_uint32 sampleFraction; ma_uint32 playCount; } ma_dr_wav_smpl_loop; @@ -60493,7 +62042,7 @@ typedef struct ma_uint8 dataChunkId[4]; ma_uint32 chunkStart; ma_uint32 blockStart; - ma_uint32 sampleByteOffset; + ma_uint32 sampleOffset; } ma_dr_wav_cue_point; typedef struct { @@ -60595,6 +62144,7 @@ typedef struct ma_dr_wav_read_proc onRead; ma_dr_wav_write_proc onWrite; ma_dr_wav_seek_proc onSeek; + ma_dr_wav_tell_proc onTell; void* pUserData; ma_allocation_callbacks allocationCallbacks; ma_dr_wav_container container; @@ -60637,9 +62187,9 @@ typedef struct ma_bool8 isUnsigned; } aiff; } ma_dr_wav; -MA_API ma_bool32 ma_dr_wav_init(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_bool32 ma_dr_wav_init_ex(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_chunk_proc onChunk, void* pReadSeekUserData, void* pChunkUserData, ma_uint32 flags, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_bool32 ma_dr_wav_init_with_metadata(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pUserData, ma_uint32 flags, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_bool32 ma_dr_wav_init(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_tell_proc onTell, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_bool32 ma_dr_wav_init_ex(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_tell_proc onTell, ma_dr_wav_chunk_proc onChunk, void* pReadSeekTellUserData, void* pChunkUserData, ma_uint32 flags, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_bool32 ma_dr_wav_init_with_metadata(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_tell_proc onTell, void* pUserData, ma_uint32 flags, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_bool32 ma_dr_wav_init_write(ma_dr_wav* pWav, const ma_dr_wav_data_format* pFormat, ma_dr_wav_write_proc onWrite, ma_dr_wav_seek_proc onSeek, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_bool32 ma_dr_wav_init_write_sequential(ma_dr_wav* pWav, const ma_dr_wav_data_format* pFormat, ma_uint64 totalSampleCount, ma_dr_wav_write_proc onWrite, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_bool32 ma_dr_wav_init_write_sequential_pcm_frames(ma_dr_wav* pWav, const ma_dr_wav_data_format* pFormat, ma_uint64 totalPCMFrameCount, ma_dr_wav_write_proc onWrite, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); @@ -60711,9 +62261,9 @@ MA_API ma_bool32 ma_dr_wav_init_memory_write(ma_dr_wav* pWav, void** ppData, siz MA_API ma_bool32 ma_dr_wav_init_memory_write_sequential(ma_dr_wav* pWav, void** ppData, size_t* pDataSize, const ma_dr_wav_data_format* pFormat, ma_uint64 totalSampleCount, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_bool32 ma_dr_wav_init_memory_write_sequential_pcm_frames(ma_dr_wav* pWav, void** ppData, size_t* pDataSize, const ma_dr_wav_data_format* pFormat, ma_uint64 totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); #ifndef MA_DR_WAV_NO_CONVERSION_API -MA_API ma_int16* ma_dr_wav_open_and_read_pcm_frames_s16(ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API float* ma_dr_wav_open_and_read_pcm_frames_f32(ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_int32* ma_dr_wav_open_and_read_pcm_frames_s32(ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_int16* ma_dr_wav_open_and_read_pcm_frames_s16(ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API float* ma_dr_wav_open_and_read_pcm_frames_f32(ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_int32* ma_dr_wav_open_and_read_pcm_frames_s32(ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks); #ifndef MA_DR_WAV_NO_STDIO MA_API ma_int16* ma_dr_wav_open_file_and_read_pcm_frames_s16(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks); MA_API float* ma_dr_wav_open_file_and_read_pcm_frames_f32(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks); @@ -60753,8 +62303,8 @@ extern "C" { #define MA_DR_FLAC_STRINGIFY(x) #x #define MA_DR_FLAC_XSTRINGIFY(x) MA_DR_FLAC_STRINGIFY(x) #define MA_DR_FLAC_VERSION_MAJOR 0 -#define MA_DR_FLAC_VERSION_MINOR 12 -#define MA_DR_FLAC_VERSION_REVISION 43 +#define MA_DR_FLAC_VERSION_MINOR 13 +#define MA_DR_FLAC_VERSION_REVISION 1 #define MA_DR_FLAC_VERSION_STRING MA_DR_FLAC_XSTRINGIFY(MA_DR_FLAC_VERSION_MAJOR) "." MA_DR_FLAC_XSTRINGIFY(MA_DR_FLAC_VERSION_MINOR) "." MA_DR_FLAC_XSTRINGIFY(MA_DR_FLAC_VERSION_REVISION) #include #if defined(_MSC_VER) && _MSC_VER >= 1700 @@ -60817,8 +62367,9 @@ typedef enum } ma_dr_flac_container; typedef enum { - ma_dr_flac_seek_origin_start, - ma_dr_flac_seek_origin_current + MA_DR_FLAC_SEEK_SET, + MA_DR_FLAC_SEEK_CUR, + MA_DR_FLAC_SEEK_END } ma_dr_flac_seek_origin; typedef struct { @@ -60894,6 +62445,7 @@ typedef struct } ma_dr_flac_metadata; typedef size_t (* ma_dr_flac_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead); typedef ma_bool32 (* ma_dr_flac_seek_proc)(void* pUserData, int offset, ma_dr_flac_seek_origin origin); +typedef ma_bool32 (* ma_dr_flac_tell_proc)(void* pUserData, ma_int64* pCursor); typedef void (* ma_dr_flac_meta_proc)(void* pUserData, ma_dr_flac_metadata* pMetadata); typedef struct { @@ -60905,6 +62457,7 @@ typedef struct { ma_dr_flac_read_proc onRead; ma_dr_flac_seek_proc onSeek; + ma_dr_flac_tell_proc onTell; void* pUserData; size_t unalignedByteCount; ma_dr_flac_cache_t unalignedCache; @@ -60964,10 +62517,10 @@ typedef struct ma_dr_flac_bs bs; ma_uint8 pExtraData[1]; } ma_dr_flac; -MA_API ma_dr_flac* ma_dr_flac_open(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_dr_flac* ma_dr_flac_open_relaxed(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_container container, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_dr_flac* ma_dr_flac_open_with_metadata(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_meta_proc onMeta, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_dr_flac* ma_dr_flac_open_with_metadata_relaxed(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_meta_proc onMeta, ma_dr_flac_container container, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_dr_flac* ma_dr_flac_open(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_dr_flac* ma_dr_flac_open_relaxed(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, ma_dr_flac_container container, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_dr_flac* ma_dr_flac_open_with_metadata(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, ma_dr_flac_meta_proc onMeta, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_dr_flac* ma_dr_flac_open_with_metadata_relaxed(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, ma_dr_flac_meta_proc onMeta, ma_dr_flac_container container, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); MA_API void ma_dr_flac_close(ma_dr_flac* pFlac); MA_API ma_uint64 ma_dr_flac_read_pcm_frames_s32(ma_dr_flac* pFlac, ma_uint64 framesToRead, ma_int32* pBufferOut); MA_API ma_uint64 ma_dr_flac_read_pcm_frames_s16(ma_dr_flac* pFlac, ma_uint64 framesToRead, ma_int16* pBufferOut); @@ -60981,9 +62534,9 @@ MA_API ma_dr_flac* ma_dr_flac_open_file_with_metadata_w(const wchar_t* pFileName #endif MA_API ma_dr_flac* ma_dr_flac_open_memory(const void* pData, size_t dataSize, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_dr_flac* ma_dr_flac_open_memory_with_metadata(const void* pData, size_t dataSize, ma_dr_flac_meta_proc onMeta, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_int32* ma_dr_flac_open_and_read_pcm_frames_s32(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, ma_uint64* totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_int16* ma_dr_flac_open_and_read_pcm_frames_s16(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, ma_uint64* totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API float* ma_dr_flac_open_and_read_pcm_frames_f32(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, ma_uint64* totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_int32* ma_dr_flac_open_and_read_pcm_frames_s32(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, void* pUserData, unsigned int* channels, unsigned int* sampleRate, ma_uint64* totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_int16* ma_dr_flac_open_and_read_pcm_frames_s16(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, void* pUserData, unsigned int* channels, unsigned int* sampleRate, ma_uint64* totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API float* ma_dr_flac_open_and_read_pcm_frames_f32(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, void* pUserData, unsigned int* channels, unsigned int* sampleRate, ma_uint64* totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); #ifndef MA_DR_FLAC_NO_STDIO MA_API ma_int32* ma_dr_flac_open_file_and_read_pcm_frames_s32(const char* filename, unsigned int* channels, unsigned int* sampleRate, ma_uint64* totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_int16* ma_dr_flac_open_file_and_read_pcm_frames_s16(const char* filename, unsigned int* channels, unsigned int* sampleRate, ma_uint64* totalPCMFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); @@ -61031,6 +62584,12 @@ MA_API ma_bool32 ma_dr_flac_next_cuesheet_track(ma_dr_flac_cuesheet_track_iterat #endif /* MA_NO_FLAC */ #if !defined(MA_NO_MP3) && !defined(MA_NO_DECODING) +#ifndef MA_DR_MP3_NO_SIMD + #if (defined(MA_NO_NEON) && defined(MA_ARM)) || (defined(MA_NO_SSE2) && (defined(MA_X86) || defined(MA_X64))) + #define MA_DR_MP3_NO_SIMD + #endif +#endif + /* dr_mp3_h begin */ #ifndef ma_dr_mp3_h #define ma_dr_mp3_h @@ -61040,8 +62599,8 @@ extern "C" { #define MA_DR_MP3_STRINGIFY(x) #x #define MA_DR_MP3_XSTRINGIFY(x) MA_DR_MP3_STRINGIFY(x) #define MA_DR_MP3_VERSION_MAJOR 0 -#define MA_DR_MP3_VERSION_MINOR 6 -#define MA_DR_MP3_VERSION_REVISION 40 +#define MA_DR_MP3_VERSION_MINOR 7 +#define MA_DR_MP3_VERSION_REVISION 1 #define MA_DR_MP3_VERSION_STRING MA_DR_MP3_XSTRINGIFY(MA_DR_MP3_VERSION_MAJOR) "." MA_DR_MP3_XSTRINGIFY(MA_DR_MP3_VERSION_MINOR) "." MA_DR_MP3_XSTRINGIFY(MA_DR_MP3_VERSION_REVISION) #include #define MA_DR_MP3_MAX_PCM_FRAMES_PER_MP3_FRAME 1152 @@ -61050,7 +62609,7 @@ MA_API void ma_dr_mp3_version(ma_uint32* pMajor, ma_uint32* pMinor, ma_uint32* p MA_API const char* ma_dr_mp3_version_string(void); typedef struct { - int frame_bytes, channels, hz, layer, bitrate_kbps; + int frame_bytes, channels, sample_rate, layer, bitrate_kbps; } ma_dr_mp3dec_frame_info; typedef struct { @@ -61063,8 +62622,9 @@ MA_API int ma_dr_mp3dec_decode_frame(ma_dr_mp3dec *dec, const ma_uint8 *mp3, int MA_API void ma_dr_mp3dec_f32_to_s16(const float *in, ma_int16 *out, size_t num_samples); typedef enum { - ma_dr_mp3_seek_origin_start, - ma_dr_mp3_seek_origin_current + MA_DR_MP3_SEEK_SET, + MA_DR_MP3_SEEK_CUR, + MA_DR_MP3_SEEK_END } ma_dr_mp3_seek_origin; typedef struct { @@ -61073,8 +62633,24 @@ typedef struct ma_uint16 mp3FramesToDiscard; ma_uint16 pcmFramesToDiscard; } ma_dr_mp3_seek_point; +typedef enum +{ + MA_DR_MP3_METADATA_TYPE_ID3V1, + MA_DR_MP3_METADATA_TYPE_ID3V2, + MA_DR_MP3_METADATA_TYPE_APE, + MA_DR_MP3_METADATA_TYPE_XING, + MA_DR_MP3_METADATA_TYPE_VBRI +} ma_dr_mp3_metadata_type; +typedef struct +{ + ma_dr_mp3_metadata_type type; + const void* pRawData; + size_t rawDataSize; +} ma_dr_mp3_metadata; typedef size_t (* ma_dr_mp3_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead); typedef ma_bool32 (* ma_dr_mp3_seek_proc)(void* pUserData, int offset, ma_dr_mp3_seek_origin origin); +typedef ma_bool32 (* ma_dr_mp3_tell_proc)(void* pUserData, ma_int64* pCursor); +typedef void (* ma_dr_mp3_meta_proc)(void* pUserData, const ma_dr_mp3_metadata* pMetadata); typedef struct { ma_uint32 channels; @@ -61087,7 +62663,9 @@ typedef struct ma_uint32 sampleRate; ma_dr_mp3_read_proc onRead; ma_dr_mp3_seek_proc onSeek; + ma_dr_mp3_meta_proc onMeta; void* pUserData; + void* pUserDataMeta; ma_allocation_callbacks allocationCallbacks; ma_uint32 mp3FrameChannels; ma_uint32 mp3FrameSampleRate; @@ -61096,13 +62674,20 @@ typedef struct ma_uint8 pcmFrames[sizeof(float)*MA_DR_MP3_MAX_SAMPLES_PER_FRAME]; ma_uint64 currentPCMFrame; ma_uint64 streamCursor; + ma_uint64 streamLength; + ma_uint64 streamStartOffset; ma_dr_mp3_seek_point* pSeekPoints; ma_uint32 seekPointCount; + ma_uint32 delayInPCMFrames; + ma_uint32 paddingInPCMFrames; + ma_uint64 totalPCMFrameCount; + ma_bool32 isVBR; + ma_bool32 isCBR; size_t dataSize; size_t dataCapacity; size_t dataConsumed; ma_uint8* pData; - ma_bool32 atEnd : 1; + ma_bool32 atEnd; struct { const ma_uint8* pData; @@ -61110,9 +62695,12 @@ typedef struct size_t currentReadPos; } memory; } ma_dr_mp3; -MA_API ma_bool32 ma_dr_mp3_init(ma_dr_mp3* pMP3, ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_bool32 ma_dr_mp3_init(ma_dr_mp3* pMP3, ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, ma_dr_mp3_tell_proc onTell, ma_dr_mp3_meta_proc onMeta, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_bool32 ma_dr_mp3_init_memory_with_metadata(ma_dr_mp3* pMP3, const void* pData, size_t dataSize, ma_dr_mp3_meta_proc onMeta, void* pUserDataMeta, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_bool32 ma_dr_mp3_init_memory(ma_dr_mp3* pMP3, const void* pData, size_t dataSize, const ma_allocation_callbacks* pAllocationCallbacks); #ifndef MA_DR_MP3_NO_STDIO +MA_API ma_bool32 ma_dr_mp3_init_file_with_metadata(ma_dr_mp3* pMP3, const char* pFilePath, ma_dr_mp3_meta_proc onMeta, void* pUserDataMeta, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_bool32 ma_dr_mp3_init_file_with_metadata_w(ma_dr_mp3* pMP3, const wchar_t* pFilePath, ma_dr_mp3_meta_proc onMeta, void* pUserDataMeta, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_bool32 ma_dr_mp3_init_file(ma_dr_mp3* pMP3, const char* pFilePath, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_bool32 ma_dr_mp3_init_file_w(ma_dr_mp3* pMP3, const wchar_t* pFilePath, const ma_allocation_callbacks* pAllocationCallbacks); #endif @@ -61125,8 +62713,8 @@ MA_API ma_uint64 ma_dr_mp3_get_mp3_frame_count(ma_dr_mp3* pMP3); MA_API ma_bool32 ma_dr_mp3_get_mp3_and_pcm_frame_count(ma_dr_mp3* pMP3, ma_uint64* pMP3FrameCount, ma_uint64* pPCMFrameCount); MA_API ma_bool32 ma_dr_mp3_calculate_seek_points(ma_dr_mp3* pMP3, ma_uint32* pSeekPointCount, ma_dr_mp3_seek_point* pSeekPoints); MA_API ma_bool32 ma_dr_mp3_bind_seek_table(ma_dr_mp3* pMP3, ma_uint32 seekPointCount, ma_dr_mp3_seek_point* pSeekPoints); -MA_API float* ma_dr_mp3_open_and_read_pcm_frames_f32(ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, void* pUserData, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_int16* ma_dr_mp3_open_and_read_pcm_frames_s16(ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, void* pUserData, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API float* ma_dr_mp3_open_and_read_pcm_frames_f32(ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, ma_dr_mp3_tell_proc onTell, void* pUserData, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_int16* ma_dr_mp3_open_and_read_pcm_frames_s16(ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, ma_dr_mp3_tell_proc onTell, void* pUserData, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); MA_API float* ma_dr_mp3_open_memory_and_read_pcm_frames_f32(const void* pData, size_t dataSize, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_int16* ma_dr_mp3_open_memory_and_read_pcm_frames_s16(const void* pData, size_t dataSize, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount, const ma_allocation_callbacks* pAllocationCallbacks); #ifndef MA_DR_MP3_NO_STDIO @@ -61679,8 +63267,10 @@ static ma_bool32 ma_wav_dr_callback__seek(void* pUserData, int offset, ma_dr_wav MA_ASSERT(pWav != NULL); maSeekOrigin = ma_seek_origin_start; - if (origin == ma_dr_wav_seek_origin_current) { - maSeekOrigin = ma_seek_origin_current; + if (origin == MA_DR_WAV_SEEK_CUR) { + maSeekOrigin = ma_seek_origin_current; + } else if (origin == MA_DR_WAV_SEEK_END) { + maSeekOrigin = ma_seek_origin_end; } result = pWav->onSeek(pWav->pReadSeekTellUserData, offset, maSeekOrigin); @@ -61690,6 +63280,26 @@ static ma_bool32 ma_wav_dr_callback__seek(void* pUserData, int offset, ma_dr_wav return MA_TRUE; } + +static ma_bool32 ma_wav_dr_callback__tell(void* pUserData, ma_int64* pCursor) +{ + ma_wav* pWav = (ma_wav*)pUserData; + ma_result result; + + MA_ASSERT(pWav != NULL); + MA_ASSERT(pCursor != NULL); + + if (pWav->onTell == NULL) { + return MA_FALSE; /* Not implemented. */ + } + + result = pWav->onTell(pWav->pReadSeekTellUserData, pCursor); + if (result != MA_SUCCESS) { + return MA_FALSE; /* Failed to tell. */ + } + + return MA_TRUE; +} #endif static ma_result ma_wav_init_internal(const ma_decoding_backend_config* pConfig, ma_wav* pWav) @@ -61784,7 +63394,7 @@ MA_API ma_result ma_wav_init(ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_p { ma_bool32 wavResult; - wavResult = ma_dr_wav_init(&pWav->dr, ma_wav_dr_callback__read, ma_wav_dr_callback__seek, pWav, pAllocationCallbacks); + wavResult = ma_dr_wav_init(&pWav->dr, ma_wav_dr_callback__read, ma_wav_dr_callback__seek, ma_wav_dr_callback__tell, pWav, pAllocationCallbacks); if (wavResult != MA_TRUE) { return MA_INVALID_FILE; } @@ -62363,8 +63973,10 @@ static ma_bool32 ma_flac_dr_callback__seek(void* pUserData, int offset, ma_dr_fl MA_ASSERT(pFlac != NULL); maSeekOrigin = ma_seek_origin_start; - if (origin == ma_dr_flac_seek_origin_current) { - maSeekOrigin = ma_seek_origin_current; + if (origin == MA_DR_FLAC_SEEK_CUR) { + maSeekOrigin = ma_seek_origin_current; + } else if (origin == MA_DR_FLAC_SEEK_END) { + maSeekOrigin = ma_seek_origin_end; } result = pFlac->onSeek(pFlac->pReadSeekTellUserData, offset, maSeekOrigin); @@ -62374,6 +63986,26 @@ static ma_bool32 ma_flac_dr_callback__seek(void* pUserData, int offset, ma_dr_fl return MA_TRUE; } + +static ma_bool32 ma_flac_dr_callback__tell(void* pUserData, ma_int64* pCursor) +{ + ma_flac* pFlac = (ma_flac*)pUserData; + ma_result result; + + MA_ASSERT(pFlac != NULL); + MA_ASSERT(pCursor != NULL); + + if (pFlac->onTell == NULL) { + return MA_FALSE; /* Not implemented. */ + } + + result = pFlac->onTell(pFlac->pReadSeekTellUserData, pCursor); + if (result != MA_SUCCESS) { + return MA_FALSE; /* Failed to tell. */ + } + + return MA_TRUE; +} #endif static ma_result ma_flac_init_internal(const ma_decoding_backend_config* pConfig, ma_flac* pFlac) @@ -62425,7 +64057,7 @@ MA_API ma_result ma_flac_init(ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_ #if !defined(MA_NO_FLAC) { - pFlac->dr = ma_dr_flac_open(ma_flac_dr_callback__read, ma_flac_dr_callback__seek, pFlac, pAllocationCallbacks); + pFlac->dr = ma_dr_flac_open(ma_flac_dr_callback__read, ma_flac_dr_callback__seek, ma_flac_dr_callback__tell, pFlac, pAllocationCallbacks); if (pFlac->dr == NULL) { return MA_INVALID_FILE; } @@ -62986,9 +64618,12 @@ static ma_bool32 ma_mp3_dr_callback__seek(void* pUserData, int offset, ma_dr_mp3 MA_ASSERT(pMP3 != NULL); - maSeekOrigin = ma_seek_origin_start; - if (origin == ma_dr_mp3_seek_origin_current) { - maSeekOrigin = ma_seek_origin_current; + if (origin == MA_DR_MP3_SEEK_SET) { + maSeekOrigin = ma_seek_origin_start; + } else if (origin == MA_DR_MP3_SEEK_END) { + maSeekOrigin = ma_seek_origin_end; + } else { + maSeekOrigin = ma_seek_origin_current; } result = pMP3->onSeek(pMP3->pReadSeekTellUserData, offset, maSeekOrigin); @@ -62998,6 +64633,21 @@ static ma_bool32 ma_mp3_dr_callback__seek(void* pUserData, int offset, ma_dr_mp3 return MA_TRUE; } + +static ma_bool32 ma_mp3_dr_callback__tell(void* pUserData, ma_int64* pCursor) +{ + ma_mp3* pMP3 = (ma_mp3*)pUserData; + ma_result result; + + MA_ASSERT(pMP3 != NULL); + + result = pMP3->onTell(pMP3->pReadSeekTellUserData, pCursor); + if (result != MA_SUCCESS) { + return MA_FALSE; + } + + return MA_TRUE; +} #endif static ma_result ma_mp3_init_internal(const ma_decoding_backend_config* pConfig, ma_mp3* pMP3) @@ -63098,7 +64748,7 @@ MA_API ma_result ma_mp3_init(ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_p { ma_bool32 mp3Result; - mp3Result = ma_dr_mp3_init(&pMP3->dr, ma_mp3_dr_callback__read, ma_mp3_dr_callback__seek, pMP3, pAllocationCallbacks); + mp3Result = ma_dr_mp3_init(&pMP3->dr, ma_mp3_dr_callback__read, ma_mp3_dr_callback__seek, ma_mp3_dr_callback__tell, NULL, pMP3, pAllocationCallbacks); if (mp3Result != MA_TRUE) { return MA_INVALID_FILE; } @@ -64997,14 +66647,16 @@ static ma_bool32 ma_path_extension_equal_w(const wchar_t* path, const wchar_t* e ext1 = extension; ext2 = ma_path_extension_w(path); -#if defined(_MSC_VER) || defined(__WATCOMC__) || defined(__DMC__) - return _wcsicmp(ext1, ext2) == 0; -#else - /* - I'm not aware of a wide character version of strcasecmp(). I'm therefore converting the extensions to multibyte strings and comparing those. This - isn't the most efficient way to do it, but it should work OK. - */ + #if (defined(_MSC_VER) || defined(__WATCOMC__) || defined(__DMC__)) && !defined(MA_XBOX_NXDK) { + return _wcsicmp(ext1, ext2) == 0; + } + #elif !defined(MA_XBOX_NXDK) && !defined(MA_DOS) + { + /* + I'm not aware of a wide character version of strcasecmp(). I'm therefore converting the extensions to multibyte strings and comparing those. This + isn't the most efficient way to do it, but it should work OK. + */ char ext1MB[4096]; char ext2MB[4096]; const wchar_t* pext1 = ext1; @@ -65024,7 +66676,13 @@ static ma_bool32 ma_path_extension_equal_w(const wchar_t* path, const wchar_t* e return strcasecmp(ext1MB, ext2MB) == 0; } -#endif + #else + { + /* Getting here means we don't have a way to do a case-sensitive comparison for wide strings. Fall back to a simple case-sensitive comparison. */ + /* TODO: Implement our own wchar_t-to-char conversion routine and then use the char* version for comparing. */ + return ma_wcscmp(ext1, ext2) == 0; + } + #endif } #endif /* MA_HAS_PATH_API */ @@ -66119,10 +67777,18 @@ static ma_bool32 ma_encoder__internal_on_seek_wav(void* pUserData, int offset, m { ma_encoder* pEncoder = (ma_encoder*)pUserData; ma_result result; + ma_seek_origin maSeekOrigin; MA_ASSERT(pEncoder != NULL); - result = pEncoder->onSeek(pEncoder, offset, (origin == ma_dr_wav_seek_origin_start) ? ma_seek_origin_start : ma_seek_origin_current); + maSeekOrigin = ma_seek_origin_start; + if (origin == MA_DR_WAV_SEEK_CUR) { + maSeekOrigin = ma_seek_origin_current; + } else if (origin == MA_DR_WAV_SEEK_END) { + maSeekOrigin = ma_seek_origin_end; + } + + result = pEncoder->onSeek(pEncoder, offset, maSeekOrigin); if (result != MA_SUCCESS) { return MA_FALSE; } else { @@ -67644,7 +69310,7 @@ static MA_INLINE ma_uint32 ma_hash_getblock(const ma_uint32* blocks, int i) ma_uint32 block; /* Try silencing a sanitization warning about unaligned access by doing a memcpy() instead of assignment. */ - MA_COPY_MEMORY(&block, ma_offset_ptr(blocks, i * sizeof(block)), sizeof(block)); + MA_COPY_MEMORY(&block, ma_offset_ptr(blocks, i * (int) sizeof(block)), sizeof(block)); if (ma_is_little_endian()) { return block; @@ -67720,7 +69386,7 @@ static ma_uint32 ma_hash_string_32(const char* str) static ma_uint32 ma_hash_string_w_32(const wchar_t* str) { - return ma_hash_32(str, (int)wcslen(str) * sizeof(*str), MA_DEFAULT_HASH_SEED); + return ma_hash_32(str, (int)ma_wcslen(str) * sizeof(*str), MA_DEFAULT_HASH_SEED); } @@ -67880,6 +69546,7 @@ static MA_INLINE ma_resource_manager_data_buffer_node* ma_resource_manager_data_ return ma_resource_manager_data_buffer_node_find_min(pDataBufferNode->pChildHi); } +#if 0 /* Currently unused, but might make use of this later. */ static MA_INLINE ma_resource_manager_data_buffer_node* ma_resource_manager_data_buffer_node_find_inorder_predecessor(ma_resource_manager_data_buffer_node* pDataBufferNode) { MA_ASSERT(pDataBufferNode != NULL); @@ -67887,6 +69554,7 @@ static MA_INLINE ma_resource_manager_data_buffer_node* ma_resource_manager_data_ return ma_resource_manager_data_buffer_node_find_max(pDataBufferNode->pChildLo); } +#endif static ma_result ma_resource_manager_data_buffer_node_remove(ma_resource_manager* pResourceManager, ma_resource_manager_data_buffer_node* pDataBufferNode) { @@ -69009,16 +70677,19 @@ static ma_result ma_resource_manager_data_buffer_node_acquire_critical_section(m /* Failed to post job. Probably ran out of memory. */ ma_log_postf(ma_resource_manager_get_log(pResourceManager), MA_LOG_LEVEL_ERROR, "Failed to post MA_JOB_TYPE_RESOURCE_MANAGER_LOAD_DATA_BUFFER_NODE job. %s.\n", ma_result_description(result)); - /* - Fences were acquired before posting the job, but since the job was not able to - be posted, we need to make sure we release them so nothing gets stuck waiting. - */ - if (pInitFence != NULL) { ma_fence_release(pInitFence); } - if (pDoneFence != NULL) { ma_fence_release(pDoneFence); } - if ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT) != 0) { ma_resource_manager_inline_notification_uninit(pInitNotification); } else { + /* + Fences were acquired before posting the job, but since the job was not able to + be posted, we need to make sure we release them so nothing gets stuck waiting. + + In the WAIT_INIT case, these will have already been released in ma_job_process() + so we should only release fences in this branch. + */ + if (pInitFence != NULL) { ma_fence_release(pInitFence); } + if (pDoneFence != NULL) { ma_fence_release(pDoneFence); } + /* These will have been freed by the job thread, but with WAIT_INIT they will already have happened since the job has already been handled. */ ma_free(pFilePathCopy, &pResourceManager->config.allocationCallbacks); ma_free(pFilePathWCopy, &pResourceManager->config.allocationCallbacks); @@ -76674,7 +78345,7 @@ static ma_result ma_sound_init_from_data_source_internal(ma_engine* pEngine, con } if (pConfig->loopPointBegInPCMFrames != 0 || pConfig->loopPointEndInPCMFrames != ~((ma_uint64)0)) { - ma_data_source_set_range_in_pcm_frames(ma_sound_get_data_source(pSound), pConfig->loopPointBegInPCMFrames, pConfig->loopPointEndInPCMFrames); + ma_data_source_set_loop_point_in_pcm_frames(ma_sound_get_data_source(pSound), pConfig->loopPointBegInPCMFrames, pConfig->loopPointEndInPCMFrames); } ma_sound_set_looping(pSound, pConfig->isLooping || ((pConfig->flags & MA_SOUND_FLAG_LOOPING) != 0)); @@ -76736,6 +78407,7 @@ MA_API ma_result ma_sound_init_from_file_internal(ma_engine* pEngine, const ma_s result = ma_resource_manager_data_source_init_ex(pEngine->pResourceManager, &resourceManagerDataSourceConfig, pSound->pResourceManagerDataSource); if (result != MA_SUCCESS) { + ma_free(pSound->pResourceManagerDataSource, &pEngine->allocationCallbacks); goto done; } @@ -77541,7 +79213,12 @@ MA_API ma_uint64 ma_sound_get_time_in_pcm_frames(const ma_sound* pSound) MA_API ma_uint64 ma_sound_get_time_in_milliseconds(const ma_sound* pSound) { - return ma_sound_get_time_in_pcm_frames(pSound) * 1000 / ma_engine_get_sample_rate(ma_sound_get_engine(pSound)); + ma_uint32 sampleRate = ma_engine_get_sample_rate(ma_sound_get_engine(pSound)); + if (sampleRate == 0) { + return 0; /* Prevent a division by zero. */ + } + + return ma_sound_get_time_in_pcm_frames(pSound) * 1000 / sampleRate; } MA_API void ma_sound_set_looping(ma_sound* pSound, ma_bool32 isLooping) @@ -77625,7 +79302,7 @@ MA_API ma_result ma_sound_seek_to_second(ma_sound* pSound, float seekPointInSeco return ma_sound_seek_to_pcm_frame(pSound, frameIndex); } -MA_API ma_result ma_sound_get_data_format(ma_sound* pSound, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) +MA_API ma_result ma_sound_get_data_format(const ma_sound* pSound, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) { if (pSound == NULL) { return MA_INVALID_ARGS; @@ -77658,7 +79335,7 @@ MA_API ma_result ma_sound_get_data_format(ma_sound* pSound, ma_format* pFormat, } } -MA_API ma_result ma_sound_get_cursor_in_pcm_frames(ma_sound* pSound, ma_uint64* pCursor) +MA_API ma_result ma_sound_get_cursor_in_pcm_frames(const ma_sound* pSound, ma_uint64* pCursor) { ma_uint64 seekTarget; @@ -77680,7 +79357,7 @@ MA_API ma_result ma_sound_get_cursor_in_pcm_frames(ma_sound* pSound, ma_uint64* } } -MA_API ma_result ma_sound_get_length_in_pcm_frames(ma_sound* pSound, ma_uint64* pLength) +MA_API ma_result ma_sound_get_length_in_pcm_frames(const ma_sound* pSound, ma_uint64* pLength) { if (pSound == NULL) { return MA_INVALID_ARGS; @@ -77694,7 +79371,7 @@ MA_API ma_result ma_sound_get_length_in_pcm_frames(ma_sound* pSound, ma_uint64* return ma_data_source_get_length_in_pcm_frames(pSound->pDataSource, pLength); } -MA_API ma_result ma_sound_get_cursor_in_seconds(ma_sound* pSound, float* pCursor) +MA_API ma_result ma_sound_get_cursor_in_seconds(const ma_sound* pSound, float* pCursor) { ma_result result; ma_uint64 cursorInPCMFrames; @@ -77720,7 +79397,7 @@ MA_API ma_result ma_sound_get_cursor_in_seconds(ma_sound* pSound, float* pCursor return MA_SUCCESS; } -MA_API ma_result ma_sound_get_length_in_seconds(ma_sound* pSound, float* pLength) +MA_API ma_result ma_sound_get_length_in_seconds(const ma_sound* pSound, float* pLength) { if (pSound == NULL) { return MA_INVALID_ARGS; @@ -78539,12 +80216,12 @@ MA_PRIVATE ma_bool32 ma_dr_wav__seek_forward(ma_dr_wav_seek_proc onSeek, ma_uint ma_uint64 bytesRemainingToSeek = offset; while (bytesRemainingToSeek > 0) { if (bytesRemainingToSeek > 0x7FFFFFFF) { - if (!onSeek(pUserData, 0x7FFFFFFF, ma_dr_wav_seek_origin_current)) { + if (!onSeek(pUserData, 0x7FFFFFFF, MA_DR_WAV_SEEK_CUR)) { return MA_FALSE; } bytesRemainingToSeek -= 0x7FFFFFFF; } else { - if (!onSeek(pUserData, (int)bytesRemainingToSeek, ma_dr_wav_seek_origin_current)) { + if (!onSeek(pUserData, (int)bytesRemainingToSeek, MA_DR_WAV_SEEK_CUR)) { return MA_FALSE; } bytesRemainingToSeek = 0; @@ -78555,17 +80232,17 @@ MA_PRIVATE ma_bool32 ma_dr_wav__seek_forward(ma_dr_wav_seek_proc onSeek, ma_uint MA_PRIVATE ma_bool32 ma_dr_wav__seek_from_start(ma_dr_wav_seek_proc onSeek, ma_uint64 offset, void* pUserData) { if (offset <= 0x7FFFFFFF) { - return onSeek(pUserData, (int)offset, ma_dr_wav_seek_origin_start); + return onSeek(pUserData, (int)offset, MA_DR_WAV_SEEK_SET); } - if (!onSeek(pUserData, 0x7FFFFFFF, ma_dr_wav_seek_origin_start)) { + if (!onSeek(pUserData, 0x7FFFFFFF, MA_DR_WAV_SEEK_SET)) { return MA_FALSE; } offset -= 0x7FFFFFFF; for (;;) { if (offset <= 0x7FFFFFFF) { - return onSeek(pUserData, (int)offset, ma_dr_wav_seek_origin_current); + return onSeek(pUserData, (int)offset, MA_DR_WAV_SEEK_CUR); } - if (!onSeek(pUserData, 0x7FFFFFFF, ma_dr_wav_seek_origin_current)) { + if (!onSeek(pUserData, 0x7FFFFFFF, MA_DR_WAV_SEEK_CUR)) { return MA_FALSE; } offset -= 0x7FFFFFFF; @@ -78588,7 +80265,7 @@ MA_PRIVATE ma_bool32 ma_dr_wav__on_seek(ma_dr_wav_seek_proc onSeek, void* pUserD if (!onSeek(pUserData, offset, origin)) { return MA_FALSE; } - if (origin == ma_dr_wav_seek_origin_start) { + if (origin == MA_DR_WAV_SEEK_SET) { *pCursor = offset; } else { *pCursor += offset; @@ -78707,12 +80384,12 @@ MA_PRIVATE ma_uint64 ma_dr_wav__read_smpl_to_metadata_obj(ma_dr_wav__metadata_pa ma_uint8 smplLoopData[MA_DR_WAV_SMPL_LOOP_BYTES]; bytesJustRead = ma_dr_wav__metadata_parser_read(pParser, smplLoopData, sizeof(smplLoopData), &totalBytesRead); if (bytesJustRead == sizeof(smplLoopData)) { - pMetadata->data.smpl.pLoops[iSampleLoop].cuePointId = ma_dr_wav_bytes_to_u32(smplLoopData + 0); - pMetadata->data.smpl.pLoops[iSampleLoop].type = ma_dr_wav_bytes_to_u32(smplLoopData + 4); - pMetadata->data.smpl.pLoops[iSampleLoop].firstSampleByteOffset = ma_dr_wav_bytes_to_u32(smplLoopData + 8); - pMetadata->data.smpl.pLoops[iSampleLoop].lastSampleByteOffset = ma_dr_wav_bytes_to_u32(smplLoopData + 12); - pMetadata->data.smpl.pLoops[iSampleLoop].sampleFraction = ma_dr_wav_bytes_to_u32(smplLoopData + 16); - pMetadata->data.smpl.pLoops[iSampleLoop].playCount = ma_dr_wav_bytes_to_u32(smplLoopData + 20); + pMetadata->data.smpl.pLoops[iSampleLoop].cuePointId = ma_dr_wav_bytes_to_u32(smplLoopData + 0); + pMetadata->data.smpl.pLoops[iSampleLoop].type = ma_dr_wav_bytes_to_u32(smplLoopData + 4); + pMetadata->data.smpl.pLoops[iSampleLoop].firstSampleOffset = ma_dr_wav_bytes_to_u32(smplLoopData + 8); + pMetadata->data.smpl.pLoops[iSampleLoop].lastSampleOffset = ma_dr_wav_bytes_to_u32(smplLoopData + 12); + pMetadata->data.smpl.pLoops[iSampleLoop].sampleFraction = ma_dr_wav_bytes_to_u32(smplLoopData + 16); + pMetadata->data.smpl.pLoops[iSampleLoop].playCount = ma_dr_wav_bytes_to_u32(smplLoopData + 20); } else { break; } @@ -78756,7 +80433,7 @@ MA_PRIVATE ma_uint64 ma_dr_wav__read_cue_to_metadata_obj(ma_dr_wav__metadata_par pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[3] = cuePointData[11]; pMetadata->data.cue.pCuePoints[iCuePoint].chunkStart = ma_dr_wav_bytes_to_u32(cuePointData + 12); pMetadata->data.cue.pCuePoints[iCuePoint].blockStart = ma_dr_wav_bytes_to_u32(cuePointData + 16); - pMetadata->data.cue.pCuePoints[iCuePoint].sampleByteOffset = ma_dr_wav_bytes_to_u32(cuePointData + 20); + pMetadata->data.cue.pCuePoints[iCuePoint].sampleOffset = ma_dr_wav_bytes_to_u32(cuePointData + 20); } else { break; } @@ -79096,7 +80773,7 @@ MA_PRIVATE ma_uint64 ma_dr_wav__metadata_process_chunk(ma_dr_wav__metadata_parse if (pParser->stage == ma_dr_wav__metadata_parser_stage_count) { ma_uint8 buffer[4]; size_t bytesJustRead; - if (!pParser->onSeek(pParser->pReadSeekUserData, 28, ma_dr_wav_seek_origin_current)) { + if (!pParser->onSeek(pParser->pReadSeekUserData, 28, MA_DR_WAV_SEEK_CUR)) { return bytesRead; } bytesRead += 28; @@ -79191,7 +80868,7 @@ MA_PRIVATE ma_uint64 ma_dr_wav__metadata_process_chunk(ma_dr_wav__metadata_parse return bytesRead; } allocSizeNeeded += ma_dr_wav__strlen(buffer) + 1; - allocSizeNeeded += (size_t)pChunkHeader->sizeInBytes - MA_DR_WAV_BEXT_BYTES; + allocSizeNeeded += (size_t)pChunkHeader->sizeInBytes - MA_DR_WAV_BEXT_BYTES + 1; ma_dr_wav__metadata_request_extra_memory_for_stage_2(pParser, allocSizeNeeded, 1); pParser->metadataCount += 1; } else { @@ -79274,6 +80951,16 @@ MA_PRIVATE ma_uint64 ma_dr_wav__metadata_process_chunk(ma_dr_wav__metadata_parse subchunkBytesRead = ma_dr_wav__metadata_process_info_text_chunk(pParser, subchunkDataSize, ma_dr_wav_metadata_type_list_info_album); } else if (ma_dr_wav__chunk_matches(allowedMetadataTypes, subchunkId, ma_dr_wav_metadata_type_list_info_tracknumber, "ITRK")) { subchunkBytesRead = ma_dr_wav__metadata_process_info_text_chunk(pParser, subchunkDataSize, ma_dr_wav_metadata_type_list_info_tracknumber); + } else if (ma_dr_wav__chunk_matches(allowedMetadataTypes, subchunkId, ma_dr_wav_metadata_type_list_info_location, "IARL")) { + subchunkBytesRead = ma_dr_wav__metadata_process_info_text_chunk(pParser, subchunkDataSize, ma_dr_wav_metadata_type_list_info_location); + } else if (ma_dr_wav__chunk_matches(allowedMetadataTypes, subchunkId, ma_dr_wav_metadata_type_list_info_organization, "ICMS")) { + subchunkBytesRead = ma_dr_wav__metadata_process_info_text_chunk(pParser, subchunkDataSize, ma_dr_wav_metadata_type_list_info_organization); + } else if (ma_dr_wav__chunk_matches(allowedMetadataTypes, subchunkId, ma_dr_wav_metadata_type_list_info_keywords, "IKEY")) { + subchunkBytesRead = ma_dr_wav__metadata_process_info_text_chunk(pParser, subchunkDataSize, ma_dr_wav_metadata_type_list_info_keywords); + } else if (ma_dr_wav__chunk_matches(allowedMetadataTypes, subchunkId, ma_dr_wav_metadata_type_list_info_medium, "IMED")) { + subchunkBytesRead = ma_dr_wav__metadata_process_info_text_chunk(pParser, subchunkDataSize, ma_dr_wav_metadata_type_list_info_medium); + } else if (ma_dr_wav__chunk_matches(allowedMetadataTypes, subchunkId, ma_dr_wav_metadata_type_list_info_description, "ISBJ")) { + subchunkBytesRead = ma_dr_wav__metadata_process_info_text_chunk(pParser, subchunkDataSize, ma_dr_wav_metadata_type_list_info_description); } else if ((allowedMetadataTypes & ma_dr_wav_metadata_type_unknown) != 0) { subchunkBytesRead = ma_dr_wav__metadata_process_unknown_chunk(pParser, subchunkId, subchunkDataSize, listType); } @@ -79281,13 +80968,13 @@ MA_PRIVATE ma_uint64 ma_dr_wav__metadata_process_chunk(ma_dr_wav__metadata_parse MA_DR_WAV_ASSERT(subchunkBytesRead <= subchunkDataSize); if (subchunkBytesRead < subchunkDataSize) { ma_uint64 bytesToSeek = subchunkDataSize - subchunkBytesRead; - if (!pParser->onSeek(pParser->pReadSeekUserData, (int)bytesToSeek, ma_dr_wav_seek_origin_current)) { + if (!pParser->onSeek(pParser->pReadSeekUserData, (int)bytesToSeek, MA_DR_WAV_SEEK_CUR)) { break; } bytesRead += bytesToSeek; } if ((subchunkDataSize % 2) == 1) { - if (!pParser->onSeek(pParser->pReadSeekUserData, 1, ma_dr_wav_seek_origin_current)) { + if (!pParser->onSeek(pParser->pReadSeekUserData, 1, MA_DR_WAV_SEEK_CUR)) { break; } bytesRead += 1; @@ -79324,7 +81011,7 @@ MA_API ma_uint16 ma_dr_wav_fmt_get_format(const ma_dr_wav_fmt* pFMT) return ma_dr_wav_bytes_to_u16(pFMT->subFormat); } } -MA_PRIVATE ma_bool32 ma_dr_wav_preinit(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pReadSeekUserData, const ma_allocation_callbacks* pAllocationCallbacks) +MA_PRIVATE ma_bool32 ma_dr_wav_preinit(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_tell_proc onTell, void* pReadSeekTellUserData, const ma_allocation_callbacks* pAllocationCallbacks) { if (pWav == NULL || onRead == NULL || onSeek == NULL) { return MA_FALSE; @@ -79332,7 +81019,8 @@ MA_PRIVATE ma_bool32 ma_dr_wav_preinit(ma_dr_wav* pWav, ma_dr_wav_read_proc onRe MA_DR_WAV_ZERO_MEMORY(pWav, sizeof(*pWav)); pWav->onRead = onRead; pWav->onSeek = onSeek; - pWav->pUserData = pReadSeekUserData; + pWav->onTell = onTell; + pWav->pUserData = pReadSeekTellUserData; pWav->allocationCallbacks = ma_dr_wav_copy_allocation_callbacks_or_defaults(pAllocationCallbacks); if (pWav->allocationCallbacks.onFree == NULL || (pWav->allocationCallbacks.onMalloc == NULL && pWav->allocationCallbacks.onRealloc == NULL)) { return MA_FALSE; @@ -79546,14 +81234,14 @@ MA_PRIVATE ma_bool32 ma_dr_wav_init__internal(ma_dr_wav* pWav, ma_dr_wav_chunk_p fmt.channelMask = ma_dr_wav_bytes_to_u32_ex(fmtext + 2, pWav->container); ma_dr_wav_bytes_to_guid(fmtext + 6, fmt.subFormat); } else { - if (pWav->onSeek(pWav->pUserData, fmt.extendedSize, ma_dr_wav_seek_origin_current) == MA_FALSE) { + if (pWav->onSeek(pWav->pUserData, fmt.extendedSize, MA_DR_WAV_SEEK_CUR) == MA_FALSE) { return MA_FALSE; } } cursor += fmt.extendedSize; bytesReadSoFar += fmt.extendedSize; } - if (pWav->onSeek(pWav->pUserData, (int)(header.sizeInBytes - bytesReadSoFar), ma_dr_wav_seek_origin_current) == MA_FALSE) { + if (pWav->onSeek(pWav->pUserData, (int)(header.sizeInBytes - bytesReadSoFar), MA_DR_WAV_SEEK_CUR) == MA_FALSE) { return MA_FALSE; } cursor += (header.sizeInBytes - bytesReadSoFar); @@ -79704,15 +81392,26 @@ MA_PRIVATE ma_bool32 ma_dr_wav_init__internal(ma_dr_wav* pWav, ma_dr_wav_chunk_p return MA_FALSE; } offset = ma_dr_wav_bytes_to_u32_ex(offsetAndBlockSizeData + 0, pWav->container); - if (ma_dr_wav__seek_forward(pWav->onSeek, offset, pWav->pUserData) == MA_FALSE) { - return MA_FALSE; - } - cursor += offset; - pWav->dataChunkDataPos = cursor; + pWav->dataChunkDataPos = cursor + offset; dataChunkSize = chunkSize; - if (sequential || !isProcessingMetadata) { - break; + if (dataChunkSize > offset) { + dataChunkSize -= offset; } else { + dataChunkSize = 0; + } + if (sequential) { + if (foundChunk_fmt) { + if (ma_dr_wav__seek_forward(pWav->onSeek, offset, pWav->pUserData) == MA_FALSE) { + return MA_FALSE; + } + cursor += offset; + break; + } else { + return MA_FALSE; + } + } else { + chunkSize += header.paddingSize; + chunkSize -= sizeof(offsetAndBlockSizeData); if (ma_dr_wav__seek_forward(pWav->onSeek, chunkSize, pWav->pUserData) == MA_FALSE) { break; } @@ -79776,6 +81475,17 @@ MA_PRIVATE ma_bool32 ma_dr_wav_init__internal(ma_dr_wav* pWav, ma_dr_wav_chunk_p pWav->pMetadata = metadataParser.pMetadata; pWav->metadataCount = metadataParser.metadataCount; } + if (pWav->onTell != NULL && pWav->onSeek != NULL) { + if (pWav->onSeek(pWav->pUserData, 0, MA_DR_WAV_SEEK_END) == MA_TRUE) { + ma_int64 fileSize; + if (pWav->onTell(pWav->pUserData, &fileSize)) { + if (dataChunkSize + pWav->dataChunkDataPos > (ma_uint64)fileSize) { + dataChunkSize = (ma_uint64)fileSize - pWav->dataChunkDataPos; + } + } + } else { + } + } if (dataChunkSize == 0xFFFFFFFF && (pWav->container == ma_dr_wav_container_riff || pWav->container == ma_dr_wav_container_rifx) && pWav->isSequentialWrite == MA_FALSE) { dataChunkSize = 0; for (;;) { @@ -79795,8 +81505,14 @@ MA_PRIVATE ma_bool32 ma_dr_wav_init__internal(ma_dr_wav* pWav, ma_dr_wav_chunk_p pWav->sampleRate = fmt.sampleRate; pWav->channels = fmt.channels; pWav->bitsPerSample = fmt.bitsPerSample; - pWav->bytesRemaining = dataChunkSize; pWav->translatedFormatTag = translatedFormatTag; + if (!ma_dr_wav__is_compressed_format_tag(translatedFormatTag)) { + ma_uint32 bytesPerFrame = ma_dr_wav_get_bytes_per_pcm_frame(pWav); + if (bytesPerFrame > 0) { + dataChunkSize -= (dataChunkSize % bytesPerFrame); + } + } + pWav->bytesRemaining = dataChunkSize; pWav->dataChunkDataSize = dataChunkSize; if (sampleCountFromFactChunk != 0) { pWav->totalPCMFrameCount = sampleCountFromFactChunk; @@ -79851,20 +81567,20 @@ MA_PRIVATE ma_bool32 ma_dr_wav_init__internal(ma_dr_wav* pWav, ma_dr_wav_chunk_p #endif return MA_TRUE; } -MA_API ma_bool32 ma_dr_wav_init(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_bool32 ma_dr_wav_init(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_tell_proc onTell, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) { - return ma_dr_wav_init_ex(pWav, onRead, onSeek, NULL, pUserData, NULL, 0, pAllocationCallbacks); + return ma_dr_wav_init_ex(pWav, onRead, onSeek, onTell, NULL, pUserData, NULL, 0, pAllocationCallbacks); } -MA_API ma_bool32 ma_dr_wav_init_ex(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_chunk_proc onChunk, void* pReadSeekUserData, void* pChunkUserData, ma_uint32 flags, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_bool32 ma_dr_wav_init_ex(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_tell_proc onTell, ma_dr_wav_chunk_proc onChunk, void* pReadSeekTellUserData, void* pChunkUserData, ma_uint32 flags, const ma_allocation_callbacks* pAllocationCallbacks) { - if (!ma_dr_wav_preinit(pWav, onRead, onSeek, pReadSeekUserData, pAllocationCallbacks)) { + if (!ma_dr_wav_preinit(pWav, onRead, onSeek, onTell, pReadSeekTellUserData, pAllocationCallbacks)) { return MA_FALSE; } return ma_dr_wav_init__internal(pWav, onChunk, pChunkUserData, flags); } -MA_API ma_bool32 ma_dr_wav_init_with_metadata(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pUserData, ma_uint32 flags, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_bool32 ma_dr_wav_init_with_metadata(ma_dr_wav* pWav, ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_tell_proc onTell, void* pUserData, ma_uint32 flags, const ma_allocation_callbacks* pAllocationCallbacks) { - if (!ma_dr_wav_preinit(pWav, onRead, onSeek, pUserData, pAllocationCallbacks)) { + if (!ma_dr_wav_preinit(pWav, onRead, onSeek, onTell, pUserData, pAllocationCallbacks)) { return MA_FALSE; } return ma_dr_wav_init__internal(pWav, NULL, NULL, flags | MA_DR_WAV_WITH_METADATA); @@ -80026,8 +81742,8 @@ MA_PRIVATE size_t ma_dr_wav__write_or_count_metadata(ma_dr_wav* pWav, ma_dr_wav_ for (iLoop = 0; iLoop < pMetadata->data.smpl.sampleLoopCount; ++iLoop) { bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].cuePointId); bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].type); - bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].firstSampleByteOffset); - bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].lastSampleByteOffset); + bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].firstSampleOffset); + bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].lastSampleOffset); bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].sampleFraction); bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].playCount); } @@ -80061,7 +81777,7 @@ MA_PRIVATE size_t ma_dr_wav__write_or_count_metadata(ma_dr_wav* pWav, ma_dr_wav_ bytesWritten += ma_dr_wav__write_or_count(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId, 4); bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].chunkStart); bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].blockStart); - bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].sampleByteOffset); + bytesWritten += ma_dr_wav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].sampleOffset); } } break; case ma_dr_wav_metadata_type_acid: @@ -80147,15 +81863,20 @@ MA_PRIVATE size_t ma_dr_wav__write_or_count_metadata(ma_dr_wav* pWav, ma_dr_wav_ if (pMetadata->type & ma_dr_wav_metadata_type_list_all_info_strings) { const char* pID = NULL; switch (pMetadata->type) { - case ma_dr_wav_metadata_type_list_info_software: pID = "ISFT"; break; - case ma_dr_wav_metadata_type_list_info_copyright: pID = "ICOP"; break; - case ma_dr_wav_metadata_type_list_info_title: pID = "INAM"; break; - case ma_dr_wav_metadata_type_list_info_artist: pID = "IART"; break; - case ma_dr_wav_metadata_type_list_info_comment: pID = "ICMT"; break; - case ma_dr_wav_metadata_type_list_info_date: pID = "ICRD"; break; - case ma_dr_wav_metadata_type_list_info_genre: pID = "IGNR"; break; - case ma_dr_wav_metadata_type_list_info_album: pID = "IPRD"; break; - case ma_dr_wav_metadata_type_list_info_tracknumber: pID = "ITRK"; break; + case ma_dr_wav_metadata_type_list_info_software: pID = "ISFT"; break; + case ma_dr_wav_metadata_type_list_info_copyright: pID = "ICOP"; break; + case ma_dr_wav_metadata_type_list_info_title: pID = "INAM"; break; + case ma_dr_wav_metadata_type_list_info_artist: pID = "IART"; break; + case ma_dr_wav_metadata_type_list_info_comment: pID = "ICMT"; break; + case ma_dr_wav_metadata_type_list_info_date: pID = "ICRD"; break; + case ma_dr_wav_metadata_type_list_info_genre: pID = "IGNR"; break; + case ma_dr_wav_metadata_type_list_info_album: pID = "IPRD"; break; + case ma_dr_wav_metadata_type_list_info_tracknumber: pID = "ITRK"; break; + case ma_dr_wav_metadata_type_list_info_location: pID = "IARL"; break; + case ma_dr_wav_metadata_type_list_info_organization: pID = "ICMS"; break; + case ma_dr_wav_metadata_type_list_info_keywords: pID = "IKEY"; break; + case ma_dr_wav_metadata_type_list_info_medium: pID = "IMED"; break; + case ma_dr_wav_metadata_type_list_info_description: pID = "ISBJ"; break; default: break; } MA_DR_WAV_ASSERT(pID != NULL); @@ -80370,7 +82091,7 @@ MA_PRIVATE ma_bool32 ma_dr_wav_init_write__internal(ma_dr_wav* pWav, const ma_dr } pWav->dataChunkDataSizeTargetWrite = initialDataChunkSize; if (pFormat->container == ma_dr_wav_container_riff) { - ma_uint32 chunkSizeRIFF = 28 + (ma_uint32)initialDataChunkSize; + ma_uint32 chunkSizeRIFF = 36 + (ma_uint32)initialDataChunkSize; runningPos += ma_dr_wav__write(pWav, "RIFF", 4); runningPos += ma_dr_wav__write_u32ne_to_le(pWav, chunkSizeRIFF); runningPos += ma_dr_wav__write(pWav, "WAVE", 4); @@ -80493,7 +82214,31 @@ MA_PRIVATE size_t ma_dr_wav__on_write_stdio(void* pUserData, const void* pData, } MA_PRIVATE ma_bool32 ma_dr_wav__on_seek_stdio(void* pUserData, int offset, ma_dr_wav_seek_origin origin) { - return fseek((FILE*)pUserData, offset, (origin == ma_dr_wav_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0; + int whence = SEEK_SET; + if (origin == MA_DR_WAV_SEEK_CUR) { + whence = SEEK_CUR; + } else if (origin == MA_DR_WAV_SEEK_END) { + whence = SEEK_END; + } + return fseek((FILE*)pUserData, offset, whence) == 0; +} +MA_PRIVATE ma_bool32 ma_dr_wav__on_tell_stdio(void* pUserData, ma_int64* pCursor) +{ + FILE* pFileStdio = (FILE*)pUserData; + ma_int64 result; + MA_DR_WAV_ASSERT(pFileStdio != NULL); + MA_DR_WAV_ASSERT(pCursor != NULL); +#if defined(_WIN32) && !defined(NXDK) + #if defined(_MSC_VER) && _MSC_VER > 1200 + result = _ftelli64(pFileStdio); + #else + result = ftell(pFileStdio); + #endif +#else + result = ftell(pFileStdio); +#endif + *pCursor = result; + return MA_TRUE; } MA_API ma_bool32 ma_dr_wav_init_file(ma_dr_wav* pWav, const char* filename, const ma_allocation_callbacks* pAllocationCallbacks) { @@ -80502,7 +82247,7 @@ MA_API ma_bool32 ma_dr_wav_init_file(ma_dr_wav* pWav, const char* filename, cons MA_PRIVATE ma_bool32 ma_dr_wav_init_file__internal_FILE(ma_dr_wav* pWav, FILE* pFile, ma_dr_wav_chunk_proc onChunk, void* pChunkUserData, ma_uint32 flags, const ma_allocation_callbacks* pAllocationCallbacks) { ma_bool32 result; - result = ma_dr_wav_preinit(pWav, ma_dr_wav__on_read_stdio, ma_dr_wav__on_seek_stdio, (void*)pFile, pAllocationCallbacks); + result = ma_dr_wav_preinit(pWav, ma_dr_wav__on_read_stdio, ma_dr_wav__on_seek_stdio, ma_dr_wav__on_tell_stdio, (void*)pFile, pAllocationCallbacks); if (result != MA_TRUE) { fclose(pFile); return result; @@ -80639,25 +82384,27 @@ MA_PRIVATE size_t ma_dr_wav__on_read_memory(void* pUserData, void* pBufferOut, s MA_PRIVATE ma_bool32 ma_dr_wav__on_seek_memory(void* pUserData, int offset, ma_dr_wav_seek_origin origin) { ma_dr_wav* pWav = (ma_dr_wav*)pUserData; + ma_int64 newCursor; MA_DR_WAV_ASSERT(pWav != NULL); - if (origin == ma_dr_wav_seek_origin_current) { - if (offset > 0) { - if (pWav->memoryStream.currentReadPos + offset > pWav->memoryStream.dataSize) { - return MA_FALSE; - } - } else { - if (pWav->memoryStream.currentReadPos < (size_t)-offset) { - return MA_FALSE; - } - } - pWav->memoryStream.currentReadPos += offset; + newCursor = pWav->memoryStream.currentReadPos; + if (origin == MA_DR_WAV_SEEK_SET) { + newCursor = 0; + } else if (origin == MA_DR_WAV_SEEK_CUR) { + newCursor = (ma_int64)pWav->memoryStream.currentReadPos; + } else if (origin == MA_DR_WAV_SEEK_END) { + newCursor = (ma_int64)pWav->memoryStream.dataSize; } else { - if ((ma_uint32)offset <= pWav->memoryStream.dataSize) { - pWav->memoryStream.currentReadPos = offset; - } else { - return MA_FALSE; - } + MA_DR_WAV_ASSERT(!"Invalid seek origin"); + return MA_FALSE; } + newCursor += offset; + if (newCursor < 0) { + return MA_FALSE; + } + if ((size_t)newCursor > pWav->memoryStream.dataSize) { + return MA_FALSE; + } + pWav->memoryStream.currentReadPos = (size_t)newCursor; return MA_TRUE; } MA_PRIVATE size_t ma_dr_wav__on_write_memory(void* pUserData, const void* pDataIn, size_t bytesToWrite) @@ -80691,25 +82438,35 @@ MA_PRIVATE size_t ma_dr_wav__on_write_memory(void* pUserData, const void* pDataI MA_PRIVATE ma_bool32 ma_dr_wav__on_seek_memory_write(void* pUserData, int offset, ma_dr_wav_seek_origin origin) { ma_dr_wav* pWav = (ma_dr_wav*)pUserData; + ma_int64 newCursor; MA_DR_WAV_ASSERT(pWav != NULL); - if (origin == ma_dr_wav_seek_origin_current) { - if (offset > 0) { - if (pWav->memoryStreamWrite.currentWritePos + offset > pWav->memoryStreamWrite.dataSize) { - offset = (int)(pWav->memoryStreamWrite.dataSize - pWav->memoryStreamWrite.currentWritePos); - } - } else { - if (pWav->memoryStreamWrite.currentWritePos < (size_t)-offset) { - offset = -(int)pWav->memoryStreamWrite.currentWritePos; - } - } - pWav->memoryStreamWrite.currentWritePos += offset; + newCursor = pWav->memoryStreamWrite.currentWritePos; + if (origin == MA_DR_WAV_SEEK_SET) { + newCursor = 0; + } else if (origin == MA_DR_WAV_SEEK_CUR) { + newCursor = (ma_int64)pWav->memoryStreamWrite.currentWritePos; + } else if (origin == MA_DR_WAV_SEEK_END) { + newCursor = (ma_int64)pWav->memoryStreamWrite.dataSize; } else { - if ((ma_uint32)offset <= pWav->memoryStreamWrite.dataSize) { - pWav->memoryStreamWrite.currentWritePos = offset; - } else { - pWav->memoryStreamWrite.currentWritePos = pWav->memoryStreamWrite.dataSize; - } + MA_DR_WAV_ASSERT(!"Invalid seek origin"); + return MA_INVALID_ARGS; } + newCursor += offset; + if (newCursor < 0) { + return MA_FALSE; + } + if ((size_t)newCursor > pWav->memoryStreamWrite.dataSize) { + return MA_FALSE; + } + pWav->memoryStreamWrite.currentWritePos = (size_t)newCursor; + return MA_TRUE; +} +MA_PRIVATE ma_bool32 ma_dr_wav__on_tell_memory(void* pUserData, ma_int64* pCursor) +{ + ma_dr_wav* pWav = (ma_dr_wav*)pUserData; + MA_DR_WAV_ASSERT(pWav != NULL); + MA_DR_WAV_ASSERT(pCursor != NULL); + *pCursor = (ma_int64)pWav->memoryStream.currentReadPos; return MA_TRUE; } MA_API ma_bool32 ma_dr_wav_init_memory(ma_dr_wav* pWav, const void* data, size_t dataSize, const ma_allocation_callbacks* pAllocationCallbacks) @@ -80721,7 +82478,7 @@ MA_API ma_bool32 ma_dr_wav_init_memory_ex(ma_dr_wav* pWav, const void* data, siz if (data == NULL || dataSize == 0) { return MA_FALSE; } - if (!ma_dr_wav_preinit(pWav, ma_dr_wav__on_read_memory, ma_dr_wav__on_seek_memory, pWav, pAllocationCallbacks)) { + if (!ma_dr_wav_preinit(pWav, ma_dr_wav__on_read_memory, ma_dr_wav__on_seek_memory, ma_dr_wav__on_tell_memory, pWav, pAllocationCallbacks)) { return MA_FALSE; } pWav->memoryStream.data = (const ma_uint8*)data; @@ -80734,7 +82491,7 @@ MA_API ma_bool32 ma_dr_wav_init_memory_with_metadata(ma_dr_wav* pWav, const void if (data == NULL || dataSize == 0) { return MA_FALSE; } - if (!ma_dr_wav_preinit(pWav, ma_dr_wav__on_read_memory, ma_dr_wav__on_seek_memory, pWav, pAllocationCallbacks)) { + if (!ma_dr_wav_preinit(pWav, ma_dr_wav__on_read_memory, ma_dr_wav__on_seek_memory, ma_dr_wav__on_tell_memory, pWav, pAllocationCallbacks)) { return MA_FALSE; } pWav->memoryStream.data = (const ma_uint8*)data; @@ -80793,30 +82550,30 @@ MA_API ma_result ma_dr_wav_uninit(ma_dr_wav* pWav) } if (pWav->onSeek && !pWav->isSequentialWrite) { if (pWav->container == ma_dr_wav_container_riff) { - if (pWav->onSeek(pWav->pUserData, 4, ma_dr_wav_seek_origin_start)) { + if (pWav->onSeek(pWav->pUserData, 4, MA_DR_WAV_SEEK_SET)) { ma_uint32 riffChunkSize = ma_dr_wav__riff_chunk_size_riff(pWav->dataChunkDataSize, pWav->pMetadata, pWav->metadataCount); ma_dr_wav__write_u32ne_to_le(pWav, riffChunkSize); } - if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos - 4, ma_dr_wav_seek_origin_start)) { + if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos - 4, MA_DR_WAV_SEEK_SET)) { ma_uint32 dataChunkSize = ma_dr_wav__data_chunk_size_riff(pWav->dataChunkDataSize); ma_dr_wav__write_u32ne_to_le(pWav, dataChunkSize); } } else if (pWav->container == ma_dr_wav_container_w64) { - if (pWav->onSeek(pWav->pUserData, 16, ma_dr_wav_seek_origin_start)) { + if (pWav->onSeek(pWav->pUserData, 16, MA_DR_WAV_SEEK_SET)) { ma_uint64 riffChunkSize = ma_dr_wav__riff_chunk_size_w64(pWav->dataChunkDataSize); ma_dr_wav__write_u64ne_to_le(pWav, riffChunkSize); } - if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos - 8, ma_dr_wav_seek_origin_start)) { + if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos - 8, MA_DR_WAV_SEEK_SET)) { ma_uint64 dataChunkSize = ma_dr_wav__data_chunk_size_w64(pWav->dataChunkDataSize); ma_dr_wav__write_u64ne_to_le(pWav, dataChunkSize); } } else if (pWav->container == ma_dr_wav_container_rf64) { int ds64BodyPos = 12 + 8; - if (pWav->onSeek(pWav->pUserData, ds64BodyPos + 0, ma_dr_wav_seek_origin_start)) { + if (pWav->onSeek(pWav->pUserData, ds64BodyPos + 0, MA_DR_WAV_SEEK_SET)) { ma_uint64 riffChunkSize = ma_dr_wav__riff_chunk_size_rf64(pWav->dataChunkDataSize, pWav->pMetadata, pWav->metadataCount); ma_dr_wav__write_u64ne_to_le(pWav, riffChunkSize); } - if (pWav->onSeek(pWav->pUserData, ds64BodyPos + 8, ma_dr_wav_seek_origin_start)) { + if (pWav->onSeek(pWav->pUserData, ds64BodyPos + 8, MA_DR_WAV_SEEK_SET)) { ma_uint64 dataChunkSize = ma_dr_wav__data_chunk_size_rf64(pWav->dataChunkDataSize); ma_dr_wav__write_u64ne_to_le(pWav, dataChunkSize); } @@ -80863,7 +82620,7 @@ MA_API size_t ma_dr_wav_read_raw(ma_dr_wav* pWav, size_t bytesToRead, void* pBuf if (bytesToSeek > 0x7FFFFFFF) { bytesToSeek = 0x7FFFFFFF; } - if (pWav->onSeek(pWav->pUserData, (int)bytesToSeek, ma_dr_wav_seek_origin_current) == MA_FALSE) { + if (pWav->onSeek(pWav->pUserData, (int)bytesToSeek, MA_DR_WAV_SEEK_CUR) == MA_FALSE) { break; } bytesRead += bytesToSeek; @@ -80962,7 +82719,7 @@ MA_PRIVATE ma_bool32 ma_dr_wav_seek_to_first_pcm_frame(ma_dr_wav* pWav) if (pWav->onWrite != NULL) { return MA_FALSE; } - if (!pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos, ma_dr_wav_seek_origin_start)) { + if (!pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos, MA_DR_WAV_SEEK_SET)) { return MA_FALSE; } if (ma_dr_wav__is_compressed_format_tag(pWav->translatedFormatTag)) { @@ -81043,7 +82800,7 @@ MA_API ma_bool32 ma_dr_wav_seek_to_pcm_frame(ma_dr_wav* pWav, ma_uint64 targetFr } while (offset > 0) { int offset32 = ((offset > INT_MAX) ? INT_MAX : (int)offset); - if (!pWav->onSeek(pWav->pUserData, offset32, ma_dr_wav_seek_origin_current)) { + if (!pWav->onSeek(pWav->pUserData, offset32, MA_DR_WAV_SEEK_CUR)) { return MA_FALSE; } pWav->readCursorInPCMFrames += offset32 / bytesPerFrame; @@ -81169,12 +82926,12 @@ MA_API ma_uint64 ma_dr_wav_write_pcm_frames(ma_dr_wav* pWav, ma_uint64 framesToW MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_s16__msadpcm(ma_dr_wav* pWav, ma_uint64 framesToRead, ma_int16* pBufferOut) { ma_uint64 totalFramesRead = 0; - static ma_int32 adaptationTable[] = { + static const ma_int32 adaptationTable[] = { 230, 230, 230, 230, 307, 409, 512, 614, 768, 614, 512, 409, 307, 230, 230, 230 }; - static ma_int32 coeff1Table[] = { 256, 512, 0, 192, 240, 460, 392 }; - static ma_int32 coeff2Table[] = { 0, -256, 0, 64, 0, -208, -232 }; + static const ma_int32 coeff1Table[] = { 256, 512, 0, 192, 240, 460, 392 }; + static const ma_int32 coeff2Table[] = { 0, -256, 0, 64, 0, -208, -232 }; MA_DR_WAV_ASSERT(pWav != NULL); MA_DR_WAV_ASSERT(framesToRead > 0); while (pWav->readCursorInPCMFrames < pWav->totalPCMFrameCount) { @@ -81307,11 +83064,11 @@ MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_s16__ima(ma_dr_wav* pWav, ma_uint { ma_uint64 totalFramesRead = 0; ma_uint32 iChannel; - static ma_int32 indexTable[16] = { + static const ma_int32 indexTable[16] = { -1, -1, -1, -1, 2, 4, 6, 8, -1, -1, -1, -1, 2, 4, 6, 8 }; - static ma_int32 stepTable[89] = { + static const ma_int32 stepTable[89] = { 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, @@ -81334,7 +83091,7 @@ MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_s16__ima(ma_dr_wav* pWav, ma_uint } pWav->ima.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header); if (header[2] >= ma_dr_wav_countof(stepTable)) { - pWav->onSeek(pWav->pUserData, pWav->ima.bytesRemainingInBlock, ma_dr_wav_seek_origin_current); + pWav->onSeek(pWav->pUserData, pWav->ima.bytesRemainingInBlock, MA_DR_WAV_SEEK_CUR); pWav->ima.bytesRemainingInBlock = 0; return totalFramesRead; } @@ -81349,7 +83106,7 @@ MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_s16__ima(ma_dr_wav* pWav, ma_uint } pWav->ima.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header); if (header[2] >= ma_dr_wav_countof(stepTable) || header[6] >= ma_dr_wav_countof(stepTable)) { - pWav->onSeek(pWav->pUserData, pWav->ima.bytesRemainingInBlock, ma_dr_wav_seek_origin_current); + pWav->onSeek(pWav->pUserData, pWav->ima.bytesRemainingInBlock, MA_DR_WAV_SEEK_CUR); pWav->ima.bytesRemainingInBlock = 0; return totalFramesRead; } @@ -81424,7 +83181,7 @@ MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_s16__ima(ma_dr_wav* pWav, ma_uint return totalFramesRead; } #ifndef MA_DR_WAV_NO_CONVERSION_API -static unsigned short g_ma_dr_wavAlawTable[256] = { +static const unsigned short ma_dr_wav_gAlawTable[256] = { 0xEA80, 0xEB80, 0xE880, 0xE980, 0xEE80, 0xEF80, 0xEC80, 0xED80, 0xE280, 0xE380, 0xE080, 0xE180, 0xE680, 0xE780, 0xE480, 0xE580, 0xF540, 0xF5C0, 0xF440, 0xF4C0, 0xF740, 0xF7C0, 0xF640, 0xF6C0, 0xF140, 0xF1C0, 0xF040, 0xF0C0, 0xF340, 0xF3C0, 0xF240, 0xF2C0, 0xAA00, 0xAE00, 0xA200, 0xA600, 0xBA00, 0xBE00, 0xB200, 0xB600, 0x8A00, 0x8E00, 0x8200, 0x8600, 0x9A00, 0x9E00, 0x9200, 0x9600, @@ -81442,7 +83199,7 @@ static unsigned short g_ma_dr_wavAlawTable[256] = { 0x0560, 0x0520, 0x05E0, 0x05A0, 0x0460, 0x0420, 0x04E0, 0x04A0, 0x0760, 0x0720, 0x07E0, 0x07A0, 0x0660, 0x0620, 0x06E0, 0x06A0, 0x02B0, 0x0290, 0x02F0, 0x02D0, 0x0230, 0x0210, 0x0270, 0x0250, 0x03B0, 0x0390, 0x03F0, 0x03D0, 0x0330, 0x0310, 0x0370, 0x0350 }; -static unsigned short g_ma_dr_wavMulawTable[256] = { +static const unsigned short ma_dr_wav_gMulawTable[256] = { 0x8284, 0x8684, 0x8A84, 0x8E84, 0x9284, 0x9684, 0x9A84, 0x9E84, 0xA284, 0xA684, 0xAA84, 0xAE84, 0xB284, 0xB684, 0xBA84, 0xBE84, 0xC184, 0xC384, 0xC584, 0xC784, 0xC984, 0xCB84, 0xCD84, 0xCF84, 0xD184, 0xD384, 0xD584, 0xD784, 0xD984, 0xDB84, 0xDD84, 0xDF84, 0xE104, 0xE204, 0xE304, 0xE404, 0xE504, 0xE604, 0xE704, 0xE804, 0xE904, 0xEA04, 0xEB04, 0xEC04, 0xED04, 0xEE04, 0xEF04, 0xF004, @@ -81462,11 +83219,11 @@ static unsigned short g_ma_dr_wavMulawTable[256] = { }; static MA_INLINE ma_int16 ma_dr_wav__alaw_to_s16(ma_uint8 sampleIn) { - return (short)g_ma_dr_wavAlawTable[sampleIn]; + return (short)ma_dr_wav_gAlawTable[sampleIn]; } static MA_INLINE ma_int16 ma_dr_wav__mulaw_to_s16(ma_uint8 sampleIn) { - return (short)g_ma_dr_wavMulawTable[sampleIn]; + return (short)ma_dr_wav_gMulawTable[sampleIn]; } MA_PRIVATE void ma_dr_wav__pcm_to_s16(ma_int16* pOut, const ma_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample) { @@ -82625,7 +84382,7 @@ MA_PRIVATE ma_int32* ma_dr_wav__read_pcm_frames_and_close_s32(ma_dr_wav* pWav, u } return pSampleData; } -MA_API ma_int16* ma_dr_wav_open_and_read_pcm_frames_s16(ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_int16* ma_dr_wav_open_and_read_pcm_frames_s16(ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) { ma_dr_wav wav; if (channelsOut) { @@ -82637,12 +84394,12 @@ MA_API ma_int16* ma_dr_wav_open_and_read_pcm_frames_s16(ma_dr_wav_read_proc onRe if (totalFrameCountOut) { *totalFrameCountOut = 0; } - if (!ma_dr_wav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) { + if (!ma_dr_wav_init(&wav, onRead, onSeek, onTell, pUserData, pAllocationCallbacks)) { return NULL; } return ma_dr_wav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut); } -MA_API float* ma_dr_wav_open_and_read_pcm_frames_f32(ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API float* ma_dr_wav_open_and_read_pcm_frames_f32(ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) { ma_dr_wav wav; if (channelsOut) { @@ -82654,12 +84411,12 @@ MA_API float* ma_dr_wav_open_and_read_pcm_frames_f32(ma_dr_wav_read_proc onRead, if (totalFrameCountOut) { *totalFrameCountOut = 0; } - if (!ma_dr_wav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) { + if (!ma_dr_wav_init(&wav, onRead, onSeek, onTell, pUserData, pAllocationCallbacks)) { return NULL; } return ma_dr_wav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); } -MA_API ma_int32* ma_dr_wav_open_and_read_pcm_frames_s32(ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_int32* ma_dr_wav_open_and_read_pcm_frames_s32(ma_dr_wav_read_proc onRead, ma_dr_wav_seek_proc onSeek, ma_dr_wav_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) { ma_dr_wav wav; if (channelsOut) { @@ -82671,7 +84428,7 @@ MA_API ma_int32* ma_dr_wav_open_and_read_pcm_frames_s32(ma_dr_wav_read_proc onRe if (totalFrameCountOut) { *totalFrameCountOut = 0; } - if (!ma_dr_wav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) { + if (!ma_dr_wav_init(&wav, onRead, onSeek, onTell, pUserData, pAllocationCallbacks)) { return NULL; } return ma_dr_wav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); @@ -84106,23 +85863,23 @@ static ma_bool32 ma_dr_flac__seek_to_byte(ma_dr_flac_bs* bs, ma_uint64 offsetFro MA_DR_FLAC_ASSERT(offsetFromStart > 0); if (offsetFromStart > 0x7FFFFFFF) { ma_uint64 bytesRemaining = offsetFromStart; - if (!bs->onSeek(bs->pUserData, 0x7FFFFFFF, ma_dr_flac_seek_origin_start)) { + if (!bs->onSeek(bs->pUserData, 0x7FFFFFFF, MA_DR_FLAC_SEEK_SET)) { return MA_FALSE; } bytesRemaining -= 0x7FFFFFFF; while (bytesRemaining > 0x7FFFFFFF) { - if (!bs->onSeek(bs->pUserData, 0x7FFFFFFF, ma_dr_flac_seek_origin_current)) { + if (!bs->onSeek(bs->pUserData, 0x7FFFFFFF, MA_DR_FLAC_SEEK_CUR)) { return MA_FALSE; } bytesRemaining -= 0x7FFFFFFF; } if (bytesRemaining > 0) { - if (!bs->onSeek(bs->pUserData, (int)bytesRemaining, ma_dr_flac_seek_origin_current)) { + if (!bs->onSeek(bs->pUserData, (int)bytesRemaining, MA_DR_FLAC_SEEK_CUR)) { return MA_FALSE; } } } else { - if (!bs->onSeek(bs->pUserData, (int)offsetFromStart, ma_dr_flac_seek_origin_start)) { + if (!bs->onSeek(bs->pUserData, (int)offsetFromStart, MA_DR_FLAC_SEEK_SET)) { return MA_FALSE; } } @@ -86600,6 +88357,7 @@ typedef struct { ma_dr_flac_read_proc onRead; ma_dr_flac_seek_proc onSeek; + ma_dr_flac_tell_proc onTell; ma_dr_flac_meta_proc onMeta; ma_dr_flac_container container; void* pUserData; @@ -86728,11 +88486,12 @@ static void ma_dr_flac__free_from_callbacks(void* p, const ma_allocation_callbac pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData); } } -static ma_bool32 ma_dr_flac__read_and_decode_metadata(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_meta_proc onMeta, void* pUserData, void* pUserDataMD, ma_uint64* pFirstFramePos, ma_uint64* pSeektablePos, ma_uint32* pSeekpointCount, ma_allocation_callbacks* pAllocationCallbacks) +static ma_bool32 ma_dr_flac__read_and_decode_metadata(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, ma_dr_flac_meta_proc onMeta, void* pUserData, void* pUserDataMD, ma_uint64* pFirstFramePos, ma_uint64* pSeektablePos, ma_uint32* pSeekpointCount, ma_allocation_callbacks* pAllocationCallbacks) { ma_uint64 runningFilePos = 42; ma_uint64 seektablePos = 0; ma_uint32 seektableSize = 0; + (void)onTell; for (;;) { ma_dr_flac_metadata metadata; ma_uint8 isLastBlock = 0; @@ -86990,7 +88749,7 @@ static ma_bool32 ma_dr_flac__read_and_decode_metadata(ma_dr_flac_read_proc onRea { if (onMeta) { metadata.data.padding.unused = 0; - if (!onSeek(pUserData, blockSize, ma_dr_flac_seek_origin_current)) { + if (!onSeek(pUserData, blockSize, MA_DR_FLAC_SEEK_CUR)) { isLastBlock = MA_TRUE; } else { onMeta(pUserDataMD, &metadata); @@ -87000,7 +88759,7 @@ static ma_bool32 ma_dr_flac__read_and_decode_metadata(ma_dr_flac_read_proc onRea case MA_DR_FLAC_METADATA_BLOCK_TYPE_INVALID: { if (onMeta) { - if (!onSeek(pUserData, blockSize, ma_dr_flac_seek_origin_current)) { + if (!onSeek(pUserData, blockSize, MA_DR_FLAC_SEEK_CUR)) { isLastBlock = MA_TRUE; } } @@ -87024,7 +88783,7 @@ static ma_bool32 ma_dr_flac__read_and_decode_metadata(ma_dr_flac_read_proc onRea } break; } if (onMeta == NULL && blockSize > 0) { - if (!onSeek(pUserData, blockSize, ma_dr_flac_seek_origin_current)) { + if (!onSeek(pUserData, blockSize, MA_DR_FLAC_SEEK_CUR)) { isLastBlock = MA_TRUE; } } @@ -87288,6 +89047,7 @@ typedef struct { ma_dr_flac_read_proc onRead; ma_dr_flac_seek_proc onSeek; + ma_dr_flac_tell_proc onTell; void* pUserData; ma_uint64 currentBytePos; ma_uint64 firstBytePos; @@ -87306,29 +89066,29 @@ static size_t ma_dr_flac_oggbs__read_physical(ma_dr_flac_oggbs* oggbs, void* buf } static ma_bool32 ma_dr_flac_oggbs__seek_physical(ma_dr_flac_oggbs* oggbs, ma_uint64 offset, ma_dr_flac_seek_origin origin) { - if (origin == ma_dr_flac_seek_origin_start) { + if (origin == MA_DR_FLAC_SEEK_SET) { if (offset <= 0x7FFFFFFF) { - if (!oggbs->onSeek(oggbs->pUserData, (int)offset, ma_dr_flac_seek_origin_start)) { + if (!oggbs->onSeek(oggbs->pUserData, (int)offset, MA_DR_FLAC_SEEK_SET)) { return MA_FALSE; } oggbs->currentBytePos = offset; return MA_TRUE; } else { - if (!oggbs->onSeek(oggbs->pUserData, 0x7FFFFFFF, ma_dr_flac_seek_origin_start)) { + if (!oggbs->onSeek(oggbs->pUserData, 0x7FFFFFFF, MA_DR_FLAC_SEEK_SET)) { return MA_FALSE; } oggbs->currentBytePos = offset; - return ma_dr_flac_oggbs__seek_physical(oggbs, offset - 0x7FFFFFFF, ma_dr_flac_seek_origin_current); + return ma_dr_flac_oggbs__seek_physical(oggbs, offset - 0x7FFFFFFF, MA_DR_FLAC_SEEK_CUR); } } else { while (offset > 0x7FFFFFFF) { - if (!oggbs->onSeek(oggbs->pUserData, 0x7FFFFFFF, ma_dr_flac_seek_origin_current)) { + if (!oggbs->onSeek(oggbs->pUserData, 0x7FFFFFFF, MA_DR_FLAC_SEEK_CUR)) { return MA_FALSE; } oggbs->currentBytePos += 0x7FFFFFFF; offset -= 0x7FFFFFFF; } - if (!oggbs->onSeek(oggbs->pUserData, (int)offset, ma_dr_flac_seek_origin_current)) { + if (!oggbs->onSeek(oggbs->pUserData, (int)offset, MA_DR_FLAC_SEEK_CUR)) { return MA_FALSE; } oggbs->currentBytePos += offset; @@ -87354,7 +89114,7 @@ static ma_bool32 ma_dr_flac_oggbs__goto_next_page(ma_dr_flac_oggbs* oggbs, ma_dr continue; } if (header.serialNumber != oggbs->serialNumber) { - if (pageBodySize > 0 && !ma_dr_flac_oggbs__seek_physical(oggbs, pageBodySize, ma_dr_flac_seek_origin_current)) { + if (pageBodySize > 0 && !ma_dr_flac_oggbs__seek_physical(oggbs, pageBodySize, MA_DR_FLAC_SEEK_CUR)) { return MA_FALSE; } continue; @@ -87416,7 +89176,7 @@ static ma_bool32 ma_dr_flac_oggbs__seek_to_next_packet(ma_dr_flac_oggbs* oggbs) } bytesToEndOfPacketOrPage += segmentSize; } - ma_dr_flac_oggbs__seek_physical(oggbs, bytesToEndOfPacketOrPage, ma_dr_flac_seek_origin_current); + ma_dr_flac_oggbs__seek_physical(oggbs, bytesToEndOfPacketOrPage, MA_DR_FLAC_SEEK_CUR); oggbs->bytesRemainingInPage -= bytesToEndOfPacketOrPage; if (atEndOfPage) { if (!ma_dr_flac_oggbs__goto_next_page(oggbs)) { @@ -87469,36 +89229,44 @@ static ma_bool32 ma_dr_flac__on_seek_ogg(void* pUserData, int offset, ma_dr_flac int bytesSeeked = 0; MA_DR_FLAC_ASSERT(oggbs != NULL); MA_DR_FLAC_ASSERT(offset >= 0); - if (origin == ma_dr_flac_seek_origin_start) { - if (!ma_dr_flac_oggbs__seek_physical(oggbs, (int)oggbs->firstBytePos, ma_dr_flac_seek_origin_start)) { + if (origin == MA_DR_FLAC_SEEK_SET) { + if (!ma_dr_flac_oggbs__seek_physical(oggbs, (int)oggbs->firstBytePos, MA_DR_FLAC_SEEK_SET)) { return MA_FALSE; } if (!ma_dr_flac_oggbs__goto_next_page(oggbs, ma_dr_flac_ogg_fail_on_crc_mismatch)) { return MA_FALSE; } - return ma_dr_flac__on_seek_ogg(pUserData, offset, ma_dr_flac_seek_origin_current); - } - MA_DR_FLAC_ASSERT(origin == ma_dr_flac_seek_origin_current); - while (bytesSeeked < offset) { - int bytesRemainingToSeek = offset - bytesSeeked; - MA_DR_FLAC_ASSERT(bytesRemainingToSeek >= 0); - if (oggbs->bytesRemainingInPage >= (size_t)bytesRemainingToSeek) { - bytesSeeked += bytesRemainingToSeek; - (void)bytesSeeked; - oggbs->bytesRemainingInPage -= bytesRemainingToSeek; - break; - } - if (oggbs->bytesRemainingInPage > 0) { - bytesSeeked += (int)oggbs->bytesRemainingInPage; - oggbs->bytesRemainingInPage = 0; - } - MA_DR_FLAC_ASSERT(bytesRemainingToSeek > 0); - if (!ma_dr_flac_oggbs__goto_next_page(oggbs, ma_dr_flac_ogg_fail_on_crc_mismatch)) { - return MA_FALSE; + return ma_dr_flac__on_seek_ogg(pUserData, offset, MA_DR_FLAC_SEEK_CUR); + } else if (origin == MA_DR_FLAC_SEEK_CUR) { + while (bytesSeeked < offset) { + int bytesRemainingToSeek = offset - bytesSeeked; + MA_DR_FLAC_ASSERT(bytesRemainingToSeek >= 0); + if (oggbs->bytesRemainingInPage >= (size_t)bytesRemainingToSeek) { + bytesSeeked += bytesRemainingToSeek; + (void)bytesSeeked; + oggbs->bytesRemainingInPage -= bytesRemainingToSeek; + break; + } + if (oggbs->bytesRemainingInPage > 0) { + bytesSeeked += (int)oggbs->bytesRemainingInPage; + oggbs->bytesRemainingInPage = 0; + } + MA_DR_FLAC_ASSERT(bytesRemainingToSeek > 0); + if (!ma_dr_flac_oggbs__goto_next_page(oggbs, ma_dr_flac_ogg_fail_on_crc_mismatch)) { + return MA_FALSE; + } } + } else if (origin == MA_DR_FLAC_SEEK_END) { + return MA_FALSE; } return MA_TRUE; } +static ma_bool32 ma_dr_flac__on_tell_ogg(void* pUserData, ma_int64* pCursor) +{ + (void)pUserData; + (void)pCursor; + return MA_FALSE; +} static ma_bool32 ma_dr_flac_ogg__seek_to_pcm_frame(ma_dr_flac* pFlac, ma_uint64 pcmFrameIndex) { ma_dr_flac_oggbs* oggbs = (ma_dr_flac_oggbs*)pFlac->_oggbs; @@ -87515,7 +89283,7 @@ static ma_bool32 ma_dr_flac_ogg__seek_to_pcm_frame(ma_dr_flac* pFlac, ma_uint64 runningGranulePosition = 0; for (;;) { if (!ma_dr_flac_oggbs__goto_next_page(oggbs, ma_dr_flac_ogg_recover_on_crc_mismatch)) { - ma_dr_flac_oggbs__seek_physical(oggbs, originalBytePos, ma_dr_flac_seek_origin_start); + ma_dr_flac_oggbs__seek_physical(oggbs, originalBytePos, MA_DR_FLAC_SEEK_SET); return MA_FALSE; } runningFrameBytePos = oggbs->currentBytePos - ma_dr_flac_ogg__get_page_header_size(&oggbs->currentPageHeader) - oggbs->pageDataSize; @@ -87534,7 +89302,7 @@ static ma_bool32 ma_dr_flac_ogg__seek_to_pcm_frame(ma_dr_flac* pFlac, ma_uint64 } } } - if (!ma_dr_flac_oggbs__seek_physical(oggbs, runningFrameBytePos, ma_dr_flac_seek_origin_start)) { + if (!ma_dr_flac_oggbs__seek_physical(oggbs, runningFrameBytePos, MA_DR_FLAC_SEEK_SET)) { return MA_FALSE; } if (!ma_dr_flac_oggbs__goto_next_page(oggbs, ma_dr_flac_ogg_recover_on_crc_mismatch)) { @@ -87629,7 +89397,7 @@ static ma_bool32 ma_dr_flac__init_private__ogg(ma_dr_flac_init_info* pInit, ma_d if (mappingVersion[0] != 1) { return MA_FALSE; } - if (!onSeek(pUserData, 2, ma_dr_flac_seek_origin_current)) { + if (!onSeek(pUserData, 2, MA_DR_FLAC_SEEK_CUR)) { return MA_FALSE; } if (onRead(pUserData, sig, 4) != 4) { @@ -87674,17 +89442,17 @@ static ma_bool32 ma_dr_flac__init_private__ogg(ma_dr_flac_init_info* pInit, ma_d return MA_FALSE; } } else { - if (!onSeek(pUserData, bytesRemainingInPage, ma_dr_flac_seek_origin_current)) { + if (!onSeek(pUserData, bytesRemainingInPage, MA_DR_FLAC_SEEK_CUR)) { return MA_FALSE; } } } else { - if (!onSeek(pUserData, bytesRemainingInPage, ma_dr_flac_seek_origin_current)) { + if (!onSeek(pUserData, bytesRemainingInPage, MA_DR_FLAC_SEEK_CUR)) { return MA_FALSE; } } } else { - if (!onSeek(pUserData, pageBodySize, ma_dr_flac_seek_origin_current)) { + if (!onSeek(pUserData, pageBodySize, MA_DR_FLAC_SEEK_CUR)) { return MA_FALSE; } } @@ -87698,7 +89466,7 @@ static ma_bool32 ma_dr_flac__init_private__ogg(ma_dr_flac_init_info* pInit, ma_d return MA_TRUE; } #endif -static ma_bool32 ma_dr_flac__init_private(ma_dr_flac_init_info* pInit, ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_meta_proc onMeta, ma_dr_flac_container container, void* pUserData, void* pUserDataMD) +static ma_bool32 ma_dr_flac__init_private(ma_dr_flac_init_info* pInit, ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, ma_dr_flac_meta_proc onMeta, ma_dr_flac_container container, void* pUserData, void* pUserDataMD) { ma_bool32 relaxed; ma_uint8 id[4]; @@ -87708,12 +89476,14 @@ static ma_bool32 ma_dr_flac__init_private(ma_dr_flac_init_info* pInit, ma_dr_fla MA_DR_FLAC_ZERO_MEMORY(pInit, sizeof(*pInit)); pInit->onRead = onRead; pInit->onSeek = onSeek; + pInit->onTell = onTell; pInit->onMeta = onMeta; pInit->container = container; pInit->pUserData = pUserData; pInit->pUserDataMD = pUserDataMD; pInit->bs.onRead = onRead; pInit->bs.onSeek = onSeek; + pInit->bs.onTell = onTell; pInit->bs.pUserData = pUserData; ma_dr_flac__reset_cache(&pInit->bs); relaxed = container != ma_dr_flac_container_unknown; @@ -87736,7 +89506,7 @@ static ma_bool32 ma_dr_flac__init_private(ma_dr_flac_init_info* pInit, ma_dr_fla if (flags & 0x10) { headerSize += 10; } - if (!onSeek(pUserData, headerSize, ma_dr_flac_seek_origin_current)) { + if (!onSeek(pUserData, headerSize, MA_DR_FLAC_SEEK_CUR)) { return MA_FALSE; } pInit->runningFilePos += headerSize; @@ -87779,7 +89549,7 @@ static void ma_dr_flac__init_from_info(ma_dr_flac* pFlac, const ma_dr_flac_init_ pFlac->totalPCMFrameCount = pInit->totalPCMFrameCount; pFlac->container = pInit->container; } -static ma_dr_flac* ma_dr_flac_open_with_metadata_private(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_meta_proc onMeta, ma_dr_flac_container container, void* pUserData, void* pUserDataMD, const ma_allocation_callbacks* pAllocationCallbacks) +static ma_dr_flac* ma_dr_flac_open_with_metadata_private(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, ma_dr_flac_meta_proc onMeta, ma_dr_flac_container container, void* pUserData, void* pUserDataMD, const ma_allocation_callbacks* pAllocationCallbacks) { ma_dr_flac_init_info init; ma_uint32 allocationSize; @@ -87794,7 +89564,7 @@ static ma_dr_flac* ma_dr_flac_open_with_metadata_private(ma_dr_flac_read_proc on ma_allocation_callbacks allocationCallbacks; ma_dr_flac* pFlac; ma_dr_flac__init_cpu_caps(); - if (!ma_dr_flac__init_private(&init, onRead, onSeek, onMeta, container, pUserData, pUserDataMD)) { + if (!ma_dr_flac__init_private(&init, onRead, onSeek, onTell, onMeta, container, pUserData, pUserDataMD)) { return NULL; } if (pAllocationCallbacks != NULL) { @@ -87827,6 +89597,7 @@ static ma_dr_flac* ma_dr_flac_open_with_metadata_private(ma_dr_flac_read_proc on MA_DR_FLAC_ZERO_MEMORY(pOggbs, sizeof(*pOggbs)); pOggbs->onRead = onRead; pOggbs->onSeek = onSeek; + pOggbs->onTell = onTell; pOggbs->pUserData = pUserData; pOggbs->currentBytePos = init.oggFirstBytePos; pOggbs->firstBytePos = init.oggFirstBytePos; @@ -87841,15 +89612,17 @@ static ma_dr_flac* ma_dr_flac_open_with_metadata_private(ma_dr_flac_read_proc on if (init.hasMetadataBlocks) { ma_dr_flac_read_proc onReadOverride = onRead; ma_dr_flac_seek_proc onSeekOverride = onSeek; + ma_dr_flac_tell_proc onTellOverride = onTell; void* pUserDataOverride = pUserData; #ifndef MA_DR_FLAC_NO_OGG if (init.container == ma_dr_flac_container_ogg) { onReadOverride = ma_dr_flac__on_read_ogg; onSeekOverride = ma_dr_flac__on_seek_ogg; + onTellOverride = ma_dr_flac__on_tell_ogg; pUserDataOverride = (void*)pOggbs; } #endif - if (!ma_dr_flac__read_and_decode_metadata(onReadOverride, onSeekOverride, onMeta, pUserDataOverride, pUserDataMD, &firstFramePos, &seektablePos, &seekpointCount, &allocationCallbacks)) { + if (!ma_dr_flac__read_and_decode_metadata(onReadOverride, onSeekOverride, onTellOverride, onMeta, pUserDataOverride, pUserDataMD, &firstFramePos, &seektablePos, &seekpointCount, &allocationCallbacks)) { #ifndef MA_DR_FLAC_NO_OGG ma_dr_flac__free_from_callbacks(pOggbs, &allocationCallbacks); #endif @@ -87875,6 +89648,7 @@ static ma_dr_flac* ma_dr_flac_open_with_metadata_private(ma_dr_flac_read_proc on pOggbs = NULL; pFlac->bs.onRead = ma_dr_flac__on_read_ogg; pFlac->bs.onSeek = ma_dr_flac__on_seek_ogg; + pFlac->bs.onTell = ma_dr_flac__on_tell_ogg; pFlac->bs.pUserData = (void*)pInternalOggbs; pFlac->_oggbs = (void*)pInternalOggbs; } @@ -87894,7 +89668,7 @@ static ma_dr_flac* ma_dr_flac_open_with_metadata_private(ma_dr_flac_read_proc on pFlac->pSeekpoints = (ma_dr_flac_seekpoint*)((ma_uint8*)pFlac->pDecodedSamples + decodedSamplesAllocationSize); MA_DR_FLAC_ASSERT(pFlac->bs.onSeek != NULL); MA_DR_FLAC_ASSERT(pFlac->bs.onRead != NULL); - if (pFlac->bs.onSeek(pFlac->bs.pUserData, (int)seektablePos, ma_dr_flac_seek_origin_start)) { + if (pFlac->bs.onSeek(pFlac->bs.pUserData, (int)seektablePos, MA_DR_FLAC_SEEK_SET)) { ma_uint32 iSeekpoint; for (iSeekpoint = 0; iSeekpoint < seekpointCount; iSeekpoint += 1) { if (pFlac->bs.onRead(pFlac->bs.pUserData, pFlac->pSeekpoints + iSeekpoint, MA_DR_FLAC_SEEKPOINT_SIZE_IN_BYTES) == MA_DR_FLAC_SEEKPOINT_SIZE_IN_BYTES) { @@ -87907,7 +89681,7 @@ static ma_dr_flac* ma_dr_flac_open_with_metadata_private(ma_dr_flac_read_proc on break; } } - if (!pFlac->bs.onSeek(pFlac->bs.pUserData, (int)pFlac->firstFLACFramePosInBytes, ma_dr_flac_seek_origin_start)) { + if (!pFlac->bs.onSeek(pFlac->bs.pUserData, (int)pFlac->firstFLACFramePosInBytes, MA_DR_FLAC_SEEK_SET)) { ma_dr_flac__free_from_callbacks(pFlac, &allocationCallbacks); return NULL; } @@ -87950,8 +89724,31 @@ static size_t ma_dr_flac__on_read_stdio(void* pUserData, void* bufferOut, size_t } static ma_bool32 ma_dr_flac__on_seek_stdio(void* pUserData, int offset, ma_dr_flac_seek_origin origin) { - MA_DR_FLAC_ASSERT(offset >= 0); - return fseek((FILE*)pUserData, offset, (origin == ma_dr_flac_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0; + int whence = SEEK_SET; + if (origin == MA_DR_FLAC_SEEK_CUR) { + whence = SEEK_CUR; + } else if (origin == MA_DR_FLAC_SEEK_END) { + whence = SEEK_END; + } + return fseek((FILE*)pUserData, offset, whence) == 0; +} +static ma_bool32 ma_dr_flac__on_tell_stdio(void* pUserData, ma_int64* pCursor) +{ + FILE* pFileStdio = (FILE*)pUserData; + ma_int64 result; + MA_DR_FLAC_ASSERT(pFileStdio != NULL); + MA_DR_FLAC_ASSERT(pCursor != NULL); +#if defined(_WIN32) && !defined(NXDK) + #if defined(_MSC_VER) && _MSC_VER > 1200 + result = _ftelli64(pFileStdio); + #else + result = ftell(pFileStdio); + #endif +#else + result = ftell(pFileStdio); +#endif + *pCursor = result; + return MA_TRUE; } MA_API ma_dr_flac* ma_dr_flac_open_file(const char* pFileName, const ma_allocation_callbacks* pAllocationCallbacks) { @@ -87960,7 +89757,7 @@ MA_API ma_dr_flac* ma_dr_flac_open_file(const char* pFileName, const ma_allocati if (ma_fopen(&pFile, pFileName, "rb") != MA_SUCCESS) { return NULL; } - pFlac = ma_dr_flac_open(ma_dr_flac__on_read_stdio, ma_dr_flac__on_seek_stdio, (void*)pFile, pAllocationCallbacks); + pFlac = ma_dr_flac_open(ma_dr_flac__on_read_stdio, ma_dr_flac__on_seek_stdio, ma_dr_flac__on_tell_stdio, (void*)pFile, pAllocationCallbacks); if (pFlac == NULL) { fclose(pFile); return NULL; @@ -87975,7 +89772,7 @@ MA_API ma_dr_flac* ma_dr_flac_open_file_w(const wchar_t* pFileName, const ma_all if (ma_wfopen(&pFile, pFileName, L"rb", pAllocationCallbacks) != MA_SUCCESS) { return NULL; } - pFlac = ma_dr_flac_open(ma_dr_flac__on_read_stdio, ma_dr_flac__on_seek_stdio, (void*)pFile, pAllocationCallbacks); + pFlac = ma_dr_flac_open(ma_dr_flac__on_read_stdio, ma_dr_flac__on_seek_stdio, ma_dr_flac__on_tell_stdio, (void*)pFile, pAllocationCallbacks); if (pFlac == NULL) { fclose(pFile); return NULL; @@ -87990,7 +89787,7 @@ MA_API ma_dr_flac* ma_dr_flac_open_file_with_metadata(const char* pFileName, ma_ if (ma_fopen(&pFile, pFileName, "rb") != MA_SUCCESS) { return NULL; } - pFlac = ma_dr_flac_open_with_metadata_private(ma_dr_flac__on_read_stdio, ma_dr_flac__on_seek_stdio, onMeta, ma_dr_flac_container_unknown, (void*)pFile, pUserData, pAllocationCallbacks); + pFlac = ma_dr_flac_open_with_metadata_private(ma_dr_flac__on_read_stdio, ma_dr_flac__on_seek_stdio, ma_dr_flac__on_tell_stdio, onMeta, ma_dr_flac_container_unknown, (void*)pFile, pUserData, pAllocationCallbacks); if (pFlac == NULL) { fclose(pFile); return pFlac; @@ -88005,7 +89802,7 @@ MA_API ma_dr_flac* ma_dr_flac_open_file_with_metadata_w(const wchar_t* pFileName if (ma_wfopen(&pFile, pFileName, L"rb", pAllocationCallbacks) != MA_SUCCESS) { return NULL; } - pFlac = ma_dr_flac_open_with_metadata_private(ma_dr_flac__on_read_stdio, ma_dr_flac__on_seek_stdio, onMeta, ma_dr_flac_container_unknown, (void*)pFile, pUserData, pAllocationCallbacks); + pFlac = ma_dr_flac_open_with_metadata_private(ma_dr_flac__on_read_stdio, ma_dr_flac__on_seek_stdio, ma_dr_flac__on_tell_stdio, onMeta, ma_dr_flac_container_unknown, (void*)pFile, pUserData, pAllocationCallbacks); if (pFlac == NULL) { fclose(pFile); return pFlac; @@ -88033,24 +89830,35 @@ static size_t ma_dr_flac__on_read_memory(void* pUserData, void* bufferOut, size_ static ma_bool32 ma_dr_flac__on_seek_memory(void* pUserData, int offset, ma_dr_flac_seek_origin origin) { ma_dr_flac__memory_stream* memoryStream = (ma_dr_flac__memory_stream*)pUserData; + ma_int64 newCursor; MA_DR_FLAC_ASSERT(memoryStream != NULL); - MA_DR_FLAC_ASSERT(offset >= 0); - if (offset > (ma_int64)memoryStream->dataSize) { + newCursor = memoryStream->currentReadPos; + if (origin == MA_DR_FLAC_SEEK_SET) { + newCursor = 0; + } else if (origin == MA_DR_FLAC_SEEK_CUR) { + newCursor = (ma_int64)memoryStream->currentReadPos; + } else if (origin == MA_DR_FLAC_SEEK_END) { + newCursor = (ma_int64)memoryStream->dataSize; + } else { + MA_DR_FLAC_ASSERT(!"Invalid seek origin"); return MA_FALSE; } - if (origin == ma_dr_flac_seek_origin_current) { - if (memoryStream->currentReadPos + offset <= memoryStream->dataSize) { - memoryStream->currentReadPos += offset; - } else { - return MA_FALSE; - } - } else { - if ((ma_uint32)offset <= memoryStream->dataSize) { - memoryStream->currentReadPos = offset; - } else { - return MA_FALSE; - } + newCursor += offset; + if (newCursor < 0) { + return MA_FALSE; } + if ((size_t)newCursor > memoryStream->dataSize) { + return MA_FALSE; + } + memoryStream->currentReadPos = (size_t)newCursor; + return MA_TRUE; +} +static ma_bool32 ma_dr_flac__on_tell_memory(void* pUserData, ma_int64* pCursor) +{ + ma_dr_flac__memory_stream* memoryStream = (ma_dr_flac__memory_stream*)pUserData; + MA_DR_FLAC_ASSERT(memoryStream != NULL); + MA_DR_FLAC_ASSERT(pCursor != NULL); + *pCursor = (ma_int64)memoryStream->currentReadPos; return MA_TRUE; } MA_API ma_dr_flac* ma_dr_flac_open_memory(const void* pData, size_t dataSize, const ma_allocation_callbacks* pAllocationCallbacks) @@ -88060,7 +89868,7 @@ MA_API ma_dr_flac* ma_dr_flac_open_memory(const void* pData, size_t dataSize, co memoryStream.data = (const ma_uint8*)pData; memoryStream.dataSize = dataSize; memoryStream.currentReadPos = 0; - pFlac = ma_dr_flac_open(ma_dr_flac__on_read_memory, ma_dr_flac__on_seek_memory, &memoryStream, pAllocationCallbacks); + pFlac = ma_dr_flac_open(ma_dr_flac__on_read_memory, ma_dr_flac__on_seek_memory, ma_dr_flac__on_tell_memory, &memoryStream, pAllocationCallbacks); if (pFlac == NULL) { return NULL; } @@ -88085,7 +89893,7 @@ MA_API ma_dr_flac* ma_dr_flac_open_memory_with_metadata(const void* pData, size_ memoryStream.data = (const ma_uint8*)pData; memoryStream.dataSize = dataSize; memoryStream.currentReadPos = 0; - pFlac = ma_dr_flac_open_with_metadata_private(ma_dr_flac__on_read_memory, ma_dr_flac__on_seek_memory, onMeta, ma_dr_flac_container_unknown, &memoryStream, pUserData, pAllocationCallbacks); + pFlac = ma_dr_flac_open_with_metadata_private(ma_dr_flac__on_read_memory, ma_dr_flac__on_seek_memory, ma_dr_flac__on_tell_memory, onMeta, ma_dr_flac_container_unknown, &memoryStream, pUserData, pAllocationCallbacks); if (pFlac == NULL) { return NULL; } @@ -88103,21 +89911,21 @@ MA_API ma_dr_flac* ma_dr_flac_open_memory_with_metadata(const void* pData, size_ } return pFlac; } -MA_API ma_dr_flac* ma_dr_flac_open(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_dr_flac* ma_dr_flac_open(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) { - return ma_dr_flac_open_with_metadata_private(onRead, onSeek, NULL, ma_dr_flac_container_unknown, pUserData, pUserData, pAllocationCallbacks); + return ma_dr_flac_open_with_metadata_private(onRead, onSeek, onTell, NULL, ma_dr_flac_container_unknown, pUserData, pUserData, pAllocationCallbacks); } -MA_API ma_dr_flac* ma_dr_flac_open_relaxed(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_container container, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_dr_flac* ma_dr_flac_open_relaxed(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, ma_dr_flac_container container, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) { - return ma_dr_flac_open_with_metadata_private(onRead, onSeek, NULL, container, pUserData, pUserData, pAllocationCallbacks); + return ma_dr_flac_open_with_metadata_private(onRead, onSeek, onTell, NULL, container, pUserData, pUserData, pAllocationCallbacks); } -MA_API ma_dr_flac* ma_dr_flac_open_with_metadata(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_meta_proc onMeta, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_dr_flac* ma_dr_flac_open_with_metadata(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, ma_dr_flac_meta_proc onMeta, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) { - return ma_dr_flac_open_with_metadata_private(onRead, onSeek, onMeta, ma_dr_flac_container_unknown, pUserData, pUserData, pAllocationCallbacks); + return ma_dr_flac_open_with_metadata_private(onRead, onSeek, onTell, onMeta, ma_dr_flac_container_unknown, pUserData, pUserData, pAllocationCallbacks); } -MA_API ma_dr_flac* ma_dr_flac_open_with_metadata_relaxed(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_meta_proc onMeta, ma_dr_flac_container container, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_dr_flac* ma_dr_flac_open_with_metadata_relaxed(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, ma_dr_flac_meta_proc onMeta, ma_dr_flac_container container, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) { - return ma_dr_flac_open_with_metadata_private(onRead, onSeek, onMeta, container, pUserData, pUserData, pAllocationCallbacks); + return ma_dr_flac_open_with_metadata_private(onRead, onSeek, onTell, onMeta, container, pUserData, pUserData, pAllocationCallbacks); } MA_API void ma_dr_flac_close(ma_dr_flac* pFlac) { @@ -90410,7 +92218,7 @@ on_error: MA_DR_FLAC_DEFINE_FULL_READ_AND_CLOSE(s32, ma_int32) MA_DR_FLAC_DEFINE_FULL_READ_AND_CLOSE(s16, ma_int16) MA_DR_FLAC_DEFINE_FULL_READ_AND_CLOSE(f32, float) -MA_API ma_int32* ma_dr_flac_open_and_read_pcm_frames_s32(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalPCMFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_int32* ma_dr_flac_open_and_read_pcm_frames_s32(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalPCMFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) { ma_dr_flac* pFlac; if (channelsOut) { @@ -90422,13 +92230,13 @@ MA_API ma_int32* ma_dr_flac_open_and_read_pcm_frames_s32(ma_dr_flac_read_proc on if (totalPCMFrameCountOut) { *totalPCMFrameCountOut = 0; } - pFlac = ma_dr_flac_open(onRead, onSeek, pUserData, pAllocationCallbacks); + pFlac = ma_dr_flac_open(onRead, onSeek, onTell, pUserData, pAllocationCallbacks); if (pFlac == NULL) { return NULL; } return ma_dr_flac__full_read_and_close_s32(pFlac, channelsOut, sampleRateOut, totalPCMFrameCountOut); } -MA_API ma_int16* ma_dr_flac_open_and_read_pcm_frames_s16(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalPCMFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_int16* ma_dr_flac_open_and_read_pcm_frames_s16(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalPCMFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) { ma_dr_flac* pFlac; if (channelsOut) { @@ -90440,13 +92248,13 @@ MA_API ma_int16* ma_dr_flac_open_and_read_pcm_frames_s16(ma_dr_flac_read_proc on if (totalPCMFrameCountOut) { *totalPCMFrameCountOut = 0; } - pFlac = ma_dr_flac_open(onRead, onSeek, pUserData, pAllocationCallbacks); + pFlac = ma_dr_flac_open(onRead, onSeek, onTell, pUserData, pAllocationCallbacks); if (pFlac == NULL) { return NULL; } return ma_dr_flac__full_read_and_close_s16(pFlac, channelsOut, sampleRateOut, totalPCMFrameCountOut); } -MA_API float* ma_dr_flac_open_and_read_pcm_frames_f32(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalPCMFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API float* ma_dr_flac_open_and_read_pcm_frames_f32(ma_dr_flac_read_proc onRead, ma_dr_flac_seek_proc onSeek, ma_dr_flac_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, ma_uint64* totalPCMFrameCountOut, const ma_allocation_callbacks* pAllocationCallbacks) { ma_dr_flac* pFlac; if (channelsOut) { @@ -90458,7 +92266,7 @@ MA_API float* ma_dr_flac_open_and_read_pcm_frames_f32(ma_dr_flac_read_proc onRea if (totalPCMFrameCountOut) { *totalPCMFrameCountOut = 0; } - pFlac = ma_dr_flac_open(onRead, onSeek, pUserData, pAllocationCallbacks); + pFlac = ma_dr_flac_open(onRead, onSeek, onTell, pUserData, pAllocationCallbacks); if (pFlac == NULL) { return NULL; } @@ -91262,6 +93070,10 @@ static float ma_dr_mp3_L3_ldexp_q2(float y, int exp_q2) } while ((exp_q2 -= e) > 0); return y; } +#if (defined(__GNUC__) && (__GNUC__ >= 14)) && !defined(__clang__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wstringop-overflow" +#endif static void ma_dr_mp3_L3_decode_scalefactors(const ma_uint8 *hdr, ma_uint8 *ist_pos, ma_dr_mp3_bs *bs, const ma_dr_mp3_L3_gr_info *gr, float *scf, int ch) { static const ma_uint8 g_scf_partitions[3][28] = { @@ -91320,7 +93132,10 @@ static void ma_dr_mp3_L3_decode_scalefactors(const ma_uint8 *hdr, ma_uint8 *ist_ scf[i] = ma_dr_mp3_L3_ldexp_q2(gain, iscf[i] << scf_shift); } } -static const float g_ma_dr_mp3_pow43[129 + 16] = { +#if (defined(__GNUC__) && (__GNUC__ >= 14)) && !defined(__clang__) + #pragma GCC diagnostic pop +#endif +static const float ma_dr_mp3_g_pow43[129 + 16] = { 0,-1,-2.519842f,-4.326749f,-6.349604f,-8.549880f,-10.902724f,-13.390518f,-16.000000f,-18.720754f,-21.544347f,-24.463781f,-27.473142f,-30.567351f,-33.741992f,-36.993181f, 0,1,2.519842f,4.326749f,6.349604f,8.549880f,10.902724f,13.390518f,16.000000f,18.720754f,21.544347f,24.463781f,27.473142f,30.567351f,33.741992f,36.993181f,40.317474f,43.711787f,47.173345f,50.699631f,54.288352f,57.937408f,61.644865f,65.408941f,69.227979f,73.100443f,77.024898f,81.000000f,85.024491f,89.097188f,93.216975f,97.382800f,101.593667f,105.848633f,110.146801f,114.487321f,118.869381f,123.292209f,127.755065f,132.257246f,136.798076f,141.376907f,145.993119f,150.646117f,155.335327f,160.060199f,164.820202f,169.614826f,174.443577f,179.305980f,184.201575f,189.129918f,194.090580f,199.083145f,204.107210f,209.162385f,214.248292f,219.364564f,224.510845f,229.686789f,234.892058f,240.126328f,245.389280f,250.680604f,256.000000f,261.347174f,266.721841f,272.123723f,277.552547f,283.008049f,288.489971f,293.998060f,299.532071f,305.091761f,310.676898f,316.287249f,321.922592f,327.582707f,333.267377f,338.976394f,344.709550f,350.466646f,356.247482f,362.051866f,367.879608f,373.730522f,379.604427f,385.501143f,391.420496f,397.362314f,403.326427f,409.312672f,415.320884f,421.350905f,427.402579f,433.475750f,439.570269f,445.685987f,451.822757f,457.980436f,464.158883f,470.357960f,476.577530f,482.817459f,489.077615f,495.357868f,501.658090f,507.978156f,514.317941f,520.677324f,527.056184f,533.454404f,539.871867f,546.308458f,552.764065f,559.238575f,565.731879f,572.243870f,578.774440f,585.323483f,591.890898f,598.476581f,605.080431f,611.702349f,618.342238f,625.000000f,631.675540f,638.368763f,645.079578f }; @@ -91330,7 +93145,7 @@ static float ma_dr_mp3_L3_pow_43(int x) int sign, mult = 256; if (x < 129) { - return g_ma_dr_mp3_pow43[16 + x]; + return ma_dr_mp3_g_pow43[16 + x]; } if (x < 1024) { @@ -91339,7 +93154,7 @@ static float ma_dr_mp3_L3_pow_43(int x) } sign = 2*x & 64; frac = (float)((x & 63) - sign) / ((x & ~63) + sign); - return g_ma_dr_mp3_pow43[16 + ((x + sign) >> 6)]*(1.f + frac*((4.f/3) + frac*(2.f/9)))*mult; + return ma_dr_mp3_g_pow43[16 + ((x + sign) >> 6)]*(1.f + frac*((4.f/3) + frac*(2.f/9)))*mult; } static void ma_dr_mp3_L3_huffman(float *dst, ma_dr_mp3_bs *bs, const ma_dr_mp3_L3_gr_info *gr_info, const float *scf, int layer3gr_limit) { @@ -91409,7 +93224,7 @@ static void ma_dr_mp3_L3_huffman(float *dst, ma_dr_mp3_bs *bs, const ma_dr_mp3_L *dst = one*ma_dr_mp3_L3_pow_43(lsb)*((ma_int32)bs_cache < 0 ? -1: 1); } else { - *dst = g_ma_dr_mp3_pow43[16 + lsb - 16*(bs_cache >> 31)]*one; + *dst = ma_dr_mp3_g_pow43[16 + lsb - 16*(bs_cache >> 31)]*one; } MA_DR_MP3_FLUSH_BITS(lsb ? 1 : 0); } @@ -91437,7 +93252,7 @@ static void ma_dr_mp3_L3_huffman(float *dst, ma_dr_mp3_bs *bs, const ma_dr_mp3_L for (j = 0; j < 2; j++, dst++, leaf >>= 4) { int lsb = leaf & 0x0F; - *dst = g_ma_dr_mp3_pow43[16 + lsb - 16*(bs_cache >> 31)]*one; + *dst = ma_dr_mp3_g_pow43[16 + lsb - 16*(bs_cache >> 31)]*one; MA_DR_MP3_FLUSH_BITS(lsb ? 1 : 0); } MA_DR_MP3_CHECK_BITS; @@ -92268,7 +94083,7 @@ MA_API int ma_dr_mp3dec_decode_frame(ma_dr_mp3dec *dec, const ma_uint8 *mp3, int MA_DR_MP3_COPY_MEMORY(dec->header, hdr, MA_DR_MP3_HDR_SIZE); info->frame_bytes = i + frame_size; info->channels = MA_DR_MP3_HDR_IS_MONO(hdr) ? 1 : 2; - info->hz = ma_dr_mp3_hdr_sample_rate_hz(hdr); + info->sample_rate = ma_dr_mp3_hdr_sample_rate_hz(hdr); info->layer = 4 - MA_DR_MP3_HDR_GET_LAYER(hdr); info->bitrate_kbps = ma_dr_mp3_hdr_bitrate_kbps(hdr); ma_dr_mp3_bs_init(bs_frame, hdr + MA_DR_MP3_HDR_SIZE, frame_size - MA_DR_MP3_HDR_SIZE); @@ -92491,19 +94306,41 @@ static ma_allocation_callbacks ma_dr_mp3_copy_allocation_callbacks_or_defaults(c } static size_t ma_dr_mp3__on_read(ma_dr_mp3* pMP3, void* pBufferOut, size_t bytesToRead) { - size_t bytesRead = pMP3->onRead(pMP3->pUserData, pBufferOut, bytesToRead); + size_t bytesRead; + MA_DR_MP3_ASSERT(pMP3 != NULL); + MA_DR_MP3_ASSERT(pMP3->onRead != NULL); + if (bytesToRead == 0) { + return 0; + } + bytesRead = pMP3->onRead(pMP3->pUserData, pBufferOut, bytesToRead); pMP3->streamCursor += bytesRead; return bytesRead; } +static size_t ma_dr_mp3__on_read_clamped(ma_dr_mp3* pMP3, void* pBufferOut, size_t bytesToRead) +{ + MA_DR_MP3_ASSERT(pMP3 != NULL); + MA_DR_MP3_ASSERT(pMP3->onRead != NULL); + if (pMP3->streamLength == MA_UINT64_MAX) { + return ma_dr_mp3__on_read(pMP3, pBufferOut, bytesToRead); + } else { + ma_uint64 bytesRemaining; + bytesRemaining = (pMP3->streamLength - pMP3->streamCursor); + if (bytesToRead > bytesRemaining) { + bytesToRead = (size_t)bytesRemaining; + } + return ma_dr_mp3__on_read(pMP3, pBufferOut, bytesToRead); + } +} static ma_bool32 ma_dr_mp3__on_seek(ma_dr_mp3* pMP3, int offset, ma_dr_mp3_seek_origin origin) { MA_DR_MP3_ASSERT(offset >= 0); + MA_DR_MP3_ASSERT(origin == MA_DR_MP3_SEEK_SET || origin == MA_DR_MP3_SEEK_CUR); if (!pMP3->onSeek(pMP3->pUserData, offset, origin)) { return MA_FALSE; } - if (origin == ma_dr_mp3_seek_origin_start) { + if (origin == MA_DR_MP3_SEEK_SET) { pMP3->streamCursor = (ma_uint64)offset; - } else { + } else{ pMP3->streamCursor += offset; } return MA_TRUE; @@ -92513,18 +94350,18 @@ static ma_bool32 ma_dr_mp3__on_seek_64(ma_dr_mp3* pMP3, ma_uint64 offset, ma_dr_ if (offset <= 0x7FFFFFFF) { return ma_dr_mp3__on_seek(pMP3, (int)offset, origin); } - if (!ma_dr_mp3__on_seek(pMP3, 0x7FFFFFFF, ma_dr_mp3_seek_origin_start)) { + if (!ma_dr_mp3__on_seek(pMP3, 0x7FFFFFFF, MA_DR_MP3_SEEK_SET)) { return MA_FALSE; } offset -= 0x7FFFFFFF; while (offset > 0) { if (offset <= 0x7FFFFFFF) { - if (!ma_dr_mp3__on_seek(pMP3, (int)offset, ma_dr_mp3_seek_origin_current)) { + if (!ma_dr_mp3__on_seek(pMP3, (int)offset, MA_DR_MP3_SEEK_CUR)) { return MA_FALSE; } offset = 0; } else { - if (!ma_dr_mp3__on_seek(pMP3, 0x7FFFFFFF, ma_dr_mp3_seek_origin_current)) { + if (!ma_dr_mp3__on_seek(pMP3, 0x7FFFFFFF, MA_DR_MP3_SEEK_CUR)) { return MA_FALSE; } offset -= 0x7FFFFFFF; @@ -92532,7 +94369,18 @@ static ma_bool32 ma_dr_mp3__on_seek_64(ma_dr_mp3* pMP3, ma_uint64 offset, ma_dr_ } return MA_TRUE; } -static ma_uint32 ma_dr_mp3_decode_next_frame_ex__callbacks(ma_dr_mp3* pMP3, ma_dr_mp3d_sample_t* pPCMFrames) +static void ma_dr_mp3__on_meta(ma_dr_mp3* pMP3, ma_dr_mp3_metadata_type type, const void* pRawData, size_t rawDataSize) +{ + if (pMP3->onMeta) { + ma_dr_mp3_metadata metadata; + MA_DR_MP3_ZERO_OBJECT(&metadata); + metadata.type = type; + metadata.pRawData = pRawData; + metadata.rawDataSize = rawDataSize; + pMP3->onMeta(pMP3->pUserDataMeta, &metadata); + } +} +static ma_uint32 ma_dr_mp3_decode_next_frame_ex__callbacks(ma_dr_mp3* pMP3, ma_dr_mp3d_sample_t* pPCMFrames, ma_dr_mp3dec_frame_info* pMP3FrameInfo, const ma_uint8** ppMP3FrameData) { ma_uint32 pcmFramesRead = 0; MA_DR_MP3_ASSERT(pMP3 != NULL); @@ -92559,7 +94407,7 @@ static ma_uint32 ma_dr_mp3_decode_next_frame_ex__callbacks(ma_dr_mp3* pMP3, ma_d pMP3->pData = pNewData; pMP3->dataCapacity = newDataCap; } - bytesRead = ma_dr_mp3__on_read(pMP3, pMP3->pData + pMP3->dataSize, (pMP3->dataCapacity - pMP3->dataSize)); + bytesRead = ma_dr_mp3__on_read_clamped(pMP3, pMP3->pData + pMP3->dataSize, (pMP3->dataCapacity - pMP3->dataSize)); if (bytesRead == 0) { if (pMP3->dataSize == 0) { pMP3->atEnd = MA_TRUE; @@ -92578,16 +94426,20 @@ static ma_uint32 ma_dr_mp3_decode_next_frame_ex__callbacks(ma_dr_mp3* pMP3, ma_d return 0; } pcmFramesRead = ma_dr_mp3dec_decode_frame(&pMP3->decoder, pMP3->pData + pMP3->dataConsumed, (int)pMP3->dataSize, pPCMFrames, &info); - if (info.frame_bytes > 0) { - pMP3->dataConsumed += (size_t)info.frame_bytes; - pMP3->dataSize -= (size_t)info.frame_bytes; - } + pMP3->dataConsumed += (size_t)info.frame_bytes; + pMP3->dataSize -= (size_t)info.frame_bytes; if (pcmFramesRead > 0) { pcmFramesRead = ma_dr_mp3_hdr_frame_samples(pMP3->decoder.header); pMP3->pcmFramesConsumedInMP3Frame = 0; pMP3->pcmFramesRemainingInMP3Frame = pcmFramesRead; pMP3->mp3FrameChannels = info.channels; - pMP3->mp3FrameSampleRate = info.hz; + pMP3->mp3FrameSampleRate = info.sample_rate; + if (pMP3FrameInfo != NULL) { + *pMP3FrameInfo = info; + } + if (ppMP3FrameData != NULL) { + *ppMP3FrameData = pMP3->pData + pMP3->dataConsumed - (size_t)info.frame_bytes; + } break; } else if (info.frame_bytes == 0) { size_t bytesRead; @@ -92604,7 +94456,7 @@ static ma_uint32 ma_dr_mp3_decode_next_frame_ex__callbacks(ma_dr_mp3* pMP3, ma_d pMP3->pData = pNewData; pMP3->dataCapacity = newDataCap; } - bytesRead = ma_dr_mp3__on_read(pMP3, pMP3->pData + pMP3->dataSize, (pMP3->dataCapacity - pMP3->dataSize)); + bytesRead = ma_dr_mp3__on_read_clamped(pMP3, pMP3->pData + pMP3->dataSize, (pMP3->dataCapacity - pMP3->dataSize)); if (bytesRead == 0) { pMP3->atEnd = MA_TRUE; return 0; @@ -92614,7 +94466,7 @@ static ma_uint32 ma_dr_mp3_decode_next_frame_ex__callbacks(ma_dr_mp3* pMP3, ma_d }; return pcmFramesRead; } -static ma_uint32 ma_dr_mp3_decode_next_frame_ex__memory(ma_dr_mp3* pMP3, ma_dr_mp3d_sample_t* pPCMFrames) +static ma_uint32 ma_dr_mp3_decode_next_frame_ex__memory(ma_dr_mp3* pMP3, ma_dr_mp3d_sample_t* pPCMFrames, ma_dr_mp3dec_frame_info* pMP3FrameInfo, const ma_uint8** ppMP3FrameData) { ma_uint32 pcmFramesRead = 0; ma_dr_mp3dec_frame_info info; @@ -92630,36 +94482,44 @@ static ma_uint32 ma_dr_mp3_decode_next_frame_ex__memory(ma_dr_mp3* pMP3, ma_dr_m pMP3->pcmFramesConsumedInMP3Frame = 0; pMP3->pcmFramesRemainingInMP3Frame = pcmFramesRead; pMP3->mp3FrameChannels = info.channels; - pMP3->mp3FrameSampleRate = info.hz; + pMP3->mp3FrameSampleRate = info.sample_rate; + if (pMP3FrameInfo != NULL) { + *pMP3FrameInfo = info; + } + if (ppMP3FrameData != NULL) { + *ppMP3FrameData = pMP3->memory.pData + pMP3->memory.currentReadPos; + } break; } else if (info.frame_bytes > 0) { pMP3->memory.currentReadPos += (size_t)info.frame_bytes; + pMP3->streamCursor += (size_t)info.frame_bytes; } else { break; } } pMP3->memory.currentReadPos += (size_t)info.frame_bytes; + pMP3->streamCursor += (size_t)info.frame_bytes; return pcmFramesRead; } -static ma_uint32 ma_dr_mp3_decode_next_frame_ex(ma_dr_mp3* pMP3, ma_dr_mp3d_sample_t* pPCMFrames) +static ma_uint32 ma_dr_mp3_decode_next_frame_ex(ma_dr_mp3* pMP3, ma_dr_mp3d_sample_t* pPCMFrames, ma_dr_mp3dec_frame_info* pMP3FrameInfo, const ma_uint8** ppMP3FrameData) { if (pMP3->memory.pData != NULL && pMP3->memory.dataSize > 0) { - return ma_dr_mp3_decode_next_frame_ex__memory(pMP3, pPCMFrames); + return ma_dr_mp3_decode_next_frame_ex__memory(pMP3, pPCMFrames, pMP3FrameInfo, ppMP3FrameData); } else { - return ma_dr_mp3_decode_next_frame_ex__callbacks(pMP3, pPCMFrames); + return ma_dr_mp3_decode_next_frame_ex__callbacks(pMP3, pPCMFrames, pMP3FrameInfo, ppMP3FrameData); } } static ma_uint32 ma_dr_mp3_decode_next_frame(ma_dr_mp3* pMP3) { MA_DR_MP3_ASSERT(pMP3 != NULL); - return ma_dr_mp3_decode_next_frame_ex(pMP3, (ma_dr_mp3d_sample_t*)pMP3->pcmFrames); + return ma_dr_mp3_decode_next_frame_ex(pMP3, (ma_dr_mp3d_sample_t*)pMP3->pcmFrames, NULL, NULL); } #if 0 static ma_uint32 ma_dr_mp3_seek_next_frame(ma_dr_mp3* pMP3) { ma_uint32 pcmFrameCount; MA_DR_MP3_ASSERT(pMP3 != NULL); - pcmFrameCount = ma_dr_mp3_decode_next_frame_ex(pMP3, NULL); + pcmFrameCount = ma_dr_mp3_decode_next_frame_ex(pMP3, NULL, NULL, NULL); if (pcmFrameCount == 0) { return 0; } @@ -92669,33 +94529,249 @@ static ma_uint32 ma_dr_mp3_seek_next_frame(ma_dr_mp3* pMP3) return pcmFrameCount; } #endif -static ma_bool32 ma_dr_mp3_init_internal(ma_dr_mp3* pMP3, ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) +static ma_bool32 ma_dr_mp3_init_internal(ma_dr_mp3* pMP3, ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, ma_dr_mp3_tell_proc onTell, ma_dr_mp3_meta_proc onMeta, void* pUserData, void* pUserDataMeta, const ma_allocation_callbacks* pAllocationCallbacks) { + ma_dr_mp3dec_frame_info firstFrameInfo; + const ma_uint8* pFirstFrameData; + ma_uint32 firstFramePCMFrameCount; + ma_uint32 detectedMP3FrameCount = 0xFFFFFFFF; MA_DR_MP3_ASSERT(pMP3 != NULL); MA_DR_MP3_ASSERT(onRead != NULL); ma_dr_mp3dec_init(&pMP3->decoder); pMP3->onRead = onRead; pMP3->onSeek = onSeek; + pMP3->onMeta = onMeta; pMP3->pUserData = pUserData; + pMP3->pUserDataMeta = pUserDataMeta; pMP3->allocationCallbacks = ma_dr_mp3_copy_allocation_callbacks_or_defaults(pAllocationCallbacks); if (pMP3->allocationCallbacks.onFree == NULL || (pMP3->allocationCallbacks.onMalloc == NULL && pMP3->allocationCallbacks.onRealloc == NULL)) { return MA_FALSE; } - if (ma_dr_mp3_decode_next_frame(pMP3) == 0) { + pMP3->streamCursor = 0; + pMP3->streamLength = MA_UINT64_MAX; + pMP3->streamStartOffset = 0; + pMP3->delayInPCMFrames = 0; + pMP3->paddingInPCMFrames = 0; + pMP3->totalPCMFrameCount = MA_UINT64_MAX; + #if 1 + if (onSeek != NULL && onTell != NULL) { + if (onSeek(pUserData, 0, MA_DR_MP3_SEEK_END)) { + ma_int64 streamLen; + int streamEndOffset = 0; + if (onTell(pUserData, &streamLen)) { + if (streamLen > 128) { + char id3[3]; + if (onSeek(pUserData, streamEndOffset - 128, MA_DR_MP3_SEEK_END)) { + if (onRead(pUserData, id3, 3) == 3 && id3[0] == 'T' && id3[1] == 'A' && id3[2] == 'G') { + streamEndOffset -= 128; + streamLen -= 128; + if (onMeta != NULL) { + ma_uint8 tag[128]; + tag[0] = 'T'; tag[1] = 'A'; tag[2] = 'G'; + if (onRead(pUserData, tag + 3, 125) == 125) { + ma_dr_mp3__on_meta(pMP3, MA_DR_MP3_METADATA_TYPE_ID3V1, tag, 128); + } + } + } else { + } + } else { + } + } else { + } + if (streamLen > 32) { + char ape[32]; + if (onSeek(pUserData, streamEndOffset - 32, MA_DR_MP3_SEEK_END)) { + if (onRead(pUserData, ape, 32) == 32 && ape[0] == 'A' && ape[1] == 'P' && ape[2] == 'E' && ape[3] == 'T' && ape[4] == 'A' && ape[5] == 'G' && ape[6] == 'E' && ape[7] == 'X') { + ma_uint32 tagSize = + ((ma_uint32)ape[24] << 0) | + ((ma_uint32)ape[25] << 8) | + ((ma_uint32)ape[26] << 16) | + ((ma_uint32)ape[27] << 24); + streamEndOffset -= 32 + tagSize; + streamLen -= 32 + tagSize; + if (onMeta != NULL) { + if (onSeek(pUserData, streamEndOffset, MA_DR_MP3_SEEK_END)) { + size_t apeTagSize = (size_t)tagSize + 32; + ma_uint8* pTagData = (ma_uint8*)ma_dr_mp3_malloc(apeTagSize, pAllocationCallbacks); + if (pTagData != NULL) { + if (onRead(pUserData, pTagData, apeTagSize) == apeTagSize) { + ma_dr_mp3__on_meta(pMP3, MA_DR_MP3_METADATA_TYPE_APE, pTagData, apeTagSize); + } + ma_dr_mp3_free(pTagData, pAllocationCallbacks); + } + } + } + } + } + } else { + } + if (!onSeek(pUserData, 0, MA_DR_MP3_SEEK_SET)) { + return MA_FALSE; + } + pMP3->streamLength = (ma_uint64)streamLen; + if (pMP3->memory.pData != NULL) { + pMP3->memory.dataSize = (size_t)pMP3->streamLength; + } + } else { + if (!onSeek(pUserData, 0, MA_DR_MP3_SEEK_SET)) { + return MA_FALSE; + } + } + } else { + } + } else { + } + #endif + #if 1 + { + char header[10]; + if (onRead(pUserData, header, 10) == 10) { + if (header[0] == 'I' && header[1] == 'D' && header[2] == '3') { + ma_uint32 tagSize = + (((ma_uint32)header[6] & 0x7F) << 21) | + (((ma_uint32)header[7] & 0x7F) << 14) | + (((ma_uint32)header[8] & 0x7F) << 7) | + (((ma_uint32)header[9] & 0x7F) << 0); + if (header[5] & 0x10) { + tagSize += 10; + } + if (onMeta != NULL) { + size_t tagSizeWithHeader = 10 + tagSize; + ma_uint8* pTagData = (ma_uint8*)ma_dr_mp3_malloc(tagSizeWithHeader, pAllocationCallbacks); + if (pTagData != NULL) { + MA_DR_MP3_COPY_MEMORY(pTagData, header, 10); + if (onRead(pUserData, pTagData + 10, tagSize) == tagSize) { + ma_dr_mp3__on_meta(pMP3, MA_DR_MP3_METADATA_TYPE_ID3V2, pTagData, tagSizeWithHeader); + } + ma_dr_mp3_free(pTagData, pAllocationCallbacks); + } + } else { + if (onSeek != NULL) { + if (!onSeek(pUserData, tagSize, MA_DR_MP3_SEEK_CUR)) { + return MA_FALSE; + } + } else { + char discard[1024]; + while (tagSize > 0) { + size_t bytesToRead = tagSize; + if (bytesToRead > sizeof(discard)) { + bytesToRead = sizeof(discard); + } + if (onRead(pUserData, discard, bytesToRead) != bytesToRead) { + return MA_FALSE; + } + tagSize -= (ma_uint32)bytesToRead; + } + } + } + pMP3->streamStartOffset += 10 + tagSize; + pMP3->streamCursor = pMP3->streamStartOffset; + } else { + if (onSeek != NULL) { + if (!onSeek(pUserData, 0, MA_DR_MP3_SEEK_SET)) { + return MA_FALSE; + } + } else { + } + } + } else { + return MA_FALSE; + } + } + #endif + firstFramePCMFrameCount = ma_dr_mp3_decode_next_frame_ex(pMP3, (ma_dr_mp3d_sample_t*)pMP3->pcmFrames, &firstFrameInfo, &pFirstFrameData); + if (firstFramePCMFrameCount > 0) { + MA_DR_MP3_ASSERT(pFirstFrameData != NULL); + #if 1 + MA_DR_MP3_ASSERT(firstFrameInfo.frame_bytes > 0); + { + ma_dr_mp3_bs bs; + ma_dr_mp3_L3_gr_info grInfo[4]; + const ma_uint8* pTagData = pFirstFrameData; + ma_dr_mp3_bs_init(&bs, pFirstFrameData + MA_DR_MP3_HDR_SIZE, firstFrameInfo.frame_bytes - MA_DR_MP3_HDR_SIZE); + if (MA_DR_MP3_HDR_IS_CRC(pFirstFrameData)) { + ma_dr_mp3_bs_get_bits(&bs, 16); + } + if (ma_dr_mp3_L3_read_side_info(&bs, grInfo, pFirstFrameData) >= 0) { + ma_bool32 isXing = MA_FALSE; + ma_bool32 isInfo = MA_FALSE; + const ma_uint8* pTagDataBeg; + pTagDataBeg = pFirstFrameData + MA_DR_MP3_HDR_SIZE + (bs.pos/8); + pTagData = pTagDataBeg; + isXing = (pTagData[0] == 'X' && pTagData[1] == 'i' && pTagData[2] == 'n' && pTagData[3] == 'g'); + isInfo = (pTagData[0] == 'I' && pTagData[1] == 'n' && pTagData[2] == 'f' && pTagData[3] == 'o'); + if (isXing || isInfo) { + ma_uint32 bytes = 0; + ma_uint32 flags = pTagData[7]; + pTagData += 8; + if (flags & 0x01) { + detectedMP3FrameCount = (ma_uint32)pTagData[0] << 24 | (ma_uint32)pTagData[1] << 16 | (ma_uint32)pTagData[2] << 8 | (ma_uint32)pTagData[3]; + pTagData += 4; + } + if (flags & 0x02) { + bytes = (ma_uint32)pTagData[0] << 24 | (ma_uint32)pTagData[1] << 16 | (ma_uint32)pTagData[2] << 8 | (ma_uint32)pTagData[3]; + (void)bytes; + pTagData += 4; + } + if (flags & 0x04) { + pTagData += 100; + } + if (flags & 0x08) { + pTagData += 4; + } + if (pTagData[0]) { + pTagData += 21; + if (pTagData - pFirstFrameData + 14 < firstFrameInfo.frame_bytes) { + int delayInPCMFrames; + int paddingInPCMFrames; + delayInPCMFrames = (( (ma_uint32)pTagData[0] << 4) | ((ma_uint32)pTagData[1] >> 4)) + (528 + 1); + paddingInPCMFrames = ((((ma_uint32)pTagData[1] & 0xF) << 8) | ((ma_uint32)pTagData[2] )) - (528 + 1); + if (paddingInPCMFrames < 0) { + paddingInPCMFrames = 0; + } + pMP3->delayInPCMFrames = (ma_uint32)delayInPCMFrames; + pMP3->paddingInPCMFrames = (ma_uint32)paddingInPCMFrames; + } + } + if (isXing) { + pMP3->isVBR = MA_TRUE; + } else if (isInfo) { + pMP3->isCBR = MA_TRUE; + } + if (onMeta != NULL) { + ma_dr_mp3_metadata_type metadataType = isXing ? MA_DR_MP3_METADATA_TYPE_XING : MA_DR_MP3_METADATA_TYPE_VBRI; + size_t tagDataSize; + tagDataSize = (size_t)firstFrameInfo.frame_bytes; + tagDataSize -= (size_t)(pTagDataBeg - pFirstFrameData); + ma_dr_mp3__on_meta(pMP3, metadataType, pTagDataBeg, tagDataSize); + } + pMP3->pcmFramesRemainingInMP3Frame = 0; + pMP3->streamStartOffset += (ma_uint32)(firstFrameInfo.frame_bytes); + pMP3->streamCursor = pMP3->streamStartOffset; + ma_dr_mp3dec_init(&pMP3->decoder); + } + } else { + } + } + #endif + } else { ma_dr_mp3__free_from_callbacks(pMP3->pData, &pMP3->allocationCallbacks); return MA_FALSE; } + if (detectedMP3FrameCount != 0xFFFFFFFF) { + pMP3->totalPCMFrameCount = detectedMP3FrameCount * firstFramePCMFrameCount; + } pMP3->channels = pMP3->mp3FrameChannels; pMP3->sampleRate = pMP3->mp3FrameSampleRate; return MA_TRUE; } -MA_API ma_bool32 ma_dr_mp3_init(ma_dr_mp3* pMP3, ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_bool32 ma_dr_mp3_init(ma_dr_mp3* pMP3, ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, ma_dr_mp3_tell_proc onTell, ma_dr_mp3_meta_proc onMeta, void* pUserData, const ma_allocation_callbacks* pAllocationCallbacks) { if (pMP3 == NULL || onRead == NULL) { return MA_FALSE; } MA_DR_MP3_ZERO_OBJECT(pMP3); - return ma_dr_mp3_init_internal(pMP3, onRead, onSeek, pUserData, pAllocationCallbacks); + return ma_dr_mp3_init_internal(pMP3, onRead, onSeek, onTell, onMeta, pUserData, pUserData, pAllocationCallbacks); } static size_t ma_dr_mp3__on_read_memory(void* pUserData, void* pBufferOut, size_t bytesToRead) { @@ -92716,29 +94792,40 @@ static size_t ma_dr_mp3__on_read_memory(void* pUserData, void* pBufferOut, size_ static ma_bool32 ma_dr_mp3__on_seek_memory(void* pUserData, int byteOffset, ma_dr_mp3_seek_origin origin) { ma_dr_mp3* pMP3 = (ma_dr_mp3*)pUserData; + ma_int64 newCursor; MA_DR_MP3_ASSERT(pMP3 != NULL); - if (origin == ma_dr_mp3_seek_origin_current) { - if (byteOffset > 0) { - if (pMP3->memory.currentReadPos + byteOffset > pMP3->memory.dataSize) { - byteOffset = (int)(pMP3->memory.dataSize - pMP3->memory.currentReadPos); - } - } else { - if (pMP3->memory.currentReadPos < (size_t)-byteOffset) { - byteOffset = -(int)pMP3->memory.currentReadPos; - } - } - pMP3->memory.currentReadPos += byteOffset; + newCursor = pMP3->memory.currentReadPos; + if (origin == MA_DR_MP3_SEEK_SET) { + newCursor = 0; + } else if (origin == MA_DR_MP3_SEEK_CUR) { + newCursor = (ma_int64)pMP3->memory.currentReadPos; + } else if (origin == MA_DR_MP3_SEEK_END) { + newCursor = (ma_int64)pMP3->memory.dataSize; } else { - if ((ma_uint32)byteOffset <= pMP3->memory.dataSize) { - pMP3->memory.currentReadPos = byteOffset; - } else { - pMP3->memory.currentReadPos = pMP3->memory.dataSize; - } + MA_DR_MP3_ASSERT(!"Invalid seek origin"); + return MA_FALSE; } + newCursor += byteOffset; + if (newCursor < 0) { + return MA_FALSE; + } + if ((size_t)newCursor > pMP3->memory.dataSize) { + return MA_FALSE; + } + pMP3->memory.currentReadPos = (size_t)newCursor; return MA_TRUE; } -MA_API ma_bool32 ma_dr_mp3_init_memory(ma_dr_mp3* pMP3, const void* pData, size_t dataSize, const ma_allocation_callbacks* pAllocationCallbacks) +static ma_bool32 ma_dr_mp3__on_tell_memory(void* pUserData, ma_int64* pCursor) { + ma_dr_mp3* pMP3 = (ma_dr_mp3*)pUserData; + MA_DR_MP3_ASSERT(pMP3 != NULL); + MA_DR_MP3_ASSERT(pCursor != NULL); + *pCursor = (ma_int64)pMP3->memory.currentReadPos; + return MA_TRUE; +} +MA_API ma_bool32 ma_dr_mp3_init_memory_with_metadata(ma_dr_mp3* pMP3, const void* pData, size_t dataSize, ma_dr_mp3_meta_proc onMeta, void* pUserDataMeta, const ma_allocation_callbacks* pAllocationCallbacks) +{ + ma_bool32 result; if (pMP3 == NULL) { return MA_FALSE; } @@ -92749,7 +94836,21 @@ MA_API ma_bool32 ma_dr_mp3_init_memory(ma_dr_mp3* pMP3, const void* pData, size_ pMP3->memory.pData = (const ma_uint8*)pData; pMP3->memory.dataSize = dataSize; pMP3->memory.currentReadPos = 0; - return ma_dr_mp3_init_internal(pMP3, ma_dr_mp3__on_read_memory, ma_dr_mp3__on_seek_memory, pMP3, pAllocationCallbacks); + result = ma_dr_mp3_init_internal(pMP3, ma_dr_mp3__on_read_memory, ma_dr_mp3__on_seek_memory, ma_dr_mp3__on_tell_memory, onMeta, pMP3, pUserDataMeta, pAllocationCallbacks); + if (result == MA_FALSE) { + return MA_FALSE; + } + if (pMP3->streamLength <= (ma_uint64)MA_SIZE_MAX) { + pMP3->memory.dataSize = (size_t)pMP3->streamLength; + } + if (pMP3->streamStartOffset > (ma_uint64)MA_SIZE_MAX) { + return MA_FALSE; + } + return MA_TRUE; +} +MA_API ma_bool32 ma_dr_mp3_init_memory(ma_dr_mp3* pMP3, const void* pData, size_t dataSize, const ma_allocation_callbacks* pAllocationCallbacks) +{ + return ma_dr_mp3_init_memory_with_metadata(pMP3, pData, dataSize, NULL, NULL, pAllocationCallbacks); } #ifndef MA_DR_MP3_NO_STDIO #include @@ -92760,36 +94861,76 @@ static size_t ma_dr_mp3__on_read_stdio(void* pUserData, void* pBufferOut, size_t } static ma_bool32 ma_dr_mp3__on_seek_stdio(void* pUserData, int offset, ma_dr_mp3_seek_origin origin) { - return fseek((FILE*)pUserData, offset, (origin == ma_dr_mp3_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0; + int whence = SEEK_SET; + if (origin == MA_DR_MP3_SEEK_CUR) { + whence = SEEK_CUR; + } else if (origin == MA_DR_MP3_SEEK_END) { + whence = SEEK_END; + } + return fseek((FILE*)pUserData, offset, whence) == 0; } -MA_API ma_bool32 ma_dr_mp3_init_file(ma_dr_mp3* pMP3, const char* pFilePath, const ma_allocation_callbacks* pAllocationCallbacks) +static ma_bool32 ma_dr_mp3__on_tell_stdio(void* pUserData, ma_int64* pCursor) +{ + FILE* pFileStdio = (FILE*)pUserData; + ma_int64 result; + MA_DR_MP3_ASSERT(pFileStdio != NULL); + MA_DR_MP3_ASSERT(pCursor != NULL); +#if defined(_WIN32) && !defined(NXDK) + #if defined(_MSC_VER) && _MSC_VER > 1200 + result = _ftelli64(pFileStdio); + #else + result = ftell(pFileStdio); + #endif +#else + result = ftell(pFileStdio); +#endif + *pCursor = result; + return MA_TRUE; +} +MA_API ma_bool32 ma_dr_mp3_init_file_with_metadata(ma_dr_mp3* pMP3, const char* pFilePath, ma_dr_mp3_meta_proc onMeta, void* pUserDataMeta, const ma_allocation_callbacks* pAllocationCallbacks) { ma_bool32 result; FILE* pFile; + if (pMP3 == NULL) { + return MA_FALSE; + } + MA_DR_MP3_ZERO_OBJECT(pMP3); if (ma_fopen(&pFile, pFilePath, "rb") != MA_SUCCESS) { return MA_FALSE; } - result = ma_dr_mp3_init(pMP3, ma_dr_mp3__on_read_stdio, ma_dr_mp3__on_seek_stdio, (void*)pFile, pAllocationCallbacks); + result = ma_dr_mp3_init_internal(pMP3, ma_dr_mp3__on_read_stdio, ma_dr_mp3__on_seek_stdio, ma_dr_mp3__on_tell_stdio, onMeta, (void*)pFile, pUserDataMeta, pAllocationCallbacks); if (result != MA_TRUE) { fclose(pFile); return result; } return MA_TRUE; } -MA_API ma_bool32 ma_dr_mp3_init_file_w(ma_dr_mp3* pMP3, const wchar_t* pFilePath, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_bool32 ma_dr_mp3_init_file_with_metadata_w(ma_dr_mp3* pMP3, const wchar_t* pFilePath, ma_dr_mp3_meta_proc onMeta, void* pUserDataMeta, const ma_allocation_callbacks* pAllocationCallbacks) { ma_bool32 result; FILE* pFile; + if (pMP3 == NULL) { + return MA_FALSE; + } + MA_DR_MP3_ZERO_OBJECT(pMP3); if (ma_wfopen(&pFile, pFilePath, L"rb", pAllocationCallbacks) != MA_SUCCESS) { return MA_FALSE; } - result = ma_dr_mp3_init(pMP3, ma_dr_mp3__on_read_stdio, ma_dr_mp3__on_seek_stdio, (void*)pFile, pAllocationCallbacks); + result = ma_dr_mp3_init_internal(pMP3, ma_dr_mp3__on_read_stdio, ma_dr_mp3__on_seek_stdio, ma_dr_mp3__on_tell_stdio, onMeta, (void*)pFile, pUserDataMeta, pAllocationCallbacks); if (result != MA_TRUE) { fclose(pFile); return result; } return MA_TRUE; } +MA_API ma_bool32 ma_dr_mp3_init_file(ma_dr_mp3* pMP3, const char* pFilePath, const ma_allocation_callbacks* pAllocationCallbacks) +{ + return ma_dr_mp3_init_file_with_metadata(pMP3, pFilePath, NULL, NULL, pAllocationCallbacks); +} +MA_API ma_bool32 ma_dr_mp3_init_file_w(ma_dr_mp3* pMP3, const wchar_t* pFilePath, const ma_allocation_callbacks* pAllocationCallbacks) +{ + return ma_dr_mp3_init_file_with_metadata_w(pMP3, pFilePath, NULL, NULL, pAllocationCallbacks); +} #endif MA_API void ma_dr_mp3_uninit(ma_dr_mp3* pMP3) { @@ -92859,17 +95000,38 @@ static ma_uint64 ma_dr_mp3_read_pcm_frames_raw(ma_dr_mp3* pMP3, ma_uint64 frames MA_DR_MP3_ASSERT(pMP3 != NULL); MA_DR_MP3_ASSERT(pMP3->onRead != NULL); while (framesToRead > 0) { - ma_uint32 framesToConsume = (ma_uint32)MA_DR_MP3_MIN(pMP3->pcmFramesRemainingInMP3Frame, framesToRead); + ma_uint32 framesToConsume; + if (pMP3->currentPCMFrame < pMP3->delayInPCMFrames) { + ma_uint32 framesToSkip = (ma_uint32)MA_DR_MP3_MIN(pMP3->pcmFramesRemainingInMP3Frame, pMP3->delayInPCMFrames - pMP3->currentPCMFrame); + pMP3->currentPCMFrame += framesToSkip; + pMP3->pcmFramesConsumedInMP3Frame += framesToSkip; + pMP3->pcmFramesRemainingInMP3Frame -= framesToSkip; + } + framesToConsume = (ma_uint32)MA_DR_MP3_MIN(pMP3->pcmFramesRemainingInMP3Frame, framesToRead); + if (pMP3->totalPCMFrameCount != MA_UINT64_MAX && pMP3->totalPCMFrameCount > pMP3->paddingInPCMFrames) { + if (pMP3->currentPCMFrame < (pMP3->totalPCMFrameCount - pMP3->paddingInPCMFrames)) { + ma_uint64 framesRemainigToPadding = (pMP3->totalPCMFrameCount - pMP3->paddingInPCMFrames) - pMP3->currentPCMFrame; + if (framesToConsume > framesRemainigToPadding) { + framesToConsume = (ma_uint32)framesRemainigToPadding; + } + } else { + break; + } + } if (pBufferOut != NULL) { - #if defined(MA_DR_MP3_FLOAT_OUTPUT) - float* pFramesOutF32 = (float*)MA_DR_MP3_OFFSET_PTR(pBufferOut, sizeof(float) * totalFramesRead * pMP3->channels); - float* pFramesInF32 = (float*)MA_DR_MP3_OFFSET_PTR(&pMP3->pcmFrames[0], sizeof(float) * pMP3->pcmFramesConsumedInMP3Frame * pMP3->mp3FrameChannels); - MA_DR_MP3_COPY_MEMORY(pFramesOutF32, pFramesInF32, sizeof(float) * framesToConsume * pMP3->channels); - #else - ma_int16* pFramesOutS16 = (ma_int16*)MA_DR_MP3_OFFSET_PTR(pBufferOut, sizeof(ma_int16) * totalFramesRead * pMP3->channels); - ma_int16* pFramesInS16 = (ma_int16*)MA_DR_MP3_OFFSET_PTR(&pMP3->pcmFrames[0], sizeof(ma_int16) * pMP3->pcmFramesConsumedInMP3Frame * pMP3->mp3FrameChannels); - MA_DR_MP3_COPY_MEMORY(pFramesOutS16, pFramesInS16, sizeof(ma_int16) * framesToConsume * pMP3->channels); - #endif + #if defined(MA_DR_MP3_FLOAT_OUTPUT) + { + float* pFramesOutF32 = (float*)MA_DR_MP3_OFFSET_PTR(pBufferOut, sizeof(float) * totalFramesRead * pMP3->channels); + float* pFramesInF32 = (float*)MA_DR_MP3_OFFSET_PTR(&pMP3->pcmFrames[0], sizeof(float) * pMP3->pcmFramesConsumedInMP3Frame * pMP3->mp3FrameChannels); + MA_DR_MP3_COPY_MEMORY(pFramesOutF32, pFramesInF32, sizeof(float) * framesToConsume * pMP3->channels); + } + #else + { + ma_int16* pFramesOutS16 = (ma_int16*)MA_DR_MP3_OFFSET_PTR(pBufferOut, sizeof(ma_int16) * totalFramesRead * pMP3->channels); + ma_int16* pFramesInS16 = (ma_int16*)MA_DR_MP3_OFFSET_PTR(&pMP3->pcmFrames[0], sizeof(ma_int16) * pMP3->pcmFramesConsumedInMP3Frame * pMP3->mp3FrameChannels); + MA_DR_MP3_COPY_MEMORY(pFramesOutS16, pFramesInS16, sizeof(ma_int16) * framesToConsume * pMP3->channels); + } + #endif } pMP3->currentPCMFrame += framesToConsume; pMP3->pcmFramesConsumedInMP3Frame += framesToConsume; @@ -92879,6 +95041,9 @@ static ma_uint64 ma_dr_mp3_read_pcm_frames_raw(ma_dr_mp3* pMP3, ma_uint64 frames if (framesToRead == 0) { break; } + if (pMP3->totalPCMFrameCount != MA_UINT64_MAX && pMP3->totalPCMFrameCount > pMP3->paddingInPCMFrames && pMP3->currentPCMFrame >= (pMP3->totalPCMFrameCount - pMP3->paddingInPCMFrames)) { + break; + } MA_DR_MP3_ASSERT(pMP3->pcmFramesRemainingInMP3Frame == 0); if (ma_dr_mp3_decode_next_frame(pMP3) == 0) { break; @@ -92958,7 +95123,7 @@ static ma_bool32 ma_dr_mp3_seek_to_start_of_stream(ma_dr_mp3* pMP3) { MA_DR_MP3_ASSERT(pMP3 != NULL); MA_DR_MP3_ASSERT(pMP3->onSeek != NULL); - if (!ma_dr_mp3__on_seek(pMP3, 0, ma_dr_mp3_seek_origin_start)) { + if (!ma_dr_mp3__on_seek_64(pMP3, pMP3->streamStartOffset, MA_DR_MP3_SEEK_SET)) { return MA_FALSE; } ma_dr_mp3_reset(pMP3); @@ -93024,7 +95189,7 @@ static ma_bool32 ma_dr_mp3_seek_to_pcm_frame__seek_table(ma_dr_mp3* pMP3, ma_uin seekPoint.mp3FramesToDiscard = 0; seekPoint.pcmFramesToDiscard = 0; } - if (!ma_dr_mp3__on_seek_64(pMP3, seekPoint.seekPosInBytes, ma_dr_mp3_seek_origin_start)) { + if (!ma_dr_mp3__on_seek_64(pMP3, seekPoint.seekPosInBytes, MA_DR_MP3_SEEK_SET)) { return MA_FALSE; } ma_dr_mp3_reset(pMP3); @@ -93035,7 +95200,7 @@ static ma_bool32 ma_dr_mp3_seek_to_pcm_frame__seek_table(ma_dr_mp3* pMP3, ma_uin if (iMP3Frame == seekPoint.mp3FramesToDiscard-1) { pPCMFrames = (ma_dr_mp3d_sample_t*)pMP3->pcmFrames; } - pcmFramesRead = ma_dr_mp3_decode_next_frame_ex(pMP3, pPCMFrames); + pcmFramesRead = ma_dr_mp3_decode_next_frame_ex(pMP3, pPCMFrames, NULL, NULL); if (pcmFramesRead == 0) { return MA_FALSE; } @@ -93077,7 +95242,7 @@ MA_API ma_bool32 ma_dr_mp3_get_mp3_and_pcm_frame_count(ma_dr_mp3* pMP3, ma_uint6 totalMP3FrameCount = 0; for (;;) { ma_uint32 pcmFramesInCurrentMP3Frame; - pcmFramesInCurrentMP3Frame = ma_dr_mp3_decode_next_frame_ex(pMP3, NULL); + pcmFramesInCurrentMP3Frame = ma_dr_mp3_decode_next_frame_ex(pMP3, NULL, NULL, NULL); if (pcmFramesInCurrentMP3Frame == 0) { break; } @@ -93101,10 +95266,26 @@ MA_API ma_bool32 ma_dr_mp3_get_mp3_and_pcm_frame_count(ma_dr_mp3* pMP3, ma_uint6 MA_API ma_uint64 ma_dr_mp3_get_pcm_frame_count(ma_dr_mp3* pMP3) { ma_uint64 totalPCMFrameCount; - if (!ma_dr_mp3_get_mp3_and_pcm_frame_count(pMP3, NULL, &totalPCMFrameCount)) { + if (pMP3 == NULL) { return 0; } - return totalPCMFrameCount; + if (pMP3->totalPCMFrameCount != MA_UINT64_MAX) { + totalPCMFrameCount = pMP3->totalPCMFrameCount; + if (totalPCMFrameCount >= pMP3->delayInPCMFrames) { + totalPCMFrameCount -= pMP3->delayInPCMFrames; + } else { + } + if (totalPCMFrameCount >= pMP3->paddingInPCMFrames) { + totalPCMFrameCount -= pMP3->paddingInPCMFrames; + } else { + } + return totalPCMFrameCount; + } else { + if (!ma_dr_mp3_get_mp3_and_pcm_frame_count(pMP3, NULL, &totalPCMFrameCount)) { + return 0; + } + return totalPCMFrameCount; + } } MA_API ma_uint64 ma_dr_mp3_get_mp3_frame_count(ma_dr_mp3* pMP3) { @@ -93174,7 +95355,7 @@ MA_API ma_bool32 ma_dr_mp3_calculate_seek_points(ma_dr_mp3* pMP3, ma_uint32* pSe MA_DR_MP3_ASSERT(pMP3->streamCursor >= pMP3->dataSize); mp3FrameInfo[iMP3Frame].bytePos = pMP3->streamCursor - pMP3->dataSize; mp3FrameInfo[iMP3Frame].pcmFrameIndex = runningPCMFrameCount; - pcmFramesInCurrentMP3FrameIn = ma_dr_mp3_decode_next_frame_ex(pMP3, NULL); + pcmFramesInCurrentMP3FrameIn = ma_dr_mp3_decode_next_frame_ex(pMP3, NULL, NULL, NULL); if (pcmFramesInCurrentMP3FrameIn == 0) { return MA_FALSE; } @@ -93198,7 +95379,7 @@ MA_API ma_bool32 ma_dr_mp3_calculate_seek_points(ma_dr_mp3* pMP3, ma_uint32* pSe } mp3FrameInfo[MA_DR_MP3_COUNTOF(mp3FrameInfo)-1].bytePos = pMP3->streamCursor - pMP3->dataSize; mp3FrameInfo[MA_DR_MP3_COUNTOF(mp3FrameInfo)-1].pcmFrameIndex = runningPCMFrameCount; - pcmFramesInCurrentMP3FrameIn = ma_dr_mp3_decode_next_frame_ex(pMP3, NULL); + pcmFramesInCurrentMP3FrameIn = ma_dr_mp3_decode_next_frame_ex(pMP3, NULL, NULL, NULL); if (pcmFramesInCurrentMP3FrameIn == 0) { pSeekPoints[iSeekPoint].seekPosInBytes = mp3FrameInfo[0].bytePos; pSeekPoints[iSeekPoint].pcmFrameIndex = nextTargetPCMFrame; @@ -93336,18 +95517,18 @@ static ma_int16* ma_dr_mp3__full_read_and_close_s16(ma_dr_mp3* pMP3, ma_dr_mp3_c } return pFrames; } -MA_API float* ma_dr_mp3_open_and_read_pcm_frames_f32(ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, void* pUserData, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API float* ma_dr_mp3_open_and_read_pcm_frames_f32(ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, ma_dr_mp3_tell_proc onTell, void* pUserData, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount, const ma_allocation_callbacks* pAllocationCallbacks) { ma_dr_mp3 mp3; - if (!ma_dr_mp3_init(&mp3, onRead, onSeek, pUserData, pAllocationCallbacks)) { + if (!ma_dr_mp3_init(&mp3, onRead, onSeek, onTell, NULL, pUserData, pAllocationCallbacks)) { return NULL; } return ma_dr_mp3__full_read_and_close_f32(&mp3, pConfig, pTotalFrameCount); } -MA_API ma_int16* ma_dr_mp3_open_and_read_pcm_frames_s16(ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, void* pUserData, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount, const ma_allocation_callbacks* pAllocationCallbacks) +MA_API ma_int16* ma_dr_mp3_open_and_read_pcm_frames_s16(ma_dr_mp3_read_proc onRead, ma_dr_mp3_seek_proc onSeek, ma_dr_mp3_tell_proc onTell, void* pUserData, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount, const ma_allocation_callbacks* pAllocationCallbacks) { ma_dr_mp3 mp3; - if (!ma_dr_mp3_init(&mp3, onRead, onSeek, pUserData, pAllocationCallbacks)) { + if (!ma_dr_mp3_init(&mp3, onRead, onSeek, onTell, NULL, pUserData, pAllocationCallbacks)) { return NULL; } return ma_dr_mp3__full_read_and_close_s16(&mp3, pConfig, pTotalFrameCount); @@ -93465,4 +95646,4 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ +*/ \ No newline at end of file From 1937fedf08a0385c2d7075a914e9e30f4672816d Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 4 Oct 2025 20:07:39 +0200 Subject: [PATCH 087/167] rlparser: Minor tweaks --- tools/rlparser/rlparser.c | 72 +++++++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 30 deletions(-) diff --git a/tools/rlparser/rlparser.c b/tools/rlparser/rlparser.c index 2432af4af..2a112468f 100644 --- a/tools/rlparser/rlparser.c +++ b/tools/rlparser/rlparser.c @@ -80,7 +80,7 @@ // Types and Structures Definition //---------------------------------------------------------------------------------- -// Type of parsed define +// Define value type typedef enum { UNKNOWN = 0, MACRO, @@ -101,7 +101,7 @@ typedef enum { // Define info data typedef struct DefineInfo { char name[64]; // Define name - int type; // Define type + int type; // Define type: enum DefineType char value[256]; // Define value char desc[128]; // Define description bool isHex; // Define is hex number (for types INT, LONG) @@ -169,7 +169,7 @@ static char apiDefine[32] = { 0 }; // Functions define (i.e. RLAPI for r static char truncAfter[32] = { 0 }; // Truncate marker (i.e. "RLGL IMPLEMENTATION" for rlgl.h) static int outputFormat = DEFAULT; -// NOTE: Max length depends on OS, in Windows MAX_PATH = 256 +// NOTE: Filename max length depends on OS, in Windows MAX_PATH = 256 static char inFileName[512] = { 0 }; // Input file name (required in case of drag & drop over executable) static char outFileName[512] = { 0 }; // Output file name (required for file save/export) @@ -179,15 +179,17 @@ static char outFileName[512] = { 0 }; // Output file name (required for fi static void ShowCommandLineInfo(void); // Show command line usage info static void ProcessCommandLine(int argc, char *argv[]); // Process command line input -static char *LoadFileText(const char *fileName, int *length); -static char **GetTextLines(const char *buffer, int length, int *linesCount); -static void GetDataTypeAndName(const char *typeName, int typeNameLen, char *type, char *name); -static void GetDescription(const char *source, char *description); +static char *LoadFileText(const char *fileName, int *length); // Load text file - UnloadFileText() required! +static void UnloadFileText(char *text); // Unload text data +static char **LoadTextLines(const char *buffer, int length, int *lineCount); // Load all lines from a text buffer (expecting lines ending with '\n') - UnloadTextLines() required +static void UnloadTextLines(char **lines, int lineCount); // Unload text lines data +static void GetDataTypeAndName(const char *typeName, int typeNameLen, char *type, char *name); // Get data type and name from a string containing both (i.e function param and struct fields) +static void GetDescription(const char *source, char *description); // Get description comment from a line, do nothing if no comment in line static void MoveArraySize(char *name, char *type); // Move array size from name to type static unsigned int TextLength(const char *text); // Get text length in bytes, check for \0 character static bool IsTextEqual(const char *text1, const char *text2, unsigned int count); static int TextFindIndex(const char *text, const char *find); // Find first text occurrence within a string -static void MemoryCopy(void *dest, const void *src, unsigned int count); +static void MemoryCopy(void *dest, const void *src, unsigned int count); // Memory copy, memcpy() replacement to avoid static char *EscapeBackslashes(char *text); // Replace '\' by "\\" when exporting to JSON and XML static const char *StrDefineType(DefineType type); // Get string of define type @@ -217,21 +219,21 @@ int main(int argc, char* argv[]) } // Preprocess buffer to get separate lines - // NOTE: GetTextLines() also removes leading spaces/tabs - int linesCount = 0; - char **lines = GetTextLines(buffer, length, &linesCount); + // NOTE: LoadTextLines() also removes leading spaces/tabs + int lineCount = 0; + char **lines = LoadTextLines(buffer, length, &lineCount); - // Truncate lines + // Truncate lines (if required) if (truncAfter[0] != '\0') { int newCount = -1; - for (int i = 0; i < linesCount; i++) + for (int i = 0; i < lineCount; i++) { if (newCount > -1) free(lines[i]); else if (TextFindIndex(lines[i], truncAfter) > -1) newCount = i; } - if (newCount > -1) linesCount = newCount; - printf("Number of truncated text lines: %i\n", linesCount); + if (newCount > -1) lineCount = newCount; + printf("Number of truncated text lines: %i\n", lineCount); } // Defines line indices @@ -254,9 +256,8 @@ int main(int argc, char* argv[]) // Prepare required lines for parsing //---------------------------------------------------------------------------------- - // Read define lines - for (int i = 0; i < linesCount; i++) + for (int i = 0; i < lineCount; i++) { int j = 0; while ((lines[i][j] == ' ') || (lines[i][j] == '\t')) j++; // skip spaces and tabs in the begining @@ -271,7 +272,7 @@ int main(int argc, char* argv[]) } // Read struct lines - for (int i = 0; i < linesCount; i++) + for (int i = 0; i < lineCount; i++) { // Find structs // starting with "typedef struct ... {" or "typedef struct ... ; \n struct ... {" @@ -298,7 +299,7 @@ int main(int argc, char* argv[]) } // Read alias lines - for (int i = 0; i < linesCount; i++) + for (int i = 0; i < lineCount; i++) { // Find aliases (lines with "typedef ... ...;") if (IsTextEqual(lines[i], "typedef", 7)) @@ -320,7 +321,7 @@ int main(int argc, char* argv[]) } // Read enum lines - for (int i = 0; i < linesCount; i++) + for (int i = 0; i < lineCount; i++) { // Read enum line if (IsTextEqual(lines[i], "typedef enum {", 14) && (lines[i][TextLength(lines[i])-1] != ';')) // ignore inline enums @@ -333,7 +334,7 @@ int main(int argc, char* argv[]) } // Read callback lines - for (int i = 0; i < linesCount; i++) + for (int i = 0; i < lineCount; i++) { // Find callbacks (lines with "typedef ... (* ... )( ... );") if (IsTextEqual(lines[i], "typedef", 7)) @@ -359,7 +360,7 @@ int main(int argc, char* argv[]) } // Read function lines - for (int i = 0; i < linesCount; i++) + for (int i = 0; i < lineCount; i++) { // Read function line (starting with `define`, i.e. for raylib.h "RLAPI") if (IsTextEqual(lines[i], apiDefine, TextLength(apiDefine))) @@ -371,14 +372,13 @@ int main(int argc, char* argv[]) // At this point we have all raylib defines, structs, aliases, enums, callbacks, functions lines data to start parsing - free(buffer); // Unload text buffer + UnloadFileText(buffer); // Unload text buffer // Parsing raylib data //---------------------------------------------------------------------------------- - // Define info data - defines = (DefineInfo *)calloc(MAX_DEFINES_TO_PARSE, sizeof(DefineInfo)); int defineIndex = 0; + defines = (DefineInfo *)calloc(MAX_DEFINES_TO_PARSE, sizeof(DefineInfo)); for (int i = 0; i < defineCount; i++) { @@ -1038,8 +1038,7 @@ int main(int argc, char* argv[]) } free(funcLines); - for (int i = 0; i < linesCount; i++) free(lines[i]); - free(lines); + UnloadTextLines(lines, lineCount); // At this point, all raylib data has been parsed! //---------------------------------------------------------------------------------- @@ -1219,8 +1218,14 @@ static char *LoadFileText(const char *fileName, int *length) return text; } +// Unload text data +static void UnloadFileText(char *text) +{ + free(text); +} + // Get all lines from a text buffer (expecting lines ending with '\n') -static char **GetTextLines(const char *buffer, int length, int *linesCount) +static char **LoadTextLines(const char *buffer, int length, int *lineCount) { // Get the number of lines in the text int count = 0; @@ -1235,7 +1240,7 @@ static char **GetTextLines(const char *buffer, int length, int *linesCount) for (int i = 0; (i < count) || (bufferPtr[0] != '\0'); i++) { - lines[i] = (char *)calloc(MAX_LINE_LENGTH, sizeof(char)); + lines[i] = (char *)calloc(MAX_LINE_LENGTH, sizeof(char)); // MAX_LINE_LENGTH=1024 // Remove line leading spaces // Find last index of space/tab character @@ -1252,10 +1257,17 @@ static char **GetTextLines(const char *buffer, int length, int *linesCount) bufferPtr += (index + j + 1); } - *linesCount = count; + *lineCount = count; return lines; } +// Unload text lines data +static void UnloadTextLines(char **lines, int lineCount) +{ + for (int i = 0; i < lineCount; i++) free(lines[i]); + free(lines); +} + // Get data type and name from a string containing both // NOTE: Useful to parse function parameters and struct fields static void GetDataTypeAndName(const char *typeName, int typeNameLen, char *type, char *name) From b9e7cb64c5aff120d80caeb7fe8312eba06f2e70 Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 4 Oct 2025 20:16:16 +0200 Subject: [PATCH 088/167] rlparser: Reviewed command-line info --- tools/rlparser/rlparser.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/tools/rlparser/rlparser.c b/tools/rlparser/rlparser.c index 2a112468f..d5b03fa01 100644 --- a/tools/rlparser/rlparser.c +++ b/tools/rlparser/rlparser.c @@ -1049,6 +1049,11 @@ int main(int argc, char* argv[]) // callbacks[] -> We have all the callbacks decomposed into pieces for further analysis // funcs[] -> We have all the functions decomposed into pieces for further analysis + // Export data as required + // NOTE: We are exporting data in several common formats (JSON, XML, LUA...) for convenience + // but this data can be directly used to create bindings for other languages modifying this + // small parser for every binding need, there is no need to use (and re-parse) the + // generated files... despite it seems that's the usual approach... printf("\nInput file: %s", inFileName); printf("\nOutput file: %s", outFileName); if (outputFormat == DEFAULT) printf("\nOutput format: DEFAULT\n\n"); @@ -1070,22 +1075,21 @@ int main(int argc, char* argv[]) //---------------------------------------------------------------------------------- // Module Functions Definition //---------------------------------------------------------------------------------- - // Show command line usage info static void ShowCommandLineInfo(void) { printf("\n//////////////////////////////////////////////////////////////////////////////////\n"); printf("// //\n"); - printf("// raylib API parser //\n"); + printf("// rlparser - raylib header API parser //\n"); printf("// //\n"); - printf("// more info and bugs-report: github.com/raysan5/raylib/parser //\n"); + printf("// more info and bugs-report: github.com/raysan5/raylib/tools/rlparser //\n"); printf("// //\n"); printf("// Copyright (c) 2021-2025 Ramon Santamaria (@raysan5) //\n"); printf("// //\n"); printf("//////////////////////////////////////////////////////////////////////////////////\n\n"); printf("USAGE:\n\n"); - printf(" > raylib_parser [--help] [--input ] [--output ] [--format ]\n"); + printf(" > rlparser [--help] [--input ] [--output ] [--format ]\n"); printf("\nOPTIONS:\n\n"); printf(" -h, --help : Show tool version and command line usage help\n\n"); @@ -1102,11 +1106,11 @@ static void ShowCommandLineInfo(void) printf(" NOTE: If not specified, the full input file is parsed.\n\n"); printf("\nEXAMPLES:\n\n"); - printf(" > raylib_parser --input raylib.h --output api.json\n"); + printf(" > rlparser --input raylib.h --output api.json\n"); printf(" Process to generate \n\n"); - printf(" > raylib_parser --output raylib_data.info --format XML\n"); + printf(" > rlparser --output raylib_data.info --format XML\n"); printf(" Process to generate as XML text data\n\n"); - printf(" > raylib_parser --input raymath.h --output raymath_data.info --format XML --define RMAPI\n"); + printf(" > rlparser --input raymath.h --output raymath_data.info --format XML --define RMAPI\n"); printf(" Process to generate as XML text data\n\n"); } From de50402dd5236dcf856f90e9cb82c56df8372874 Mon Sep 17 00:00:00 2001 From: Maicon Santana Date: Sun, 5 Oct 2025 21:26:25 +0100 Subject: [PATCH 089/167] Check if video mode is valid and rename to match with other methods (#5235) --- src/platforms/rcore_desktop_glfw.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/platforms/rcore_desktop_glfw.c b/src/platforms/rcore_desktop_glfw.c index cab497266..a9ee199c6 100644 --- a/src/platforms/rcore_desktop_glfw.c +++ b/src/platforms/rcore_desktop_glfw.c @@ -959,8 +959,11 @@ int GetMonitorRefreshRate(int monitor) if ((monitor >= 0) && (monitor < monitorCount)) { - const GLFWvidmode *vidmode = glfwGetVideoMode(monitors[monitor]); - refresh = vidmode->refreshRate; + const GLFWvidmode *mode = glfwGetVideoMode(monitors[monitor]); + + if (mode) refresh = mode->refreshRate; + else TRACELOG(LOG_WARNING, "GLFW: Failed to find video mode for selected monitor"); + } else TRACELOG(LOG_WARNING, "GLFW: Failed to find selected monitor"); From a683dd96159dbde28390c1fa1585af19ce661b85 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 6 Oct 2025 17:40:39 +0200 Subject: [PATCH 090/167] Update analyze_codeql.yml --- .github/workflows/analyze_codeql.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/analyze_codeql.yml b/.github/workflows/analyze_codeql.yml index 98d32a499..1ef6605bd 100644 --- a/.github/workflows/analyze_codeql.yml +++ b/.github/workflows/analyze_codeql.yml @@ -71,7 +71,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -90,7 +90,7 @@ jobs: cmake --build . --config $BUILD_TYPE - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 with: category: "/language:${{matrix.language}}" upload: false @@ -99,7 +99,7 @@ jobs: # Filter out rules with low severity or high false positve rate # Also filter out warnings in third-party code - name: Filter out unwanted errors and warnings - uses: advanced-security/filter-sarif@v1 + uses: advanced-security/filter-sarif@v3 with: patterns: | -**:cpp/path-injection @@ -121,7 +121,7 @@ jobs: output: ${{ steps.step1.outputs.sarif-output }}/cpp.sarif - name: Upload CodeQL results to code scanning - uses: github/codeql-action/upload-sarif@v2 + uses: github/codeql-action/upload-sarif@v3 with: sarif_file: ${{ steps.step1.outputs.sarif-output }} category: "/language:${{matrix.language}}" From 59c3fcc23a7cdab97dc0dbb05fddbdd75bfbc973 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 6 Oct 2025 18:15:32 +0200 Subject: [PATCH 091/167] Update analyze_codeql.yml --- .github/workflows/analyze_codeql.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/analyze_codeql.yml b/.github/workflows/analyze_codeql.yml index 1ef6605bd..7be6d2c10 100644 --- a/.github/workflows/analyze_codeql.yml +++ b/.github/workflows/analyze_codeql.yml @@ -99,7 +99,7 @@ jobs: # Filter out rules with low severity or high false positve rate # Also filter out warnings in third-party code - name: Filter out unwanted errors and warnings - uses: advanced-security/filter-sarif@v3 + uses: advanced-security/filter-sarif@v2 with: patterns: | -**:cpp/path-injection @@ -121,7 +121,7 @@ jobs: output: ${{ steps.step1.outputs.sarif-output }}/cpp.sarif - name: Upload CodeQL results to code scanning - uses: github/codeql-action/upload-sarif@v3 + uses: github/codeql-action/upload-sarif@v2 with: sarif_file: ${{ steps.step1.outputs.sarif-output }} category: "/language:${{matrix.language}}" From b067b0b878a12195a26e8be8105d6637b905e38a Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 6 Oct 2025 18:27:56 +0200 Subject: [PATCH 092/167] Update analyze_codeql.yml --- .github/workflows/analyze_codeql.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/analyze_codeql.yml b/.github/workflows/analyze_codeql.yml index 7be6d2c10..5fd169dd0 100644 --- a/.github/workflows/analyze_codeql.yml +++ b/.github/workflows/analyze_codeql.yml @@ -99,7 +99,7 @@ jobs: # Filter out rules with low severity or high false positve rate # Also filter out warnings in third-party code - name: Filter out unwanted errors and warnings - uses: advanced-security/filter-sarif@v2 + uses: advanced-security/filter-sarif@v1 with: patterns: | -**:cpp/path-injection From b99a6cc6bd93f1355317a1ac49d889b35498158a Mon Sep 17 00:00:00 2001 From: Jopestpe <47086979+Jopestpe@users.noreply.github.com> Date: Mon, 6 Oct 2025 17:35:18 -0300 Subject: [PATCH 093/167] [examples] Added `shapes_recursive_tree` (#5229) * ADDED: example: shapes_recursive_tree * [examples] Added shapes_recursive_tree * [examples] shapes_recursive_tree: adjustments * Reduced tree depth from 12 to 10 * new shapes_recursive_tree.png * follow the conventions * follow the conventions 2 --- examples/Makefile | 1 + examples/Makefile.Web | 4 + examples/README.md | 5 +- examples/examples_list.txt | 1 + examples/shapes/shapes_recursive_tree.c | 141 ++++++++++++++++++++++ examples/shapes/shapes_recursive_tree.png | Bin 0 -> 18375 bytes 6 files changed, 150 insertions(+), 2 deletions(-) create mode 100644 examples/shapes/shapes_recursive_tree.c create mode 100644 examples/shapes/shapes_recursive_tree.png diff --git a/examples/Makefile b/examples/Makefile index fb33b4894..a36b9e447 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -559,6 +559,7 @@ SHAPES = \ shapes/shapes_logo_raylib_anim \ shapes/shapes_rectangle_advanced \ shapes/shapes_rectangle_scaling \ + shapes/shapes_recursive_tree \ shapes/shapes_ring_drawing \ shapes/shapes_rounded_rectangle_drawing \ shapes/shapes_splines_drawing \ diff --git a/examples/Makefile.Web b/examples/Makefile.Web index 0dbefadf2..2d3018abf 100644 --- a/examples/Makefile.Web +++ b/examples/Makefile.Web @@ -559,6 +559,7 @@ SHAPES = \ shapes/shapes_logo_raylib_anim \ shapes/shapes_rectangle_advanced \ shapes/shapes_rectangle_scaling \ + shapes/shapes_recursive_tree \ shapes/shapes_ring_drawing \ shapes/shapes_rounded_rectangle_drawing \ shapes/shapes_splines_drawing \ @@ -868,6 +869,9 @@ shapes/shapes_rectangle_advanced: shapes/shapes_rectangle_advanced.c shapes/shapes_rectangle_scaling: shapes/shapes_rectangle_scaling.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) +shapes/shapes_recursive_tree: shapes/shapes_recursive_tree.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) + shapes/shapes_ring_drawing: shapes/shapes_ring_drawing.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) diff --git a/examples/README.md b/examples/README.md index 70e07df2b..d852e7105 100644 --- a/examples/README.md +++ b/examples/README.md @@ -17,7 +17,7 @@ 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: 172] +## EXAMPLES COLLECTION [TOTAL: 173] ### category: core [40] @@ -66,7 +66,7 @@ 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) | -### category: shapes [23] +### category: shapes [24] Examples using raylib shapes drawing functionality, provided by raylib [shapes](../src/rshapes.c) module. @@ -84,6 +84,7 @@ Examples using raylib shapes drawing functionality, provided by raylib [shapes]( | [shapes_following_eyes](shapes/shapes_following_eyes.c) | shapes_following_eyes | ⭐⭐☆☆ | 2.5 | 2.5 | [Ramon Santamaria](https://github.com/raysan5) | | [shapes_easings_ball](shapes/shapes_easings_ball.c) | shapes_easings_ball | ⭐⭐☆☆ | 2.5 | 2.5 | [Ramon Santamaria](https://github.com/raysan5) | | [shapes_easings_box](shapes/shapes_easings_box.c) | shapes_easings_box | ⭐⭐☆☆ | 2.5 | 2.5 | [Ramon Santamaria](https://github.com/raysan5) | +| [shapes_recursive_tree](shapes/shapes_recursive_tree.c) | shapes_recursive_tree | ⭐⭐⭐☆ | 5.6-dev | 5.6-dev| [Jopestpe](https://github.com/jopestpe) | | [shapes_easings_rectangles](shapes/shapes_easings_rectangles.c) | shapes_easings_rectangles | ⭐⭐⭐☆ | 2.0 | 2.5 | [Ramon Santamaria](https://github.com/raysan5) | | [shapes_ring_drawing](shapes/shapes_ring_drawing.c) | shapes_ring_drawing | ⭐⭐⭐☆ | 2.5 | 2.5 | [Vlad Adrian](https://github.com/demizdor) | | [shapes_circle_sector_drawing](shapes/shapes_circle_sector_drawing.c) | shapes_circle_sector_drawing | ⭐⭐⭐☆ | 2.5 | 2.5 | [Vlad Adrian](https://github.com/demizdor) | diff --git a/examples/examples_list.txt b/examples/examples_list.txt index 50643bf2b..5a0c679a4 100644 --- a/examples/examples_list.txt +++ b/examples/examples_list.txt @@ -60,6 +60,7 @@ shapes;shapes_following_eyes;★★☆☆;2.5;2.5;2013;2025;"Ramon Santamaria";@ shapes;shapes_easings_ball;★★☆☆;2.5;2.5;2014;2025;"Ramon Santamaria";@raysan5 shapes;shapes_easings_box;★★☆☆;2.5;2.5;2014;2025;"Ramon Santamaria";@raysan5 shapes;shapes_easings_rectangles;★★★☆;2.0;2.5;2014;2025;"Ramon Santamaria";@raysan5 +shapes;shapes_recursive_tree;★★★☆;5.6-dev;5.6-dev;2025;2025;"Jopestpe";@jopestpe shapes;shapes_ring_drawing;★★★☆;2.5;2.5;2018;2025;"Vlad Adrian";@demizdor shapes;shapes_circle_sector_drawing;★★★☆;2.5;2.5;2018;2025;"Vlad Adrian";@demizdor shapes;shapes_rounded_rectangle_drawing;★★★☆;2.5;2.5;2018;2025;"Vlad Adrian";@demizdor diff --git a/examples/shapes/shapes_recursive_tree.c b/examples/shapes/shapes_recursive_tree.c new file mode 100644 index 000000000..3ec46de4b --- /dev/null +++ b/examples/shapes/shapes_recursive_tree.c @@ -0,0 +1,141 @@ +/******************************************************************************************* +* +* raylib [shapes] example - shapes recursive tree +* +* Example complexity rating: [★★★☆] 3/4 +* +* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev +* +* Example contributed by Jopestpe (@jopestpe) +* +* 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) 2018-2025 Jopestpe (@jopestpe) +* +********************************************************************************************/ + +#include "raylib.h" +#include + +#define RAYGUI_IMPLEMENTATION +#include "raygui.h" // Required for GUI controls + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- +typedef struct { + Vector2 start; + Vector2 end; + float angle; + float length; +} Branch; + +//---------------------------------------------------------------------------------- +// Module Functions Declaration +//---------------------------------------------------------------------------------- +static Vector2 CalculateBranchEnd(Vector2 start, float angle, float length); + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [shapes] example - shapes recursive tree"); + + Vector2 start = { (screenWidth/2.0f) - 125.0f, screenHeight }; + float angle = 40.0f; + float thick = 1.0f; + float treeDepth = 10.0f; + float branchDecay = 0.66f; + float length = 120.0f; + bool bezier = false; + + 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 + //---------------------------------------------------------------------------------- + + float theta = angle*DEG2RAD; + int maxBranches = (int)(powf(2, (int)(treeDepth))); + Branch branches[1024] = { 0 }; + int count = 0; + + Vector2 initialEnd = CalculateBranchEnd(start, 0.0f, length); + branches[count++] = (Branch){start, initialEnd, 0.0f, length}; + + for (int i = 0; i < count; i++) + { + Branch branch = branches[i]; + if (branch.length < 2) continue; + + float nextLength = branch.length*branchDecay; + + if (count < maxBranches && nextLength >= 2) + { + 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}; + } + } + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + for (int i = 0; i < count; i++) + { + 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); + } + } + + DrawLine(580, 0, 580, GetScreenHeight(), (Color){ 218, 218, 218, 255 }); + DrawRectangle(580, 0, GetScreenWidth(), GetScreenHeight(), (Color){ 232, 232, 232, 255 }); + + // Draw GUI controls + //------------------------------------------------------------------------------ + GuiSliderBar((Rectangle){ 640, 40, 120, 20}, "Angle", TextFormat("%.0f", angle), &angle, 0, 180); + GuiSliderBar((Rectangle){ 640, 70, 120, 20 }, "Length", TextFormat("%.0f", length), &length, 12.0f, 240.0f); + GuiSliderBar((Rectangle){ 640, 100, 120, 20}, "Decay", TextFormat("%.2f", branchDecay), &branchDecay, 0.1f, 0.78f); + GuiSliderBar((Rectangle){ 640, 130, 120, 20 }, "Depth", TextFormat("%.0f", treeDepth), &treeDepth, 1.0f, 10.f); + GuiSliderBar((Rectangle){ 640, 160, 120, 20}, "Thick", TextFormat("%.0f", thick), &thick, 1, 8); + GuiCheckBox((Rectangle){ 640, 190, 20, 20 }, "Bezier", &bezier); + //------------------------------------------------------------------------------ + + DrawFPS(10, 10); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + 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 diff --git a/examples/shapes/shapes_recursive_tree.png b/examples/shapes/shapes_recursive_tree.png new file mode 100644 index 0000000000000000000000000000000000000000..88932c204bcd24be38c10978b75cda9b002234d8 GIT binary patch literal 18375 zcmeHvc{G&&-!~IQS}aA$mL&-zB-tf9QPzyLkY((Hu``t-j3rBCDP&)=jD4#xL?ipY zWE%!Ec8&G9rsdoBKF>e*AI~}WdG7ObPN$l=uFv(}->>&_3B9MKa{46mNis6B(`u@U zI%H(WILOGzKT#bAK4G#fYy%tUUoQRrTICkYlilg99uw$dQh zC|;Gxp}&kL3(!uG8{ugc_as&n1v;>J+t>Q)=}9ufimX3E-oqV#-puy!}z0zLUH~S zewvbOq1ZosN;3Qae%80Q2aJl{Uo`nsE(eW?S12q0L;qVTa%xrhi zSGnO_9OM^y4Sdx95xj*LIU(p2yTY;G8dPTZvAr^CpHO+|=j>N(sgAt#RWq=IG9G5N zOF((UT1{etV$nU(f5>=*m{TBx2b;UvuzDFIh;>rXGwSkAQYojxe=&05zQt0J`>c~k zW@pHiT|Xgm>bCl6yBohl3PjNlFaSGh&^-u9dDFJqXfRdbVP{_w>L#2Cp_FTn@u@}Nfwf86aj-O%1v!D872 z-t(-&-jI`7^oPSuB9XXZ*>XDh*V$fmO=vVap|Y~_I}37uAHPGGY~25TAe0?W)DApa z;#;wuH7AMx$NJ&ngxCw#sG`pqus^H^Qk%GDC&?ffLG)3Kc{uLhy47Qh3er2SKW+_b ztSzuU{Wp?utlk2+pHXmX`h5bRs3L|{ssWE}$e-wFa%F06wPS&O@&m=}nl9OI39Kq2 z28(%!FPhGS0-o=j^l)KPcSY;Q$#7H%O+brQPx!R{(QA-=br41780L?rNLFD5 z$VuemIo>~3$RYpML>{E$gjN0Pbrd3i(Ii^D{1@H#z#Qa!m9W1-og9=1@T_^g{`UnI=MaqtYh4-cVzp@`M<|PQ zZSn?9kV|wyH2yx9O^Acsd;c8SU%scL0abVpK>l$^j#ZK$NC%uG`|Sr1D!;w$m5!yr z!b79{Mvpgzt?3gLpkC>*BzE7xiFBL)qH|h~Z=p@nA0J$4**Kcm-5L2D71YP5&;Ex< z6$?kh%uUSZK4!abb^@epLA42l{l&{CcYjkPt#C{fu70rjlYeNdrXR(`tjP)k+b z>BhTL!M`MW;m+F^N>dkfe1;XKa712mJ34)jKXUY>C^92Ec?Q7`sLl`vee>&%Dpb?J z-i2y{odb`6P5lkOB@P)Emu~Ojm-E?OU0rF$`bB2H)h=E z8v~CH=gtxWFFx+9WE438xt;vn>&rj!Nrp@+hvX*l_fW)x9rCToeTbU`;Yc~K-KWK zJ70vDk^~u}wv>yqcuDB+f`{er_*cU)RC9;5+E}oC0i68V!`2aw7YiwrlM|7rZljYy z|FQRL)U(`l64v}4+G65NA>2)<`4o!T`B&|$zqmjMQ@Am~b8U9f7f@!h0GwHG&bcJ| ziyfEHrimGW>c}R*DXK#|d1#qsOgXkvyAwASe|m*B(>IRajK5_-L`FsmIXgS2Y-Tx$ zR|Hru?d=fE4_6NpY9ew4ji-PV0o@kPJqF~5wYh@>8U5v+u9YB@FU78Z{7QzrmVHa0 zzfVgZ)Pphj`bP}9fIVirK@09p!GqBfzcb}8>l_9GtAogif9dSrwJExSf64hcqwN}K zvx%i9ARTZbMTfh86yQVWbpVM8q%yfYW#d(RZ}7@5KE6dXr35~&yky0C`8vbunUKZ5 zQ81{<4tQK|j+o-#v=Kzn%Lt=+T*f(f8khv;d-HMm_(RjYS2$ zKK5H0Br21ytnT$fdT4)3K1iMkG}#zPNN1PqR-QUIsK471XAi{vCwixUUtz&bN({(8 zQ~%Q^0qJu+Sg(0RAGNfM()`Uy)h~arc7#^Fmp`Hofy+Z$&By=s$o>C<6#&xy@L|fg zdUV(kxCh_Z2uwR%-LmOTEB2Qq_+~EG73ujy!KhKyE#A4_Yo58DTxTSNH6=1zFD`0p zUCJ%xOVbPV|CND#&iz>2*x10bNo8qM*wbi+RUhpK9uC^~Z?sGpBoZINcX#ysb89L{ zx7urVG%s#V7Va7|7x!JzNlOTK?Yb<6)C=Tvm4dOoZ=HdGC>s2Tzwoo?$rh3~_F_iT zlq5GKoxGPv(hB>xcFz~c)gAHlgo`|--k&5K&2+3Ae#r7J6_ZoPTJS}%k{tCkZZL4sq>vT#%b$MI&qXfCT19nWZ$f ze>7T=vz<-jz>{ag%cje+e{!JLX7(=nsD{QA+8tjrlcG^IP?>b#zm@IjUu`L!;kP1O zf$X@rv2Y6R2;@dB3n<*mdC)4r#uqm{@~F(TxL=dQTpkqTJWmB`0T~mX*2TPs(BNX= zTHD9<^34V5Ga&w>`Pl}ST3)pxD5#{>EmEat5BDG-w|-W<3guUeGQfj|t?;oaj3)OR zcW@A67N>EP)39=8qi)sqGV=KivDU)f!Ej@=S4T#IH}~2t$xE!-QxHTw{6>ZBsJdna zTW^i$GYG+S3a2>OwYn{PXVclxqTyDAYUDr z>AKSd5Obot(N7ZymlfIXL-Ku>qI3JS&~;z+M50HPzgRf#ch5rc^>EGdvASZFT@=d( zR$T>2}m5St%pOQr6vnNzL%|aUTfzVeJUB6g`Ts9~W^u$tsq${;6@wFmP zvTuBR3AJa$Z}<9A--6}cGQD(NKy34~eUnL(iG3_v5{w(fNM>^+IdzCJI3 zW64i&O4&9&9fXo-+NKIhA1v-v(Vg13c-mnc}`eu^A414K6APdXkZ<}#B& zP4Sxb4s|D?NXWbs@9_?`^<;H|6*mE=t1x?M-uiZs+ZD=I-*76oYV%fBq3n)q2J^KQ}`HPz@N4!PAHxaYK@D zyWP`bPN7579L-o;+^}5(D@%sGZ%6BOQMo1(xWh}|PQKK@`A#P*{0z@U=T^_O#qEw9 zMl_Yb9Wh?bV*K3E;v^K-J{LCH(c&E$*&{Fs4{4Yw*+Hs0!$0}HPvGfOYmQXgOp@by>Us@zKVhrW}X ze5b|}V9emm*4u~F?x@Oa{ee3w)w~84+^Zc(o0A^$CHfr>Pwc$ky6{}~@}e|J>cy`ZKz5VLA<;7oVtCwOo2rwG{H-`^+7 zein|2rf?&CQD)T04R*J3g*>Xd8Lt9KVlm%idkr{KH?X-k{j@Cf{vehNPxD6VQ@m3=o8J{Y)6Ni9KmsZfg52h4O`5E^ zBlhS}a83qwr(d_smiNTuoKw?!8BrJ-Ny)lGfU+3VjO&@ihwT=oM2z{&S9H%h2+bR} zqsKfY($ZbMQKQ$uD)Vb2a7$)OcTAtEOJw-R5|ZP)1Oj$&U^#X`Wlod27-*a_UZWvp zP8B~Ukt)=jK~wI{UWrT;a)>-`;b@ZE;-B|5q#t79M*kF*5~*5{-Jr5tC5EY2nbf%% z-L*6AYsD6a^uCyYl3ngkVMqvx{MGlc&~B3Am`7WKjA{D#a)%(-zcLwai1x zeJj^vmM7QU1tS<_e{qhm+ufL3>u44h&*J;c2bQ4Oh@s%XrCbx=5}&Ix(8gRCjG00a zKAFks2n()ge`y1P*XCtXH7YBa&UBZ;=jaW-{#Xz9@->-jA5bnyLJu?;y>kQR`Vw_- z#_8QXxR$%&;b2wr+IT0a9|985o*1Bi&bZ>#A{_Tku~iT9IPsj~Bl;AkT<_X_Kat6e z9J++D06y)vh6vtdJ5hHzwz3;jULvwv&-yH!S=kmw#u3MxR~7tI~l;Ta)zm2caI#HhJPBlR4V% zvI4K(7P=~r%FIX^irhq#U|Q1<;LRm7;+g~vw!22g&39?=3!iE!uA;oc!4vagjf*LW zdZlGO=e&ct*E(}MBPMt=#kz{=(r`6o?>_7EzS@(<{+)INeU&~bND()<5W5CZh@a70 zuaD@wY)yi6QzXo4gFf2q#)7K`809y(xv@p=c#AyRUm+%$X$dLby81P*xTC>(Mhl<;zst zD(D3-kRWA)|K7IsQed&Cd0OE?*%nq808N7EOnd-kR`r0!*@IKgLeW)5a_SR;3(*$k zu9>OB>~_+=YLlunUSF5=Onj2}jQyGUF0!}lo2T(!*FNXQ_<}wh`!$Z43zKLmHlopg znOu#UC~a&}EpH?nATm8Z8NFM#b#=hZr1a_7YEWT7QOndBS36as_c$VQBv!Nj(412z z*pP?9lQO=&)eUXsy$W&b8U3W&MqLN6I)B>(F_-SLaz6_fk$0Uh>SafN7_ks8QG_?7 z-zKM2);?sT<-Aju+vJwO9plp3p(^VnDeQDzfV%DUlUqHsS+yICasEmxxT-#{=sKZp z-%Vu`Je^90S87vim6yqqcL}?7vzY=rkB&GFJHVwN&O9A;r}`S0vD#mY$#qc_?4!iN zc|A~%U&rhs$cAQ!T*BDI_vl>JF0%Hz15I-E>ZXReKc-m}E1w4PQL;FNK*1H~WfDTd z>Cn8}I;0v6eq){p>a#Rj0Wp}~!vq%E;qIkp2y-F0Mz(G*n99_NV@9=3^X5ByvoVy#(l{no1 zPyWFkcC@s>=<40i?<&o9NsMIlq{=BJZNyR!3wp&He-Tt5@0DNsQ@);m8m+H%z>Rx70z$CQ*eZSr6^$v=Yf zz|CgPHf3Wxifdy|0q68ac6w2TtLAh*5~%VlRLSK&OIZz#zt_>Yn%&|h?thc@8#O;kptXD9r+j>n2{6~kyZcXu3~l2b~@ck=t(j;D}aNB}wm8;*DN zh-x}b0o1#$Pw!v&6at8VF2hqNEhFrpUPUUNCceH@VnvD3fLHkRu;$&yInzz9$X(6X z-PPB*57knT&9|oO{PtaoC;BpCqPMlCyH6p|Gyp!4n;-*p%J#7ab2uO<#6D`jR;3gs z>C74%c*==rJKnv9Aw2GyoXpWD49o{?teb z0bfOqoi|@H{Mu5)=b~xBHp=BHJ3ynN4f2h=#Y#k0hOa~ig#OI$;Q(~FDD?QQub=zn z>*FOws0V5?u!(as&*K`WbwqEfOkhJ-2bP^P>uY1%y#-3$J3Dro)t4lEFno@Ku0IoA z3IM5!$_ROLMAP0e%8zyX1L@q^n8Mv{##$6(zbWN=1sk2NrG%T&K8;fgWrw~5`pgk9 zYcDHuv`k{1HE>v<@v{o9gNU5G3~v2dlsA%K9^KKoA>Z&Ts3~J#7W*Y8R~?$n7%7|z zQ!P9Vl>1{2DF-nRtD5C5t)5}7_u~fl?m&q$9YixH9=2#SXXS|Nv4@+(*+&3@Z9s3? zAazhsy^F~;nsR(#d;!(cypEZt7sxImmO#Vav|%~~L7o=0uu9c}ouq5tbw%@*k{iJU z@|aQ98pZ?^;l~80+>WnAF;t@1Z3%LmduQLhHi(&2rL%EZoR}rQZFcEV`y;1R7lBui z*8aX><8vu%$-!$Q(^p2e83?7yj`J`pezp$o>vII~mY-P1he#Yjq=Elf6 z$!w%SD+T1XwsKwDw~SkhHup;QogBx5+EV!GLrsL|0I&XyeoPLu9xa0Gs%iPuY`5{> z;=%3%t*LKo1(_wdjt(KG_T4IR<)Chr^%gDC@-H#rhH&G z?Xi8XqvTeN{MgG5y8L>}LB>{<5lPXT60Yqlg9G3hw}iaryc?nItatMES!25TF8FIr zIUpcvcUG+C9ZsyI0PS&!$^BBs;)WmqXI%X>F`ex}FG8@y370N-K@#{)XTgHHH2sBD zvtX}COnWVwN78(o&Dgi!^#(YXNV{U=RGqQGRVhOfg!~i>fCD8k38>Oa4nflb@Ck-o z8|cT~-HpN)!i2Cd0agwX*lHLORBPJ~PjJO}S6VoJtgU!$GTI%2$tIRWTNdroSKy5? za6d<05#|JM&N6EwXn}-f&9$Nt9>7fyZsd(m^qt^gTrj3n#&bKsoa%e2r-}VwhW-<} z)3!xMGxaUjR&+J-Z|B((q)w=}!kVRg9L~acc4`wL`_3&QJ7eD@Lql6t zB|t(5-oujvOC`BUkrw@V9pQe@ftjyOvo}0eg-NYtb{sjGZPF*ofoFHkiDW5$)$27zBwYR9T(k(EqkV*&iyq>{%Q2$j;s zqj6@w+*~$MD7=p{Q?G>|> zs8h#%3Dqb+G=rC<9~dIZ5au+%WWq7dYDtIT0mGkNfUcc=GjuEq@0Ej-`$dyQi$;nT z0ce*c{CB?>j|fg)?c-=s#s@NBO&>Ld3i_9#)AWgHf*l1BB|BB+n?w0hDA@fna~_z` zR@?XlcqyL{y|G2NPSHrElrc>tn1i=Y) z#`D$X#$h32rb%V^b#s5T3_Q7d4!b7hw(RE=*O_609b2#7xS@ZTqn~#eQ`Omc)N$#w z&6OX<;u6~pGaFr5C4`mv*v=9bm^C%+E%1l%|pRkl{95B4y zJ(EDw-S^28y37N|X*3AE7nUq5v<-JFNSIv9xnmC(%RalY@oA)vKQYX(mB&7Z1yOsl zfQO?O$k+y`owj&%30~Nko8wrku-k1@@X2{}C&7!&h^2s4N}F~YH!%_&x^3g!&Aw(w zw=Fs%X!NYhQfCBhYqD(uqn{Y7#X?uKR^pHnHpp0ka2Re<|M3N7N_u>9)6zJEmTjrEashpDL7RW;$6z=6paLa8d<- z9!R$iI3Wt}*2_5Sd!>2{8!HDZc>{5G+^XHIVtK)69l2S1W3m0Biki-A-N0+P`KVR% zfmiAZ^R7m%S9!@tq_pc~jq~}%c;`b^@*D~uPoS% z^lYXXH`%yZx|O47kA9fQ!eV+Wj-?TGoi7&(b#=2=g$mR`c%39<1zUU5F@3Kg6~m?Y zzN!IPp~bF=9ihsG9>V&Kc+~jlTs0Ir2AxB0XLBD%Uest49tlW4{dT_+_07$!D zKwCbuH>ZoqHo9fRKqRVms$*`**tTG$FY{2K^1zT7qODf{9^GfQJfJBHSo4H}6aPcO ztp`$05G#BOzSA`!ywLMVefNVVJ@SeJ6dPSHH~Mm=yF?&zQX?coilrLcH)2U@%~DY9 za{^sV_nQJjyU|iFp?ptbMhG)7Khhn%;>U*BlZqUNnA?|+ekw=LW^76|uylw>m;?k?J{s<^BC?ue z!jd;EZ#-;2Fys3f&0NWa-k}S%gd_wXaWM_%!a9PTF(oR;tNI5~a?U09B%sOF$||iR z_V3CQEDHP$_!CDU99>J!tmxcAW+3O$2zFGujPBvV3_)C}_Y>yucI`VEv&qaWX>KH3 zMa%Tz7=0yk)~x%x35aF|a~ov6%;a^SSx)%_um1Ji5>eRv4~zrU&hPQ4%E&dN&4DEC zZXaa0vmkiGYNp`Q$&G;J6tq2343`gdXep>zfaBc8KB%AO5^zXAmJ$;lV>ROhzp4R0 ztG=AR#>WT00fsYor7+g>xF&W5Ge)+>b#`T-#}@Z}`#!C8(R&^E#F1tyK&7DI|Nbj; zIyP|<|-#zwO8GWn6c4CwshHklQX4ZS_Br+rrKY{zTih84kwJlY*>?V}8 zhBN%3{`>3o$QZ(~DdP(KqRNs)#^K)2-kkG2*|H+-DM@b^!KnKC!W{7k#Cf6{=?Yq_sVrXKo_<|@Ktsp;l34Ayfbdj0c-YFkLJCrg^3y(-gewdVIrK;avrr>V?rTYpcr-U^SS% znBHya_>S2}gfi91NH%sm%R-iQTNPD zqx8Padzu~PaXZKgD}5o=w~h;5sRvZ@z3zP>@a69%Xg-T7n_lsE33ajgTW`slyoVk-X z9@CXQG zJwt5CvKVqBpnt(~Wmn-_Vz6?E#(Wf;u^%y=XnFY*X>H`^vI&*?EPiZcqoW%BUh0B< zDUBFoO}nxrp9|KsP%9*?cCFm|!KwasL@w;%=0Rjzb=9lOOUD6Yd=3D7clw4xn#qY^ z*phI9*7M9ufXUllqrEGT1)DP?^6pQ`_gdtTo^ufp&Z&X{rAly+1l$s9J^mHSD!j$O z;SwyrSnWu#-s5k5cbC*K(Fdk$uCqIyvTpQ|g%4xRa)cgtlPVkoN+e#d6MknqK!9A1 zs)|%FLu5T^aZw7u;}`TecH8=+@s-lN?28GOBs9wlq}>M7G z`DV~G`D|hUUb#&y{*XK#K~xG@aZ00E9j5DMLtv>LQhc+_vm|Gv%LiVFPRMwhl}Ee= z)Y(Ydj7&Q1%TyIVdIW_t4T9H={cl;`cDb*5LnBC@3o*9Q?)IW$&f6v*=ow_Rzl8u4 z@81D*+kIoG_N`XrQ1vGq~B7q^9b$ULyWstT~e}<_k4#m7YbSOF5)m8~a(Whqfh0U%Omp?q>^c5HL2R zO>;MQ=Huz;M-Z?y#_zdQzc_H(J;SL^SV!Lmr1o-5WDV@LBOvUnKx;fUC&f<_-y&P- z7xvwRNMkP8nxO@v2oU^cU&#gZ)I!SrD#86WKNl$hFx`Qbzj6CPe3-O3YvJChXBkqr zY&P!$raw!)S^D(D)&m2a^u_U%l|_>zrpxb1GHwKJqIncM!a7v5sx;A9g)5q6%;27V zLY<`silFdOlg;{Gc;K&`3$wtSQO_$M{P7Q8)382K)T`caUdLoA@4|lwCNTOq@)6^wp7gr zky}&)x{s?}={Z~~fDx6$TFSN#!7CG7l-pIzmZ!p2gbdoIo}~_7=k&yliTj%^l?+NN zkr-0KW{!5dYHdAE zo$QS`|996Tgtz!D-ZLV(D(uay?Htuuqh4~E}$zls&+jgQd=n|YEI#@nh?d4cH5&ZRR5oyI-FlPe#YOv(F01FS&vAZJoT8SB z%C)j=uw18zyuzUN9w3VfSVwtsPw=H6VQ57r0HvvguYz(=+X;8{sacp$A;VUPUsF&p ztd5o0A(E|uw85}&x2f2|gEpGzJfu=9`e|dNyQH&YT)5<#tIH{bC!_4UJQ9G|-+5n>16J`C z*p<#C$3fy$@XIP@r~FM>2yO_0>Zjg17sT#NF@oTuwOWlcmJ{?scVb zY5$$<%7+Xb->Lz}dj+~N{?6C5E$e87=fVb!Rrwh7>W0c${d zHup0rX&YIA+9^UAbMaVQ@+F1(y+sl-Edugf@;L;N5@zovL?^MHicVp~!dH^xkgXL_048+QL#Y%b(Y4Qb2+whcHTJf#>M_JCU zfofN0!yjt0T&;R(KqN~bK_;(wfzlmtR)$;viZMQ$+ayI(ZM-VFiM3HmtSc}k^3q+; zJD24xs7OiZ;kCO8_^PT0&v|xudXb;<_$k2Wt44*)RvyN4)AOKBnD0dZk#p)eD1dV5 z8OOZYR7Jpd>->E9*ovy4$b6cd<36vZ(cM!5tIsact6+jv{M@?cj%jn50-;1+7kGf~ zgx8!eoG;Sk`i#s%r4{asQ~Som0n(t0s+qzK>yPt22lXh>fht4A1yXHA4Y;@B$q=>F z`#<+l$B*~VcvXO1-ZM4y00W57WzSi>+bkGUE% z^=Fwr#icMmyf!m?MEB)WCngQ13KT7AT!H@b2Urf`I?$>wRvQNqh1C%cV z_?=I<`r|ZZZG|FDX`Qe#RF|*Wy~kRtE&M0LC57;%mpF+zw-WUMQ$e%>k*T%Gm}V#= zl1gBSRhW8FY)$npb)@V2XZQnRPN?#=Yh1jXf-#YFUAegz_DEQ&9tay+;mtq<7*T73 zUKIp4qe7MMO6#1F2vrLk%HG9p_#t>@pNK;^OXFzgRrUr|G_gIksl~|MTdBb9DipxR z3tjyaODt0dW7xL|q4@fpVvbCu7v-rZlv3Qj$x$}XCxm|6+d)|$bw0I8p#?54n|3T8 z1V9Zq%b(gQQy`5H?w)1}?Lq=PPe1jX#|n)vPp zWdJj>Tb8cCYtb-o{AJ z_b;<=nVz!EKbIxN3`JnKF`ZF*{)^(&mx^qucKXO6#pu^9$(XA=jC)_|xj7Aa+2`9Y zPAUVtIW9IpEtf_+&Y#B9knRYN+2D;cA8QxS_im1(8A+PCm0v`3YBLI3Z-{r;bZ1)sL~A3ug?v3t(&oQbIyM(eYWIaeBP2&~dG*0SJS1&*e-H#VK)}hYDog}JldIY0 zAH7RhSB`==$Hl)^_=jAm6is!&V#7QO4|HIKX{ejxn2`9J07xzkQu!bm5`Z87#7`e7 z@e0j=NxTtoF+ZXVJvvfV)bA7Qfwwfm*kHe&5F|}_=z*4fMm25qsuK@=F3og59Ls45 zZQgCO_a3B?>hOt=PV!mB$fPMduWnwiP(2kJO6^6#5A13pAOK(XYGB-Ot#3+AlOxXs zuvf&Bes7eg0*<0>CmT6qi<%7xLYBup_=i6(%sm;@kYf%m z9JSX~gI2NiP*k-m_B@ z?z&BNA`(B*6|h?l>yX8@;nC5SWl}XTd7*Cx4jw}A#F?|TxI4Qe8dqg$tomG0qeICg3*==yKT zKQ$1d9zL5)`1+Qi*0nM+z!{m^b?L137LdR%C^u;=MBEVzRQ8%x>TdIQW|{8D>pJl6 z?vV6x`#g_ppF+$lr{&MdF>1zu=#1LFk4sZr**UFG>VKyvY zcKR(71=W}e0NdRJV2rBuV;&ug8|}%F&Q8RHESZbVT`Sw{2W%Lg>d1#%->`>V`7cOl z2w2OV^-j_8@xk2MQ5Y_T;mIocWDF{Y_NUR)Lnij#?m{JrPRm|t8P?_fz&k$(f53~9 zrSHtEwX8o`K7()nSalzkA!iwQ<6QkRBOB|BnJ$J0cs5D)G@D``QW-%?GosHoD0D`N zP&jo$XnSHDMZ$A8lHp69W^cQ)4#P+l0UEOrG=ue!P8s@7xJ$ zQUk0@>q%kG}ntk223`5ha$((m~(8Chi4NV)k1Kt%P`s~us}Zo;T7fuj-19);y}4$p~Y)5#Mh zqJzZd+A7};m5l*RqOW*Boip5(OiVkdiHl-6$mGI&ee=Vb5b)7a|M+6n;8CTj?7r+_ z@T+vUUU+Q=KQTx8Hn^au-}`ZZS#lct4ki~Wb(yKhHVKH3m87QA{SYh=*(TE_clG1r zX+EIR_Uc1a%Fa{bOBs6H@P@Mn`u8k|MLJ<`_=<}JuwU1s2MS@X`G*wV=YZZuQz4K{ zS)aqb2YmuQI=HHg($uqRJvna5>`hK!DrVLU(aLj33@PAY*VS3y4OCO+eI+jr#G7PN zyg5zWyzp^^vUFYvCPcK2UUvWDzvm>#BZ=lbmWm%fe|18^N>Td zU(8;iubwlvl!;l`w0bYpxX*ejLtx=+z3eekGz;7qH5j&S2W>=m|@?gcF+M4xp2kluZL#$Y9fN@?4b@un;iB%UyAq zO&F^{icLP+RwoVRvj9|^H6O7g>Gr)*xI^&yfQAE4N9Aj+{HL^|d#wX)q<{%DG5GGo zIxmyU#d(Jmw|_L`z08<%_mfYR&Sd}RXV-ofZ|4E+pnIo1*5pdbKIAOjs$%tA$>VO8 zUU3m|AA6s%vAN)lvSc3_rZN*fan*tYU;{(0z z+D#q=bQw3-WSS>@vj6$U)uAAey2-EHS!Av4nc?JC@w9<#^Y_55w<$5^|L%XVHl6xh7{G@TrEmqyg+)l(TN{;>TQKLyBaeC;14LFAI5sofH5DP zp#GduGmP_(Dx06nc+&6kVFT7Nk)daU2Mb`onLW8ow7n&vM+&zJfH*IY#l3J81Yu0b z3L@lC7ULRvMfknAwdLv+Jx$minAmn+s&ap%+WK(ZWG{7_wwHJs32Q0;`GO-4u-kC$ ze(luj!Z1HvcMdbn-Wa8FxnKDh$1%^|DOBE8M4OOI?q>eIwBOP{nqMO`}p} z4S?VcpqRoM89L`~DkS&P(V$rh_u?b!ux0Sd-K|8*DSxaArVWy&JLc6M`n(iKKvl{> z!iw0-Eo=b);9)xGNf6JVA*1Qh&Hnhk71_MhR`Nos=!pYDwNBkBh~=)82F7yuDV!8E zsBSQ=()+-sZ=Rkt38@6{`i6yjuir2IW-DrsG82s2)2XS3c{K0Z2PU2Ey&K&oVat5m zY5fs?>%4D0sWolVbfzt6wDPN{_;wKI_Cilo>0}jFYRff3RdEW1T41$OCCOkn-DdTy!~&fxlM6+fh!NBciQOJsetR8vIF(z54Y zdk^&AxL6|!jF}cz7x#lmq4X3av%?rzuR~g9B6~!jGz?+gI$r}KjeTRa(}$hwklPMK zR;`sMtd7p=;BAbx*vP#TB!MRX9LCpqhi$-RI3uN%zH}0l@uxW;hA@iL$($c5ZpAvJ zDoozxiYEAFYGNcF6J?FXFG&8}tGx`EX^7pJLU)Tr=GcTrM(^~);#Ad3GwO1c*bVQ? ztvkslatT`oPfGl zKX@*qTKD3#>3#H|*|wQf_AG`ba_xNZXVNP@7t{fxyc3*nYO`Z@)pW0u^PQ=Ha)HE7 z@GKoVr^^))!(My+#dL%E0Le!Db;an1fQ^)R;+i&MtTwiKPMCpXRRA#tQ*jRE^NZ>eN_$+f^$FR&;#1~a}_6mIsd+#OVXnr z&?D7*s7Fou_wTFd0NNGRF8=+1A`hrb^RDMT`~7s1DTe?Pjr7c)tB}8M(+3F9zo7qX zb^7O7@<4_6uNP!Vx1m>_7m<;jcu4xa0M`Iwu7zLw^J*Ay38W&n*L)=|NmOk)X_2BnHrJ8 UY;H5)H}jCGDQPJdDOf!DKSc&#FaQ7m literal 0 HcmV?d00001 From ca664cb0236a05b58737f6a74ed9cb1a0fec5ac9 Mon Sep 17 00:00:00 2001 From: Maicon Santana Date: Tue, 7 Oct 2025 11:00:50 +0100 Subject: [PATCH 094/167] Fix zig compileRaylib target to emscripten (#5239) --- build.zig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build.zig b/build.zig index a8f0df618..031a6824d 100644 --- a/build.zig +++ b/build.zig @@ -386,6 +386,8 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std. setDesktopPlatform(raylib, options.platform); }, .emscripten => { + const activate_emsdk_step = emsdk.zemscripten.activateEmsdkStep(b); + raylib.step.dependOn(activate_emsdk_step); raylib.root_module.addCMacro("PLATFORM_WEB", ""); if (options.opengl_version == .auto) { raylib.root_module.addCMacro("GRAPHICS_API_OPENGL_ES3", ""); From 5dd97ecf2f17d43ca65527b1436c73c845d0e643 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 7 Oct 2025 19:42:05 +0200 Subject: [PATCH 095/167] REVIEWED: `TextToPascal()`, fix https://github.com/raylibtech/rtools/issues/57 --- src/rtext.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/rtext.c b/src/rtext.c index ce9f381c4..6a87fe3db 100644 --- a/src/rtext.c +++ b/src/rtext.c @@ -1954,6 +1954,7 @@ char *TextToPascal(const char *text) { j++; if ((text[j] >= 'a') && (text[j] <= 'z')) buffer[i] = text[j] - 32; + else if ((text[j] >= '0') && (text[j] <= '9')) buffer[i] = text[j]; } } } From 4cfae99a746b60d5747a0e20a16c84a5c4b0d2f6 Mon Sep 17 00:00:00 2001 From: Jopestpe <47086979+Jopestpe@users.noreply.github.com> Date: Tue, 7 Oct 2025 15:25:22 -0300 Subject: [PATCH 096/167] [examples] Added `shapes_triangle_strip` (#5240) * [examples] Add shapes_triangle_strip * Remove functions --- examples/Makefile | 1 + examples/Makefile.Web | 4 + examples/README.md | 5 +- examples/examples_list.txt | 1 + examples/shapes/shapes_triangle_strip.c | 106 ++++++++++++++++++++++ examples/shapes/shapes_triangle_strip.png | Bin 0 -> 12694 bytes 6 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 examples/shapes/shapes_triangle_strip.c create mode 100644 examples/shapes/shapes_triangle_strip.png diff --git a/examples/Makefile b/examples/Makefile index a36b9e447..d5fb730ec 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -564,6 +564,7 @@ SHAPES = \ shapes/shapes_rounded_rectangle_drawing \ shapes/shapes_splines_drawing \ shapes/shapes_top_down_lights \ + shapes/shapes_triangle_strip \ shapes/shapes_vector_angle TEXTURES = \ diff --git a/examples/Makefile.Web b/examples/Makefile.Web index 2d3018abf..c053528b6 100644 --- a/examples/Makefile.Web +++ b/examples/Makefile.Web @@ -564,6 +564,7 @@ SHAPES = \ shapes/shapes_rounded_rectangle_drawing \ shapes/shapes_splines_drawing \ shapes/shapes_top_down_lights \ + shapes/shapes_triangle_strip \ shapes/shapes_vector_angle TEXTURES = \ @@ -884,6 +885,9 @@ shapes/shapes_splines_drawing: shapes/shapes_splines_drawing.c shapes/shapes_top_down_lights: shapes/shapes_top_down_lights.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) +shapes/shapes_triangle_strip: shapes/shapes_triangle_strip.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) + shapes/shapes_vector_angle: shapes/shapes_vector_angle.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) diff --git a/examples/README.md b/examples/README.md index d852e7105..9f6784e65 100644 --- a/examples/README.md +++ b/examples/README.md @@ -17,7 +17,7 @@ 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: 173] +## EXAMPLES COLLECTION [TOTAL: 174] ### category: core [40] @@ -66,7 +66,7 @@ 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) | -### category: shapes [24] +### category: shapes [25] Examples using raylib shapes drawing functionality, provided by raylib [shapes](../src/rshapes.c) module. @@ -95,6 +95,7 @@ Examples using raylib shapes drawing functionality, provided by raylib [shapes]( | [shapes_digital_clock](shapes/shapes_digital_clock.c) | shapes_digital_clock | ⭐⭐⭐⭐️ | 5.5 | 5.6 | [Hamza RAHAL](https://github.com/hmz-rhl) | | [shapes_double_pendulum](shapes/shapes_double_pendulum.c) | shapes_double_pendulum | ⭐⭐☆☆ | 5.5 | 5.5 | [JoeCheong](https://github.com/Joecheong2006) | | [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) | ### category: textures [26] diff --git a/examples/examples_list.txt b/examples/examples_list.txt index 5a0c679a4..879f5707b 100644 --- a/examples/examples_list.txt +++ b/examples/examples_list.txt @@ -70,6 +70,7 @@ shapes;shapes_splines_drawing;★★★☆;5.0;5.0;2023;2025;"Ramon Santamaria"; shapes;shapes_digital_clock;★★★★;5.5;5.6;2025;2025;"Hamza RAHAL";@hmz-rhl shapes;shapes_double_pendulum;★★☆☆;5.5;5.5;2025;2025;"JoeCheong";@Joecheong2006 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 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 diff --git a/examples/shapes/shapes_triangle_strip.c b/examples/shapes/shapes_triangle_strip.c new file mode 100644 index 000000000..ee4556d25 --- /dev/null +++ b/examples/shapes/shapes_triangle_strip.c @@ -0,0 +1,106 @@ +/******************************************************************************************* +* +* raylib [shapes] example - triangle strip +* +* Example complexity rating: [★★☆☆] 2/4 +* +* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev +* +* Example contributed by Jopestpe (@jopestpe) +* +* 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) 2018-2025 Jopestpe (@jopestpe) +* +********************************************************************************************/ + +#include "raylib.h" +#include + +#define RAYGUI_IMPLEMENTATION +#include "raygui.h" // Required for GUI controls + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [shapes] example - triangle strip"); + + Vector2 points[120] = { 0 }; + Vector2 center = { (screenWidth/2.0f) - 125.f, screenHeight/2.0f }; + float segments = 6.0f; + float insideRadius = 100.0f; + float outsideRadius = 150.0f; + bool outline = true; + + 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 + //---------------------------------------------------------------------------------- + int pointCount = (int)(segments); + float angleStep = (360.0f/pointCount)*DEG2RAD; + + for (int i = 0, i2 = 0; i < pointCount; i++, i2 += 2) + { + float angle1 = i*angleStep; + points[i2] = (Vector2){ center.x + cosf(angle1)*insideRadius, center.y + sinf(angle1)*insideRadius }; + float angle2 = angle1 + angleStep/2.0f; + points[i2 + 1] = (Vector2){ center.x + cosf(angle2)*outsideRadius, center.y + sinf(angle2)*outsideRadius }; + } + + points[pointCount*2] = points[0]; + points[pointCount*2 + 1] = points[1]; + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + for (int i = 0, i2 = 0; i < pointCount; i++, i2 += 2) + { + 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); + + 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); + } + + DrawLine(580, 0, 580, GetScreenHeight(), (Color){ 218, 218, 218, 255 }); + DrawRectangle(580, 0, GetScreenWidth(), GetScreenHeight(), (Color){ 232, 232, 232, 255 }); + + // Draw GUI controls + //------------------------------------------------------------------------------ + GuiSliderBar((Rectangle){ 640, 40, 120, 20}, "Segments", TextFormat("%.0f", segments), &segments, 6.0f, 60.f); + GuiCheckBox((Rectangle){ 640, 70, 20, 20 }, "Outline", &outline); + //------------------------------------------------------------------------------ + + DrawFPS(10, 10); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} \ No newline at end of file diff --git a/examples/shapes/shapes_triangle_strip.png b/examples/shapes/shapes_triangle_strip.png new file mode 100644 index 0000000000000000000000000000000000000000..c291a084918ee0a2ae7c9f3ae267cb5716f9f167 GIT binary patch literal 12694 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 literal 0 HcmV?d00001 From 9bf7699624fa0e761e0b82aa9dee3b268304e263 Mon Sep 17 00:00:00 2001 From: Hugo Date: Wed, 8 Oct 2025 00:10:43 +0200 Subject: [PATCH 097/167] [examples] Added `shapes_kaleidoscope` (#5233) * ADDED: example: `shapes_kaleidoscope` * Add line reflection * Updated with `rexm update` * Follow raylib's conventions --- examples/Makefile | 1 + examples/Makefile.Web | 4 + examples/README.md | 7 +- examples/examples_list.txt | 1 + examples/shapes/shapes_kaleidoscope.c | 92 +++ examples/shapes/shapes_kaleidoscope.png | Bin 0 -> 39307 bytes .../examples/shapes_kaleidoscope.vcxproj | 569 ++++++++++++++++++ projects/VS2022/raylib.sln | 99 ++- tools/rexm/examples_report.md | 3 + 9 files changed, 764 insertions(+), 12 deletions(-) create mode 100644 examples/shapes/shapes_kaleidoscope.c create mode 100644 examples/shapes/shapes_kaleidoscope.png create mode 100644 projects/VS2022/examples/shapes_kaleidoscope.vcxproj diff --git a/examples/Makefile b/examples/Makefile index d5fb730ec..6e2853edb 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -554,6 +554,7 @@ SHAPES = \ shapes/shapes_easings_box \ shapes/shapes_easings_rectangles \ shapes/shapes_following_eyes \ + shapes/shapes_kaleidoscope \ shapes/shapes_lines_bezier \ shapes/shapes_logo_raylib \ shapes/shapes_logo_raylib_anim \ diff --git a/examples/Makefile.Web b/examples/Makefile.Web index c053528b6..f1662a301 100644 --- a/examples/Makefile.Web +++ b/examples/Makefile.Web @@ -554,6 +554,7 @@ SHAPES = \ shapes/shapes_easings_box \ shapes/shapes_easings_rectangles \ shapes/shapes_following_eyes \ + shapes/shapes_kaleidoscope \ shapes/shapes_lines_bezier \ shapes/shapes_logo_raylib \ shapes/shapes_logo_raylib_anim \ @@ -855,6 +856,9 @@ shapes/shapes_easings_rectangles: shapes/shapes_easings_rectangles.c shapes/shapes_following_eyes: shapes/shapes_following_eyes.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) +shapes/shapes_kaleidoscope: shapes/shapes_kaleidoscope.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) + shapes/shapes_lines_bezier: shapes/shapes_lines_bezier.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) diff --git a/examples/README.md b/examples/README.md index 9f6784e65..441c5a368 100644 --- a/examples/README.md +++ b/examples/README.md @@ -17,7 +17,7 @@ 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: 174] +## EXAMPLES COLLECTION [TOTAL: 175] ### category: core [40] @@ -66,7 +66,7 @@ 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) | -### category: shapes [25] +### category: shapes [26] Examples using raylib shapes drawing functionality, provided by raylib [shapes](../src/rshapes.c) module. @@ -84,8 +84,8 @@ Examples using raylib shapes drawing functionality, provided by raylib [shapes]( | [shapes_following_eyes](shapes/shapes_following_eyes.c) | shapes_following_eyes | ⭐⭐☆☆ | 2.5 | 2.5 | [Ramon Santamaria](https://github.com/raysan5) | | [shapes_easings_ball](shapes/shapes_easings_ball.c) | shapes_easings_ball | ⭐⭐☆☆ | 2.5 | 2.5 | [Ramon Santamaria](https://github.com/raysan5) | | [shapes_easings_box](shapes/shapes_easings_box.c) | shapes_easings_box | ⭐⭐☆☆ | 2.5 | 2.5 | [Ramon Santamaria](https://github.com/raysan5) | -| [shapes_recursive_tree](shapes/shapes_recursive_tree.c) | shapes_recursive_tree | ⭐⭐⭐☆ | 5.6-dev | 5.6-dev| [Jopestpe](https://github.com/jopestpe) | | [shapes_easings_rectangles](shapes/shapes_easings_rectangles.c) | shapes_easings_rectangles | ⭐⭐⭐☆ | 2.0 | 2.5 | [Ramon Santamaria](https://github.com/raysan5) | +| [shapes_recursive_tree](shapes/shapes_recursive_tree.c) | shapes_recursive_tree | ⭐⭐⭐☆ | 5.6-dev | 5.6-dev | [Jopestpe](https://github.com/jopestpe) | | [shapes_ring_drawing](shapes/shapes_ring_drawing.c) | shapes_ring_drawing | ⭐⭐⭐☆ | 2.5 | 2.5 | [Vlad Adrian](https://github.com/demizdor) | | [shapes_circle_sector_drawing](shapes/shapes_circle_sector_drawing.c) | shapes_circle_sector_drawing | ⭐⭐⭐☆ | 2.5 | 2.5 | [Vlad Adrian](https://github.com/demizdor) | | [shapes_rounded_rectangle_drawing](shapes/shapes_rounded_rectangle_drawing.c) | shapes_rounded_rectangle_drawing | ⭐⭐⭐☆ | 2.5 | 2.5 | [Vlad Adrian](https://github.com/demizdor) | @@ -97,6 +97,7 @@ 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_kaleidoscope](shapes/shapes_kaleidoscope.c) | shapes_kaleidoscope | ⭐⭐☆☆ | 5.5 | 5.6 | [Hugo ARNAL](https://github.com/hugoarnal) | ### category: textures [26] diff --git a/examples/examples_list.txt b/examples/examples_list.txt index 879f5707b..c6f2a97b3 100644 --- a/examples/examples_list.txt +++ b/examples/examples_list.txt @@ -181,3 +181,4 @@ 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 diff --git a/examples/shapes/shapes_kaleidoscope.c b/examples/shapes/shapes_kaleidoscope.c new file mode 100644 index 000000000..07c96344c --- /dev/null +++ b/examples/shapes/shapes_kaleidoscope.c @@ -0,0 +1,92 @@ +/******************************************************************************************* +* +* raylib [shapes] example - kaleidoscope +* +* Example complexity rating: [★★☆☆] 2/4 +* +* Example originally created with raylib 5.5, last time updated with raylib 5.6 +* +* Example contributed by Hugo ARNAL (@hugoarnal) 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 Hugo ARNAL (@hugoarnal) +* +********************************************************************************************/ + +#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 - kaleidoscope"); + + int symmetry = 6; + float angle = 360.0f/(float)symmetry; + float thickness = 3.0f; + Vector2 prevMousePos = { 0 }; + + SetTargetFPS(60); + ClearBackground(BLACK); + + Vector2 offset = { (float)screenWidth/2.0f, (float)screenHeight/2.0f }; + Camera2D camera = { 0 }; + camera.target = (Vector2){ 0 }; + camera.offset = offset; + camera.rotation = 0.0f; + camera.zoom = 1.0f; + + Vector2 scaleVector = { 1.0f, -1.0f }; + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + Vector2 mousePos = GetMousePosition(); + Vector2 lineStart = Vector2Subtract(mousePos, offset); + Vector2 lineEnd = Vector2Subtract(prevMousePos, offset); + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + BeginMode2D(camera); + if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) { + for (int i = 0; i < symmetry; i++) { + lineStart = Vector2Rotate(lineStart, angle*DEG2RAD); + lineEnd = Vector2Rotate(lineEnd, angle*DEG2RAD); + + DrawLineEx(lineStart, lineEnd, thickness, WHITE); + + Vector2 reflectLineStart = Vector2Multiply(lineStart, scaleVector); + Vector2 reflectLineEnd = Vector2Multiply(lineEnd, scaleVector); + + DrawLineEx(reflectLineStart, reflectLineEnd, thickness, WHITE); + } + } + + prevMousePos = mousePos; + EndMode2D(); + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} diff --git a/examples/shapes/shapes_kaleidoscope.png b/examples/shapes/shapes_kaleidoscope.png new file mode 100644 index 0000000000000000000000000000000000000000..d14571ab735c1d50b3dac244566dd5a8c04e4137 GIT binary patch literal 39307 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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 + + + + {6B1A933E-71B8-4C1F-9E79-02D98830E671} + Win32Proj + shapes_kaleidoscope + 10.0 + shapes_kaleidoscope + + + + 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\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + 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 0d7019b61..0c710a731 100644 --- a/projects/VS2022/raylib.sln +++ b/projects/VS2022/raylib.sln @@ -365,6 +365,12 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_monitor_change", "exam EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "web_basic_window", "examples\web_basic_window.vcxproj", "{6B1A933E-71B8-4C1F-9E79-02D98830E671}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_kaleidoscope", "examples\shapes_kaleidoscope.vcxproj", "{6B1A933E-71B8-4C1F-9E79-02D98830E671}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_recursive_tree", "examples\shapes_recursive_tree.vcxproj", "{6B1A933E-71B8-4C1F-9E79-02D98830E671}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_triangle_strip", "examples\shapes_triangle_strip.vcxproj", "{2CCCD9E4-9058-4291-BD89-39C979F0CA1E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug.DLL|ARM64 = Debug.DLL|ARM64 @@ -4507,10 +4513,82 @@ Global {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 - EndGlobalSection + {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 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug|ARM64.Build.0 = Debug|ARM64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug|x64.ActiveCfg = Debug|x64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug|x64.Build.0 = Debug|x64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug|x86.ActiveCfg = Debug|Win32 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug|x86.Build.0 = Debug|Win32 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release|ARM64.ActiveCfg = Release|ARM64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release|ARM64.Build.0 = Release|ARM64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release|x64.ActiveCfg = Release|x64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release|x64.Build.0 = Release|x64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release|x86.ActiveCfg = Release|Win32 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection GlobalSection(NestedProjects) = preSolution {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} = {8716DC0F-4FDE-4F57-8E25-5F78DFB80FE1} {278D8859-20B1-428F-8448-064F46E1F021} = {8716DC0F-4FDE-4F57-8E25-5F78DFB80FE1} @@ -4690,8 +4768,11 @@ Global {2CCCD9E4-9058-4291-BD89-39C979F0CA1E} = {AF5BEC5C-1F2B-4DA8-B12D-D09FE569237C} {9DB1F875-6E65-4195-B23F-ED8095C0B99C} = {5317807F-61D4-4E0F-B6DC-2D9F12621ED9} {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {E926C768-6307-4423-A1EC-57E95B1FAB29} - EndGlobalSection -EndGlobal + {6B1A933E-71B8-4C1F-9E79-02D98830E671} = {278D8859-20B1-428F-8448-064F46E1F021} + {6B1A933E-71B8-4C1F-9E79-02D98830E671} = {278D8859-20B1-428F-8448-064F46E1F021} + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E} = {278D8859-20B1-428F-8448-064F46E1F021} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {E926C768-6307-4423-A1EC-57E95B1FAB29} + EndGlobalSection +EndGlobal diff --git a/tools/rexm/examples_report.md b/tools/rexm/examples_report.md index bf2dbde8b..60da00dd5 100644 --- a/tools/rexm/examples_report.md +++ b/tools/rexm/examples_report.md @@ -73,6 +73,7 @@ Example elements validated: | shapes_easings_ball | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shapes_easings_box | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shapes_easings_rectangles | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| shapes_recursive_tree | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shapes_ring_drawing | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shapes_circle_sector_drawing | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shapes_rounded_rectangle_drawing | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | @@ -82,7 +83,9 @@ Example elements validated: | shapes_digital_clock | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shapes_double_pendulum | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shapes_dashed_line | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| shapes_triangle_strip | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shapes_vector_angle | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| shapes_kaleidoscope | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | textures_logo_raylib | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | textures_srcrec_dstrec | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | textures_image_drawing | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | From 6f584464b6c2314eb5cddce267c49a5414829ab0 Mon Sep 17 00:00:00 2001 From: JohnnyCena123 Date: Wed, 8 Oct 2025 16:04:29 +0300 Subject: [PATCH 098/167] remove duplicate entry from `keyMappingRGFW` (#5242) --- src/platforms/rcore_desktop_rgfw.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/platforms/rcore_desktop_rgfw.c b/src/platforms/rcore_desktop_rgfw.c index f2e2a7407..8c4deeb9a 100644 --- a/src/platforms/rcore_desktop_rgfw.c +++ b/src/platforms/rcore_desktop_rgfw.c @@ -135,7 +135,6 @@ static bool RGFW_disableCursor = false; static const unsigned short keyMappingRGFW[] = { [RGFW_keyNULL] = KEY_NULL, [RGFW_return] = KEY_ENTER, - [RGFW_return] = KEY_ENTER, [RGFW_apostrophe] = KEY_APOSTROPHE, [RGFW_comma] = KEY_COMMA, [RGFW_minus] = KEY_MINUS, From f62565dc726df092e8c136a924f3ecf9abf8b4d9 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 8 Oct 2025 18:16:46 +0200 Subject: [PATCH 099/167] Update text_unicode_ranges.c --- examples/text/text_unicode_ranges.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/text/text_unicode_ranges.c b/examples/text/text_unicode_ranges.c index 473bee64f..2ed25e72f 100644 --- a/examples/text/text_unicode_ranges.c +++ b/examples/text/text_unicode_ranges.c @@ -6,12 +6,12 @@ * * Example originally created with raylib 5.5, last time updated with raylib 5.6 * -* Example contributed by Vlad Adrian (@demizdor) and reviewed by Ramon Santamaria (@raysan5) +* Example contributed by Vadim Gunko (@GuvaCode) 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 Vlad Adrian (@demizdor) and Ramon Santamaria (@raysan5) +* Copyright (c) 2025 Vadim Gunko (@GuvaCode) and Ramon Santamaria (@raysan5) * ********************************************************************************************/ From 04a1a0293e886f396ac89118e3e14979123d727f Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 8 Oct 2025 18:17:32 +0200 Subject: [PATCH 100/167] Update examples_list.txt --- examples/examples_list.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/examples_list.txt b/examples/examples_list.txt index c6f2a97b3..81a61fb97 100644 --- a/examples/examples_list.txt +++ b/examples/examples_list.txt @@ -108,7 +108,7 @@ text;text_input_box;★★☆☆;1.7;3.5;2017;2025;"Ramon Santamaria";@raysan5 text;text_writing_anim;★★☆☆;1.4;1.4;2016;2025;"Ramon Santamaria";@raysan5 text;text_rectangle_bounds;★★★★;2.5;4.0;2018;2025;"Vlad Adrian";@demizdor text;text_unicode_emojis;★★★★;2.5;4.0;2019;2025;"Vlad Adrian";@demizdor -text;text_unicode_ranges;★★★★;5.5;5.6;2025;2025;"Vlad Adrian";@demizdor +text;text_unicode_ranges;★★★★;5.5;5.6;2025;2025;"Vadim Gunko";@GuvaCode text;text_3d_drawing;★★★★;3.5;4.0;2021;2025;"Vlad Adrian";@demizdor text;text_codepoints_loading;★★★☆;4.2;4.2;2022;2025;"Ramon Santamaria";@raysan5 text;text_inline_styling;★★★☆;5.6-dev;5.6-dev;2025;2025;"Wagner Barongello";@SultansOfCode From 767df4cf526b78a64393a790d252bea21b71627c Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 9 Oct 2025 01:09:55 +0200 Subject: [PATCH 101/167] Update core_render_texture.c --- examples/core/core_render_texture.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/core/core_render_texture.c b/examples/core/core_render_texture.c index a48982b3d..974d6f350 100644 --- a/examples/core/core_render_texture.c +++ b/examples/core/core_render_texture.c @@ -65,6 +65,7 @@ int main(void) ClearBackground(SKYBLUE); + DrawRectangle(0, 0, 20, 20, RED); DrawCircleV(ballPosition, (float)ballRadius, MAROON); EndTextureMode(); @@ -75,11 +76,12 @@ int main(void) ClearBackground(RAYWHITE); // Draw our render texture with rotation applied - // NOTE: We set the origin of the texture to the center of the render texture + // 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, (Rectangle){ 0, 0, target.texture.width, -target.texture.height }, - (Rectangle){ screenWidth/2, screenHeight/2, target.texture.width, -target.texture.height }, (Vector2){ target.texture.width/2, target.texture.height/2 }, rotation, WHITE); + (Rectangle){ screenWidth/2, screenHeight/2, target.texture.width, target.texture.height }, DrawText("DRAWING BOUNCING BALL INSIDE RENDER TEXTURE!", 10, screenHeight - 40, 20, BLACK); From 9f831428e6be0eba8762a154e3e9139d4f071970 Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 9 Oct 2025 17:16:54 +0200 Subject: [PATCH 102/167] Update core_render_texture.c --- examples/core/core_render_texture.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/core/core_render_texture.c b/examples/core/core_render_texture.c index 974d6f350..6b2232f23 100644 --- a/examples/core/core_render_texture.c +++ b/examples/core/core_render_texture.c @@ -80,8 +80,8 @@ int main(void) // NOTE 2: We flip vertically the texture setting negative source rectangle height DrawTexturePro(target.texture, (Rectangle){ 0, 0, target.texture.width, -target.texture.height }, + (Rectangle){ screenWidth/2, screenHeight/2, target.texture.width, target.texture.height }, (Vector2){ target.texture.width/2, target.texture.height/2 }, rotation, WHITE); - (Rectangle){ screenWidth/2, screenHeight/2, target.texture.width, target.texture.height }, DrawText("DRAWING BOUNCING BALL INSIDE RENDER TEXTURE!", 10, screenHeight - 40, 20, BLACK); From 2d7b66dd374eb9d9d1b8bab58318ea8f292d7139 Mon Sep 17 00:00:00 2001 From: Thomas Anderson <5776225+CrackedPixel@users.noreply.github.com> Date: Mon, 13 Oct 2025 15:15:20 -0500 Subject: [PATCH 103/167] change free to RL_FREE (#5265) --- src/rcore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rcore.c b/src/rcore.c index b9098db02..dff2c71a9 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -3075,7 +3075,7 @@ unsigned int *ComputeSHA1(unsigned char *data, int dataSize) hash[4] += e; } - free(msg); + RL_FREE(msg); return hash; } From aaf4c1d3aea4d6dafc33cd7333e251774831982a Mon Sep 17 00:00:00 2001 From: Jeffery Myers Date: Tue, 14 Oct 2025 15:18:48 -0700 Subject: [PATCH 104/167] always forward declare the windows stuff, prevents failure of rgfw in GCC. (#5269) --- src/rcore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rcore.c b/src/rcore.c index dff2c71a9..ccc02ab28 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -161,7 +161,7 @@ #endif // Platform specific defines to handle GetApplicationDirectory() -#if (defined(_WIN32) && !defined(PLATFORM_DESKTOP_RGFW)) || (defined(_MSC_VER) && defined(PLATFORM_DESKTOP_RGFW)) +#if (defined(_WIN32)) #ifndef MAX_PATH #define MAX_PATH 1025 #endif From e3a562ab57a9fa4a9dbaa3d5ffb67f31c25a4a36 Mon Sep 17 00:00:00 2001 From: Arrangemonk <34814431+Arrangemonk@users.noreply.github.com> Date: Wed, 15 Oct 2025 19:00:24 +0200 Subject: [PATCH 105/167] UpdateModelAnimation does matrixtranspose(matrixinvert) only once per bone instead of per vertex (#5244) --- src/rmodels.c | 79 +++++++++++++++++++++++++++------------------------ 1 file changed, 42 insertions(+), 37 deletions(-) diff --git a/src/rmodels.c b/src/rmodels.c index 1e7599004..f800ad1b1 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -2352,6 +2352,8 @@ void UpdateModelAnimation(Model model, ModelAnimation anim, int frame) Mesh mesh = model.meshes[m]; Vector3 animVertex = { 0 }; Vector3 animNormal = { 0 }; + Matrix boneMatrix = { 0 }; + Matrix InverseBoneMatrix = { 0 }; int boneId = 0; int boneCounter = 0; float boneWeight = 0.0; @@ -2359,47 +2361,50 @@ void UpdateModelAnimation(Model model, ModelAnimation anim, int frame) const int vValues = mesh.vertexCount*3; // Skip if missing bone data, causes segfault without on some models - if ((mesh.boneWeights == NULL) || (mesh.boneIds == NULL)) continue; + if ((mesh.boneWeights == NULL) || (mesh.boneIds == NULL)) continue; - for (int vCounter = 0; vCounter < vValues; vCounter += 3) - { - mesh.animVertices[vCounter] = 0; - mesh.animVertices[vCounter + 1] = 0; - mesh.animVertices[vCounter + 2] = 0; - if (mesh.animNormals != NULL) - { - mesh.animNormals[vCounter] = 0; - mesh.animNormals[vCounter + 1] = 0; - mesh.animNormals[vCounter + 2] = 0; - } + // Iterates over 4 bones per vertex + for (int j = 0; j < 4; j++, boneCounter++) + { + boneWeight = mesh.boneWeights[boneCounter]; + boneId = mesh.boneIds[boneCounter]; - // Iterates over 4 bones per vertex - for (int j = 0; j < 4; j++, boneCounter++) - { - boneWeight = mesh.boneWeights[boneCounter]; - boneId = mesh.boneIds[boneCounter]; + // Early stop when no transformation will be applied + if (boneWeight == 0.0f) continue; - // Early stop when no transformation will be applied - if (boneWeight == 0.0f) continue; - animVertex = (Vector3){ mesh.vertices[vCounter], mesh.vertices[vCounter + 1], mesh.vertices[vCounter + 2] }; - animVertex = Vector3Transform(animVertex,model.meshes[m].boneMatrices[boneId]); - mesh.animVertices[vCounter] += animVertex.x*boneWeight; - mesh.animVertices[vCounter+1] += animVertex.y*boneWeight; - mesh.animVertices[vCounter+2] += animVertex.z*boneWeight; - updated = true; + boneMatrix = model.meshes[m].boneMatrices[boneId]; + InverseBoneMatrix = MatrixTranspose(MatrixInvert(boneMatrix)); - // Normals processing - // NOTE: We use meshes.baseNormals (default normal) to calculate meshes.normals (animated normals) - if ((mesh.normals != NULL) && (mesh.animNormals != NULL )) - { - animNormal = (Vector3){ mesh.normals[vCounter], mesh.normals[vCounter + 1], mesh.normals[vCounter + 2] }; - animNormal = Vector3Transform(animNormal, MatrixTranspose(MatrixInvert(model.meshes[m].boneMatrices[boneId]))); - mesh.animNormals[vCounter] += animNormal.x*boneWeight; - mesh.animNormals[vCounter + 1] += animNormal.y*boneWeight; - mesh.animNormals[vCounter + 2] += animNormal.z*boneWeight; - } - } - } + for (int vCounter = 0; vCounter < vValues; vCounter += 3) + { + mesh.animVertices[vCounter] = 0; + mesh.animVertices[vCounter + 1] = 0; + mesh.animVertices[vCounter + 2] = 0; + if (mesh.animNormals != NULL) + { + mesh.animNormals[vCounter] = 0; + mesh.animNormals[vCounter + 1] = 0; + mesh.animNormals[vCounter + 2] = 0; + } + animVertex = (Vector3){ mesh.vertices[vCounter], mesh.vertices[vCounter + 1], mesh.vertices[vCounter + 2] }; + animVertex = Vector3Transform(animVertex, boneMatrix); + mesh.animVertices[vCounter] += animVertex.x*boneWeight; + mesh.animVertices[vCounter+1] += animVertex.y*boneWeight; + mesh.animVertices[vCounter+2] += animVertex.z*boneWeight; + updated = true; + + // Normals processing + // NOTE: We use meshes.baseNormals (default normal) to calculate meshes.normals (animated normals) + if ((mesh.normals != NULL) && (mesh.animNormals != NULL)) + { + animNormal = (Vector3){ mesh.normals[vCounter], mesh.normals[vCounter + 1], mesh.normals[vCounter + 2] }; + animNormal = Vector3Transform(animNormal, InverseBoneMatrix); + mesh.animNormals[vCounter] += animNormal.x*boneWeight; + mesh.animNormals[vCounter + 1] += animNormal.y*boneWeight; + mesh.animNormals[vCounter + 2] += animNormal.z*boneWeight; + } + } + } if (updated) { From 7191749d66aca458ac5d8cc0401c2c87331b367a Mon Sep 17 00:00:00 2001 From: Jeffery Myers Date: Wed, 15 Oct 2025 10:02:52 -0700 Subject: [PATCH 106/167] [examples] Fix examples to work in MSVC (#5267) * Fix warnings in many examples Add examples to MSVC solution correctly * fix CI error --------- Co-authored-by: Ray --- examples/audio/audio_sound_positioning.c | 2 +- examples/core/core_3d_camera_fps.c | 8 +- examples/core/core_input_gestures_testbed.c | 66 +- examples/core/core_monitor_change.c | 15 +- examples/core/core_render_texture.c | 6 +- examples/core/core_undo_redo.c | 62 +- examples/models/models_basic_voxel.c | 4 +- .../models/models_geometry_textures_cube.c | 2 +- examples/models/models_tesseract_view.c | 2 +- examples/others/rlgl_compute_shader.c | 2 +- examples/shaders/shaders_basic_pbr.c | 6 +- examples/shaders/shaders_lightmap_rendering.c | 8 +- .../shaders/shaders_normalmap_rendering.c | 2 +- examples/shapes/shapes_bullet_hell.c | 12 +- examples/shapes/shapes_dashed_line.c | 2 +- examples/shapes/shapes_digital_clock.c | 22 +- examples/shapes/shapes_double_pendulum.c | 24 +- examples/shapes/shapes_recursive_tree.c | 4 +- examples/shapes/shapes_vector_angle.c | 12 +- examples/text/text_inline_styling.c | 8 +- examples/text/text_unicode_ranges.c | 6 +- examples/textures/textures_image_channel.c | 10 +- .../VS2022/examples/core_delta_time.vcxproj | 2 +- .../examples/core_monitor_change.vcxproj | 2 +- .../models_geometry_textures_cube.vcxproj | 2 +- .../examples/shaders_ascii_rendering.vcxproj | 2 +- .../examples/shapes_dashed_line.vcxproj | 2 +- .../examples/shapes_digital_clock.vcxproj | 16 +- .../examples/shapes_kaleidoscope.vcxproj | 2 +- .../examples/shapes_recursive_tree.vcxproj | 569 ++++++++++++++++++ .../examples/shapes_triangle_strip.vcxproj | 569 ++++++++++++++++++ .../VS2022/examples/web_basic_window.vcxproj | 2 +- projects/VS2022/raylib.sln | 496 +++++++-------- src/rcore.c | 6 +- 34 files changed, 1550 insertions(+), 405 deletions(-) create mode 100644 projects/VS2022/examples/shapes_recursive_tree.vcxproj create mode 100644 projects/VS2022/examples/shapes_triangle_strip.vcxproj diff --git a/examples/audio/audio_sound_positioning.c b/examples/audio/audio_sound_positioning.c index 69756fa23..4d29954f6 100644 --- a/examples/audio/audio_sound_positioning.c +++ b/examples/audio/audio_sound_positioning.c @@ -60,7 +60,7 @@ int main(void) //---------------------------------------------------------------------------------- UpdateCamera(&camera, CAMERA_FREE); - float th = GetTime(); + float th = (float)GetTime(); Vector3 spherePos = { .x = 5.0f*cosf(th), diff --git a/examples/core/core_3d_camera_fps.c b/examples/core/core_3d_camera_fps.c index c3c779431..7aa79c174 100644 --- a/examples/core/core_3d_camera_fps.c +++ b/examples/core/core_3d_camera_fps.c @@ -198,8 +198,8 @@ void UpdateBody(Body *body, float rot, char side, char forward, bool jumpPressed //PlaySound(fxJump); } - Vector3 front = (Vector3){ sin(rot), 0.f, cos(rot) }; - Vector3 right = (Vector3){ cos(-rot), 0.f, sin(-rot) }; + Vector3 front = (Vector3){ sinf(rot), 0.f, cosf(rot) }; + Vector3 right = (Vector3){ cosf(-rot), 0.f, sinf(-rot) }; Vector3 desiredDir = (Vector3){ input.x*right.x + input.y*front.x, 0.0f, input.x*right.z + input.y*front.z, }; body->dir = Vector3Lerp(body->dir, desiredDir, CONTROL*delta); @@ -267,8 +267,8 @@ static void UpdateCameraFPS(Camera *camera) // Head animation // Rotate up direction around forward axis - float headSin = sin(headTimer*PI); - float headCos = cos(headTimer*PI); + float headSin = sinf(headTimer*PI); + float headCos = cosf(headTimer*PI); const float stepRotation = 0.01f; camera->up = Vector3RotateByAxisAngle(up, pitch, headSin*stepRotation + lean.x); diff --git a/examples/core/core_input_gestures_testbed.c b/examples/core/core_input_gestures_testbed.c index 055240801..dc47136c2 100644 --- a/examples/core/core_input_gestures_testbed.c +++ b/examples/core/core_input_gestures_testbed.c @@ -177,33 +177,33 @@ int main(void) ClearBackground(RAYWHITE); // Draw common elements - DrawText("*", messagePosition.x + 5, messagePosition.y + 5, 10, BLACK); - DrawText("Example optimized for Web/HTML5\non Smartphones with Touch Screen.", messagePosition.x + 15, messagePosition.y + 5, 10, BLACK); - DrawText("*", messagePosition.x + 5, messagePosition.y + 35, 10, BLACK); - DrawText("While running on Desktop Web Browsers,\ninspect and turn on Touch Emulation.", messagePosition.x + 15, messagePosition.y + 35, 10, BLACK); + DrawText("*", (int)messagePosition.x + 5, (int)messagePosition.y + 5, 10, BLACK); + DrawText("Example optimized for Web/HTML5\non Smartphones with Touch Screen.", (int)messagePosition.x + 15, (int)messagePosition.y + 5, 10, BLACK); + DrawText("*", (int)messagePosition.x + 5, (int)messagePosition.y + 35, 10, BLACK); + DrawText("While running on Desktop Web Browsers,\ninspect and turn on Touch Emulation.", (int)messagePosition.x + 15, (int)messagePosition.y + 35, 10, BLACK); // Draw last gesture - DrawText("Last gesture", lastGesturePosition.x + 33, lastGesturePosition.y - 47, 20, BLACK); - DrawText("Swipe Tap Pinch Touch", lastGesturePosition.x + 17, lastGesturePosition.y - 18, 10, BLACK); - DrawRectangle(lastGesturePosition.x + 20, lastGesturePosition.y, 20, 20, lastGesture == GESTURE_SWIPE_UP ? RED : LIGHTGRAY); - DrawRectangle(lastGesturePosition.x, lastGesturePosition.y + 20, 20, 20, lastGesture == GESTURE_SWIPE_LEFT ? RED : LIGHTGRAY); - DrawRectangle(lastGesturePosition.x + 40, lastGesturePosition.y + 20, 20, 20, lastGesture == GESTURE_SWIPE_RIGHT ? RED : LIGHTGRAY); - DrawRectangle(lastGesturePosition.x + 20, lastGesturePosition.y + 40, 20, 20, lastGesture == GESTURE_SWIPE_DOWN ? RED : LIGHTGRAY); - DrawCircle(lastGesturePosition.x + 80, lastGesturePosition.y + 16, 10, lastGesture == GESTURE_TAP ? BLUE : LIGHTGRAY); + DrawText("Last gesture", (int)lastGesturePosition.x + 33, (int)lastGesturePosition.y - 47, 20, BLACK); + DrawText("Swipe Tap Pinch Touch", (int)lastGesturePosition.x + 17, (int)lastGesturePosition.y - 18, 10, BLACK); + DrawRectangle((int)lastGesturePosition.x + 20, (int)lastGesturePosition.y, 20, 20, lastGesture == GESTURE_SWIPE_UP ? RED : LIGHTGRAY); + DrawRectangle((int)lastGesturePosition.x, (int)lastGesturePosition.y + 20, 20, 20, lastGesture == GESTURE_SWIPE_LEFT ? RED : LIGHTGRAY); + DrawRectangle((int)lastGesturePosition.x + 40, (int)lastGesturePosition.y + 20, 20, 20, lastGesture == GESTURE_SWIPE_RIGHT ? RED : LIGHTGRAY); + DrawRectangle((int)lastGesturePosition.x + 20, (int)lastGesturePosition.y + 40, 20, 20, lastGesture == GESTURE_SWIPE_DOWN ? RED : LIGHTGRAY); + DrawCircle((int)lastGesturePosition.x + 80, (int)lastGesturePosition.y + 16, 10, lastGesture == GESTURE_TAP ? BLUE : LIGHTGRAY); DrawRing( (Vector2){lastGesturePosition.x + 103, lastGesturePosition.y + 16}, 6.0f, 11.0f, 0.0f, 360.0f, 0, lastGesture == GESTURE_DRAG ? LIME : LIGHTGRAY); - DrawCircle(lastGesturePosition.x + 80, lastGesturePosition.y + 43, 10, lastGesture == GESTURE_DOUBLETAP ? SKYBLUE : LIGHTGRAY); - DrawCircle(lastGesturePosition.x + 103, lastGesturePosition.y + 43, 10, lastGesture == GESTURE_DOUBLETAP ? SKYBLUE : LIGHTGRAY); - DrawTriangle((Vector2){ lastGesturePosition.x + 122, lastGesturePosition.y + 16 }, (Vector2){ lastGesturePosition.x + 137, lastGesturePosition.y + 26 }, (Vector2){ lastGesturePosition.x + 137, lastGesturePosition.y + 6 }, lastGesture == GESTURE_PINCH_OUT? ORANGE : LIGHTGRAY); + DrawCircle((int)lastGesturePosition.x + 80, (int)lastGesturePosition.y + 43, 10, lastGesture == GESTURE_DOUBLETAP ? SKYBLUE : LIGHTGRAY); + DrawCircle((int)lastGesturePosition.x + 103, (int)lastGesturePosition.y + 43, 10, lastGesture == GESTURE_DOUBLETAP ? SKYBLUE : LIGHTGRAY); + DrawTriangle((Vector2){ lastGesturePosition.x + 122, lastGesturePosition.y + 16 }, (Vector2){ lastGesturePosition.x + 137, lastGesturePosition.y + 26 }, (Vector2){lastGesturePosition.x + 137, lastGesturePosition.y + 6 }, lastGesture == GESTURE_PINCH_OUT? ORANGE : LIGHTGRAY); DrawTriangle((Vector2){ lastGesturePosition.x + 147, lastGesturePosition.y + 6 }, (Vector2){ lastGesturePosition.x + 147, lastGesturePosition.y + 26 }, (Vector2){ lastGesturePosition.x + 162, lastGesturePosition.y + 16 }, lastGesture == GESTURE_PINCH_OUT? ORANGE : LIGHTGRAY); DrawTriangle((Vector2){ lastGesturePosition.x + 125, lastGesturePosition.y + 33 }, (Vector2){ lastGesturePosition.x + 125, lastGesturePosition.y + 53 }, (Vector2){ lastGesturePosition.x + 140, lastGesturePosition.y + 43 }, lastGesture == GESTURE_PINCH_IN? VIOLET : LIGHTGRAY); DrawTriangle((Vector2){ lastGesturePosition.x + 144, lastGesturePosition.y + 43 }, (Vector2){ lastGesturePosition.x + 159, lastGesturePosition.y + 53 }, (Vector2){ lastGesturePosition.x + 159, lastGesturePosition.y + 33 }, lastGesture == GESTURE_PINCH_IN? VIOLET : LIGHTGRAY); - for (i = 0; i < 4; i++) DrawCircle(lastGesturePosition.x + 180, lastGesturePosition.y + 7 + i*15, 5, touchCount <= i? LIGHTGRAY : gestureColor); + for (i = 0; i < 4; i++) DrawCircle((int)lastGesturePosition.x + 180, (int)lastGesturePosition.y + 7 + i*15, 5, touchCount <= i? LIGHTGRAY : gestureColor); // Draw gesture log - DrawText("Log", gestureLogPosition.x, gestureLogPosition.y, 20, BLACK); + DrawText("Log", (int)gestureLogPosition.x, (int)gestureLogPosition.y, 20, BLACK); // Loop in both directions to print the gesture log array in the inverted order (and looping around if the index started somewhere in the middle) - for (i = 0, ii = gestureLogIndex; i < GESTURE_LOG_SIZE; i++, ii = (ii + 1) % GESTURE_LOG_SIZE) DrawText(gestureLog[ii], gestureLogPosition.x, gestureLogPosition.y + 410 - i*20, 20, (i == 0 ? gestureColor : LIGHTGRAY)); + for (i = 0, ii = gestureLogIndex; i < GESTURE_LOG_SIZE; i++, ii = (ii + 1) % GESTURE_LOG_SIZE) DrawText(gestureLog[ii], (int)gestureLogPosition.x, (int)gestureLogPosition.y + 410 - i*20, 20, (i == 0 ? gestureColor : LIGHTGRAY)); Color logButton1Color, logButton2Color; switch (logMode) { @@ -213,31 +213,31 @@ int main(void) default: logButton1Color=GRAY; logButton2Color=GRAY; break; } DrawRectangleRec(logButton1, logButton1Color); - DrawText("Hide", logButton1.x + 7, logButton1.y + 3, 10, WHITE); - DrawText("Repeat", logButton1.x + 7, logButton1.y + 13, 10, WHITE); + DrawText("Hide", (int)logButton1.x + 7, (int)logButton1.y + 3, 10, WHITE); + DrawText("Repeat", (int)logButton1.x + 7, (int)logButton1.y + 13, 10, WHITE); DrawRectangleRec(logButton2, logButton2Color); - DrawText("Hide", logButton1.x + 62, logButton1.y + 3, 10, WHITE); - DrawText("Hold", logButton1.x + 62, logButton1.y + 13, 10, WHITE); + DrawText("Hide", (int)logButton1.x + 62, (int)logButton1.y + 3, 10, WHITE); + DrawText("Hold", (int)logButton1.x + 62, (int)logButton1.y + 13, 10, WHITE); // Draw protractor - DrawText("Angle", protractorPosition.x + 55, protractorPosition.y + 76, 10, BLACK); + DrawText("Angle", (int)protractorPosition.x + 55, (int)protractorPosition.y + 76, 10, BLACK); const char *angleString = TextFormat("%f", currentAngleDegrees); const int angleStringDot = TextFindIndex(angleString, "."); const char *angleStringTrim = TextSubtext(angleString, 0, angleStringDot + 3); - DrawText( angleStringTrim, protractorPosition.x + 55, protractorPosition.y + 92, 20, gestureColor); - DrawCircle(protractorPosition.x, protractorPosition.y, 80.0f, WHITE); + DrawText( angleStringTrim, (int)protractorPosition.x + 55, (int)protractorPosition.y + 92, 20, gestureColor); + DrawCircleV(protractorPosition, 80.0f, WHITE); DrawLineEx((Vector2){ protractorPosition.x - 90, protractorPosition.y }, (Vector2){ protractorPosition.x + 90, protractorPosition.y }, 3.0f, LIGHTGRAY); DrawLineEx((Vector2){ protractorPosition.x, protractorPosition.y - 90 }, (Vector2){ protractorPosition.x, protractorPosition.y + 90 }, 3.0f, LIGHTGRAY); DrawLineEx((Vector2){ protractorPosition.x - 80, protractorPosition.y - 45 }, (Vector2){ protractorPosition.x + 80, protractorPosition.y + 45 }, 3.0f, GREEN); DrawLineEx((Vector2){ protractorPosition.x - 80, protractorPosition.y + 45 }, (Vector2){ protractorPosition.x + 80, protractorPosition.y - 45 }, 3.0f, GREEN); - DrawText("0", protractorPosition.x + 96, protractorPosition.y - 9, 20, BLACK); - DrawText("30", protractorPosition.x + 74, protractorPosition.y - 68, 20, BLACK); - DrawText("90", protractorPosition.x - 11, protractorPosition.y - 110, 20, BLACK); - DrawText("150", protractorPosition.x - 100, protractorPosition.y - 68, 20, BLACK); - DrawText("180", protractorPosition.x - 124, protractorPosition.y - 9, 20, BLACK); - DrawText("210", protractorPosition.x - 100, protractorPosition.y + 50, 20, BLACK); - DrawText("270", protractorPosition.x - 18, protractorPosition.y + 92, 20, BLACK); - DrawText("330", protractorPosition.x + 72, protractorPosition.y + 50, 20, BLACK); + DrawText("0", (int)protractorPosition.x + 96, (int)protractorPosition.y - 9, 20, BLACK); + DrawText("30", (int)protractorPosition.x + 74, (int)protractorPosition.y - 68, 20, BLACK); + DrawText("90", (int)protractorPosition.x - 11, (int)protractorPosition.y - 110, 20, BLACK); + DrawText("150", (int)protractorPosition.x - 100, (int)protractorPosition.y - 68, 20, BLACK); + DrawText("180", (int)protractorPosition.x - 124, (int)protractorPosition.y - 9, 20, BLACK); + DrawText("210", (int)protractorPosition.x - 100, (int)protractorPosition.y + 50, 20, BLACK); + DrawText("270", (int)protractorPosition.x - 18, (int)protractorPosition.y + 92, 20, BLACK); + DrawText("330", (int)protractorPosition.x + 72, (int)protractorPosition.y + 50, 20, BLACK); if (currentAngleDegrees != 0.0f) DrawLineEx(protractorPosition, finalVector, 3.0f, gestureColor); // Draw touch and mouse pointer points @@ -251,7 +251,7 @@ int main(void) DrawCircleV(touchPosition[i], 5.0f, gestureColor); } - if (touchCount == 2) DrawLineEx(touchPosition[0], touchPosition[1], ((currentGesture == 512)? 8 : 12), gestureColor); + if (touchCount == 2) DrawLineEx(touchPosition[0], touchPosition[1], ((currentGesture == 512)? 8.0f : 12.0f), gestureColor); } else { diff --git a/examples/core/core_monitor_change.c b/examples/core/core_monitor_change.c index c85b3f633..3286ba22d 100644 --- a/examples/core/core_monitor_change.c +++ b/examples/core/core_monitor_change.c @@ -22,7 +22,7 @@ // Monitor Details typedef struct Monitor { Vector2 position; - char *name; + const char *name; int width; int height; int physicalWidth; @@ -76,10 +76,10 @@ int main(void) GetMonitorPhysicalHeight(i), GetMonitorRefreshRate(i) }; - if (monitors[i].position.x < monitorOffsetX) monitorOffsetX = monitors[i].position.x*-1; + if (monitors[i].position.x < monitorOffsetX) monitorOffsetX = (int)monitors[i].position.x*-1; - const int width = monitors[i].position.x + monitors[i].width; - const int height = monitors[i].position.y + monitors[i].height; + const int width = (int)monitors[i].position.x + monitors[i].width; + const int height = (int)monitors[i].position.y + monitors[i].height; if (maxWidth < width) maxWidth = width; if (maxHeight < height) maxHeight = height; @@ -99,9 +99,8 @@ int main(void) // Get currentMonitorIndex if manually moved currentMonitorIndex = GetCurrentMonitor(); } - const Monitor currentMonitor = monitors[currentMonitorIndex]; - float monitorScale = 0.6; + float monitorScale = 0.6f; if(maxHeight > maxWidth + monitorOffsetX) monitorScale *= ((float)screenHeight/(float)maxHeight); else monitorScale *= ((float)screenWidth/(float)(maxWidth + monitorOffsetX)); @@ -128,7 +127,7 @@ int main(void) }; // Draw monitor name and information inside the rectangle - DrawText(TextFormat("[%i] %s", i, monitors[i].name), rec.x + 10, rec.y + (int)(100*monitorScale), (int)(120*monitorScale), BLUE); + DrawText(TextFormat("[%i] %s", i, monitors[i].name), (int)rec.x + 10, (int)rec.y + (int)(100*monitorScale), (int)(120*monitorScale), BLUE); DrawText( TextFormat("Resolution: [%ipx x %ipx]\nRefreshRate: [%ihz]\nPhysical Size: [%imm x %imm]\nPosition: %3.0f x %3.0f", monitors[i].width, @@ -138,7 +137,7 @@ int main(void) monitors[i].physicalHeight, monitors[i].position.x, monitors[i].position.y - ), rec.x + 10, rec.y + (int)(200*monitorScale), (int)(120*monitorScale), DARKGRAY); + ), (int)rec.x + 10, (int)rec.y + (int)(200*monitorScale), (int)(120*monitorScale), DARKGRAY); // Highlight current monitor if (i == currentMonitorIndex) diff --git a/examples/core/core_render_texture.c b/examples/core/core_render_texture.c index 6b2232f23..47dc66e0f 100644 --- a/examples/core/core_render_texture.c +++ b/examples/core/core_render_texture.c @@ -79,9 +79,9 @@ int main(void) // 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, - (Rectangle){ 0, 0, target.texture.width, -target.texture.height }, - (Rectangle){ screenWidth/2, screenHeight/2, target.texture.width, target.texture.height }, - (Vector2){ target.texture.width/2, target.texture.height/2 }, rotation, WHITE); + (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); diff --git a/examples/core/core_undo_redo.c b/examples/core/core_undo_redo.c index 874f68800..45b19e10f 100644 --- a/examples/core/core_undo_redo.c +++ b/examples/core/core_undo_redo.c @@ -187,42 +187,42 @@ int main(void) if (lastUndoIndex > firstUndoIndex) { for (int i = firstUndoIndex; i < currentUndoIndex; i++) - DrawRectangle(gridPosition.x + states[i].cell.x*GRID_CELL_SIZE, gridPosition.y + states[i].cell.y*GRID_CELL_SIZE, - GRID_CELL_SIZE, GRID_CELL_SIZE, LIGHTGRAY); + DrawRectangleRec((Rectangle){gridPosition.x + states[i].cell.x * GRID_CELL_SIZE, gridPosition.y + states[i].cell.y * GRID_CELL_SIZE, + GRID_CELL_SIZE, GRID_CELL_SIZE }, LIGHTGRAY); } else if (firstUndoIndex > lastUndoIndex) { if ((currentUndoIndex < MAX_UNDO_STATES) && (currentUndoIndex > lastUndoIndex)) { for (int i = firstUndoIndex; i < currentUndoIndex; i++) - DrawRectangle(gridPosition.x + states[i].cell.x*GRID_CELL_SIZE, gridPosition.y + states[i].cell.y*GRID_CELL_SIZE, - GRID_CELL_SIZE, GRID_CELL_SIZE, LIGHTGRAY); + DrawRectangleRec((Rectangle) { gridPosition.x + states[i].cell.x * GRID_CELL_SIZE, gridPosition.y + states[i].cell.y * GRID_CELL_SIZE, + GRID_CELL_SIZE, GRID_CELL_SIZE }, LIGHTGRAY); } else { for (int i = firstUndoIndex; i < MAX_UNDO_STATES; i++) - DrawRectangle(gridPosition.x + states[i].cell.x*GRID_CELL_SIZE, gridPosition.y + states[i].cell.y*GRID_CELL_SIZE, + DrawRectangle((int)gridPosition.x + states[i].cell.x*GRID_CELL_SIZE, (int)gridPosition.y + states[i].cell.y*GRID_CELL_SIZE, GRID_CELL_SIZE, GRID_CELL_SIZE, LIGHTGRAY); for (int i = 0; i < currentUndoIndex; i++) - DrawRectangle(gridPosition.x + states[i].cell.x*GRID_CELL_SIZE, gridPosition.y + states[i].cell.y*GRID_CELL_SIZE, + DrawRectangle((int)gridPosition.x + states[i].cell.x*GRID_CELL_SIZE, (int)gridPosition.y + states[i].cell.y*GRID_CELL_SIZE, GRID_CELL_SIZE, GRID_CELL_SIZE, LIGHTGRAY); } } // Draw game grid for (int y = 0; y <= MAX_GRID_CELLS_Y; y++) - DrawLine(gridPosition.x, gridPosition.y + y*GRID_CELL_SIZE, - gridPosition.x + MAX_GRID_CELLS_X*GRID_CELL_SIZE, gridPosition.y + y*GRID_CELL_SIZE, GRAY); + DrawLine((int)gridPosition.x, (int)gridPosition.y + y*GRID_CELL_SIZE, + (int)gridPosition.x + MAX_GRID_CELLS_X*GRID_CELL_SIZE, (int)gridPosition.y + y*GRID_CELL_SIZE, GRAY); for (int x = 0; x <= MAX_GRID_CELLS_X; x++) - DrawLine(gridPosition.x + x*GRID_CELL_SIZE, gridPosition.y, - gridPosition.x + x*GRID_CELL_SIZE, gridPosition.y + MAX_GRID_CELLS_Y*GRID_CELL_SIZE, GRAY); + DrawLine((int)gridPosition.x + x*GRID_CELL_SIZE, (int)gridPosition.y, + (int)gridPosition.x + x*GRID_CELL_SIZE, (int)gridPosition.y + MAX_GRID_CELLS_Y*GRID_CELL_SIZE, GRAY); // Draw player - DrawRectangle(gridPosition.x + player.cell.x*GRID_CELL_SIZE, gridPosition.y + player.cell.y*GRID_CELL_SIZE, + DrawRectangle((int)gridPosition.x + player.cell.x*GRID_CELL_SIZE, (int)gridPosition.y + player.cell.y*GRID_CELL_SIZE, GRID_CELL_SIZE + 1, GRID_CELL_SIZE + 1, player.color); // Draw undo system buffer info - DrawText("UNDO STATES:", undoInfoPos.x - 85, undoInfoPos.y + 9, 10, DARKGRAY); + DrawText("UNDO STATES:", (int)undoInfoPos.x - 85, (int)undoInfoPos.y + 9, 10, DARKGRAY); DrawUndoBuffer(undoInfoPos, firstUndoIndex, lastUndoIndex, currentUndoIndex, 24); EndDrawing(); @@ -247,15 +247,15 @@ int main(void) static void DrawUndoBuffer(Vector2 position, int firstUndoIndex, int lastUndoIndex, int currentUndoIndex, int slotSize) { // Draw index marks - DrawRectangle(position.x + 8 + slotSize*currentUndoIndex, position.y - 10, 8, 8, RED); - DrawRectangleLines(position.x + 2 + slotSize*firstUndoIndex, position.y + 27, 8, 8, BLACK); - DrawRectangle(position.x + 14 + slotSize*lastUndoIndex, position.y + 27, 8, 8, BLACK); + DrawRectangle((int)position.x + 8 + slotSize*currentUndoIndex, (int)position.y - 10, 8, 8, RED); + DrawRectangleLines((int)position.x + 2 + slotSize*firstUndoIndex, (int)position.y + 27, 8, 8, BLACK); + DrawRectangle((int)position.x + 14 + slotSize*lastUndoIndex, (int)position.y + 27, 8, 8, BLACK); // Draw background gray slots for (int i = 0; i < MAX_UNDO_STATES; i++) { - DrawRectangle(position.x + slotSize*i, position.y, slotSize, slotSize, LIGHTGRAY); - DrawRectangleLines(position.x + slotSize*i, position.y, slotSize, slotSize, GRAY); + DrawRectangle((int)position.x + slotSize*i, (int)position.y, slotSize, slotSize, LIGHTGRAY); + DrawRectangleLines((int)position.x + slotSize*i, (int)position.y, slotSize, slotSize, GRAY); } // Draw occupied slots: firstUndoIndex --> lastUndoIndex @@ -263,22 +263,22 @@ static void DrawUndoBuffer(Vector2 position, int firstUndoIndex, int lastUndoInd { for (int i = firstUndoIndex; i < lastUndoIndex + 1; i++) { - DrawRectangle(position.x + slotSize*i, position.y, slotSize, slotSize, SKYBLUE); - DrawRectangleLines(position.x + slotSize*i, position.y, slotSize, slotSize, BLUE); + DrawRectangle((int)position.x + slotSize*i, (int)position.y, slotSize, slotSize, SKYBLUE); + DrawRectangleLines((int)position.x + slotSize*i, (int)position.y, slotSize, slotSize, BLUE); } } else if (lastUndoIndex < firstUndoIndex) { for (int i = firstUndoIndex; i < MAX_UNDO_STATES; i++) { - DrawRectangle(position.x + slotSize*i, position.y, slotSize, slotSize, SKYBLUE); - DrawRectangleLines(position.x + slotSize*i, position.y, slotSize, slotSize, BLUE); + DrawRectangle((int)position.x + slotSize*i, (int)position.y, slotSize, slotSize, SKYBLUE); + DrawRectangleLines((int)position.x + slotSize*i, (int)position.y, slotSize, slotSize, BLUE); } for (int i = 0; i < lastUndoIndex + 1; i++) { - DrawRectangle(position.x + slotSize*i, position.y, slotSize, slotSize, SKYBLUE); - DrawRectangleLines(position.x + slotSize*i, position.y, slotSize, slotSize, BLUE); + DrawRectangle((int)position.x + slotSize*i, (int)position.y, slotSize, slotSize, SKYBLUE); + DrawRectangleLines((int)position.x + slotSize*i, (int)position.y, slotSize, slotSize, BLUE); } } @@ -287,26 +287,26 @@ static void DrawUndoBuffer(Vector2 position, int firstUndoIndex, int lastUndoInd { for (int i = firstUndoIndex; i < currentUndoIndex; i++) { - DrawRectangle(position.x + slotSize*i, position.y, slotSize, slotSize, GREEN); - DrawRectangleLines(position.x + slotSize*i, position.y, slotSize, slotSize, LIME); + DrawRectangle((int)position.x + slotSize*i, (int)position.y, slotSize, slotSize, GREEN); + DrawRectangleLines((int)position.x + slotSize*i, (int)position.y, slotSize, slotSize, LIME); } } else if (currentUndoIndex < firstUndoIndex) { for (int i = firstUndoIndex; i < MAX_UNDO_STATES; i++) { - DrawRectangle(position.x + slotSize*i, position.y, slotSize, slotSize, GREEN); - DrawRectangleLines(position.x + slotSize*i, position.y, slotSize, slotSize, LIME); + DrawRectangle((int)position.x + slotSize*i, (int)position.y, slotSize, slotSize, GREEN); + DrawRectangleLines((int)position.x + slotSize*i, (int)position.y, slotSize, slotSize, LIME); } for (int i = 0; i < currentUndoIndex; i++) { - DrawRectangle(position.x + slotSize*i, position.y, slotSize, slotSize, GREEN); - DrawRectangleLines(position.x + slotSize*i, position.y, slotSize, slotSize, LIME); + DrawRectangle((int)position.x + slotSize*i, (int)position.y, slotSize, slotSize, GREEN); + DrawRectangleLines((int)position.x + slotSize*i, (int)position.y, slotSize, slotSize, LIME); } } // Draw current selected UNDO slot - DrawRectangle(position.x + slotSize*currentUndoIndex, position.y, slotSize, slotSize, GOLD); - DrawRectangleLines(position.x + slotSize*currentUndoIndex, position.y, slotSize, slotSize, ORANGE); + DrawRectangle((int)position.x + slotSize*currentUndoIndex, (int)position.y, slotSize, slotSize, GOLD); + DrawRectangleLines((int)position.x + slotSize*currentUndoIndex, (int)position.y, slotSize, slotSize, ORANGE); } diff --git a/examples/models/models_basic_voxel.c b/examples/models/models_basic_voxel.c index 8df15d73d..a70da1822 100644 --- a/examples/models/models_basic_voxel.c +++ b/examples/models/models_basic_voxel.c @@ -88,7 +88,7 @@ int main(void) if (!voxels[x][y][z]) continue; // Skip empty voxels // Build a bounding box for this voxel - Vector3 position = { x, y, z }; + Vector3 position = { (float)x, (float)y, (float)z }; BoundingBox box = { (Vector3){ position.x - 0.5f, position.y - 0.5f, position.z - 0.5f }, (Vector3){ position.x + 0.5f, position.y + 0.5f, position.z + 0.5f } @@ -126,7 +126,7 @@ int main(void) { if (!voxels[x][y][z]) continue; - Vector3 position = { x, y, z }; + Vector3 position = { (float)x, (float)y, (float)z }; DrawModel(cubeModel, position, 1.0f, BEIGE); DrawCubeWires(position, 1.0f, 1.0f, 1.0f, BLACK); } diff --git a/examples/models/models_geometry_textures_cube.c b/examples/models/models_geometry_textures_cube.c index f8236f36d..9441c7fd4 100644 --- a/examples/models/models_geometry_textures_cube.c +++ b/examples/models/models_geometry_textures_cube.c @@ -40,7 +40,7 @@ int main(void) // Load image to create texture for the cube Model model = LoadModelFromMesh(GenMeshCube(1.0f, 1.0f, 1.0f)); Image img = LoadImage("resources/cubicmap_atlas.png"); - Image crop = ImageFromImage(img, (Rectangle){0, img.height/2, img.width/2, img.height/2}); + Image crop = ImageFromImage(img, (Rectangle){0, img.height/2.0f, img.width/2.0f, img.height/2.0f}); Texture2D texture = LoadTextureFromImage(crop); UnloadImage(img); UnloadImage(crop); diff --git a/examples/models/models_tesseract_view.c b/examples/models/models_tesseract_view.c index 97a02ca8e..1544873fb 100644 --- a/examples/models/models_tesseract_view.c +++ b/examples/models/models_tesseract_view.c @@ -65,7 +65,7 @@ int main(void) { // Update //---------------------------------------------------------------------------------- - rotation = DEG2RAD*45.0f*GetTime(); + rotation = DEG2RAD*45.0f*(float)GetTime(); for (int i = 0; i < 16; i++) { diff --git a/examples/others/rlgl_compute_shader.c b/examples/others/rlgl_compute_shader.c index 4704b4a7c..14a2b32cd 100644 --- a/examples/others/rlgl_compute_shader.c +++ b/examples/others/rlgl_compute_shader.c @@ -59,7 +59,7 @@ int main(void) InitWindow(screenWidth, screenHeight, "raylib [others] example - compute shader"); - const Vector2 resolution = { screenWidth, screenHeight }; + const Vector2 resolution = { (float)screenWidth, (float)screenHeight }; unsigned int brushSize = 8; // Game of Life logic compute shader diff --git a/examples/shaders/shaders_basic_pbr.c b/examples/shaders/shaders_basic_pbr.c index 75dacd5aa..6fb15a607 100644 --- a/examples/shaders/shaders_basic_pbr.c +++ b/examples/shaders/shaders_basic_pbr.c @@ -252,7 +252,11 @@ int main() // Draw spheres to show the lights positions for (int i = 0; i < MAX_LIGHTS; i++) { - Color lightColor = (Color){ lights[i].color[0]*255, lights[i].color[1]*255, lights[i].color[2]*255, lights[i].color[3]*255 }; + Color lightColor = (Color){ + (unsigned char)(lights[i].color[0]*255), + (unsigned char)(lights[i].color[1] * 255), + (unsigned char)(lights[i].color[2] * 255), + (unsigned char)(lights[i].color[3] * 255) }; if (lights[i].enabled) DrawSphereEx(lights[i].position, 0.2f, 8, 8, lightColor); else DrawSphereWires(lights[i].position, 0.2f, 8, 8, ColorAlpha(lightColor, 0.3f)); diff --git a/examples/shaders/shaders_lightmap_rendering.c b/examples/shaders/shaders_lightmap_rendering.c index 232e0901b..e269aada2 100644 --- a/examples/shaders/shaders_lightmap_rendering.c +++ b/examples/shaders/shaders_lightmap_rendering.c @@ -102,7 +102,7 @@ int main(void) BeginBlendMode(BLEND_ADDITIVE); DrawTexturePro( light, - (Rectangle){ 0, 0, light.width, light.height }, + (Rectangle){ 0, 0, (float)light.width, (float)light.height }, (Rectangle){ 0, 0, 20, 20 }, (Vector2){ 10.0, 10.0 }, 0.0, @@ -110,7 +110,7 @@ int main(void) ); DrawTexturePro( light, - (Rectangle){ 0, 0, light.width, light.height }, + (Rectangle){ 0, 0, (float)light.width, (float)light.height }, (Rectangle){ 8, 4, 20, 20 }, (Vector2){ 10.0, 10.0 }, 0.0, @@ -118,7 +118,7 @@ int main(void) ); DrawTexturePro( light, - (Rectangle){ 0, 0, light.width, light.height }, + (Rectangle){ 0, 0, (float)light.width, (float)light.height }, (Rectangle){ 8, 8, 10, 10 }, (Vector2){ 5.0, 5.0 }, 0.0, @@ -152,7 +152,7 @@ int main(void) DrawTexturePro( lightmap.texture, (Rectangle){ 0, 0, -MAP_SIZE, -MAP_SIZE }, - (Rectangle){ GetRenderWidth() - MAP_SIZE*8 - 10, 10, MAP_SIZE*8, MAP_SIZE*8 }, + (Rectangle){ (float)GetRenderWidth() - MAP_SIZE*8 - 10, 10, (float)MAP_SIZE*8, (float)MAP_SIZE*8 }, (Vector2){ 0.0, 0.0 }, 0.0, WHITE); diff --git a/examples/shaders/shaders_normalmap_rendering.c b/examples/shaders/shaders_normalmap_rendering.c index e66362c07..4859ec813 100644 --- a/examples/shaders/shaders_normalmap_rendering.c +++ b/examples/shaders/shaders_normalmap_rendering.c @@ -113,7 +113,7 @@ int main(void) if (IsKeyPressed(KEY_N)) useNormalMap = !useNormalMap; // Spin plane model at a constant rate - plane.transform = MatrixRotateY(GetTime()*0.5f); + plane.transform = MatrixRotateY((float)GetTime()*0.5f); // Update shader values float lightPos[3] = {lightPosition.x, lightPosition.y, lightPosition.z}; diff --git a/examples/shapes/shapes_bullet_hell.c b/examples/shapes/shapes_bullet_hell.c index 8eaddfbfe..235df4d16 100644 --- a/examples/shapes/shapes_bullet_hell.c +++ b/examples/shapes/shapes_bullet_hell.c @@ -68,8 +68,8 @@ int main(void) // Draw circle to bullet texture, then draw bullet using DrawTexture() // NOTE: This is done to improve the performance, since DrawCircle() is very slow BeginTextureMode(bulletTexture); - DrawCircle(12, 12, bulletRadius, WHITE); - DrawCircleLines(12, 12, bulletRadius, BLACK); + DrawCircle(12, 12, (float)bulletRadius, WHITE); + DrawCircleLines(12, 12, (float)bulletRadius, BLACK); EndTextureMode(); bool drawInPerformanceMode = true; // Switch between DrawCircle() and DrawTexture() @@ -192,8 +192,8 @@ int main(void) if (!bullets[i].disabled) { DrawTexture(bulletTexture.texture, - bullets[i].position.x - bulletTexture.texture.width*0.5f, - bullets[i].position.y - bulletTexture.texture.height*0.5f, + (int)(bullets[i].position.x - bulletTexture.texture.width*0.5f), + (int)(bullets[i].position.y - bulletTexture.texture.height*0.5f), bullets[i].color); } } @@ -206,8 +206,8 @@ int main(void) // Do not draw disabled bullets (out of screen) if (!bullets[i].disabled) { - DrawCircleV(bullets[i].position, bulletRadius, bullets[i].color); - DrawCircleLinesV(bullets[i].position, bulletRadius, BLACK); + DrawCircleV(bullets[i].position, (float)bulletRadius, bullets[i].color); + DrawCircleLinesV(bullets[i].position, (float)bulletRadius, BLACK); } } } diff --git a/examples/shapes/shapes_dashed_line.c b/examples/shapes/shapes_dashed_line.c index 7a6bf3eee..2a11bf64a 100644 --- a/examples/shapes/shapes_dashed_line.c +++ b/examples/shapes/shapes_dashed_line.c @@ -68,7 +68,7 @@ int main(void) ClearBackground(RAYWHITE); // Draw the dashed line with the current properties - DrawLineDashed(lineStartPosition, lineEndPosition, dashLength, blankLength, lineColors[colorIndex]); + DrawLineDashed(lineStartPosition, lineEndPosition, (int)dashLength, (int)blankLength, lineColors[colorIndex]); // Draw UI and Instructions DrawRectangle(5, 5, 265, 95, Fade(SKYBLUE, 0.5f)); diff --git a/examples/shapes/shapes_digital_clock.c b/examples/shapes/shapes_digital_clock.c index 3317202b8..77b020704 100644 --- a/examples/shapes/shapes_digital_clock.c +++ b/examples/shapes/shapes_digital_clock.c @@ -15,6 +15,8 @@ * ********************************************************************************************/ +#define _CRT_SECURE_NO_WARNINGS // Disable some Visual Studio warnings + #include "raylib.h" #include // Required for: cosf(), sinf() @@ -158,7 +160,7 @@ static void UpdateClock(Clock *clock) clock->minute.value = timeinfo->tm_min; clock->hour.value = timeinfo->tm_hour; - clock->hour.angle = (timeinfo->tm_hour%12)*180.0/6.0f; + clock->hour.angle = (timeinfo->tm_hour%12)*180.0f/6.0f; clock->hour.angle += (timeinfo->tm_min%60)*30/60.0f; clock->hour.angle -= 90; @@ -175,8 +177,8 @@ static void UpdateClock(Clock *clock) static void DrawClockAnalog(Clock clock, Vector2 position) { // Draw clock base - DrawCircleV(position, clock.second.length + 40, LIGHTGRAY); - DrawCircleV(position, 12, GRAY); + DrawCircleV(position, clock.second.length + 40.0f, LIGHTGRAY); + DrawCircleV(position, 12.0f, GRAY); // Draw clock minutes/seconds lines for (int i = 0; i < 60; i++) @@ -192,15 +194,15 @@ static void DrawClockAnalog(Clock clock, Vector2 position) } // Draw hand seconds - DrawRectanglePro((Rectangle){ position.x, position.y, clock.second.length, clock.second.thickness }, + DrawRectanglePro((Rectangle){ position.x, position.y, (float)clock.second.length, (float)clock.second.thickness }, (Vector2){ 0.0f, clock.second.thickness/2.0f }, clock.second.angle, clock.second.color); // Draw hand minutes - DrawRectanglePro((Rectangle){ position.x, position.y, clock.minute.length, clock.minute.thickness }, + DrawRectanglePro((Rectangle){ position.x, position.y, (float)clock.minute.length, (float)clock.minute.thickness }, (Vector2){ 0.0f, clock.minute.thickness/2.0f }, clock.minute.angle, clock.minute.color); // Draw hand hours - DrawRectanglePro((Rectangle){ position.x, position.y, clock.hour.length, clock.hour.thickness }, + DrawRectanglePro((Rectangle){ position.x, position.y, (float)clock.hour.length, (float)clock.hour.thickness }, (Vector2){ 0.0f, clock.hour.thickness/2.0f }, clock.hour.angle, clock.hour.color); } @@ -212,14 +214,14 @@ static void DrawClockDigital(Clock clock, Vector2 position) DrawDisplayValue((Vector2){ position.x, position.y }, clock.hour.value/10, RED, Fade(LIGHTGRAY, 0.3f)); DrawDisplayValue((Vector2){ position.x + 120, position.y }, clock.hour.value%10, RED, Fade(LIGHTGRAY, 0.3f)); - DrawCircle(position.x + 240, position.y + 70, 12, (clock.second.value%2)? RED : Fade(LIGHTGRAY, 0.3f)); - DrawCircle(position.x + 240, position.y + 150, 12, (clock.second.value%2)? RED : Fade(LIGHTGRAY, 0.3f)); + DrawCircle((int)position.x + 240, (int)position.y + 70, 12, (clock.second.value%2)? RED : Fade(LIGHTGRAY, 0.3f)); + DrawCircle((int)position.x + 240, (int)position.y + 150, 12, (clock.second.value%2)? RED : Fade(LIGHTGRAY, 0.3f)); DrawDisplayValue((Vector2){ position.x + 260, position.y }, clock.minute.value/10, RED, Fade(LIGHTGRAY, 0.3f)); DrawDisplayValue((Vector2){ position.x + 380, position.y }, clock.minute.value%10, RED, Fade(LIGHTGRAY, 0.3f)); - DrawCircle(position.x + 500, position.y + 70, 12, (clock.second.value%2)? RED : Fade(LIGHTGRAY, 0.3f)); - DrawCircle(position.x + 500, position.y + 150, 12, (clock.second.value%2)? RED : Fade(LIGHTGRAY, 0.3f)); + DrawCircle((int)position.x + 500, (int)position.y + 70, 12, (clock.second.value%2)? RED : Fade(LIGHTGRAY, 0.3f)); + DrawCircle((int)position.x + 500, (int)position.y + 150, 12, (clock.second.value%2)? RED : Fade(LIGHTGRAY, 0.3f)); DrawDisplayValue((Vector2){ position.x + 520, position.y }, clock.second.value/10, RED, Fade(LIGHTGRAY, 0.3f)); DrawDisplayValue((Vector2){ position.x + 640, position.y }, clock.second.value%10, RED, Fade(LIGHTGRAY, 0.3f)); diff --git a/examples/shapes/shapes_double_pendulum.c b/examples/shapes/shapes_double_pendulum.c index 200f9ad7e..4bcac02f9 100644 --- a/examples/shapes/shapes_double_pendulum.c +++ b/examples/shapes/shapes_double_pendulum.c @@ -21,7 +21,7 @@ // Constant for Simulation #define SIMULATION_STEPS 30 -#define G 9.81 +#define G 9.81f //---------------------------------------------------------------------------------- // Module Functions Declaration @@ -43,9 +43,9 @@ int main(void) InitWindow(screenWidth, screenHeight, "raylib [shapes] example - double pendulum"); // Simulation Paramters - float l1 = 15, m1 = 0.2, theta1 = DEG2RAD*170, w1 = 0; - float l2 = 15, m2 = 0.1, theta2 = DEG2RAD*0, w2 = 0; - float lengthScaler = 0.1; + float l1 = 15.0f, m1 = 0.2f, theta1 = DEG2RAD*170, w1 = 0; + float l2 = 15.0f, m2 = 0.1f, theta2 = DEG2RAD*0, w2 = 0; + float lengthScaler = 0.1f; float totalM = m1 + m2; Vector2 previousPosition = CalculateDoublePendulumEndPoint(l1, theta1, l2, theta2); @@ -57,8 +57,8 @@ int main(void) float L2 = l2*lengthScaler; // Draw parameters - int lineThick = 20, trailThick = 2; - float fateAlpha = 0.01; + float lineThick = 20, trailThick = 2; + float fateAlpha = 0.01f; // Create framebuffer RenderTexture2D target = LoadRenderTexture(screenWidth, screenHeight); @@ -129,15 +129,15 @@ int main(void) ClearBackground(BLACK); // Draw trails texture - DrawTextureRec(target.texture, (Rectangle){ 0, 0, target.texture.width, -target.texture.height }, (Vector2){ 0, 0 }, WHITE); + DrawTextureRec(target.texture, (Rectangle){ 0, 0, (float)target.texture.width, (float)-target.texture.height }, (Vector2){ 0, 0 }, WHITE); // Draw double pendulum - DrawRectanglePro((Rectangle){ screenWidth/2, screenHeight/2 - 100, 10*l1, lineThick }, - (Vector2){0, lineThick*0.5}, 90 - RAD2DEG*theta1, RAYWHITE); + DrawRectanglePro((Rectangle){ screenWidth/2.0f, screenHeight/2.0f - 100, 10*l1, lineThick }, + (Vector2){0, lineThick*0.5f}, 90 - RAD2DEG*theta1, RAYWHITE); Vector2 endpoint1 = CalculatePendulumEndPoint(l1, theta1); - DrawRectanglePro((Rectangle){ screenWidth/2 + endpoint1.x, screenHeight/2 - 100 + endpoint1.y, 10*l2, lineThick }, - (Vector2){0, lineThick*0.5}, 90 - RAD2DEG*theta2, RAYWHITE); + DrawRectanglePro((Rectangle){ screenWidth/2.0f + endpoint1.x, screenHeight/2.0f - 100 + endpoint1.y, 10*l2, lineThick }, + (Vector2){0, lineThick*0.5f}, 90 - RAD2DEG*theta2, RAYWHITE); EndDrawing(); //---------------------------------------------------------------------------------- @@ -159,7 +159,7 @@ int main(void) // Calculate pendulum end point static Vector2 CalculatePendulumEndPoint(float l, float theta) { - return (Vector2){ 10*l*sin(theta), 10*l*cos(theta) }; + return (Vector2){ 10*l*sinf(theta), 10*l*cosf(theta) }; } // Calculate double pendulum end point diff --git a/examples/shapes/shapes_recursive_tree.c b/examples/shapes/shapes_recursive_tree.c index 3ec46de4b..7ed02e5c2 100644 --- a/examples/shapes/shapes_recursive_tree.c +++ b/examples/shapes/shapes_recursive_tree.c @@ -48,7 +48,7 @@ int main(void) InitWindow(screenWidth, screenHeight, "raylib [shapes] example - shapes recursive tree"); - Vector2 start = { (screenWidth/2.0f) - 125.0f, screenHeight }; + Vector2 start = { (screenWidth/2.0f) - 125.0f, (float)screenHeight }; float angle = 40.0f; float thick = 1.0f; float treeDepth = 10.0f; @@ -66,7 +66,7 @@ int main(void) //---------------------------------------------------------------------------------- float theta = angle*DEG2RAD; - int maxBranches = (int)(powf(2, (int)(treeDepth))); + int maxBranches = (int)(powf(2, floorf(treeDepth))); Branch branches[1024] = { 0 }; int count = 0; diff --git a/examples/shapes/shapes_vector_angle.c b/examples/shapes/shapes_vector_angle.c index 7de296dcb..b5faf4c78 100644 --- a/examples/shapes/shapes_vector_angle.c +++ b/examples/shapes/shapes_vector_angle.c @@ -30,7 +30,7 @@ int main(void) InitWindow(screenWidth, screenHeight, "raylib [shapes] example - vector angle"); - Vector2 v0 = { screenWidth/2, screenHeight/2 }; + Vector2 v0 = { screenWidth/2.0f, screenHeight/2.0f }; Vector2 v1 = Vector2Add(v0, (Vector2){ 100.0f, 80.0f }); Vector2 v2 = { 0 }; // Updated with mouse position @@ -97,17 +97,17 @@ int main(void) DrawCircleSector(v0, 40.0f, startangle, startangle - angle, 32, Fade(GREEN, 0.6f)); } - DrawText("v0", v0.x, v0.y, 10, DARKGRAY); + DrawText("v0", (int)v0.x, (int)v0.y, 10, DARKGRAY); // If the line from v0 to v1 would overlap the text, move it's position up 10 - if (angleMode == 0 && Vector2Subtract(v0, v1).y > 0.0f) DrawText("v1", v1.x, v1.y-10.0f, 10, DARKGRAY); - if (angleMode == 0 && Vector2Subtract(v0, v1).y < 0.0f) DrawText("v1", v1.x, v1.y, 10, DARKGRAY); + if (angleMode == 0 && Vector2Subtract(v0, v1).y > 0.0f) DrawText("v1", (int)v1.x, (int)v1.y-10, 10, DARKGRAY); + if (angleMode == 0 && Vector2Subtract(v0, v1).y < 0.0f) DrawText("v1", (int)v1.x, (int)v1.y, 10, DARKGRAY); // If angle mode 1, use v1 to emphasize the horizontal line - if (angleMode == 1) DrawText("v1", v0.x + 40.0f, v0.y, 10, DARKGRAY); + if (angleMode == 1) DrawText("v1", (int)v0.x + 40, (int)v0.y, 10, DARKGRAY); // position adjusted by -10 so it isn't hidden by cursor - DrawText("v2", v2.x-10.0f, v2.y-10.0f, 10, DARKGRAY); + DrawText("v2", (int)v2.x-10, (int)v2.y-10, 10, DARKGRAY); DrawText("Press SPACE to change MODE", 460, 10, 20, DARKGRAY); DrawText(TextFormat("ANGLE: %2.2f", angle), 10, 70, 20, LIME); diff --git a/examples/text/text_inline_styling.c b/examples/text/text_inline_styling.c index 865b1c5d0..b221c7e6f 100644 --- a/examples/text/text_inline_styling.c +++ b/examples/text/text_inline_styling.c @@ -86,7 +86,7 @@ int main(void) DrawTextStyled(GetFontDefault(), text, (Vector2){ 100, 220 }, 40.0f, 2.0f, BLACK); textSize = MeasureTextStyled(GetFontDefault(), text, 40.0f, 2.0f); - DrawRectangleLines(100, 220, textSize.x, textSize.y, GREEN); + DrawRectangleLines(100, 220, (int)textSize.x, (int)textSize.y, GREEN); EndDrawing(); //---------------------------------------------------------------------------------- @@ -154,7 +154,7 @@ static void DrawTextStyled(Font font, const char *text, Vector2 position, float // Parse following color char colHexText[9] = { 0 }; - char *textPtr = &text[i]; // Color should start here, let's see... + const char *textPtr = &text[i]; // Color should start here, let's see... int colHexCount = 0; while ((textPtr != NULL) && (textPtr[colHexCount] != '\0') && (textPtr[colHexCount] != ']')) @@ -186,7 +186,7 @@ static void DrawTextStyled(Font font, const char *text, Vector2 position, float else increaseX += ((float)font.glyphs[index].advanceX*scaleFactor + spacing); // Draw background rectangle color (if required) - if (colBack.a > 0) DrawRectangle(position.x + textOffsetX, position.y + textOffsetY - backRecPadding, increaseX, fontSize + 2*backRecPadding, colBack); + if (colBack.a > 0) DrawRectangleRec((Rectangle) { position.x + textOffsetX, position.y + textOffsetY - backRecPadding, increaseX, fontSize + 2 * backRecPadding }, colBack); if ((codepoint != ' ') && (codepoint != '\t')) { @@ -236,7 +236,7 @@ static Vector2 MeasureTextStyled(Font font, const char *text, float fontSize, fl { i += 2; // Skip "[c" or "[b" to start parsing color - char *textPtr = &text[i]; // Color should start here, let's see... + const char *textPtr = &text[i]; // Color should start here, let's see... int colHexCount = 0; while ((textPtr != NULL) && (textPtr[colHexCount] != '\0') && (textPtr[colHexCount] != ']')) diff --git a/examples/text/text_unicode_ranges.c b/examples/text/text_unicode_ranges.c index 2ed25e72f..e54c052b1 100644 --- a/examples/text/text_unicode_ranges.c +++ b/examples/text/text_unicode_ranges.c @@ -144,9 +144,9 @@ int main(void) // Draw font texture scaled to screen float atlasScale = 380.0f/font.texture.width; - DrawRectangle(400, 16, font.texture.width*atlasScale, font.texture.height*atlasScale, BLACK); - DrawTexturePro(font.texture, (Rectangle){ 0, 0, font.texture.width, font.texture.height }, - (Rectangle){ 400, 16, font.texture.width*atlasScale, font.texture.height*atlasScale }, (Vector2){ 0, 0 }, 0.0f, WHITE); + DrawRectangleRec((Rectangle) { 400.0f, 16.0f, font.texture.width* atlasScale, font.texture.height* atlasScale }, BLACK); + DrawTexturePro(font.texture, (Rectangle){ 0, 0, (float)font.texture.width, (float)font.texture.height }, + (Rectangle){ 400.0f, 16.0f, font.texture.width*atlasScale, font.texture.height*atlasScale }, (Vector2){ 0, 0 }, 0.0f, WHITE); DrawRectangleLines(400, 16, 380, 380, RED); DrawText(TextFormat("ATLAS SIZE: %ix%i px (x%02.2f)", font.texture.width, font.texture.height, atlasScale), 20, 380, 20, BLUE); diff --git a/examples/textures/textures_image_channel.c b/examples/textures/textures_image_channel.c index 29622b74d..e512af366 100644 --- a/examples/textures/textures_image_channel.c +++ b/examples/textures/textures_image_channel.c @@ -61,13 +61,13 @@ int main(void) UnloadImage(imageBlue); UnloadImage(backgroundImage); - Rectangle fudesumiRec = {0, 0, fudesumiImage.width, fudesumiImage.height}; + Rectangle fudesumiRec = {0, 0, (float)fudesumiImage.width, (float)fudesumiImage.height}; Rectangle fudesumiPos = {50, 10, fudesumiImage.width*0.8f, fudesumiImage.height*0.8f}; - Rectangle redPos = { 410, 10, fudesumiPos.width/2, fudesumiPos.height/2 }; - Rectangle greenPos = { 600, 10, fudesumiPos.width/2, fudesumiPos.height/2 }; - Rectangle bluePos = { 410, 230, fudesumiPos.width/2, fudesumiPos.height/2 }; - Rectangle alphaPos = { 600, 230, fudesumiPos.width/2, fudesumiPos.height/2 }; + Rectangle redPos = { 410, 10, fudesumiPos.width/2.0f, fudesumiPos.height/2.0f }; + Rectangle greenPos = { 600, 10, fudesumiPos.width/2.0f, fudesumiPos.height/2.0f }; + Rectangle bluePos = { 410, 230, fudesumiPos.width/2.0f, fudesumiPos.height/2.0f }; + Rectangle alphaPos = { 600, 230, fudesumiPos.width/2.0f, fudesumiPos.height/2.0f }; SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- diff --git a/projects/VS2022/examples/core_delta_time.vcxproj b/projects/VS2022/examples/core_delta_time.vcxproj index 3d31afa42..1c488bb6f 100644 --- a/projects/VS2022/examples/core_delta_time.vcxproj +++ b/projects/VS2022/examples/core_delta_time.vcxproj @@ -51,7 +51,7 @@ - {6B1A933E-71B8-4C1F-9E79-02D98830E671} + {19CA0070-B4B2-4394-90B7-D0C259AA35BA} Win32Proj core_delta_time 10.0 diff --git a/projects/VS2022/examples/core_monitor_change.vcxproj b/projects/VS2022/examples/core_monitor_change.vcxproj index e372a68d0..07921bef3 100644 --- a/projects/VS2022/examples/core_monitor_change.vcxproj +++ b/projects/VS2022/examples/core_monitor_change.vcxproj @@ -51,7 +51,7 @@ - {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F} + {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3} Win32Proj core_monitor_change 10.0 diff --git a/projects/VS2022/examples/models_geometry_textures_cube.vcxproj b/projects/VS2022/examples/models_geometry_textures_cube.vcxproj index 5c8452472..77fcd94d4 100644 --- a/projects/VS2022/examples/models_geometry_textures_cube.vcxproj +++ b/projects/VS2022/examples/models_geometry_textures_cube.vcxproj @@ -51,7 +51,7 @@ - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E} + {A4662163-83E7-4309-8CAA-B0BF13655FE6} Win32Proj models_geometry_textures_cube 10.0 diff --git a/projects/VS2022/examples/shaders_ascii_rendering.vcxproj b/projects/VS2022/examples/shaders_ascii_rendering.vcxproj index 49ee10790..0bb37c6d8 100644 --- a/projects/VS2022/examples/shaders_ascii_rendering.vcxproj +++ b/projects/VS2022/examples/shaders_ascii_rendering.vcxproj @@ -51,7 +51,7 @@ - {9DB1F875-6E65-4195-B23F-ED8095C0B99C} + {5F4B766F-DD52-4B53-B6C3-BC7611E17F20} Win32Proj shaders_ascii_rendering 10.0 diff --git a/projects/VS2022/examples/shapes_dashed_line.vcxproj b/projects/VS2022/examples/shapes_dashed_line.vcxproj index 4a4b86ef3..a5d4c3e1a 100644 --- a/projects/VS2022/examples/shapes_dashed_line.vcxproj +++ b/projects/VS2022/examples/shapes_dashed_line.vcxproj @@ -51,7 +51,7 @@ - {6B1A933E-71B8-4C1F-9E79-02D98830E671} + {8E132D5A-2C00-48D0-8747-97E41356F26F} Win32Proj shapes_dashed_line 10.0 diff --git a/projects/VS2022/examples/shapes_digital_clock.vcxproj b/projects/VS2022/examples/shapes_digital_clock.vcxproj index e361eb190..c2a201a12 100644 --- a/projects/VS2022/examples/shapes_digital_clock.vcxproj +++ b/projects/VS2022/examples/shapes_digital_clock.vcxproj @@ -292,7 +292,7 @@ Level3 Disabled - WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNING;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) CompileAsC $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) @@ -309,7 +309,7 @@ Level3 Disabled - WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNING;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) CompileAsC $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) /FS %(AdditionalOptions) @@ -345,7 +345,7 @@ Level3 Disabled - WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNING;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) CompileAsC $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) @@ -366,7 +366,7 @@ Level3 Disabled - WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNING;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) CompileAsC $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) @@ -410,7 +410,7 @@ MaxSpeed true true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + _CRT_SECURE_NO_WARNING;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) CompileAsC true @@ -432,7 +432,7 @@ MaxSpeed true true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + _CRT_SECURE_NO_WARNING;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) CompileAsC true @@ -476,7 +476,7 @@ MaxSpeed true true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + _CRT_SECURE_NO_WARNING;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) CompileAsC true @@ -504,7 +504,7 @@ MaxSpeed true true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + _CRT_SECURE_NO_WARNING;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) CompileAsC true diff --git a/projects/VS2022/examples/shapes_kaleidoscope.vcxproj b/projects/VS2022/examples/shapes_kaleidoscope.vcxproj index 1fe3e7a70..52fa68e53 100644 --- a/projects/VS2022/examples/shapes_kaleidoscope.vcxproj +++ b/projects/VS2022/examples/shapes_kaleidoscope.vcxproj @@ -51,7 +51,7 @@ - {6B1A933E-71B8-4C1F-9E79-02D98830E671} + {0C442799-B09C-4CD1-9538-711B6E85E9BF} Win32Proj shapes_kaleidoscope 10.0 diff --git a/projects/VS2022/examples/shapes_recursive_tree.vcxproj b/projects/VS2022/examples/shapes_recursive_tree.vcxproj new file mode 100644 index 000000000..771860844 --- /dev/null +++ b/projects/VS2022/examples/shapes_recursive_tree.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 + + + + {DFB40A10-F8B7-412A-BCC3-5EE49294D816} + Win32Proj + shapes_recursive_tree + 10.0 + shapes_recursive_tree + + + + 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\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + + + + Level3 + Disabled + _CRT_SECURE_NO_WARNINGS;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 + _CRT_SECURE_NO_WARNINGS;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 + _CRT_SECURE_NO_WARNINGS;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 + _CRT_SECURE_NO_WARNINGS;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 + _CRT_SECURE_NO_WARNINGS;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 + _CRT_SECURE_NO_WARNINGS;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 + _CRT_SECURE_NO_WARNINGS;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 + _CRT_SECURE_NO_WARNINGS;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/shapes_triangle_strip.vcxproj b/projects/VS2022/examples/shapes_triangle_strip.vcxproj new file mode 100644 index 000000000..b128c0ff6 --- /dev/null +++ b/projects/VS2022/examples/shapes_triangle_strip.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 + + + + {BB58A5FB-1A35-4471-86D0-A5189EC541B3} + Win32Proj + shapes_triangle_strip + 10.0 + shapes_triangle_strip + + + + 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\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + 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/web_basic_window.vcxproj b/projects/VS2022/examples/web_basic_window.vcxproj index e36012ac6..6c0c7ab1f 100644 --- a/projects/VS2022/examples/web_basic_window.vcxproj +++ b/projects/VS2022/examples/web_basic_window.vcxproj @@ -51,7 +51,7 @@ - {6B1A933E-71B8-4C1F-9E79-02D98830E671} + {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC} Win32Proj web_basic_window 10.0 diff --git a/projects/VS2022/raylib.sln b/projects/VS2022/raylib.sln index 0c710a731..f72cd64a9 100644 --- a/projects/VS2022/raylib.sln +++ b/projects/VS2022/raylib.sln @@ -347,7 +347,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_undo_redo", "examples\ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_input_actions", "examples\core_input_actions.vcxproj", "{718FCBD0-591D-448C-B7D5-9F1CA8544E7B}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_delta_time", "examples\core_delta_time.vcxproj", "{6B1A933E-71B8-4C1F-9E79-02D98830E671}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_delta_time", "examples\core_delta_time.vcxproj", "{19CA0070-B4B2-4394-90B7-D0C259AA35BA}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_bullet_hell", "examples\shapes_bullet_hell.vcxproj", "{2CCCD9E4-9058-4291-BD89-39C979F0CA1E}" EndProject @@ -355,22 +355,24 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_vector_angle", "exam EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "models_basic_voxel", "examples\models_basic_voxel.vcxproj", "{52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_dashed_line", "examples\shapes_dashed_line.vcxproj", "{6B1A933E-71B8-4C1F-9E79-02D98830E671}" +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", "{2CCCD9E4-9058-4291-BD89-39C979F0CA1E}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "models_geometry_textures_cube", "examples\models_geometry_textures_cube.vcxproj", "{A4662163-83E7-4309-8CAA-B0BF13655FE6}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shaders_ascii_rendering", "examples\shaders_ascii_rendering.vcxproj", "{9DB1F875-6E65-4195-B23F-ED8095C0B99C}" +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", "{52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_monitor_change", "examples\core_monitor_change.vcxproj", "{FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "web_basic_window", "examples\web_basic_window.vcxproj", "{6B1A933E-71B8-4C1F-9E79-02D98830E671}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "web_basic_window", "examples\web_basic_window.vcxproj", "{A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_kaleidoscope", "examples\shapes_kaleidoscope.vcxproj", "{0C442799-B09C-4CD1-9538-711B6E85E9BF}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_recursive_tree", "examples\shapes_recursive_tree.vcxproj", "{DFB40A10-F8B7-412A-BCC3-5EE49294D816}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_triangle_strip", "examples\shapes_triangle_strip.vcxproj", "{BB58A5FB-1A35-4471-86D0-A5189EC541B3}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "web", "web", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_kaleidoscope", "examples\shapes_kaleidoscope.vcxproj", "{6B1A933E-71B8-4C1F-9E79-02D98830E671}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_recursive_tree", "examples\shapes_recursive_tree.vcxproj", "{6B1A933E-71B8-4C1F-9E79-02D98830E671}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_triangle_strip", "examples\shapes_triangle_strip.vcxproj", "{2CCCD9E4-9058-4291-BD89-39C979F0CA1E}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug.DLL|ARM64 = Debug.DLL|ARM64 @@ -4297,30 +4299,30 @@ Global {718FCBD0-591D-448C-B7D5-9F1CA8544E7B}.Release|x64.Build.0 = Release|x64 {718FCBD0-591D-448C-B7D5-9F1CA8544E7B}.Release|x86.ActiveCfg = Release|Win32 {718FCBD0-591D-448C-B7D5-9F1CA8544E7B}.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 + {19CA0070-B4B2-4394-90B7-D0C259AA35BA}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 + {19CA0070-B4B2-4394-90B7-D0C259AA35BA}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 + {19CA0070-B4B2-4394-90B7-D0C259AA35BA}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {19CA0070-B4B2-4394-90B7-D0C259AA35BA}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {19CA0070-B4B2-4394-90B7-D0C259AA35BA}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {19CA0070-B4B2-4394-90B7-D0C259AA35BA}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {19CA0070-B4B2-4394-90B7-D0C259AA35BA}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {19CA0070-B4B2-4394-90B7-D0C259AA35BA}.Debug|ARM64.Build.0 = Debug|ARM64 + {19CA0070-B4B2-4394-90B7-D0C259AA35BA}.Debug|x64.ActiveCfg = Debug|x64 + {19CA0070-B4B2-4394-90B7-D0C259AA35BA}.Debug|x64.Build.0 = Debug|x64 + {19CA0070-B4B2-4394-90B7-D0C259AA35BA}.Debug|x86.ActiveCfg = Debug|Win32 + {19CA0070-B4B2-4394-90B7-D0C259AA35BA}.Debug|x86.Build.0 = Debug|Win32 + {19CA0070-B4B2-4394-90B7-D0C259AA35BA}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 + {19CA0070-B4B2-4394-90B7-D0C259AA35BA}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 + {19CA0070-B4B2-4394-90B7-D0C259AA35BA}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {19CA0070-B4B2-4394-90B7-D0C259AA35BA}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {19CA0070-B4B2-4394-90B7-D0C259AA35BA}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {19CA0070-B4B2-4394-90B7-D0C259AA35BA}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {19CA0070-B4B2-4394-90B7-D0C259AA35BA}.Release|ARM64.ActiveCfg = Release|ARM64 + {19CA0070-B4B2-4394-90B7-D0C259AA35BA}.Release|ARM64.Build.0 = Release|ARM64 + {19CA0070-B4B2-4394-90B7-D0C259AA35BA}.Release|x64.ActiveCfg = Release|x64 + {19CA0070-B4B2-4394-90B7-D0C259AA35BA}.Release|x64.Build.0 = Release|x64 + {19CA0070-B4B2-4394-90B7-D0C259AA35BA}.Release|x86.ActiveCfg = Release|Win32 + {19CA0070-B4B2-4394-90B7-D0C259AA35BA}.Release|x86.Build.0 = Release|Win32 {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 @@ -4393,202 +4395,202 @@ Global {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release|x64.Build.0 = Release|x64 {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release|x86.ActiveCfg = Release|Win32 {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.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 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug|ARM64.Build.0 = Debug|ARM64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug|x64.ActiveCfg = Debug|x64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug|x64.Build.0 = Debug|x64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug|x86.ActiveCfg = Debug|Win32 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug|x86.Build.0 = Debug|Win32 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release.DLL|x64.Build.0 = Release.DLL|x64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release.DLL|x86.Build.0 = Release.DLL|Win32 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release|ARM64.ActiveCfg = Release|ARM64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release|ARM64.Build.0 = Release|ARM64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release|x64.ActiveCfg = Release|x64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release|x64.Build.0 = Release|x64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release|x86.ActiveCfg = Release|Win32 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release|x86.Build.0 = Release|Win32 - {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 - {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 - {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 - {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 - {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 - {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 - {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug|ARM64.Build.0 = Debug|ARM64 - {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug|x64.ActiveCfg = Debug|x64 - {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug|x64.Build.0 = Debug|x64 - {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug|x86.ActiveCfg = Debug|Win32 - {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug|x86.Build.0 = Debug|Win32 - {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 - {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 - {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 - {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release.DLL|x64.Build.0 = Release.DLL|x64 - {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 - {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release.DLL|x86.Build.0 = Release.DLL|Win32 - {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release|ARM64.ActiveCfg = Release|ARM64 - {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release|ARM64.Build.0 = Release|ARM64 - {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release|x64.ActiveCfg = Release|x64 - {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release|x64.Build.0 = Release|x64 - {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release|x86.ActiveCfg = Release|Win32 - {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release|x86.Build.0 = Release|Win32 - {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 - {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 - {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 - {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 - {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 - {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 - {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug|ARM64.Build.0 = Debug|ARM64 - {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug|x64.ActiveCfg = Debug|x64 - {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug|x64.Build.0 = Debug|x64 - {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug|x86.ActiveCfg = Debug|Win32 - {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug|x86.Build.0 = Debug|Win32 - {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 - {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 - {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 - {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release.DLL|x64.Build.0 = Release.DLL|x64 - {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 - {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release.DLL|x86.Build.0 = Release.DLL|Win32 - {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release|ARM64.ActiveCfg = Release|ARM64 - {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release|ARM64.Build.0 = Release|ARM64 - {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release|x64.ActiveCfg = Release|x64 - {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release|x64.Build.0 = Release|x64 - {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release|x86.ActiveCfg = Release|Win32 - {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.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 - {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 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug|ARM64.Build.0 = Debug|ARM64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug|x64.ActiveCfg = Debug|x64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug|x64.Build.0 = Debug|x64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug|x86.ActiveCfg = Debug|Win32 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug|x86.Build.0 = Debug|Win32 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release.DLL|x64.Build.0 = Release.DLL|x64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release.DLL|x86.Build.0 = Release.DLL|Win32 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release|ARM64.ActiveCfg = Release|ARM64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release|ARM64.Build.0 = Release|ARM64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release|x64.ActiveCfg = Release|x64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release|x64.Build.0 = Release|x64 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release|x86.ActiveCfg = Release|Win32 - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release|x86.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection + {8E132D5A-2C00-48D0-8747-97E41356F26F}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 + {8E132D5A-2C00-48D0-8747-97E41356F26F}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 + {8E132D5A-2C00-48D0-8747-97E41356F26F}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {8E132D5A-2C00-48D0-8747-97E41356F26F}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {8E132D5A-2C00-48D0-8747-97E41356F26F}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {8E132D5A-2C00-48D0-8747-97E41356F26F}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {8E132D5A-2C00-48D0-8747-97E41356F26F}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {8E132D5A-2C00-48D0-8747-97E41356F26F}.Debug|ARM64.Build.0 = Debug|ARM64 + {8E132D5A-2C00-48D0-8747-97E41356F26F}.Debug|x64.ActiveCfg = Debug|x64 + {8E132D5A-2C00-48D0-8747-97E41356F26F}.Debug|x64.Build.0 = Debug|x64 + {8E132D5A-2C00-48D0-8747-97E41356F26F}.Debug|x86.ActiveCfg = Debug|Win32 + {8E132D5A-2C00-48D0-8747-97E41356F26F}.Debug|x86.Build.0 = Debug|Win32 + {8E132D5A-2C00-48D0-8747-97E41356F26F}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 + {8E132D5A-2C00-48D0-8747-97E41356F26F}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 + {8E132D5A-2C00-48D0-8747-97E41356F26F}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {8E132D5A-2C00-48D0-8747-97E41356F26F}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {8E132D5A-2C00-48D0-8747-97E41356F26F}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {8E132D5A-2C00-48D0-8747-97E41356F26F}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {8E132D5A-2C00-48D0-8747-97E41356F26F}.Release|ARM64.ActiveCfg = Release|ARM64 + {8E132D5A-2C00-48D0-8747-97E41356F26F}.Release|ARM64.Build.0 = Release|ARM64 + {8E132D5A-2C00-48D0-8747-97E41356F26F}.Release|x64.ActiveCfg = Release|x64 + {8E132D5A-2C00-48D0-8747-97E41356F26F}.Release|x64.Build.0 = Release|x64 + {8E132D5A-2C00-48D0-8747-97E41356F26F}.Release|x86.ActiveCfg = Release|Win32 + {8E132D5A-2C00-48D0-8747-97E41356F26F}.Release|x86.Build.0 = Release|Win32 + {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 + {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 + {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Debug|ARM64.Build.0 = Debug|ARM64 + {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Debug|x64.ActiveCfg = Debug|x64 + {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Debug|x64.Build.0 = Debug|x64 + {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Debug|x86.ActiveCfg = Debug|Win32 + {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Debug|x86.Build.0 = Debug|Win32 + {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 + {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 + {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Release|ARM64.ActiveCfg = Release|ARM64 + {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Release|ARM64.Build.0 = Release|ARM64 + {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Release|x64.ActiveCfg = Release|x64 + {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Release|x64.Build.0 = Release|x64 + {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Release|x86.ActiveCfg = Release|Win32 + {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Release|x86.Build.0 = Release|Win32 + {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 + {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 + {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Debug|ARM64.Build.0 = Debug|ARM64 + {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Debug|x64.ActiveCfg = Debug|x64 + {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Debug|x64.Build.0 = Debug|x64 + {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Debug|x86.ActiveCfg = Debug|Win32 + {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Debug|x86.Build.0 = Debug|Win32 + {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 + {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 + {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Release|ARM64.ActiveCfg = Release|ARM64 + {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Release|ARM64.Build.0 = Release|ARM64 + {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Release|x64.ActiveCfg = Release|x64 + {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Release|x64.Build.0 = Release|x64 + {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Release|x86.ActiveCfg = Release|Win32 + {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Release|x86.Build.0 = Release|Win32 + {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 + {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 + {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Debug|ARM64.Build.0 = Debug|ARM64 + {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Debug|x64.ActiveCfg = Debug|x64 + {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Debug|x64.Build.0 = Debug|x64 + {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Debug|x86.ActiveCfg = Debug|Win32 + {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Debug|x86.Build.0 = Debug|Win32 + {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 + {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 + {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Release|ARM64.ActiveCfg = Release|ARM64 + {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Release|ARM64.Build.0 = Release|ARM64 + {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Release|x64.ActiveCfg = Release|x64 + {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Release|x64.Build.0 = Release|x64 + {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Release|x86.ActiveCfg = Release|Win32 + {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Release|x86.Build.0 = Release|Win32 + {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 + {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 + {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Debug|ARM64.Build.0 = Debug|ARM64 + {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Debug|x64.ActiveCfg = Debug|x64 + {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Debug|x64.Build.0 = Debug|x64 + {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Debug|x86.ActiveCfg = Debug|Win32 + {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Debug|x86.Build.0 = Debug|Win32 + {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 + {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 + {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Release|ARM64.ActiveCfg = Release|ARM64 + {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Release|ARM64.Build.0 = Release|ARM64 + {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Release|x64.ActiveCfg = Release|x64 + {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Release|x64.Build.0 = Release|x64 + {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Release|x86.ActiveCfg = Release|Win32 + {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Release|x86.Build.0 = Release|Win32 + {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 + {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 + {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Debug|ARM64.Build.0 = Debug|ARM64 + {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Debug|x64.ActiveCfg = Debug|x64 + {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Debug|x64.Build.0 = Debug|x64 + {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Debug|x86.ActiveCfg = Debug|Win32 + {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Debug|x86.Build.0 = Debug|Win32 + {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 + {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 + {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Release|ARM64.ActiveCfg = Release|ARM64 + {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Release|ARM64.Build.0 = Release|ARM64 + {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Release|x64.ActiveCfg = Release|x64 + {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Release|x64.Build.0 = Release|x64 + {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Release|x86.ActiveCfg = Release|Win32 + {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Release|x86.Build.0 = Release|Win32 + {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 + {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 + {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Debug|ARM64.Build.0 = Debug|ARM64 + {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Debug|x64.ActiveCfg = Debug|x64 + {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Debug|x64.Build.0 = Debug|x64 + {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Debug|x86.ActiveCfg = Debug|Win32 + {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Debug|x86.Build.0 = Debug|Win32 + {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 + {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 + {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Release|ARM64.ActiveCfg = Release|ARM64 + {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Release|ARM64.Build.0 = Release|ARM64 + {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Release|x64.ActiveCfg = Release|x64 + {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Release|x64.Build.0 = Release|x64 + {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Release|x86.ActiveCfg = Release|Win32 + {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Release|x86.Build.0 = Release|Win32 + {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 + {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 + {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Debug|ARM64.Build.0 = Debug|ARM64 + {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Debug|x64.ActiveCfg = Debug|x64 + {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Debug|x64.Build.0 = Debug|x64 + {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Debug|x86.ActiveCfg = Debug|Win32 + {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Debug|x86.Build.0 = Debug|Win32 + {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 + {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 + {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Release|ARM64.ActiveCfg = Release|ARM64 + {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Release|ARM64.Build.0 = Release|ARM64 + {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Release|x64.ActiveCfg = Release|x64 + {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Release|x64.Build.0 = Release|x64 + {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Release|x86.ActiveCfg = Release|Win32 + {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection GlobalSection(NestedProjects) = preSolution {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} = {8716DC0F-4FDE-4F57-8E25-5F78DFB80FE1} {278D8859-20B1-428F-8448-064F46E1F021} = {8716DC0F-4FDE-4F57-8E25-5F78DFB80FE1} @@ -4752,7 +4754,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} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} + {6B1A933E-71B8-4C1F-9E79-02D98830E671} = {278D8859-20B1-428F-8448-064F46E1F021} {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} @@ -4760,19 +4762,21 @@ Global {D496308F-3C3C-40B3-A3ED-EA327D244B3E} = {8D3C83B7-F1E0-4C2E-9E34-EE5F6AB2502A} {3B27F358-2679-4F38-B297-17B536F580BB} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} {718FCBD0-591D-448C-B7D5-9F1CA8544E7B} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} - {6B1A933E-71B8-4C1F-9E79-02D98830E671} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} + {19CA0070-B4B2-4394-90B7-D0C259AA35BA} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} {2CCCD9E4-9058-4291-BD89-39C979F0CA1E} = {278D8859-20B1-428F-8448-064F46E1F021} - {9DB1F875-6E65-4195-B23F-ED8095C0B99C} = {278D8859-20B1-428F-8448-064F46E1F021} - {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F} = {AF5BEC5C-1F2B-4DA8-B12D-D09FE569237C} - {6B1A933E-71B8-4C1F-9E79-02D98830E671} = {278D8859-20B1-428F-8448-064F46E1F021} - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E} = {AF5BEC5C-1F2B-4DA8-B12D-D09FE569237C} {9DB1F875-6E65-4195-B23F-ED8095C0B99C} = {5317807F-61D4-4E0F-B6DC-2D9F12621ED9} {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} - {6B1A933E-71B8-4C1F-9E79-02D98830E671} = {278D8859-20B1-428F-8448-064F46E1F021} - {6B1A933E-71B8-4C1F-9E79-02D98830E671} = {278D8859-20B1-428F-8448-064F46E1F021} - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E} = {278D8859-20B1-428F-8448-064F46E1F021} - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {E926C768-6307-4423-A1EC-57E95B1FAB29} - EndGlobalSection -EndGlobal + {8E132D5A-2C00-48D0-8747-97E41356F26F} = {278D8859-20B1-428F-8448-064F46E1F021} + {A4662163-83E7-4309-8CAA-B0BF13655FE6} = {AF5BEC5C-1F2B-4DA8-B12D-D09FE569237C} + {5F4B766F-DD52-4B53-B6C3-BC7611E17F20} = {5317807F-61D4-4E0F-B6DC-2D9F12621ED9} + {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} + {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} + {0C442799-B09C-4CD1-9538-711B6E85E9BF} = {278D8859-20B1-428F-8448-064F46E1F021} + {DFB40A10-F8B7-412A-BCC3-5EE49294D816} = {278D8859-20B1-428F-8448-064F46E1F021} + {BB58A5FB-1A35-4471-86D0-A5189EC541B3} = {278D8859-20B1-428F-8448-064F46E1F021} + {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} = {8716DC0F-4FDE-4F57-8E25-5F78DFB80FE1} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {E926C768-6307-4423-A1EC-57E95B1FAB29} + EndGlobalSection +EndGlobal diff --git a/src/rcore.c b/src/rcore.c index ccc02ab28..3b2535250 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -161,10 +161,8 @@ #endif // Platform specific defines to handle GetApplicationDirectory() -#if (defined(_WIN32)) - #ifndef MAX_PATH - #define MAX_PATH 1025 - #endif +#if (defined(_WIN32) && !defined(PLATFORM_DESKTOP_RGFW)) || (defined(_MSC_VER) && defined(PLATFORM_DESKTOP_RGFW)) + struct HINSTANCE__; __declspec(dllimport) unsigned long __stdcall GetModuleFileNameA(struct HINSTANCE__ *hModule, char *lpFilename, unsigned long nSize); __declspec(dllimport) unsigned long __stdcall GetModuleFileNameW(struct HINSTANCE__ *hModule, wchar_t *lpFilename, unsigned long nSize); From 17bc628fd9a290cc54c5aaf2a8ce74ec56569a27 Mon Sep 17 00:00:00 2001 From: JohnnyCena123 Date: Wed, 15 Oct 2025 20:07:41 +0300 Subject: [PATCH 107/167] [rcore] Add `ComputeSHA256()` function (#5264) * [rcore] Add `ComputeSHA256()` function * adjust function signatures * review issues * fix repeating 0 * fix mistake * fixed macro * remove undefs * review styling mismatches * rename `A0,1` to `SHA256_A0,1` --------- Co-authored-by: CrackedPixel <5776225+CrackedPixel@users.noreply.github.com> --- src/raylib.h | 7 ++-- src/rcore.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+), 3 deletions(-) diff --git a/src/raylib.h b/src/raylib.h index c57efc2e1..e4be11084 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1161,9 +1161,10 @@ RLAPI unsigned char *CompressData(const unsigned char *data, int dataSize, int * RLAPI unsigned char *DecompressData(const unsigned char *compData, int compDataSize, int *dataSize); // Decompress data (DEFLATE algorithm), memory must be MemFree() RLAPI char *EncodeDataBase64(const unsigned char *data, int dataSize, int *outputSize); // Encode data to Base64 string (includes NULL terminator), memory must be MemFree() RLAPI unsigned char *DecodeDataBase64(const char *text, int *outputSize); // Decode Base64 string (expected NULL terminated), memory must be MemFree() -RLAPI unsigned int ComputeCRC32(unsigned char *data, int dataSize); // Compute CRC32 hash code -RLAPI unsigned int *ComputeMD5(unsigned char *data, int dataSize); // Compute MD5 hash code, returns static int[4] (16 bytes) -RLAPI unsigned int *ComputeSHA1(unsigned char *data, int dataSize); // Compute SHA1 hash code, returns static int[5] (20 bytes) +RLAPI unsigned int ComputeCRC32(unsigned char *data, int dataSize); // Compute CRC32 hash code +RLAPI unsigned int *ComputeMD5(unsigned char *data, int dataSize); // Compute MD5 hash code, returns static int[4] (16 bytes) +RLAPI unsigned int *ComputeSHA1(unsigned char *data, int dataSize); // Compute SHA1 hash code, returns static int[5] (20 bytes) +RLAPI unsigned int *ComputeSHA256(unsigned char *data, int dataSize); // Compute SHA256 hash code, returns static int[8] (32 bytes) // Automation events functionality RLAPI AutomationEventList LoadAutomationEventList(const char *fileName); // Load automation events list from file, NULL for empty list, capacity = MAX_AUTOMATION_EVENTS diff --git a/src/rcore.c b/src/rcore.c index 3b2535250..f1c975c21 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -3078,6 +3078,108 @@ unsigned int *ComputeSHA1(unsigned char *data, int dataSize) return hash; } +// Compute SHA-256 hash code +// NOTE: Returns a static int[8] array (32 bytes) +unsigned int *ComputeSHA256(unsigned char *data, int dataSize) +{ + #define ROTATE_RIGHT(x, c) ((x >> c) | (x << ((sizeof(unsigned int) * 8) - c))) + #define SHA256_A0(x) (ROTATE_RIGHT(x, 7) ^ ROTATE_RIGHT(x, 18) ^ (x >> 3)) + #define SHA256_A1(x) (ROTATE_RIGHT(x, 17) ^ ROTATE_RIGHT(x, 19) ^ (x >> 10)) + + static const unsigned int k[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 + }; + + static unsigned int hash[8]; + hash[0] = 0x6A09e667; + hash[1] = 0xbb67ae85; + hash[2] = 0x3c6ef372; + hash[3] = 0xa54ff53a; + hash[4] = 0x510e527f; + hash[5] = 0x9b05688c; + hash[6] = 0x1f83d9ab; + hash[7] = 0x5be0cd19; + + const unsigned long long int bitLen = ((unsigned long long int)dataSize)*8; + unsigned long long int paddedSize = dataSize + sizeof(dataSize); + paddedSize += (64 - (paddedSize%64)); + unsigned char *buffer = RL_CALLOC(paddedSize, sizeof(unsigned char)); + + memcpy(buffer, data, dataSize); + buffer[dataSize] = 0x80; + for (int i = 1; i <= sizeof(bitLen); i++) + buffer[(paddedSize - sizeof(bitLen)) + (i - 1)] = (bitLen >> (8*(sizeof(bitLen) - i))) & 0xFF; + + for (unsigned long long int blockN = 0; blockN < paddedSize/64; blockN++) + { + unsigned int a = hash[0]; + unsigned int b = hash[1]; + unsigned int c = hash[2]; + unsigned int d = hash[3]; + unsigned int e = hash[4]; + unsigned int f = hash[5]; + unsigned int g = hash[6]; + unsigned int h = hash[7]; + + 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) | + ((unsigned int)block[i*4 + 2] << 8) | + ((unsigned int)block[i*4 + 3]); + } + for (int t = 16; t < 64; t++) w[t] = SHA256_A1(w[t - 2]) + w[t - 7] + SHA256_A0(w[t - 15]) + w[t - 16]; + + for (unsigned long long int t = 0; t < 64; t++) + { + unsigned int e1 = (ROTATE_RIGHT(e, 6) ^ ROTATE_RIGHT(e, 11) ^ ROTATE_RIGHT(e, 25)); + unsigned int ch = ((e & f) ^ (~e & g)); + unsigned int t1 = (h + e1 + ch + k[t] + w[t]); + unsigned int e0 = (ROTATE_RIGHT(a, 2) ^ ROTATE_RIGHT(a, 13) ^ ROTATE_RIGHT(a, 22)); + unsigned int maj = ((a & b) ^ (a & c) ^ (b & c)); + unsigned int t2 = e0 + maj; + + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + } + + hash[0] += a; + hash[1] += b; + hash[2] += c; + hash[3] += d; + hash[4] += e; + hash[5] += f; + hash[6] += g; + hash[7] += h; + } + RL_FREE(buffer); + return hash; +} + //---------------------------------------------------------------------------------- // Module Functions Definition: Automation Events Recording and Playing //---------------------------------------------------------------------------------- From adfe2c170412751d8dced8b306553c6d95454fa7 Mon Sep 17 00:00:00 2001 From: Saksham Goyal Date: Wed, 15 Oct 2025 13:11:44 -0400 Subject: [PATCH 108/167] C++ compiler support v2 (#5252) * Get C++ compilers working * Fix Formatting --- .gitignore | 3 +++ src/external/RGFW.h | 4 +-- src/external/glfw/src/context.c | 17 ++++++------- src/external/glfw/src/egl_context.c | 11 ++++----- src/external/jar_mod.h | 8 +++--- src/external/jar_xm.h | 38 ++++++++++++++--------------- src/external/qoa.h | 6 ++--- src/external/qoaplay.c | 4 +-- src/external/tinyobj_loader_c.h | 2 +- src/external/vox_loader.h | 18 +++++++------- src/external/win32_clipboard.h | 13 ++-------- src/platforms/rcore_desktop_glfw.c | 12 +++++---- src/platforms/rcore_desktop_rgfw.c | 20 ++++++++++----- src/raudio.c | 8 +++--- src/rcore.c | 10 ++++++-- src/rgestures.h | 2 +- src/rmodels.c | 14 +++++------ src/rtext.c | 4 +-- src/rtextures.c | 7 +++--- src/utils.c | 2 +- 20 files changed, 106 insertions(+), 97 deletions(-) diff --git a/.gitignore b/.gitignore index ac4f016e4..fa4c4c49d 100644 --- a/.gitignore +++ b/.gitignore @@ -55,6 +55,8 @@ packages/ *.so *.so.* *.dll +*.h.pch +./*.obj # Emscripten emsdk @@ -81,6 +83,7 @@ DerivedData/ # VSCode project .vscode +.clangd # Jetbrains project .idea/ diff --git a/src/external/RGFW.h b/src/external/RGFW.h index 8bd9b5709..7205bf9d8 100644 --- a/src/external/RGFW.h +++ b/src/external/RGFW.h @@ -7727,8 +7727,8 @@ RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW dm.dmBitsPerPel = (DWORD)(mode.red + mode.green + mode.blue); } - if (ChangeDisplaySettingsEx(dd.DeviceName, &dm, NULL, CDS_TEST, NULL) == DISP_CHANGE_SUCCESSFUL) { - if (ChangeDisplaySettingsEx(dd.DeviceName, &dm, NULL, CDS_UPDATEREGISTRY, NULL) == DISP_CHANGE_SUCCESSFUL) + if (ChangeDisplaySettingsExA((LPCSTR)dd.DeviceName, (DEVMODE *)&dm, NULL, CDS_TEST, NULL) == DISP_CHANGE_SUCCESSFUL) { + if (ChangeDisplaySettingsExA((LPCSTR)dd.DeviceName, (DEVMODE *)&dm, NULL, CDS_UPDATEREGISTRY, NULL) == DISP_CHANGE_SUCCESSFUL) return RGFW_TRUE; return RGFW_FALSE; } else return RGFW_FALSE; diff --git a/src/external/glfw/src/context.c b/src/external/glfw/src/context.c index cc1fac4f3..bcb2b51b8 100644 --- a/src/external/glfw/src/context.c +++ b/src/external/glfw/src/context.c @@ -359,7 +359,7 @@ GLFWbool _glfwRefreshContextAttribs(_GLFWwindow* window, window->context.source = ctxconfig->source; window->context.client = GLFW_OPENGL_API; - previous = _glfwPlatformGetTls(&_glfw.contextSlot); + previous = (_GLFWwindow *)_glfwPlatformGetTls(&_glfw.contextSlot); glfwMakeContextCurrent((GLFWwindow*) window); if (_glfwPlatformGetTls(&_glfw.contextSlot) != window) return GLFW_FALSE; @@ -615,12 +615,12 @@ GLFWbool _glfwStringInExtensionString(const char* string, const char* extensions GLFWAPI void glfwMakeContextCurrent(GLFWwindow* handle) { - _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFWwindow* window = (_GLFWwindow *) handle; _GLFWwindow* previous; _GLFW_REQUIRE_INIT(); - previous = _glfwPlatformGetTls(&_glfw.contextSlot); + previous = (_GLFWwindow *)_glfwPlatformGetTls(&_glfw.contextSlot); if (window && window->context.client == GLFW_NO_API) { @@ -642,12 +642,12 @@ GLFWAPI void glfwMakeContextCurrent(GLFWwindow* handle) GLFWAPI GLFWwindow* glfwGetCurrentContext(void) { _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - return _glfwPlatformGetTls(&_glfw.contextSlot); + return (GLFWwindow *)_glfwPlatformGetTls(&_glfw.contextSlot); } GLFWAPI void glfwSwapBuffers(GLFWwindow* handle) { - _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFWwindow* window = (_GLFWwindow *) handle; assert(window != NULL); _GLFW_REQUIRE_INIT(); @@ -668,7 +668,7 @@ GLFWAPI void glfwSwapInterval(int interval) _GLFW_REQUIRE_INIT(); - window = _glfwPlatformGetTls(&_glfw.contextSlot); + window = (_GLFWwindow *)_glfwPlatformGetTls(&_glfw.contextSlot); if (!window) { _glfwInputError(GLFW_NO_CURRENT_CONTEXT, @@ -686,7 +686,7 @@ GLFWAPI int glfwExtensionSupported(const char* extension) _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); - window = _glfwPlatformGetTls(&_glfw.contextSlot); + window = (_GLFWwindow *)_glfwPlatformGetTls(&_glfw.contextSlot); if (!window) { _glfwInputError(GLFW_NO_CURRENT_CONTEXT, @@ -752,7 +752,7 @@ GLFWAPI GLFWglproc glfwGetProcAddress(const char* procname) _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - window = _glfwPlatformGetTls(&_glfw.contextSlot); + window = (_GLFWwindow *)_glfwPlatformGetTls(&_glfw.contextSlot); if (!window) { _glfwInputError(GLFW_NO_CURRENT_CONTEXT, @@ -762,4 +762,3 @@ GLFWAPI GLFWglproc glfwGetProcAddress(const char* procname) return window->context.getProcAddress(procname); } - diff --git a/src/external/glfw/src/egl_context.c b/src/external/glfw/src/egl_context.c index ef65dd350..19ab3dfbe 100644 --- a/src/external/glfw/src/egl_context.c +++ b/src/external/glfw/src/egl_context.c @@ -118,10 +118,10 @@ static GLFWbool chooseEGLConfig(const _GLFWctxconfig* ctxconfig, return GLFW_FALSE; } - nativeConfigs = _glfw_calloc(nativeCount, sizeof(EGLConfig)); + nativeConfigs = (EGLConfig *)_glfw_calloc(nativeCount, sizeof(EGLConfig)); eglGetConfigs(_glfw.egl.display, nativeConfigs, nativeCount, &nativeCount); - usableConfigs = _glfw_calloc(nativeCount, sizeof(_GLFWfbconfig)); + usableConfigs = (_GLFWfbconfig *)_glfw_calloc(nativeCount, sizeof(_GLFWfbconfig)); usableCount = 0; for (i = 0; i < nativeCount; i++) @@ -308,7 +308,7 @@ static int extensionSupportedEGL(const char* extension) static GLFWglproc getProcAddressEGL(const char* procname) { - _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot); + _GLFWwindow* window = (_GLFWwindow *)_glfwPlatformGetTls(&_glfw.contextSlot); assert(window != NULL); if (window->context.egl.client) @@ -883,7 +883,7 @@ GLFWAPI EGLDisplay glfwGetEGLDisplay(void) GLFWAPI EGLContext glfwGetEGLContext(GLFWwindow* handle) { - _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFWwindow* window = (_GLFWwindow *) handle; _GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_CONTEXT); if (window->context.source != GLFW_EGL_CONTEXT_API) @@ -897,7 +897,7 @@ GLFWAPI EGLContext glfwGetEGLContext(GLFWwindow* handle) GLFWAPI EGLSurface glfwGetEGLSurface(GLFWwindow* handle) { - _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFWwindow* window = (_GLFWwindow *) handle; _GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_SURFACE); if (window->context.source != GLFW_EGL_CONTEXT_API) @@ -908,4 +908,3 @@ GLFWAPI EGLSurface glfwGetEGLSurface(GLFWwindow* handle) return window->context.egl.surface; } - diff --git a/src/external/jar_mod.h b/src/external/jar_mod.h index 2a220f8af..7ecf9f437 100644 --- a/src/external/jar_mod.h +++ b/src/external/jar_mod.h @@ -1148,7 +1148,7 @@ static bool jar_mod_load( jar_mod_context_t * modctx, void * mod_data, int mod_d { // 15 Samples modules support // Shift the whole datas to make it look likes a standard 4 channels mod. - memcopy(&(modctx->song.signature), "M.K.", 4); + memcopy(&(modctx->song.signature), (void *)"M.K.", 4); memcopy(&(modctx->song.length), &(modctx->song.samples[15]), 130); memclear(&(modctx->song.samples[15]), 0, 480); modmemory += 600; @@ -1535,13 +1535,13 @@ mulong jar_mod_load_file(jar_mod_context_t * modctx, const char* filename) if(fsize && fsize < 32*1024*1024) { - modctx->modfile = JARMOD_MALLOC(fsize); + modctx->modfile = (muchar *) JARMOD_MALLOC(fsize); modctx->modfilesize = fsize; memset(modctx->modfile, 0, fsize); fread(modctx->modfile, fsize, 1, f); fclose(f); - - if(!jar_mod_load(modctx, (void*)modctx->modfile, fsize)) fsize = 0; + + if(!jar_mod_load(modctx, (void *)modctx->modfile, fsize)) fsize = 0; } else fsize = 0; } return fsize; diff --git a/src/external/jar_xm.h b/src/external/jar_xm.h index 174c1704c..849fe62f4 100644 --- a/src/external/jar_xm.h +++ b/src/external/jar_xm.h @@ -123,7 +123,7 @@ void jar_xm_generate_samples(jar_xm_context_t* ctx, float* output, size_t numsam // * @param output buffer of 2*numsamples elements (A left and right value for each sample) // * @param numsamples number of samples to generate void jar_xm_generate_samples_16bit(jar_xm_context_t* ctx, short* output, size_t numsamples) { - float* musicBuffer = JARXM_MALLOC((2*numsamples)*sizeof(float)); + float* musicBuffer = (float *)JARXM_MALLOC((2*numsamples)*sizeof(float)); jar_xm_generate_samples(ctx, musicBuffer, numsamples); if(output){ @@ -136,7 +136,7 @@ void jar_xm_generate_samples_16bit(jar_xm_context_t* ctx, short* output, size_t // * @param output buffer of 2*numsamples elements (A left and right value for each sample) // * @param numsamples number of samples to generate void jar_xm_generate_samples_8bit(jar_xm_context_t* ctx, char* output, size_t numsamples) { - float* musicBuffer = JARXM_MALLOC((2*numsamples)*sizeof(float)); + float* musicBuffer = (float *)JARXM_MALLOC((2*numsamples)*sizeof(float)); jar_xm_generate_samples(ctx, musicBuffer, numsamples); if(output){ @@ -543,7 +543,7 @@ int jar_xm_create_context_safe(jar_xm_context_t** ctxp, const char* moddata, siz #endif bytes_needed = jar_xm_get_memory_needed_for_context(moddata, moddata_length); - mempool = JARXM_MALLOC(bytes_needed); + mempool = (char *)JARXM_MALLOC(bytes_needed); if(mempool == NULL && bytes_needed > 0) { /* JARXM_MALLOC() failed, trouble ahead */ DEBUG("call to JARXM_MALLOC() failed, returned %p", (void*)mempool); return 2; @@ -558,11 +558,11 @@ int jar_xm_create_context_safe(jar_xm_context_t** ctxp, const char* moddata, siz ctx->rate = rate; mempool = jar_xm_load_module(ctx, moddata, moddata_length, mempool); - mempool = ALIGN_PTR(mempool, 16); + mempool = (char *)ALIGN_PTR(mempool, 16); ctx->channels = (jar_xm_channel_context_t*)mempool; mempool += ctx->module.num_channels * sizeof(jar_xm_channel_context_t); - mempool = ALIGN_PTR(mempool, 16); + mempool = (char *)ALIGN_PTR(mempool, 16); ctx->default_global_volume = 1.f; ctx->global_volume = ctx->default_global_volume; @@ -583,7 +583,7 @@ int jar_xm_create_context_safe(jar_xm_context_t** ctxp, const char* moddata, siz ch->actual_panning = .5f; } - mempool = ALIGN_PTR(mempool, 16); + mempool = (char *)ALIGN_PTR(mempool, 16); ctx->row_loop_count = (uint8_t *)mempool; mempool += MAX_NUM_ROWS * sizeof(uint8_t); @@ -681,14 +681,14 @@ uint64_t jar_xm_get_latest_trigger_of_channel(jar_xm_context_t *ctx, uint16_t ch //* Bound reader macros. //* If we attempt to read the buffer out-of-bounds, pretend that the buffer is infinitely padded with zeroes. -#define READ_U8(offset) (((offset) < moddata_length) ? (*(uint8_t*)(moddata + (offset))) : 0) +#define READ_U8(offset) (((offset) < moddata_length) ? (*(uint8_t *)(moddata + (offset))) : 0) #define READ_U16(offset) ((uint16_t)READ_U8(offset) | ((uint16_t)READ_U8((offset) + 1) << 8)) #define READ_U32(offset) ((uint32_t)READ_U16(offset) | ((uint32_t)READ_U16((offset) + 2) << 16)) #define READ_MEMCPY(ptr, offset, length) memcpy_pad(ptr, length, moddata, moddata_length, offset) static void memcpy_pad(void *dst, size_t dst_len, const void *src, size_t src_len, size_t offset) { - uint8_t *dst_c = dst; - const uint8_t *src_c = src; + uint8_t *dst_c = (uint8_t *)dst; + const uint8_t *src_c = (uint8_t *)src; /* how many bytes can be copied without overrunning `src` */ size_t copy_bytes = (src_len >= offset) ? (src_len - offset) : 0; @@ -808,10 +808,10 @@ char* jar_xm_load_module(jar_xm_context_t* ctx, const char* moddata, size_t modd mod->linear_interpolation = 1; // Linear interpolation can be set after loading mod->ramping = 1; // ramping can be set after loading mempool += mod->num_patterns * sizeof(jar_xm_pattern_t); - mempool = ALIGN_PTR(mempool, 16); + mempool = (char *)ALIGN_PTR(mempool, 16); mod->instruments = (jar_xm_instrument_t*)mempool; mempool += mod->num_instruments * sizeof(jar_xm_instrument_t); - mempool = ALIGN_PTR(mempool, 16); + mempool = (char *)ALIGN_PTR(mempool, 16); uint16_t flags = READ_U32(offset + 14); mod->frequency_type = (flags & (1 << 0)) ? jar_xm_LINEAR_FREQUENCIES : jar_xm_AMIGA_FREQUENCIES; ctx->default_tempo = READ_U16(offset + 16); @@ -884,7 +884,7 @@ char* jar_xm_load_module(jar_xm_context_t* ctx, const char* moddata, size_t modd offset += packed_patterndata_size; } - mempool = ALIGN_PTR(mempool, 16); + mempool = (char *)ALIGN_PTR(mempool, 16); /* Read instruments */ for(uint16_t i = 0; i < ctx->module.num_instruments; ++i) { @@ -928,11 +928,11 @@ char* jar_xm_load_module(jar_xm_context_t* ctx, const char* moddata, size_t modd instr->panning_envelope.enabled = flags & (1 << 0); instr->panning_envelope.sustain_enabled = flags & (1 << 1); instr->panning_envelope.loop_enabled = flags & (1 << 2); - instr->vibrato_type = READ_U8(offset + 235); + instr->vibrato_type = (jar_xm_waveform_type_t)READ_U8(offset + 235); if(instr->vibrato_type == 2) { - instr->vibrato_type = 1; + instr->vibrato_type = (jar_xm_waveform_type_t)1; } else if(instr->vibrato_type == 1) { - instr->vibrato_type = 2; + instr->vibrato_type = (jar_xm_waveform_type_t)2; } instr->vibrato_sweep = READ_U8(offset + 236); instr->vibrato_depth = READ_U8(offset + 237); @@ -976,7 +976,7 @@ char* jar_xm_load_module(jar_xm_context_t* ctx, const char* moddata, size_t modd sample->panning = (float)READ_U8(offset + 15) / 255.f; sample->relative_note = (int8_t)READ_U8(offset + 16); READ_MEMCPY(sample->name, 18, SAMPLE_NAME_LENGTH); - sample->data = (float*)mempool; + sample->data = (float *)mempool; if(sample->bits == 16) { /* 16 bit sample */ mempool += sample->length * (sizeof(float) >> 1); @@ -1475,7 +1475,7 @@ static void jar_xm_handle_note_and_instrument(jar_xm_context_t* ctx, jar_xm_chan jar_xm_pitch_slide(ctx, ch, ch->fine_portamento_down_param); break; case 4: /* E4y: Set vibrato control */ - ch->vibrato_waveform = s->effect_param & 3; + ch->vibrato_waveform = (jar_xm_waveform_type_t)(s->effect_param & 3); ch->vibrato_waveform_retrigger = !((s->effect_param >> 2) & 1); break; case 5: /* E5y: Set finetune */ @@ -1502,7 +1502,7 @@ static void jar_xm_handle_note_and_instrument(jar_xm_context_t* ctx, jar_xm_chan } break; case 7: /* E7y: Set tremolo control */ - ch->tremolo_waveform = s->effect_param & 3; + ch->tremolo_waveform = (jar_xm_waveform_type_t)(s->effect_param & 3); ch->tremolo_waveform_retrigger = !((s->effect_param >> 2) & 1); break; case 0xA: /* EAy: Fine volume slide up */ @@ -2223,7 +2223,7 @@ int jar_xm_create_context_from_file(jar_xm_context_t** ctx, uint32_t rate, const return 4; } - char* data = JARXM_MALLOC(size + 1); + char* data = (char *)JARXM_MALLOC(size + 1); if(!data || fread(data, 1, size, xmf) < size) { fclose(xmf); DEBUG_ERR(data ? "fread() failed" : "JARXM_MALLOC() failed"); diff --git a/src/external/qoa.h b/src/external/qoa.h index f0f44214d..57b85d131 100644 --- a/src/external/qoa.h +++ b/src/external/qoa.h @@ -500,7 +500,7 @@ void *qoa_encode(const short *sample_data, qoa_desc *qoa, unsigned int *out_len) num_frames * QOA_LMS_LEN * 4 * qoa->channels + /* 4 * 4 bytes lms state per channel */ num_slices * 8 * qoa->channels; /* 8 byte slices */ - unsigned char *bytes = QOA_MALLOC(encoded_size); + unsigned char *bytes = (unsigned char *)QOA_MALLOC(encoded_size); for (unsigned int c = 0; c < qoa->channels; c++) { /* Set the initial LMS weights to {0, 0, -1, 2}. This helps with the @@ -657,7 +657,7 @@ short *qoa_decode(const unsigned char *bytes, int size, qoa_desc *qoa) { /* Calculate the required size of the sample buffer and allocate */ int total_samples = qoa->samples * qoa->channels; - short *sample_data = QOA_MALLOC(total_samples * sizeof(short)); + short *sample_data = (short *)QOA_MALLOC(total_samples * sizeof(short)); unsigned int sample_index = 0; unsigned int frame_len; @@ -733,7 +733,7 @@ void *qoa_read(const char *filename, qoa_desc *qoa) { bytes_read = fread(data, 1, size, f); fclose(f); - sample_data = qoa_decode(data, bytes_read, qoa); + sample_data = qoa_decode((const unsigned char *)data, bytes_read, qoa); QOA_FREE(data); return sample_data; } diff --git a/src/external/qoaplay.c b/src/external/qoaplay.c index 4378e5ebd..0ac6f6c06 100644 --- a/src/external/qoaplay.c +++ b/src/external/qoaplay.c @@ -104,7 +104,7 @@ qoaplay_desc *qoaplay_open(const char *path) // + a buffer to hold one frame of encoded data unsigned int buffer_size = qoa_max_frame_size(&qoa); unsigned int sample_data_size = qoa.channels*QOA_FRAME_LEN*sizeof(short)*2; - qoaplay_desc *qoa_ctx = QOA_MALLOC(sizeof(qoaplay_desc) + buffer_size + sample_data_size); + qoaplay_desc *qoa_ctx = (qoaplay_desc *)QOA_MALLOC(sizeof(qoaplay_desc) + buffer_size + sample_data_size); memset(qoa_ctx, 0, sizeof(qoaplay_desc)); qoa_ctx->file = file; @@ -136,7 +136,7 @@ qoaplay_desc *qoaplay_open_memory(const unsigned char *data, int data_size) // + the sample data for one frame // + a buffer to hold one frame of encoded data unsigned int sample_data_size = qoa.channels*QOA_FRAME_LEN*sizeof(short)*2; - qoaplay_desc *qoa_ctx = QOA_MALLOC(sizeof(qoaplay_desc) + sample_data_size + data_size); + qoaplay_desc *qoa_ctx = (qoaplay_desc *)QOA_MALLOC(sizeof(qoaplay_desc) + sample_data_size + data_size); memset(qoa_ctx, 0, sizeof(qoaplay_desc)); qoa_ctx->file = NULL; diff --git a/src/external/tinyobj_loader_c.h b/src/external/tinyobj_loader_c.h index 55d595a69..88b2acbdc 100644 --- a/src/external/tinyobj_loader_c.h +++ b/src/external/tinyobj_loader_c.h @@ -454,7 +454,7 @@ static void parseFloat3(float *x, float *y, float *z, const char **token) { } static unsigned int my_strnlen(const char *s, unsigned int n) { - const char *p = memchr(s, 0, n); + const char *p = (const char *)memchr(s, 0, n); return p ? (unsigned int)(p - s) : n; } diff --git a/src/external/vox_loader.h b/src/external/vox_loader.h index 0d328c078..6d933907c 100644 --- a/src/external/vox_loader.h +++ b/src/external/vox_loader.h @@ -151,7 +151,7 @@ void Vox_FreeArrays(VoxArray3D* voxarray); ///////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////// // Implementation -///////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////// #ifdef VOX_LOADER_IMPLEMENTATION @@ -165,7 +165,7 @@ void Vox_FreeArrays(VoxArray3D* voxarray); static void initArrayUShort(ArrayUShort* a, int initialSize) { - a->array = VOX_MALLOC(initialSize * sizeof(unsigned short)); + a->array = (unsigned short *)VOX_MALLOC(initialSize * sizeof(unsigned short)); a->used = 0; a->size = initialSize; } @@ -175,7 +175,7 @@ static void insertArrayUShort(ArrayUShort* a, unsigned short element) if (a->used == a->size) { a->size *= 2; - a->array = VOX_REALLOC(a->array, a->size * sizeof(unsigned short)); + a->array = (unsigned short *)VOX_REALLOC(a->array, a->size * sizeof(unsigned short)); } a->array[a->used++] = element; } @@ -194,7 +194,7 @@ static void freeArrayUShort(ArrayUShort* a) static void initArrayVector3(ArrayVector3* a, int initialSize) { - a->array = VOX_MALLOC(initialSize * sizeof(VoxVector3)); + a->array = (VoxVector3 *)VOX_MALLOC(initialSize * sizeof(VoxVector3)); a->used = 0; a->size = initialSize; } @@ -204,7 +204,7 @@ static void insertArrayVector3(ArrayVector3* a, VoxVector3 element) if (a->used == a->size) { a->size *= 2; - a->array = VOX_REALLOC(a->array, a->size * sizeof(VoxVector3)); + a->array = (VoxVector3 *)VOX_REALLOC(a->array, a->size * sizeof(VoxVector3)); } a->array[a->used++] = element; } @@ -222,7 +222,7 @@ static void freeArrayVector3(ArrayVector3* a) static void initArrayColor(ArrayColor* a, int initialSize) { - a->array = VOX_MALLOC(initialSize * sizeof(VoxColor)); + a->array = (VoxColor *)VOX_MALLOC(initialSize * sizeof(VoxColor)); a->used = 0; a->size = initialSize; } @@ -232,7 +232,7 @@ static void insertArrayColor(ArrayColor* a, VoxColor element) if (a->used == a->size) { a->size *= 2; - a->array = VOX_REALLOC(a->array, a->size * sizeof(VoxColor)); + a->array = (VoxColor *)VOX_REALLOC(a->array, a->size * sizeof(VoxColor)); } a->array[a->used++] = element; } @@ -327,7 +327,7 @@ static void Vox_AllocArray(VoxArray3D* pvoxarray, int _sx, int _sy, int _sz) // Alloc chunks array int size = sizeof(CubeChunk3D) * chx * chy * chz; - pvoxarray->m_arrayChunks = VOX_MALLOC(size); + pvoxarray->m_arrayChunks = (CubeChunk3D *)VOX_MALLOC(size); pvoxarray->arrayChunksSize = size; // Init chunks array @@ -366,7 +366,7 @@ static void Vox_SetVoxel(VoxArray3D* pvoxarray, int x, int y, int z, unsigned ch if (chunk->m_array == 0) { int size = CHUNKSIZE * CHUNKSIZE * CHUNKSIZE; - chunk->m_array = VOX_MALLOC(size); + chunk->m_array = (unsigned char *)VOX_MALLOC(size); chunk->arraySize = size; memset(chunk->m_array, 0, size); diff --git a/src/external/win32_clipboard.h b/src/external/win32_clipboard.h index 832856432..1f9a27521 100644 --- a/src/external/win32_clipboard.h +++ b/src/external/win32_clipboard.h @@ -13,7 +13,7 @@ unsigned char* Win32GetClipboardImageData(int* width, int* height, unsigned long #include #include -// NOTE: These search for architecture is taken from "Windows.h", and it's necessary if we really don't wanna import windows.h +// NOTE: These search for architecture is taken from "Windows.h", and it's necessary if we really don't wanna import windows.h // and still make it compile on msvc, because import indirectly importing "winnt.h" (e.g. ) can cause problems is these are not defined. #if !defined(_X86_) && !defined(_68K_) && !defined(_MPPC_) && !defined(_IA64_) && !defined(_AMD64_) && !defined(_ARM_) && !defined(_ARM64_) && !defined(_ARM64EC_) && defined(_M_IX86) #define _X86_ @@ -93,14 +93,6 @@ unsigned char* Win32GetClipboardImageData(int* width, int* height, unsigned long typedef int WINBOOL; - -// typedef HANDLE HGLOBAL; - -#ifndef HWND -#define HWND void* -#endif - - #if !defined(_WINUSER_) || !defined(WINUSER_ALREADY_INCLUDED) WINUSERAPI WINBOOL WINAPI OpenClipboard(HWND hWndNewOwner); WINUSERAPI WINBOOL WINAPI CloseClipboard(VOID); @@ -284,7 +276,7 @@ unsigned char* Win32GetClipboardImageData(int* width, int* height, unsigned long // This may be wrong since we might be allocating in a DLL and freeing from another module, the main application // that may cause heap corruption. We could create a FreeImage function // - bmpData = malloc(sizeof(bmpFileHeader) + clipDataSize); + bmpData = (BYTE *)malloc(sizeof(bmpFileHeader) + clipDataSize); // First we add the header for a bmp file memcpy(bmpData, &bmpFileHeader, sizeof(bmpFileHeader)); // Then we add the header for the bmp itself + the pixel data @@ -371,4 +363,3 @@ static int GetPixelDataOffset(BITMAPINFOHEADER bih) } #endif // WIN32_CLIPBOARD_IMPLEMENTATION // EOF - diff --git a/src/platforms/rcore_desktop_glfw.c b/src/platforms/rcore_desktop_glfw.c index a9ee199c6..0144f623d 100644 --- a/src/platforms/rcore_desktop_glfw.c +++ b/src/platforms/rcore_desktop_glfw.c @@ -56,10 +56,12 @@ // Support retrieving native window handlers #if defined(_WIN32) - typedef void *PVOID; - typedef PVOID HANDLE; + #if !defined(HWND) && !defined(_MSVC_LANG) + #define HWND void* + #elif !defined(HWND) && defined(_MSVC_LANG) + typedef struct HWND__ *HWND; + #endif #include "../external/win32_clipboard.h" - typedef HANDLE HWND; #define GLFW_EXPOSE_NATIVE_WIN32 #define GLFW_NATIVE_INCLUDE_NONE // To avoid some symbols re-definition in windows.h #include "GLFW/glfw3native.h" @@ -1031,7 +1033,7 @@ Image GetClipboardImage(void) fileData = (void*)Win32GetClipboardImageData(&width, &height, &dataSize); if (fileData == NULL) TRACELOG(LOG_WARNING, "Clipboard image: Couldn't get clipboard data."); - else image = LoadImageFromMemory(".bmp", fileData, (int)dataSize); + else image = LoadImageFromMemory(".bmp", (const unsigned char*)fileData, (int)dataSize); #else TRACELOG(LOG_WARNING, "GetClipboardImage() not implemented on target platform"); #endif @@ -1353,8 +1355,8 @@ int InitPlatform(void) const GLFWallocator allocator = { .allocate = AllocateWrapper, - .deallocate = DeallocateWrapper, .reallocate = ReallocateWrapper, + .deallocate = DeallocateWrapper, .user = NULL, // RL_*ALLOC macros are not capable of handling user-provided data }; diff --git a/src/platforms/rcore_desktop_rgfw.c b/src/platforms/rcore_desktop_rgfw.c index 8c4deeb9a..52ec6ac94 100644 --- a/src/platforms/rcore_desktop_rgfw.c +++ b/src/platforms/rcore_desktop_rgfw.c @@ -83,7 +83,14 @@ void CloseWindow(void); #undef MAX_PATH +#if defined(__cplusplus) +extern "C" { +#endif __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int CodePage, unsigned long dwFlags, const char *lpMultiByteStr, int cbMultiByte, wchar_t *lpWideCharStr, int cchWideChar); +#if defined(__cplusplus) +} +#endif + #endif #if defined(__APPLE__) @@ -564,7 +571,7 @@ int RGFW_formatToChannels(int format) // Set icon for window void SetWindowIcon(Image image) { - RGFW_window_setIcon(platform.window, image.data, RGFW_AREA(image.width, image.height), RGFW_formatToChannels(image.format)); + RGFW_window_setIcon(platform.window, (u8 *)image.data, RGFW_AREA(image.width, image.height), RGFW_formatToChannels(image.format)); } // Set icon for window @@ -585,8 +592,8 @@ void SetWindowIcons(Image *images, int count) if ((smallIcon == NULL) || ((images[i].width < smallIcon->width) && (images[i].height > smallIcon->height))) smallIcon = &images[i]; } - if (smallIcon != NULL) RGFW_window_setIconEx(platform.window, smallIcon->data, RGFW_AREA(smallIcon->width, smallIcon->height), RGFW_formatToChannels(smallIcon->format), RGFW_iconWindow); - if (bigIcon != NULL) RGFW_window_setIconEx(platform.window, bigIcon->data, RGFW_AREA(bigIcon->width, bigIcon->height), RGFW_formatToChannels(bigIcon->format), RGFW_iconTaskbar); + if (smallIcon != NULL) RGFW_window_setIconEx(platform.window, (u8 *)smallIcon->data, RGFW_AREA(smallIcon->width, smallIcon->height), RGFW_formatToChannels(smallIcon->format), RGFW_iconWindow); + if (bigIcon != NULL) RGFW_window_setIconEx(platform.window, (u8 *)bigIcon->data, RGFW_AREA(bigIcon->width, bigIcon->height), RGFW_formatToChannels(bigIcon->format), RGFW_iconTaskbar); } } @@ -805,7 +812,7 @@ Image GetClipboardImage(void) fileData = (void *)Win32GetClipboardImageData(&width, &height, &dataSize); if (fileData == NULL) TRACELOG(LOG_WARNING, "Clipboard image: Couldn't get clipboard data"); - else image = LoadImageFromMemory(".bmp", fileData, dataSize); + else image = LoadImageFromMemory(".bmp", (const unsigned char *)fileData, dataSize); #else TRACELOG(LOG_WARNING, "Clipboard image: PLATFORM_DESKTOP_RGFW doesn't implement GetClipboardImage() for this OS"); #endif @@ -1418,7 +1425,8 @@ void ClosePlatform(void) // Keycode mapping static KeyboardKey ConvertScancodeToKey(u32 keycode) { - if (keycode > sizeof(keyMappingRGFW)/sizeof(unsigned short)) return 0; + if (keycode > sizeof(keyMappingRGFW)/sizeof(unsigned short)) return KEY_NULL; - return keyMappingRGFW[keycode]; + return (KeyboardKey)keyMappingRGFW[keycode]; } + diff --git a/src/raudio.c b/src/raudio.c index 798c062e9..ca63b3aac 100644 --- a/src/raudio.c +++ b/src/raudio.c @@ -575,7 +575,7 @@ AudioBuffer *LoadAudioBuffer(ma_format format, ma_uint32 channels, ma_uint32 sam return NULL; } - if (sizeInFrames > 0) audioBuffer->data = RL_CALLOC(sizeInFrames*channels*ma_get_bytes_per_sample(format), 1); + if (sizeInFrames > 0) audioBuffer->data = (unsigned char *)RL_CALLOC(sizeInFrames*channels*ma_get_bytes_per_sample(format), 1); // Audio data runs through a format converter ma_data_converter_config converterConfig = ma_data_converter_config_init(format, AUDIO_DEVICE_FORMAT, channels, AUDIO_DEVICE_CHANNELS, sampleRate, AUDIO.System.device.sampleRate); @@ -808,7 +808,7 @@ Wave LoadWaveFromMemory(const char *fileType, const unsigned char *fileData, int wave.data = (short *)RL_MALLOC((size_t)wave.frameCount*wave.channels*sizeof(short)); // NOTE: We are forcing conversion to 16bit sample size on reading - drwav_read_pcm_frames_s16(&wav, wave.frameCount, wave.data); + drwav_read_pcm_frames_s16(&wav, wave.frameCount, (drwav_int16 *)wave.data); } else TRACELOG(LOG_WARNING, "WAVE: Failed to load WAV data"); @@ -1091,7 +1091,7 @@ bool ExportWave(Wave wave, const char *fileName) qoa.samplerate = wave.sampleRate; qoa.samples = wave.frameCount; - int bytesWritten = qoa_write(fileName, wave.data, &qoa); + int bytesWritten = qoa_write(fileName, (const short *)wave.data, &qoa); if (bytesWritten > 0) success = true; } else TRACELOG(LOG_WARNING, "AUDIO: Wave data must be 16 bit per sample for QOA format export"); @@ -2079,7 +2079,7 @@ float GetMusicTimePlayed(Music music) { uint64_t framesPlayed = 0; - jar_xm_get_position(music.ctxData, NULL, NULL, NULL, &framesPlayed); + jar_xm_get_position((jar_xm_context_t *)music.ctxData, NULL, NULL, NULL, &framesPlayed); secondsPlayed = (float)framesPlayed/music.stream.sampleRate; } else diff --git a/src/rcore.c b/src/rcore.c index f1c975c21..f87b68783 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -164,11 +164,17 @@ #if (defined(_WIN32) && !defined(PLATFORM_DESKTOP_RGFW)) || (defined(_MSC_VER) && defined(PLATFORM_DESKTOP_RGFW)) struct HINSTANCE__; +#if defined(__cplusplus) +extern "C" { +#endif __declspec(dllimport) unsigned long __stdcall GetModuleFileNameA(struct HINSTANCE__ *hModule, char *lpFilename, unsigned long nSize); __declspec(dllimport) unsigned long __stdcall GetModuleFileNameW(struct HINSTANCE__ *hModule, wchar_t *lpFilename, unsigned long nSize); __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default); __declspec(dllimport) unsigned int __stdcall timeBeginPeriod(unsigned int uPeriod); __declspec(dllimport) unsigned int __stdcall timeEndPeriod(unsigned int uPeriod); +#if defined(__cplusplus) +} +#endif #elif defined(__linux__) #include #elif defined(__FreeBSD__) @@ -2328,8 +2334,8 @@ const char *GetApplicationDirectory(void) int len = 0; #if defined(UNICODE) unsigned short widePath[MAX_PATH]; - len = GetModuleFileNameW(NULL, widePath, MAX_PATH); - len = WideCharToMultiByte(0, 0, widePath, len, appDir, MAX_PATH, NULL, NULL); + len = GetModuleFileNameW(NULL, (wchar_t *)widePath, MAX_PATH); + len = WideCharToMultiByte(0, 0, (wchar_t *)widePath, len, appDir, MAX_PATH, NULL, NULL); #else len = GetModuleFileNameA(NULL, appDir, MAX_PATH); #endif diff --git a/src/rgestures.h b/src/rgestures.h index 389df64a1..f601a4790 100644 --- a/src/rgestures.h +++ b/src/rgestures.h @@ -232,8 +232,8 @@ typedef struct { // Global Variables Definition //---------------------------------------------------------------------------------- static GesturesData GESTURES = { - .Touch.firstId = -1, .current = GESTURE_NONE, // No current gesture detected + .Touch.firstId = -1, .enabledFlags = 0b0000001111111111 // All gestures supported by default }; diff --git a/src/rmodels.c b/src/rmodels.c index f800ad1b1..3a5cc9004 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -5179,7 +5179,7 @@ static cgltf_result LoadFileGLTFCallback(const struct cgltf_memory_options *memo // Release file data callback for cgltf static void ReleaseFileGLTFCallback(const struct cgltf_memory_options *memoryOptions, const struct cgltf_file_options *fileOptions, void *data) { - UnloadFileData(data); + UnloadFileData((unsigned char *)data); } // Load image from different glTF provided methods (uri, path, buffer_view) @@ -6140,7 +6140,7 @@ static bool GetPoseAtTimeGLTF(cgltf_interpolation_type interpolationType, cgltf_ float tmp[3] = { 0.0f }; cgltf_accessor_read_float(output, keyframe, tmp, 3); Vector3 v1 = {tmp[0], tmp[1], tmp[2]}; - Vector3 *r = data; + Vector3 *r = (Vector3 *)data; *r = v1; } break; @@ -6151,7 +6151,7 @@ static bool GetPoseAtTimeGLTF(cgltf_interpolation_type interpolationType, cgltf_ Vector3 v1 = {tmp[0], tmp[1], tmp[2]}; cgltf_accessor_read_float(output, keyframe+1, tmp, 3); Vector3 v2 = {tmp[0], tmp[1], tmp[2]}; - Vector3 *r = data; + Vector3 *r = (Vector3 *)data; *r = Vector3Lerp(v1, v2, t); } break; @@ -6166,7 +6166,7 @@ static bool GetPoseAtTimeGLTF(cgltf_interpolation_type interpolationType, cgltf_ Vector3 v2 = {tmp[0], tmp[1], tmp[2]}; cgltf_accessor_read_float(output, 3*(keyframe+1), tmp, 3); Vector3 tangent2 = {tmp[0], tmp[1], tmp[2]}; - Vector3 *r = data; + Vector3 *r = (Vector3 *)data; *r = Vector3CubicHermite(v1, tangent1, v2, tangent2, t); } break; @@ -6183,7 +6183,7 @@ static bool GetPoseAtTimeGLTF(cgltf_interpolation_type interpolationType, cgltf_ float tmp[4] = { 0.0f }; cgltf_accessor_read_float(output, keyframe, tmp, 4); Vector4 v1 = {tmp[0], tmp[1], tmp[2], tmp[3]}; - Vector4 *r = data; + Vector4 *r = (Vector4 *)data; *r = v1; } break; @@ -6194,7 +6194,7 @@ static bool GetPoseAtTimeGLTF(cgltf_interpolation_type interpolationType, cgltf_ Vector4 v1 = {tmp[0], tmp[1], tmp[2], tmp[3]}; cgltf_accessor_read_float(output, keyframe+1, tmp, 4); Vector4 v2 = {tmp[0], tmp[1], tmp[2], tmp[3]}; - Vector4 *r = data; + Vector4 *r = (Vector4 *)data; *r = QuaternionSlerp(v1, v2, t); } break; @@ -6209,7 +6209,7 @@ static bool GetPoseAtTimeGLTF(cgltf_interpolation_type interpolationType, cgltf_ Vector4 v2 = {tmp[0], tmp[1], tmp[2], tmp[3]}; cgltf_accessor_read_float(output, 3*(keyframe+1), tmp, 4); Vector4 inTangent2 = {tmp[0], tmp[1], tmp[2], 0.0f}; - Vector4 *r = data; + Vector4 *r = (Vector4 *)data; v1 = QuaternionNormalize(v1); v2 = QuaternionNormalize(v2); diff --git a/src/rtext.c b/src/rtext.c index 6a87fe3db..9951dc66d 100644 --- a/src/rtext.c +++ b/src/rtext.c @@ -1731,7 +1731,7 @@ char *TextReplace(const char *text, const char *search, const char *replacement) // - 'text' points to the remainder of text after "end of replace" while (count--) { - insertPoint = strstr(text, search); + insertPoint = (char *)strstr(text, search); lastReplacePos = (int)(insertPoint - text); temp = strncpy(temp, text, lastReplacePos) + lastReplacePos; temp = strcpy(temp, replacement) + replaceLen; @@ -1887,7 +1887,7 @@ int TextFindIndex(const char *text, const char *search) { int position = -1; - char *ptr = strstr(text, search); + char *ptr = (char *)strstr(text, search); if (ptr != NULL) position = (int)(ptr - text); diff --git a/src/rtextures.c b/src/rtextures.c index a85467d8c..ddaee2939 100644 --- a/src/rtextures.c +++ b/src/rtextures.c @@ -1039,7 +1039,7 @@ Image GenImagePerlinNoise(int width, int height, int offsetX, int offsetY, float // We need to normalize the data from [-1..1] to [0..1] float np = (p + 1.0f)/2.0f; - int intensity = (int)(np*255.0f); + unsigned char intensity = (unsigned char)(np*255.0f); pixels[y*width + x] = (Color){ intensity, intensity, intensity, 255 }; } } @@ -1103,7 +1103,8 @@ Image GenImageCellular(int width, int height, int tileSize) int intensity = (int)(minDistance*256.0f/tileSize); if (intensity > 255) intensity = 255; - pixels[y*width + x] = (Color){ intensity, intensity, intensity, 255 }; + unsigned char intensityUC = (unsigned char)intensity; + pixels[y*width + x] = (Color){ intensityUC, intensityUC, intensityUC, 255 }; } } @@ -2405,7 +2406,7 @@ void ImageMipmaps(Image *image) image->data = temp; // Pointer to allocated memory point where store next mipmap level data - unsigned char *nextmip = image->data; + unsigned char *nextmip = (unsigned char *)image->data; mipWidth = image->width; mipHeight = image->height; diff --git a/src/utils.c b/src/utils.c index 5ccbc4fa9..123c7b0b9 100644 --- a/src/utils.c +++ b/src/utils.c @@ -374,7 +374,7 @@ char *LoadFileText(const char *fileName) // WARNING: \r\n is converted to \n on reading, so, // read bytes count gets reduced by the number of lines - if (count < size) text = RL_REALLOC(text, count + 1); + if (count < size) text = (char *)RL_REALLOC(text, count + 1); // Zero-terminate the string text[count] = '\0'; From 18e4d1d44fd27700b57f75722879e3a41557aafa Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 15 Oct 2025 19:20:11 +0200 Subject: [PATCH 109/167] Reviewed formating --- src/platforms/rcore_desktop_glfw.c | 14 ++++++++------ src/platforms/rcore_desktop_win32.c | 2 +- src/raudio.c | 4 ++-- src/rlgl.h | 2 +- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/platforms/rcore_desktop_glfw.c b/src/platforms/rcore_desktop_glfw.c index 0144f623d..729ca308c 100644 --- a/src/platforms/rcore_desktop_glfw.c +++ b/src/platforms/rcore_desktop_glfw.c @@ -56,12 +56,14 @@ // Support retrieving native window handlers #if defined(_WIN32) - #if !defined(HWND) && !defined(_MSVC_LANG) - #define HWND void* + #if !defined(HWND) && !defined(_MSVC_LANG) + #define HWND void* #elif !defined(HWND) && defined(_MSVC_LANG) - typedef struct HWND__ *HWND; + typedef struct HWND__ *HWND; #endif - #include "../external/win32_clipboard.h" + + #include "../external/win32_clipboard.h" // Clipboard image copy-paste + #define GLFW_EXPOSE_NATIVE_WIN32 #define GLFW_NATIVE_INCLUDE_NONE // To avoid some symbols re-definition in windows.h #include "GLFW/glfw3native.h" @@ -1030,10 +1032,10 @@ Image GetClipboardImage(void) int width = 0; int height = 0; - fileData = (void*)Win32GetClipboardImageData(&width, &height, &dataSize); + fileData = (void *)Win32GetClipboardImageData(&width, &height, &dataSize); if (fileData == NULL) TRACELOG(LOG_WARNING, "Clipboard image: Couldn't get clipboard data."); - else image = LoadImageFromMemory(".bmp", (const unsigned char*)fileData, (int)dataSize); + else image = LoadImageFromMemory(".bmp", (const unsigned char *)fileData, (int)dataSize); #else TRACELOG(LOG_WARNING, "GetClipboardImage() not implemented on target platform"); #endif diff --git a/src/platforms/rcore_desktop_win32.c b/src/platforms/rcore_desktop_win32.c index b9acde0e8..3ccd4d3bd 100644 --- a/src/platforms/rcore_desktop_win32.c +++ b/src/platforms/rcore_desktop_win32.c @@ -1486,7 +1486,7 @@ int InitPlatform(void) platform.hbitmap = CreateDIBSection( platform.hdcmem, &bmi, DIB_RGB_COLORS, - (void**)&platform.pixels, NULL, 0); + (void **)&platform.pixels, NULL, 0); SelectObject(platform.hdcmem, platform.hbitmap); diff --git a/src/raudio.c b/src/raudio.c index ca63b3aac..de2bf81b2 100644 --- a/src/raudio.c +++ b/src/raudio.c @@ -1587,7 +1587,7 @@ Music LoadMusicStreamFromMemory(const char *fileType, const unsigned char *data, else if ((strcmp(fileType, ".mp3") == 0) || (strcmp(fileType, ".MP3") == 0)) { drmp3 *ctxMp3 = (drmp3 *)RL_CALLOC(1, sizeof(drmp3)); - int success = drmp3_init_memory(ctxMp3, (const void*)data, dataSize, NULL); + int success = drmp3_init_memory(ctxMp3, (const void *)data, dataSize, NULL); if (success) { @@ -1631,7 +1631,7 @@ Music LoadMusicStreamFromMemory(const char *fileType, const unsigned char *data, #if defined(SUPPORT_FILEFORMAT_FLAC) else if ((strcmp(fileType, ".flac") == 0) || (strcmp(fileType, ".FLAC") == 0)) { - drflac *ctxFlac = drflac_open_memory((const void*)data, dataSize, NULL); + drflac *ctxFlac = drflac_open_memory((const void *)data, dataSize, NULL); if (ctxFlac != NULL) { diff --git a/src/rlgl.h b/src/rlgl.h index ecd3795a9..9cf8ebefb 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -3750,7 +3750,7 @@ void *rlReadTexturePixels(unsigned int id, int width, int height, int format) #if defined(GRAPHICS_API_OPENGL_11_SOFTWARE) // Copy framebuffer pixel data to internal buffer -void rlCopyFramebuffer(int x, int y, int width, int height, int format, void* pixels) +void rlCopyFramebuffer(int x, int y, int width, int height, int format, void *pixels) { unsigned int glInternalFormat, glFormat, glType; rlGetGlTextureFormats(format, &glInternalFormat, &glFormat, &glType); // Get OpenGL texture format From 1f65a172743fe56dbce943cded3b208cdf626571 Mon Sep 17 00:00:00 2001 From: Maicon Santana Date: Wed, 15 Oct 2025 18:22:05 +0100 Subject: [PATCH 110/167] Set name as Const and remove not used variable (#5245) From af118599062a436190288b8909bb0e15d2210ea6 Mon Sep 17 00:00:00 2001 From: GideonSerf Date: Wed, 15 Oct 2025 19:25:01 +0200 Subject: [PATCH 111/167] [examples] Added `shapes_pie_chart` (#5227) * Added shapes_pie_chart example * Made the example colorful * Added some interactivity to the example * Revert top comment to the standard * Remove unused MAX_SLICES constant --------- Co-authored-by: Gideon Serfontein Co-authored-by: Ray --- examples/Makefile | 1 + examples/Makefile.Web | 4 + examples/examples_list.txt | 1 + examples/shapes/shapes_pie_chart.c | 224 +++++++ examples/shapes/shapes_pie_chart.png | Bin 0 -> 17457 bytes .../VS2022/examples/shapes_pie_chart.vcxproj | 569 ++++++++++++++++++ projects/VS2022/raylib.sln | 2 + 7 files changed, 801 insertions(+) create mode 100644 examples/shapes/shapes_pie_chart.c create mode 100644 examples/shapes/shapes_pie_chart.png create mode 100644 projects/VS2022/examples/shapes_pie_chart.vcxproj diff --git a/examples/Makefile b/examples/Makefile index 6e2853edb..be6b4d52d 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -558,6 +558,7 @@ SHAPES = \ shapes/shapes_lines_bezier \ shapes/shapes_logo_raylib \ shapes/shapes_logo_raylib_anim \ + shapes/shapes_pie_chart \ shapes/shapes_rectangle_advanced \ shapes/shapes_rectangle_scaling \ shapes/shapes_recursive_tree \ diff --git a/examples/Makefile.Web b/examples/Makefile.Web index f1662a301..4ac55900f 100644 --- a/examples/Makefile.Web +++ b/examples/Makefile.Web @@ -558,6 +558,7 @@ SHAPES = \ shapes/shapes_lines_bezier \ shapes/shapes_logo_raylib \ shapes/shapes_logo_raylib_anim \ + shapes/shapes_pie_chart \ shapes/shapes_rectangle_advanced \ shapes/shapes_rectangle_scaling \ shapes/shapes_recursive_tree \ @@ -868,6 +869,9 @@ shapes/shapes_logo_raylib: shapes/shapes_logo_raylib.c shapes/shapes_logo_raylib_anim: shapes/shapes_logo_raylib_anim.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) +shapes/shapes_pie_chart: shapes/shapes_pie_chart.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) + shapes/shapes_rectangle_advanced: shapes/shapes_rectangle_advanced.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) diff --git a/examples/examples_list.txt b/examples/examples_list.txt index 81a61fb97..dc116ec75 100644 --- a/examples/examples_list.txt +++ b/examples/examples_list.txt @@ -72,6 +72,7 @@ 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 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 diff --git a/examples/shapes/shapes_pie_chart.c b/examples/shapes/shapes_pie_chart.c new file mode 100644 index 000000000..68993ed01 --- /dev/null +++ b/examples/shapes/shapes_pie_chart.c @@ -0,0 +1,224 @@ +/******************************************************************************************* +* +* raylib [shapes] example - pie chart +* +* Example complexity rating: [★★☆☆] 2/4 +* +* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev +* +* Example contributed by Gideon Serfontein (@GideonSerf) 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 Gideon Serfontein (@GideonSerf) +* +********************************************************************************************/ + +#include "raylib.h" +#include +#include + +#define RAYGUI_IMPLEMENTATION +#include "raygui.h" + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [shapes] example - interactive pie chart"); + + #define MAX_SLICES 10 + int sliceCount = 7; + 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}; + + for (int i = 0; i < MAX_SLICES; i++) + snprintf(labels[i], 32, "Slice %i", i + 1); + + bool showValues = true; + bool showPercentages = false; + int hoveredSlice = -1; + Rectangle scrollPanelBounds = {0}; + Vector2 scrollContentOffset = {0}; + Rectangle view = {0}; + + SetTargetFPS(60); + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) + { + // 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]; + + // Check for mouse hover over slices + hoveredSlice = -1; // Reset hovered slice + Vector2 mousePos = GetMousePosition(); + if (CheckCollisionPointRec(mousePos, canvas)) // Only check if mouse is inside the canvas + { + float dx = mousePos.x - center.x; + float dy = mousePos.y - center.y; + 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 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)) + { + hoveredSlice = i; + break; + } + currentAngle += sweep; + } + } + } + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + 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) + { + 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'; + + 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); + } + + startAngle += sweepAngle; + } + //------------------------------------------------------------------------------ + + // UI control panel + //------------------------------------------------------------------------------ + DrawRectangleRec(panelRect, Fade(LIGHTGRAY, 0.5f)); + DrawRectangleLinesEx(panelRect, 1.0f, GRAY); + + int currentY = (int)panelPos.y + 12; // Start a bit lower for margin + + GuiSpinner((Rectangle){ panelPos.x + 95, (float)currentY, 125, 25 }, "Slices ", &sliceCount, 1, MAX_SLICES, false); + currentY += 40; + + GuiCheckBox((Rectangle){ panelPos.x + 20, (float)currentY, 20, 20 }, "Show Values", &showValues); + currentY += 30; + + GuiCheckBox((Rectangle){ panelPos.x + 20, (float)currentY, 20, 20 }, "Show Percentages", &showPercentages); + currentY += 40; + + GuiLine((Rectangle){ panelPos.x + 10, (float)currentY, panelRect.width - 20, 1 }, NULL); + currentY += 20; + + // 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; + + GuiScrollPanel(scrollPanelBounds, NULL, + (Rectangle){ 0, 0, panelRect.width - 20, (float)contentHeight }, + &scrollContentOffset, &view); + + 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(); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} \ No newline at end of file diff --git a/examples/shapes/shapes_pie_chart.png b/examples/shapes/shapes_pie_chart.png new file mode 100644 index 0000000000000000000000000000000000000000..bad7960f476c0d66e32df5d38b7aded5a81b5a75 GIT binary patch literal 17457 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 Yx?Iq + + + + 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 + shapes_pie_chart + 10.0 + shapes_pie_chart + + + + 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\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + 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 f72cd64a9..9051f9200 100644 --- a/projects/VS2022/raylib.sln +++ b/projects/VS2022/raylib.sln @@ -373,6 +373,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_triangle_strip", "ex EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "web", "web", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_pie_chart", "examples\shapes_pie_chart.vcxproj", "{6B1A933E-71B8-4C1F-9E79-02D98830E671}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug.DLL|ARM64 = Debug.DLL|ARM64 From d2acf0677953a73b73a16c097dff123bd5ca3c38 Mon Sep 17 00:00:00 2001 From: Hugo Date: Wed, 15 Oct 2025 19:27:42 +0200 Subject: [PATCH 112/167] [examples] Added `core_directory_files` (#5230) * ADDED: example: `core_directory_files` * Follow raylib's conventions * Rework `core_directory_files` example * Removed alternating colors & text on directory * Update screenshot --------- Co-authored-by: Ray --- examples/Makefile | 1 + examples/Makefile.Web | 4 + examples/README.md | 7 +- examples/core/core_directory_files.c | 94 +++ examples/core/core_directory_files.png | Bin 0 -> 2280 bytes examples/examples_list.txt | 1 + .../examples/core_directory_files.vcxproj | 569 ++++++++++++++++++ projects/VS2022/raylib.sln | 429 ++++++------- tools/rexm/examples_report.md | 3 +- 9 files changed, 903 insertions(+), 205 deletions(-) create mode 100644 examples/core/core_directory_files.c create mode 100644 examples/core/core_directory_files.png create mode 100644 projects/VS2022/examples/core_directory_files.vcxproj diff --git a/examples/Makefile b/examples/Makefile index be6b4d52d..8b5faf634 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -515,6 +515,7 @@ CORE = \ core/core_custom_frame_control \ core/core_custom_logging \ core/core_delta_time \ + core/core_directory_files \ core/core_drop_files \ core/core_high_dpi \ core/core_input_actions \ diff --git a/examples/Makefile.Web b/examples/Makefile.Web index 4ac55900f..510725b6e 100644 --- a/examples/Makefile.Web +++ b/examples/Makefile.Web @@ -515,6 +515,7 @@ CORE = \ core/core_custom_frame_control \ core/core_custom_logging \ core/core_delta_time \ + core/core_directory_files \ core/core_drop_files \ core/core_high_dpi \ core/core_input_actions \ @@ -742,6 +743,9 @@ core/core_custom_logging: core/core_custom_logging.c core/core_delta_time: core/core_delta_time.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) +core/core_directory_files: core/core_directory_files.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) + core/core_drop_files: core/core_drop_files.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) diff --git a/examples/README.md b/examples/README.md index 441c5a368..3468ff34a 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: 175] +## EXAMPLES COLLECTION [TOTAL: 176] -### category: core [40] +### category: core [41] Examples using raylib[core](../src/rcore.c) platform functionality like window creation, inputs, drawing modes and system functionality. @@ -65,6 +65,7 @@ Examples using raylib[core](../src/rcore.c) platform functionality like window c | [core_render_texture](core/core_render_texture.c) | core_render_texture | ⭐☆☆☆ | 5.6-dev | 5.6-dev | [Ramon Santamaria](https://github.com/raysan5) | | [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) | ### category: shapes [26] @@ -148,7 +149,7 @@ Examples using raylib text functionality, including sprite fonts loading/generat | [text_writing_anim](text/text_writing_anim.c) | text_writing_anim | ⭐⭐☆☆ | 1.4 | 1.4 | [Ramon Santamaria](https://github.com/raysan5) | | [text_rectangle_bounds](text/text_rectangle_bounds.c) | text_rectangle_bounds | ⭐⭐⭐⭐️ | 2.5 | 4.0 | [Vlad Adrian](https://github.com/demizdor) | | [text_unicode_emojis](text/text_unicode_emojis.c) | text_unicode_emojis | ⭐⭐⭐⭐️ | 2.5 | 4.0 | [Vlad Adrian](https://github.com/demizdor) | -| [text_unicode_ranges](text/text_unicode_ranges.c) | text_unicode_ranges | ⭐⭐⭐⭐️ | 5.5 | 5.6 | [Vlad Adrian](https://github.com/demizdor) | +| [text_unicode_ranges](text/text_unicode_ranges.c) | text_unicode_ranges | ⭐⭐⭐⭐️ | 5.5 | 5.6 | [Vadim Gunko](https://github.com/GuvaCode) | | [text_3d_drawing](text/text_3d_drawing.c) | text_3d_drawing | ⭐⭐⭐⭐️ | 3.5 | 4.0 | [Vlad Adrian](https://github.com/demizdor) | | [text_codepoints_loading](text/text_codepoints_loading.c) | text_codepoints_loading | ⭐⭐⭐☆ | 4.2 | 4.2 | [Ramon Santamaria](https://github.com/raysan5) | | [text_inline_styling](text/text_inline_styling.c) | text_inline_styling | ⭐⭐⭐☆ | 5.6-dev | 5.6-dev | [Wagner Barongello](https://github.com/SultansOfCode) | diff --git a/examples/core/core_directory_files.c b/examples/core/core_directory_files.c new file mode 100644 index 000000000..27764315b --- /dev/null +++ b/examples/core/core_directory_files.c @@ -0,0 +1,94 @@ +/******************************************************************************************* +* +* raylib [core] example - directory files +* +* Example complexity rating: [★☆☆☆] 1/4 +* +* Example originally created with raylib 5.5, last time updated with raylib 5.6 +* +* Example contributed by Hugo ARNAL (@hugoarnal) 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 Hugo ARNAL (@hugoarnal) +* +********************************************************************************************/ + +#include "raylib.h" +#include // Required for: strcpy() + +#define MAX_FILEPATH_SIZE 2048 + +#define RAYGUI_IMPLEMENTATION +#include "../shapes/raygui.h" // Required for GUI controls + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [core] example - directory files"); + + char directory[MAX_FILEPATH_SIZE] = { 0 }; + strcpy(directory, GetWorkingDirectory()); + FilePathList files = LoadDirectoryFiles(directory); + + SetTargetFPS(60); + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + ClearBackground(RAYWHITE); + + DrawText(directory, 100, 40, 20, DARKGRAY); + + if (GuiButton((Rectangle){40.0f, 40.0f, 20, 20}, "<")) + { + strcpy(directory, GetPrevDirectoryPath(directory)); + UnloadDirectoryFiles(files); + files = LoadDirectoryFiles(directory); + } + + for (int i = 0; i < (int)files.count; i++) + { + Color color = Fade(LIGHTGRAY, 0.3f); + + if (!IsPathFile(files.paths[i])) + { + if (GuiButton((Rectangle){0.0f, 85.0f + 40.0f*(float)i, screenWidth, 40}, "")) + { + strcpy(directory, files.paths[i]); + UnloadDirectoryFiles(files); + files = LoadDirectoryFiles(directory); + } + } + DrawRectangle(0, 85 + 40*i, screenWidth, 40, color); + + DrawText(GetFileName(files.paths[i]), 120, 100 + 40*i, 10, GRAY); + } + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + UnloadDirectoryFiles(files); + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} diff --git a/examples/core/core_directory_files.png b/examples/core/core_directory_files.png new file mode 100644 index 0000000000000000000000000000000000000000..285e1745f5531fab094280af76ac32d02915f3fb GIT binary patch literal 2280 zcmb_eYdG6y6pu?=B8{x8qFB?;SnCo>+c9FPnrKmrdr{S((M3igv~|gvxXi}(A7g~l z3)0J^MX9OL#NXV3JPLi7WNQ`MwHtTjL*4Z5wA6H9BcT6 z`1h2F4~&S~wtuQwcxkzmrx_-Jc^}oOjVI7<4HJw5Rkgm0G~_;<*L{Wv(sM<9{G@2r zStk`2B3B{wBCR%GwARSNoPw$15qgXkJ@rTLCsa^_`RI`>p7!$Mr`8(XuaV9_^T7a4LO40UY38Z#F_`A#Dk z!M)5gfdY(4lji>BFfv%Ur7+so$-epX@E$Zj+DfDQdt|#J(=|5?mEOOr#M7X=w2Q+h ztnh^SogqD?n{F!vt804dkrG;P@$2Qwi$NL1MfT`RVTgkLYhTnh>C)r?98?o~+YD2kR-F@E~ITK3~gKwFvsy?PsjE+Uv`&uLA1b)d3wwa1=M zj9U%~>MZjj0x@GQU)_^8=%BPcf;B~bH-&5EoMhS1t;wx2v}a=#oyRswMzgQd=}#Vh;!syTOm5H0A? zEV0yY0MtUB{k!LFxa(h(-pwoZQs@2$HJE_)AXoSRJ#`P7L8NUVrld_wTCB5>+#&f# z0;DivTU|1%Ij(T3OMAdFXZr&k+~E{}6#eSg$N9S9HYJX9vocs{#=8f9>1Ds^+q{p@ znxnhu>+z^!FANAAI}#3rqx(kR$StR(op+0@**go)Hp*Nj-L zPI$GZ6aE+U!(20CZv`|nv@@*wFg;XeeC&mtF;PyzGJO-$!k4HU;A!uT!T%^MF6(_( zW4W6gIe+5YgwP?uxbxF69oBw~A!x4*tJ;QM8jog}&{BW^s&XamAPnYH~-MjUR` zESqbst0C2l}OuK6|mwwD2%bB2n z^#=zQ7qW70^+UymxT9A_cC)i^FjavWb$x7}m)>S!O5IT!(Yl_pxmQ&YOpiRa(r_2r zQ9EEZc_rQnSHkz%vz~4~PfnZKtGrlfk6`n!QfApe5(mBk$+V;HWVHD7jijhE*PD~K z7$WFH8U5~alyh9Tyr#6KvH5AK<$- zPF*faPK<6MqTqsIVS_>{Rg(!Bw;t`W3B)vTpHiU%54bX4g8XjdeRN#;*k6Ogq6mj1 zUoqpEg#^7CV1J!=X9B6+4%Mf}U5w}9o_P3y?CczA3T&G{)}SotWSRoWcOd~6)*{o& zbYck43il}Ko@=|iGT&-~quuVhGo0N5%{)U-)|1V>GQ^3FPiODTy2tkyf`2rNpsQ}2 z%sqY8y=Y%1dj8GISqW4<(=?SLBLWAK%Hi*6)pURIVo08tLh~J~GcdWq94t4nv}U0v zYB7HGVDSZ~Z$`_W+_b$Ov~}Fi!?4GwF0O4MyNxm%yBuFo>miuo)r+nqI=ymkj3qiM z0vvAgs+EsRNC7meJNL=0ddq}^CzR$8c!Gn=*hu3yuzoA1iW{7FZwij_4Eg$(V()n_ zzTw)m-O=6~34C&WY-RXfI~EC0Rr&^H-{w$eTPavhSF#hel6-%j#rEAux!omXk?UoB p<-nqx*sBOzF%hwY(c-YSg{-@Bmc=@1to)cj+*~}5un(W2{|%a6!;t_0 literal 0 HcmV?d00001 diff --git a/examples/examples_list.txt b/examples/examples_list.txt index dc116ec75..ed904d6f1 100644 --- a/examples/examples_list.txt +++ b/examples/examples_list.txt @@ -47,6 +47,7 @@ core;core_high_dpi;★★☆☆;5.0;5.5;2025;2025;"Jonathan Marler";@marler8997 core;core_render_texture;★☆☆☆;5.6-dev;5.6-dev;2025;2025;"Ramon Santamaria";@raysan5 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 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_directory_files.vcxproj b/projects/VS2022/examples/core_directory_files.vcxproj new file mode 100644 index 000000000..24dd573f8 --- /dev/null +++ b/projects/VS2022/examples/core_directory_files.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_directory_files + 10.0 + core_directory_files + + + + 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 9051f9200..881c489ba 100644 --- a/projects/VS2022/raylib.sln +++ b/projects/VS2022/raylib.sln @@ -375,6 +375,14 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "web", "web", "{02EA681E-C7D EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_pie_chart", "examples\shapes_pie_chart.vcxproj", "{6B1A933E-71B8-4C1F-9E79-02D98830E671}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_kaleidoscope", "examples\shapes_kaleidoscope.vcxproj", "{6B1A933E-71B8-4C1F-9E79-02D98830E671}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_recursive_tree", "examples\shapes_recursive_tree.vcxproj", "{6B1A933E-71B8-4C1F-9E79-02D98830E671}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_triangle_strip", "examples\shapes_triangle_strip.vcxproj", "{2CCCD9E4-9058-4291-BD89-39C979F0CA1E}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_directory_files", "examples\core_directory_files.vcxproj", "{6B1A933E-71B8-4C1F-9E79-02D98830E671}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug.DLL|ARM64 = Debug.DLL|ARM64 @@ -4397,198 +4405,222 @@ Global {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release|x64.Build.0 = Release|x64 {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release|x86.ActiveCfg = Release|Win32 {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release|x86.Build.0 = Release|Win32 - {8E132D5A-2C00-48D0-8747-97E41356F26F}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 - {8E132D5A-2C00-48D0-8747-97E41356F26F}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 - {8E132D5A-2C00-48D0-8747-97E41356F26F}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 - {8E132D5A-2C00-48D0-8747-97E41356F26F}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 - {8E132D5A-2C00-48D0-8747-97E41356F26F}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 - {8E132D5A-2C00-48D0-8747-97E41356F26F}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 - {8E132D5A-2C00-48D0-8747-97E41356F26F}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {8E132D5A-2C00-48D0-8747-97E41356F26F}.Debug|ARM64.Build.0 = Debug|ARM64 - {8E132D5A-2C00-48D0-8747-97E41356F26F}.Debug|x64.ActiveCfg = Debug|x64 - {8E132D5A-2C00-48D0-8747-97E41356F26F}.Debug|x64.Build.0 = Debug|x64 - {8E132D5A-2C00-48D0-8747-97E41356F26F}.Debug|x86.ActiveCfg = Debug|Win32 - {8E132D5A-2C00-48D0-8747-97E41356F26F}.Debug|x86.Build.0 = Debug|Win32 - {8E132D5A-2C00-48D0-8747-97E41356F26F}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 - {8E132D5A-2C00-48D0-8747-97E41356F26F}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 - {8E132D5A-2C00-48D0-8747-97E41356F26F}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 - {8E132D5A-2C00-48D0-8747-97E41356F26F}.Release.DLL|x64.Build.0 = Release.DLL|x64 - {8E132D5A-2C00-48D0-8747-97E41356F26F}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 - {8E132D5A-2C00-48D0-8747-97E41356F26F}.Release.DLL|x86.Build.0 = Release.DLL|Win32 - {8E132D5A-2C00-48D0-8747-97E41356F26F}.Release|ARM64.ActiveCfg = Release|ARM64 - {8E132D5A-2C00-48D0-8747-97E41356F26F}.Release|ARM64.Build.0 = Release|ARM64 - {8E132D5A-2C00-48D0-8747-97E41356F26F}.Release|x64.ActiveCfg = Release|x64 - {8E132D5A-2C00-48D0-8747-97E41356F26F}.Release|x64.Build.0 = Release|x64 - {8E132D5A-2C00-48D0-8747-97E41356F26F}.Release|x86.ActiveCfg = Release|Win32 - {8E132D5A-2C00-48D0-8747-97E41356F26F}.Release|x86.Build.0 = Release|Win32 - {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 - {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 - {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 - {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 - {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 - {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 - {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Debug|ARM64.Build.0 = Debug|ARM64 - {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Debug|x64.ActiveCfg = Debug|x64 - {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Debug|x64.Build.0 = Debug|x64 - {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Debug|x86.ActiveCfg = Debug|Win32 - {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Debug|x86.Build.0 = Debug|Win32 - {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 - {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 - {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 - {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Release.DLL|x64.Build.0 = Release.DLL|x64 - {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 - {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Release.DLL|x86.Build.0 = Release.DLL|Win32 - {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Release|ARM64.ActiveCfg = Release|ARM64 - {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Release|ARM64.Build.0 = Release|ARM64 - {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Release|x64.ActiveCfg = Release|x64 - {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Release|x64.Build.0 = Release|x64 - {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Release|x86.ActiveCfg = Release|Win32 - {A4662163-83E7-4309-8CAA-B0BF13655FE6}.Release|x86.Build.0 = Release|Win32 - {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 - {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 - {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 - {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 - {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 - {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 - {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Debug|ARM64.Build.0 = Debug|ARM64 - {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Debug|x64.ActiveCfg = Debug|x64 - {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Debug|x64.Build.0 = Debug|x64 - {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Debug|x86.ActiveCfg = Debug|Win32 - {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Debug|x86.Build.0 = Debug|Win32 - {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 - {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 - {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 - {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Release.DLL|x64.Build.0 = Release.DLL|x64 - {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 - {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Release.DLL|x86.Build.0 = Release.DLL|Win32 - {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Release|ARM64.ActiveCfg = Release|ARM64 - {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Release|ARM64.Build.0 = Release|ARM64 - {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Release|x64.ActiveCfg = Release|x64 - {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Release|x64.Build.0 = Release|x64 - {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Release|x86.ActiveCfg = Release|Win32 - {5F4B766F-DD52-4B53-B6C3-BC7611E17F20}.Release|x86.Build.0 = Release|Win32 - {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 - {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 - {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 - {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 - {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 - {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 - {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Debug|ARM64.Build.0 = Debug|ARM64 - {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Debug|x64.ActiveCfg = Debug|x64 - {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Debug|x64.Build.0 = Debug|x64 - {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Debug|x86.ActiveCfg = Debug|Win32 - {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Debug|x86.Build.0 = Debug|Win32 - {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 - {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 - {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 - {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Release.DLL|x64.Build.0 = Release.DLL|x64 - {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 - {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Release.DLL|x86.Build.0 = Release.DLL|Win32 - {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Release|ARM64.ActiveCfg = Release|ARM64 - {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Release|ARM64.Build.0 = Release|ARM64 - {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Release|x64.ActiveCfg = Release|x64 - {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Release|x64.Build.0 = Release|x64 - {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Release|x86.ActiveCfg = Release|Win32 - {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3}.Release|x86.Build.0 = Release|Win32 - {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 - {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 - {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 - {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 - {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 - {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 - {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Debug|ARM64.Build.0 = Debug|ARM64 - {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Debug|x64.ActiveCfg = Debug|x64 - {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Debug|x64.Build.0 = Debug|x64 - {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Debug|x86.ActiveCfg = Debug|Win32 - {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Debug|x86.Build.0 = Debug|Win32 - {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 - {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 - {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 - {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Release.DLL|x64.Build.0 = Release.DLL|x64 - {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 - {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Release.DLL|x86.Build.0 = Release.DLL|Win32 - {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Release|ARM64.ActiveCfg = Release|ARM64 - {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Release|ARM64.Build.0 = Release|ARM64 - {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Release|x64.ActiveCfg = Release|x64 - {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Release|x64.Build.0 = Release|x64 - {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Release|x86.ActiveCfg = Release|Win32 - {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC}.Release|x86.Build.0 = Release|Win32 - {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 - {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 - {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 - {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 - {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 - {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 - {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Debug|ARM64.Build.0 = Debug|ARM64 - {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Debug|x64.ActiveCfg = Debug|x64 - {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Debug|x64.Build.0 = Debug|x64 - {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Debug|x86.ActiveCfg = Debug|Win32 - {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Debug|x86.Build.0 = Debug|Win32 - {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 - {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 - {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 - {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Release.DLL|x64.Build.0 = Release.DLL|x64 - {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 - {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Release.DLL|x86.Build.0 = Release.DLL|Win32 - {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Release|ARM64.ActiveCfg = Release|ARM64 - {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Release|ARM64.Build.0 = Release|ARM64 - {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Release|x64.ActiveCfg = Release|x64 - {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Release|x64.Build.0 = Release|x64 - {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Release|x86.ActiveCfg = Release|Win32 - {0C442799-B09C-4CD1-9538-711B6E85E9BF}.Release|x86.Build.0 = Release|Win32 - {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 - {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 - {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 - {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 - {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 - {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 - {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Debug|ARM64.Build.0 = Debug|ARM64 - {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Debug|x64.ActiveCfg = Debug|x64 - {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Debug|x64.Build.0 = Debug|x64 - {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Debug|x86.ActiveCfg = Debug|Win32 - {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Debug|x86.Build.0 = Debug|Win32 - {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 - {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 - {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 - {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Release.DLL|x64.Build.0 = Release.DLL|x64 - {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 - {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Release.DLL|x86.Build.0 = Release.DLL|Win32 - {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Release|ARM64.ActiveCfg = Release|ARM64 - {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Release|ARM64.Build.0 = Release|ARM64 - {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Release|x64.ActiveCfg = Release|x64 - {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Release|x64.Build.0 = Release|x64 - {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Release|x86.ActiveCfg = Release|Win32 - {DFB40A10-F8B7-412A-BCC3-5EE49294D816}.Release|x86.Build.0 = Release|Win32 - {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 - {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 - {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 - {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 - {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 - {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 - {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Debug|ARM64.Build.0 = Debug|ARM64 - {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Debug|x64.ActiveCfg = Debug|x64 - {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Debug|x64.Build.0 = Debug|x64 - {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Debug|x86.ActiveCfg = Debug|Win32 - {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Debug|x86.Build.0 = Debug|Win32 - {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 - {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 - {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 - {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Release.DLL|x64.Build.0 = Release.DLL|x64 - {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 - {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Release.DLL|x86.Build.0 = Release.DLL|Win32 - {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Release|ARM64.ActiveCfg = Release|ARM64 - {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Release|ARM64.Build.0 = Release|ARM64 - {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Release|x64.ActiveCfg = Release|x64 - {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Release|x64.Build.0 = Release|x64 - {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.Release|x86.ActiveCfg = Release|Win32 - {BB58A5FB-1A35-4471-86D0-A5189EC541B3}.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 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug|ARM64.Build.0 = Debug|ARM64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug|x64.ActiveCfg = Debug|x64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug|x64.Build.0 = Debug|x64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug|x86.ActiveCfg = Debug|Win32 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug|x86.Build.0 = Debug|Win32 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release|ARM64.ActiveCfg = Release|ARM64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release|ARM64.Build.0 = Release|ARM64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release|x64.ActiveCfg = Release|x64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release|x64.Build.0 = Release|x64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release|x86.ActiveCfg = Release|Win32 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release|x86.Build.0 = Release|Win32 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug|ARM64.Build.0 = Debug|ARM64 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug|x64.ActiveCfg = Debug|x64 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug|x64.Build.0 = Debug|x64 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug|x86.ActiveCfg = Debug|Win32 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Debug|x86.Build.0 = Debug|Win32 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release|ARM64.ActiveCfg = Release|ARM64 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release|ARM64.Build.0 = Release|ARM64 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release|x64.ActiveCfg = Release|x64 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release|x64.Build.0 = Release|x64 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release|x86.ActiveCfg = Release|Win32 + {9DB1F875-6E65-4195-B23F-ED8095C0B99C}.Release|x86.Build.0 = Release|Win32 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug|ARM64.Build.0 = Debug|ARM64 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug|x64.ActiveCfg = Debug|x64 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug|x64.Build.0 = Debug|x64 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug|x86.ActiveCfg = Debug|Win32 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Debug|x86.Build.0 = Debug|Win32 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release|ARM64.ActiveCfg = Release|ARM64 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release|ARM64.Build.0 = Release|ARM64 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release|x64.ActiveCfg = Release|x64 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release|x64.Build.0 = Release|x64 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.Release|x86.ActiveCfg = Release|Win32 + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F}.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 + {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 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug|ARM64.Build.0 = Debug|ARM64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug|x64.ActiveCfg = Debug|x64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug|x64.Build.0 = Debug|x64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug|x86.ActiveCfg = Debug|Win32 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Debug|x86.Build.0 = Debug|Win32 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release|ARM64.ActiveCfg = Release|ARM64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release|ARM64.Build.0 = Release|ARM64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release|x64.ActiveCfg = Release|x64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release|x64.Build.0 = Release|x64 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.Release|x86.ActiveCfg = Release|Win32 + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E}.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 @@ -4768,15 +4800,10 @@ Global {2CCCD9E4-9058-4291-BD89-39C979F0CA1E} = {278D8859-20B1-428F-8448-064F46E1F021} {9DB1F875-6E65-4195-B23F-ED8095C0B99C} = {5317807F-61D4-4E0F-B6DC-2D9F12621ED9} {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} - {8E132D5A-2C00-48D0-8747-97E41356F26F} = {278D8859-20B1-428F-8448-064F46E1F021} - {A4662163-83E7-4309-8CAA-B0BF13655FE6} = {AF5BEC5C-1F2B-4DA8-B12D-D09FE569237C} - {5F4B766F-DD52-4B53-B6C3-BC7611E17F20} = {5317807F-61D4-4E0F-B6DC-2D9F12621ED9} - {FF5F9EE9-29C5-40EE-BBCF-AE51B001FEC3} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} - {A9C422E7-0F03-4DBC-AC93-5C3EF4942DEC} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} - {0C442799-B09C-4CD1-9538-711B6E85E9BF} = {278D8859-20B1-428F-8448-064F46E1F021} - {DFB40A10-F8B7-412A-BCC3-5EE49294D816} = {278D8859-20B1-428F-8448-064F46E1F021} - {BB58A5FB-1A35-4471-86D0-A5189EC541B3} = {278D8859-20B1-428F-8448-064F46E1F021} - {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} = {8716DC0F-4FDE-4F57-8E25-5F78DFB80FE1} + {6B1A933E-71B8-4C1F-9E79-02D98830E671} = {278D8859-20B1-428F-8448-064F46E1F021} + {6B1A933E-71B8-4C1F-9E79-02D98830E671} = {278D8859-20B1-428F-8448-064F46E1F021} + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E} = {278D8859-20B1-428F-8448-064F46E1F021} + {6B1A933E-71B8-4C1F-9E79-02D98830E671} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {E926C768-6307-4423-A1EC-57E95B1FAB29} diff --git a/tools/rexm/examples_report.md b/tools/rexm/examples_report.md index 60da00dd5..e9a70930b 100644 --- a/tools/rexm/examples_report.md +++ b/tools/rexm/examples_report.md @@ -60,6 +60,7 @@ Example elements validated: | core_render_texture | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | core_undo_redo | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | core_input_actions | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| core_directory_files | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shapes_basic_shapes | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shapes_bouncing_ball | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shapes_bullet_hell | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | @@ -85,7 +86,6 @@ Example elements validated: | shapes_dashed_line | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shapes_triangle_strip | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shapes_vector_angle | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | -| shapes_kaleidoscope | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | textures_logo_raylib | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | textures_srcrec_dstrec | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | textures_image_drawing | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | @@ -195,3 +195,4 @@ Example elements validated: | raylib_opengl_interop | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | | embedded_files_loading | ✔ | ❌ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | web_basic_window | ✔ | ❌ | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| shapes_kaleidoscope | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | From 21404d958ef7d78727c6984d87dddc9b128e538c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robin=20=E2=9D=A4=EF=B8=8F?= Date: Wed, 15 Oct 2025 13:28:38 -0400 Subject: [PATCH 113/167] [examples] Added `core_clipboard_text` (#5231) * added clipboard example * added image check * added note about windows * added indent --- examples/core/core_clipboard_text.c | 208 ++++++++++++++++++++++++++ examples/core/core_clipboard_text.png | Bin 0 -> 15878 bytes 2 files changed, 208 insertions(+) create mode 100644 examples/core/core_clipboard_text.c create mode 100644 examples/core/core_clipboard_text.png diff --git a/examples/core/core_clipboard_text.c b/examples/core/core_clipboard_text.c new file mode 100644 index 000000000..973163cb5 --- /dev/null +++ b/examples/core/core_clipboard_text.c @@ -0,0 +1,208 @@ +/******************************************************************************************* +* +* raylib [core] example - clipboard text +* +* Example complexity rating: [★☆☆☆] 1/4 +* +* Example originally created with raylib 5.6-dev +* +* 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 + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [core] example - clipboard text"); + + const char* clipboardText = NULL; + + // List of text the user can switch through and copy + const char* copyableText[] = {"raylib is fun", "hello, clipboard!", "potato chips"}; + + unsigned int textIndex = 0; + + const char* popupText = NULL; + + // Initialize timers + // The amount of time the pop-up text is on screen, before fading + const float maxTime = 3.0f; + float textTimer = 0.0f; + // The length of time text is offset + const float animMaxTime = 0.1f; + float pasteAnim = 0.0f; + float copyAnim = 0.0f; + int copyAnimMult = 1; + float textAnim = 0.0f; + float textAlpha = 0.0f; + // Offset amount for animations + const int offsetAmount = -4; + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + // Check if the user has pressed the copy/paste key combinations + bool pastePressed = (IsKeyDown(KEY_LEFT_CONTROL) && IsKeyPressed(KEY_V)); + bool copyPressed = (IsKeyDown(KEY_LEFT_CONTROL) && IsKeyPressed(KEY_C)); + + // Update animation timers + if (textTimer > 0) textTimer -= GetFrameTime(); + if (pasteAnim > 0) pasteAnim -= GetFrameTime(); + if (copyAnim > 0) copyAnim -= GetFrameTime(); + if (textAnim > 0) textAnim -= GetFrameTime(); + + // React to the user pressing paste + if (pastePressed) + { + // Most operating systems hide this information until the user presses Ctrl-V on the window. + + // Check to see if the clipboard contains an image + // This function does nothing outside of Windows, as it directly calls the Windows API + Image image = GetClipboardImage(); + + if (IsImageValid(image)) + { + // Unload the image + UnloadImage(image); + // Update visuals + popupText = "clipboard contains image"; + } + else + { + // Get text from the user's clipboard + clipboardText = GetClipboardText(); + + // Update visuals + popupText = "text pasted"; + pasteAnim = animMaxTime; + } + + // Reset animation values + textTimer = maxTime; + textAnim = animMaxTime; + textAlpha = 1; + } + + // React to the user pressing copy + if (copyPressed) + { + // Set the text on the user's clipboard + SetClipboardText(copyableText[textIndex]); + + // Reset values + textTimer = maxTime; + textAnim = animMaxTime; + copyAnim = animMaxTime; + copyAnimMult = 1; + textAlpha = 1; + // Update the text that pops up at the bottom of the screen + popupText = "text copied"; + } + + // Switch to the next item in the list when the user presses up + if (IsKeyPressed(KEY_UP)) + { + // Reset animation + copyAnim = animMaxTime; + copyAnimMult = 1; + + textIndex += 1; + + if (textIndex >= sizeof(copyableText) / sizeof(const char*)) // Length of array + { + // Loop back to the other end + textIndex = 0; + } + } + + // Switch to the previous item in the list when the user presses down + if (IsKeyPressed(KEY_DOWN)) + { + // Reset animation + copyAnim = animMaxTime; + copyAnimMult = -1; + + if (textIndex == 0) + { + // Loop back to the other end + textIndex = (sizeof(copyableText) / sizeof(const char*)) - 1; // Length of array minus one + } + else + { + textIndex -= 1; + } + } + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + // Draw the user's pasted text, if there is any yet + if (clipboardText) + { + // Offset animation + int offset = 0; + if (pasteAnim > 0) offset = offsetAmount; + + // Draw the pasted text + DrawText("pasted clipboard:", 10, 10 + offset, 20, DARKGREEN); + DrawText(clipboardText, 10, 30 + offset, 20, DARKGRAY); + } + + // Offset animation + int textOffset = 0; + if (copyAnim > 0) textOffset = offsetAmount; + + // Draw copyable text and controls + DrawText(copyableText[textIndex], 10, 330 + (textOffset * copyAnimMult), 20, MAROON); + DrawText("up/down to change string, ctrl-c to copy, ctrl-v to paste", 10, 355, 20, DARKGRAY); + + // Alpha / Offset animation + if (textAlpha > 0) + { + // Offset animation + int offset = 0; + if (textAnim > 0) offset = offsetAmount; + // Draw pop up text + DrawText(popupText, 10, 425 + offset, 20, ColorAlpha(DARKGREEN, textAlpha)); + + // Fade-out animation + if (textTimer < 0) + { + textAlpha -= GetFrameTime(); + } + } + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} \ No newline at end of file diff --git a/examples/core/core_clipboard_text.png b/examples/core/core_clipboard_text.png new file mode 100644 index 0000000000000000000000000000000000000000..caa9b314a694bdb9316f9f8d07161887d53887e6 GIT binary patch literal 15878 zcmeHOX;c&E8cu*hRDuX7B&-q9%4G=<6~Radn6QI@%SEIpTTB!YNnKb3ia~1-tQHky zYgj}?!2)6w3j{4iu%w`PKvWbd3Ix0oSp@AQ<8qHorakALd+ND&{>%w8Wajyv?|q-| zdo#~_*vo^CosFN3LZPtEPLAFvl)M27g|5da0%tUXN*hrqa*MO0z3<+Dps7jmzyZ!$ zB3_P1ka38@pbLdwde{V^sutt{z5ie>Ln)Y4n!>4NV7L$mBKKISE2s zn$VFf3kKz~s@70EcX5?W415qnxl9Za2yHU(0T4z&2)=(W1cI%6eRtq(RQ>2tHNUPS zw_;p|bkC0buwhDh&)bv**JsX=KQ%CF)?J35%<0M9gel{4#I2Zwi`XS}9+RX%a|oPq z;KX3Kw*h`1!|;m|S{XEmF2|>|xA~Dxl3IuCbC%|QZ+j?(;63znh*`5vq(F1S-n=gQ z#c>|{T5fU&u+*&KYBUH~#o=0_8`avO}An zq>6l~lZ{!<1|4MHwqw;mls^=nfPzkOld@EJ9FC=yVRW8YPj0INb5svInZJ}doJHuk z!z&6*N&jIcP-_P%86mJ_WTOe}QoHi!#Wi6Hv5T_XYmC|-v{5chCxwPH=IfVfII&(j zyFY8-heh3FRcPqWNYXkS$i;3LE^5cc108Q0?k(pR#zhn~3CFcejUXdsE670?3Iv~8IR%1>;)?H>HPwDgF9@;`ZQd zUolaiH{hWEOn-ad<8PNTuc&v&jE)$sxb_SCA>)A#Bmrm_@DbC}bb&g&PoZJ-g?Vgd zaq>Y-Ud`NmzC1bKnQfkTY9afgV!T+gQ6tW z_A56s_}Y+^1CIfelo&TXDYmnys-rd2J=fsR6z?X*(OgrYz~rfd(G&#}O~g(#&V4)d zNF|H0ZkmuJV^IdaG)0Z?CmZmN*~y|6`05ExZNJ)iAqkfH|A&QDvc345*LDQLXR^sc zCIXoV=?d_9?D>&!M8XjX#}B_7AW12q0$~AR;eBC;!~zlvNG$yOuZ2iPAQ^#V1db_1hi>ggubkWmDscZJ82TFZ;KfxrS*7;UI)gmc@@