From 57dd345dc3ac95332d656a06ac110237699e3726 Mon Sep 17 00:00:00 2001 From: Jeffery Myers Date: Sat, 3 Dec 2022 13:55:05 -0800 Subject: [PATCH 001/192] Add a textured curve example (#2821) --- examples/Makefile | 1 + .../textures/resources/roadTexture_01.png | Bin 0 -> 1006 bytes examples/textures/textures_textured_curve.c | 241 +++++++++++ examples/textures/textures_textured_curve.png | Bin 0 -> 21036 bytes .../examples/textures_textured_curve.vcxproj | 387 ++++++++++++++++++ projects/VS2022/raylib.sln | 19 + 6 files changed, 648 insertions(+) create mode 100644 examples/textures/resources/roadTexture_01.png create mode 100644 examples/textures/textures_textured_curve.c create mode 100644 examples/textures/textures_textured_curve.png create mode 100644 projects/VS2022/examples/textures_textured_curve.vcxproj diff --git a/examples/Makefile b/examples/Makefile index 9afa48cb65ef..edfbab118e5b 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -460,6 +460,7 @@ TEXTURES = \ textures/textures_sprite_anim \ textures/textures_sprite_button \ textures/textures_sprite_explosion \ + textures/textures_textured_curve \ textures/textures_bunnymark \ textures/textures_blend_modes \ textures/textures_draw_tiled \ diff --git a/examples/textures/resources/roadTexture_01.png b/examples/textures/resources/roadTexture_01.png new file mode 100644 index 0000000000000000000000000000000000000000..082f4cd2e0f45189431385d5ae9c67ffc2e193ea GIT binary patch literal 1006 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 bFq^~G`NAeyg|lH8>gVu5!vh)GwBY{>Js&=- literal 0 HcmV?d00001 diff --git a/projects/VS2022/examples/textures_textured_curve.vcxproj b/projects/VS2022/examples/textures_textured_curve.vcxproj new file mode 100644 index 000000000000..9b989f72c45e --- /dev/null +++ b/projects/VS2022/examples/textures_textured_curve.vcxproj @@ -0,0 +1,387 @@ + + + + + Debug.DLL + Win32 + + + Debug.DLL + x64 + + + Debug + Win32 + + + Debug + x64 + + + Release.DLL + Win32 + + + Release.DLL + x64 + + + Release + Win32 + + + Release + x64 + + + + {769FF0C1-4424-4FA3-BC44-D7A7DA312A06} + Win32Proj + textures_textured_curve + 10.0 + textures_textured_curve + + + + 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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)\ + + + $(SolutionDir)..\..\examples\textures + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\textures + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\textures + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\textures + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\textures + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\textures + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\textures + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\textures + 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) + + + 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)\ + + + 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 b4ab4201c3b2..13d0df6de25a 100644 --- a/projects/VS2022/raylib.sln +++ b/projects/VS2022/raylib.sln @@ -263,6 +263,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "textures_polygon", "example EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "audio_stream_effects", "examples\audio_stream_effects.vcxproj", "{4A87569C-4BD3-4113-B4B9-573D65B3D3F8}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "textures_textured_curve", "examples\textures_textured_curve.vcxproj", "{769FF0C1-4424-4FA3-BC44-D7A7DA312A06}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug.DLL|x64 = Debug.DLL|x64 @@ -2207,6 +2209,22 @@ Global {4A87569C-4BD3-4113-B4B9-573D65B3D3F8}.Release|x64.Build.0 = Release|x64 {4A87569C-4BD3-4113-B4B9-573D65B3D3F8}.Release|x86.ActiveCfg = Release|Win32 {4A87569C-4BD3-4113-B4B9-573D65B3D3F8}.Release|x86.Build.0 = Release|Win32 + {769FF0C1-4424-4FA3-BC44-D7A7DA312A06}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {769FF0C1-4424-4FA3-BC44-D7A7DA312A06}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {769FF0C1-4424-4FA3-BC44-D7A7DA312A06}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {769FF0C1-4424-4FA3-BC44-D7A7DA312A06}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {769FF0C1-4424-4FA3-BC44-D7A7DA312A06}.Debug|x64.ActiveCfg = Debug|x64 + {769FF0C1-4424-4FA3-BC44-D7A7DA312A06}.Debug|x64.Build.0 = Debug|x64 + {769FF0C1-4424-4FA3-BC44-D7A7DA312A06}.Debug|x86.ActiveCfg = Debug|Win32 + {769FF0C1-4424-4FA3-BC44-D7A7DA312A06}.Debug|x86.Build.0 = Debug|Win32 + {769FF0C1-4424-4FA3-BC44-D7A7DA312A06}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {769FF0C1-4424-4FA3-BC44-D7A7DA312A06}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {769FF0C1-4424-4FA3-BC44-D7A7DA312A06}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {769FF0C1-4424-4FA3-BC44-D7A7DA312A06}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {769FF0C1-4424-4FA3-BC44-D7A7DA312A06}.Release|x64.ActiveCfg = Release|x64 + {769FF0C1-4424-4FA3-BC44-D7A7DA312A06}.Release|x64.Build.0 = Release|x64 + {769FF0C1-4424-4FA3-BC44-D7A7DA312A06}.Release|x86.ActiveCfg = Release|Win32 + {769FF0C1-4424-4FA3-BC44-D7A7DA312A06}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -2340,6 +2358,7 @@ Global {27B110CC-43C0-400A-89D9-245E681647D7} = {8D3C83B7-F1E0-4C2E-9E34-EE5F6AB2502A} {1DE84812-E143-4C4B-A61D-9267AAD55401} = {DA049009-21FF-4AC0-84E4-830DD1BCD0CE} {4A87569C-4BD3-4113-B4B9-573D65B3D3F8} = {CC132A4D-D081-4C26-BFB9-AB11984054F8} + {769FF0C1-4424-4FA3-BC44-D7A7DA312A06} = {DA049009-21FF-4AC0-84E4-830DD1BCD0CE} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {E926C768-6307-4423-A1EC-57E95B1FAB29} From 89698844a132321fb94402e20eb095cbd6462e78 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 4 Dec 2022 11:01:59 +0100 Subject: [PATCH 002/192] REVIEWED: Example: `textures_textured_curve` --- .../{roadTexture_01.png => road.png} | Bin examples/textures/textures_textured_curve.c | 286 ++++++++++-------- examples/textures/textures_textured_curve.png | Bin 21036 -> 47993 bytes 3 files changed, 152 insertions(+), 134 deletions(-) rename examples/textures/resources/{roadTexture_01.png => road.png} (100%) diff --git a/examples/textures/resources/roadTexture_01.png b/examples/textures/resources/road.png similarity index 100% rename from examples/textures/resources/roadTexture_01.png rename to examples/textures/resources/road.png diff --git a/examples/textures/textures_textured_curve.c b/examples/textures/textures_textured_curve.c index 1407f7388c15..276670972abc 100644 --- a/examples/textures/textures_textured_curve.c +++ b/examples/textures/textures_textured_curve.c @@ -2,145 +2,219 @@ * * raylib [textures] example - Draw a texture along a segmented curve * -* Example originally created with raylib 4.5 +* Example originally created with raylib 4.5-dev * * Example contributed by Jeffery Myers 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) 2019-2022 Jeffery Myers and Ramon Santamaria (@raysan5) +* Copyright (c) 2022 Jeffery Myers and Ramon Santamaria (@raysan5) * ********************************************************************************************/ #include "raylib.h" + #include "raymath.h" #include "rlgl.h" -Texture RoadTexture = { 0 }; +#include // Required for: powf() +#include // Required for: NULL + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +static Texture texRoad = { 0 }; + +static bool showCurve = false; + +static float curveWidth = 50; +static int curveSegments = 24; + +static Vector2 curveStartPosition = { 0 }; +static Vector2 curveStartPositionTangent = { 0 }; + +static Vector2 curveEndPosition = { 0 }; +static Vector2 curveEndPositionTangent = { 0 }; + +static Vector2 *curveSelectedPoint = NULL; + +//---------------------------------------------------------------------------------- +// Module Functions Declaration +//---------------------------------------------------------------------------------- +static void UpdateOptions(void); +static void UpdateCurve(void); +static void DrawCurve(void); +static void DrawTexturedCurve(void); + -bool ShowCurve = false; +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main() +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + SetConfigFlags(FLAG_VSYNC_HINT | FLAG_MSAA_4X_HINT); + InitWindow(screenWidth, screenHeight, "raylib [textures] examples - textured curve"); + + // Load the road texture + texRoad = LoadTexture("resources/road.png"); + SetTextureFilter(texRoad, TEXTURE_FILTER_BILINEAR); + + // Setup the curve + curveStartPosition = (Vector2){ 80, 100 }; + curveStartPositionTangent = (Vector2){ 100, 300 }; + + curveEndPosition = (Vector2){ 700, 350 }; + curveEndPositionTangent = (Vector2){ 600, 100 }; + + 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 + //---------------------------------------------------------------------------------- + UpdateCurve(); + UpdateOptions(); -float Width = 50; -int Segments = 24; + //---------------------------------------------------------------------------------- -Vector2 SP = { 0 }; -Vector2 SPTangent = { 0 }; + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); -Vector2 EP = { 0 }; -Vector2 EPTangent = { 0 }; + ClearBackground(RAYWHITE); -Vector2* Selected = NULL; + DrawTexturedCurve(); + DrawCurve(); + + DrawText("Drag points to move curve, press SPACE to show/hide base curve", 10, 10, 10, DARKGRAY); + DrawText(TextFormat("Curve width: %2.0f (Use + and - to adjust)", curveWidth), 10, 30, 10, DARKGRAY); + DrawText(TextFormat("Curve segments: %d (Use LEFT and RIGHT to adjust)", curveSegments), 10, 50, 10, DARKGRAY); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } -void DrawCurve() + // De-Initialization + //-------------------------------------------------------------------------------------- + UnloadTexture(texRoad); + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} + +//---------------------------------------------------------------------------------- +// Module Functions Definition +//---------------------------------------------------------------------------------- +static void DrawCurve(void) { - if (ShowCurve) - DrawLineBezierCubic(SP, EP, SPTangent, EPTangent, 2, BLUE); + if (showCurve) DrawLineBezierCubic(curveStartPosition, curveEndPosition, curveStartPositionTangent, curveEndPositionTangent, 2, BLUE); - // draw the various control points and highlight where the mouse is - DrawLineV(SP, SPTangent, SKYBLUE); - DrawLineV(EP, EPTangent, PURPLE); + // Draw the various control points and highlight where the mouse is + DrawLineV(curveStartPosition, curveStartPositionTangent, SKYBLUE); + DrawLineV(curveEndPosition, curveEndPositionTangent, PURPLE); Vector2 mouse = GetMousePosition(); - if (CheckCollisionPointCircle(mouse, SP, 6)) - DrawCircleV(SP, 7, YELLOW); - DrawCircleV(SP, 5, RED); + if (CheckCollisionPointCircle(mouse, curveStartPosition, 6)) DrawCircleV(curveStartPosition, 7, YELLOW); + DrawCircleV(curveStartPosition, 5, RED); - if (CheckCollisionPointCircle(mouse, SPTangent, 6)) - DrawCircleV(SPTangent, 7, YELLOW); - DrawCircleV(SPTangent, 5, MAROON); + if (CheckCollisionPointCircle(mouse, curveStartPositionTangent, 6)) DrawCircleV(curveStartPositionTangent, 7, YELLOW); + DrawCircleV(curveStartPositionTangent, 5, MAROON); - if (CheckCollisionPointCircle(mouse, EP, 6)) - DrawCircleV(EP, 7, YELLOW); - DrawCircleV(EP, 5, GREEN); + if (CheckCollisionPointCircle(mouse, curveEndPosition, 6)) DrawCircleV(curveEndPosition, 7, YELLOW); + DrawCircleV(curveEndPosition, 5, GREEN); - if (CheckCollisionPointCircle(mouse, EPTangent, 6)) - DrawCircleV(EPTangent, 7, YELLOW); - DrawCircleV(EPTangent, 5, DARKGREEN); + if (CheckCollisionPointCircle(mouse, curveEndPositionTangent, 6)) DrawCircleV(curveEndPositionTangent, 7, YELLOW); + DrawCircleV(curveEndPositionTangent, 5, DARKGREEN); } -void EditCurve() +static void UpdateCurve(void) { - // if the mouse is not down, we are not editing the curve so clear the selection + // If the mouse is not down, we are not editing the curve so clear the selection if (!IsMouseButtonDown(MOUSE_LEFT_BUTTON)) { - Selected = NULL; + curveSelectedPoint = NULL; return; } - // if a point was selected, move it - if (Selected) + // If a point was selected, move it + if (curveSelectedPoint) { - *Selected = Vector2Add(*Selected, GetMouseDelta()); + *curveSelectedPoint = Vector2Add(*curveSelectedPoint, GetMouseDelta()); return; } - // the mouse is down, and nothing was selected, so see if anything was picked + // The mouse is down, and nothing was selected, so see if anything was picked Vector2 mouse = GetMousePosition(); - if (CheckCollisionPointCircle(mouse, SP, 6)) - Selected = &SP; - else if (CheckCollisionPointCircle(mouse, SPTangent, 6)) - Selected = &SPTangent; - else if (CheckCollisionPointCircle(mouse, EP, 6)) - Selected = &EP; - else if (CheckCollisionPointCircle(mouse, EPTangent, 6)) - Selected = &EPTangent; + if (CheckCollisionPointCircle(mouse, curveStartPosition, 6)) curveSelectedPoint = &curveStartPosition; + else if (CheckCollisionPointCircle(mouse, curveStartPositionTangent, 6)) curveSelectedPoint = &curveStartPositionTangent; + else if (CheckCollisionPointCircle(mouse, curveEndPosition, 6)) curveSelectedPoint = &curveEndPosition; + else if (CheckCollisionPointCircle(mouse, curveEndPositionTangent, 6)) curveSelectedPoint = &curveEndPositionTangent; } -void DrawTexturedCurve() +static void DrawTexturedCurve(void) { - const float step = 1.0f / Segments; + const float step = 1.0f/curveSegments; - Vector2 previous = SP; + Vector2 previous = curveStartPosition; Vector2 previousTangent = { 0 }; float previousV = 0; - // we can't compute a tangent for the first point, so we need to reuse the tangent from the first segment + // We can't compute a tangent for the first point, so we need to reuse the tangent from the first segment bool tangentSet = false; Vector2 current = { 0 }; float t = 0.0f; - for (int i = 1; i <= Segments; i++) + for (int i = 1; i <= curveSegments; i++) { - // segment the curve - t = step * i; + // Segment the curve + t = step*i; float a = powf(1 - t, 3); - float b = 3 * powf(1 - t, 2) * t; - float c = 3 * (1 - t) * powf(t, 2); + float b = 3*powf(1 - t, 2)*t; + float c = 3*(1 - t)*powf(t, 2); float d = powf(t, 3); - // compute the endpoint for this segment - current.y = a * SP.y + b * SPTangent.y + c * EPTangent.y + d * EP.y; - current.x = a * SP.x + b * SPTangent.x + c * EPTangent.x + d * EP.x; + // Compute the endpoint for this segment + current.y = a*curveStartPosition.y + b*curveStartPositionTangent.y + c*curveEndPositionTangent.y + d*curveEndPosition.y; + current.x = a*curveStartPosition.x + b*curveStartPositionTangent.x + c*curveEndPositionTangent.x + d*curveEndPosition.x; - // vector from previous to current + // Vector from previous to current Vector2 delta = { current.x - previous.x, current.y - previous.y }; - // the right hand normal to the delta vector + // The right hand normal to the delta vector Vector2 normal = Vector2Normalize((Vector2){ -delta.y, delta.x }); - // the v texture coordinate of the segment (add up the length of all the segments so far) + // The v texture coordinate of the segment (add up the length of all the segments so far) float v = previousV + Vector2Length(delta); - // make sure the start point has a normal + // Make sure the start point has a normal if (!tangentSet) { previousTangent = normal; tangentSet = true; } - // extend out the normals from the previous and current points to get the quad for this segment - Vector2 prevPosNormal = Vector2Add(previous, Vector2Scale(previousTangent, Width)); - Vector2 prevNegNormal = Vector2Add(previous, Vector2Scale(previousTangent, -Width)); + // Extend out the normals from the previous and current points to get the quad for this segment + Vector2 prevPosNormal = Vector2Add(previous, Vector2Scale(previousTangent, curveWidth)); + Vector2 prevNegNormal = Vector2Add(previous, Vector2Scale(previousTangent, -curveWidth)); - Vector2 currentPosNormal = Vector2Add(current, Vector2Scale(normal, Width)); - Vector2 currentNegNormal = Vector2Add(current, Vector2Scale(normal, -Width)); + Vector2 currentPosNormal = Vector2Add(current, Vector2Scale(normal, curveWidth)); + Vector2 currentNegNormal = Vector2Add(current, Vector2Scale(normal, -curveWidth)); - // draw the segment as a quad - rlSetTexture(RoadTexture.id); + // Draw the segment as a quad + rlSetTexture(texRoad.id); rlBegin(RL_QUADS); rlColor4ub(255,255,255,255); @@ -160,82 +234,26 @@ void DrawTexturedCurve() rlEnd(); - // the current step is the start of the next step + // The current step is the start of the next step previous = current; previousTangent = normal; previousV = v; } } -void UpdateOptions() +static void UpdateOptions(void) { - if (IsKeyPressed(KEY_SPACE)) - ShowCurve = !ShowCurve; - - // width - if (IsKeyPressed(KEY_EQUAL)) - Width += 2; - - if (IsKeyPressed(KEY_MINUS)) - Width -= 2; - - if (Width < 2) - Width = 2; + if (IsKeyPressed(KEY_SPACE)) showCurve = !showCurve; - // segments + // Update with + if (IsKeyPressed(KEY_EQUAL)) curveWidth += 2; + if (IsKeyPressed(KEY_MINUS)) curveWidth -= 2; - if (IsKeyPressed(KEY_LEFT_BRACKET)) - Segments -= 2; + if (curveWidth < 2) curveWidth = 2; - if (IsKeyPressed(KEY_RIGHT_BRACKET)) - Segments += 2; + // Update segments + if (IsKeyPressed(KEY_LEFT)) curveSegments -= 2; + if (IsKeyPressed(KEY_RIGHT)) curveSegments += 2; - if (Segments < 2) - Segments = 2; + if (curveSegments < 2) curveSegments = 2; } - -int main () -{ - // set up the window - SetConfigFlags(FLAG_VSYNC_HINT); - InitWindow(1280, 800, "raylib [textures] examples - textured curve"); - SetTargetFPS(144); - - // load the road texture - RoadTexture = LoadTexture("resources/roadTexture_01.png"); - - // setup the curve - SP = (Vector2){ 80, 400 }; - SPTangent = (Vector2){ 600, 100 }; - - EP = (Vector2){ 1200, 400 }; - EPTangent = (Vector2){ 600, 700 }; - - // game loop - while (!WindowShouldClose()) - { - EditCurve(); - UpdateOptions(); - - BeginDrawing(); - - ClearBackground(BLACK); - - DrawTexturedCurve(); - DrawCurve(); - - DrawText("Drag points to move curve, press space to show/hide base curve", 10, 0, 20, WHITE); - DrawText(TextFormat("Width %2.0f + and - to adjust", Width), 10, 20, 20, WHITE); - DrawText(TextFormat("Segments %d [ and ] to adjust", Segments), 10, 40, 20, WHITE); - DrawFPS(10, 60); - - EndDrawing(); - } - - // cleanup - UnloadTexture(RoadTexture); - CloseWindow(); - return 0; -} - - \ No newline at end of file diff --git a/examples/textures/textures_textured_curve.png b/examples/textures/textures_textured_curve.png index 1f45e8d2544ac297ea274c953ff74a2007432b4f..6d5efacb6c563305ee76169643fe9780eb959c10 100644 GIT binary patch literal 47993 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 bFq^~G`NAeyg|lH8>gVu5!vh)GwBY{>Js&=- From 4de64f5750eacd5d7acfb7b41d5b9f251cb502fb Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 4 Dec 2022 13:22:37 +0100 Subject: [PATCH 003/192] Expose OpenGL blending mode factors and functions/equations --- src/rlgl.h | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/src/rlgl.h b/src/rlgl.h index e4f65d69a21b..301bd976d1ef 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -264,7 +264,7 @@ #define RL_UNSIGNED_BYTE 0x1401 // GL_UNSIGNED_BYTE #define RL_FLOAT 0x1406 // GL_FLOAT -// Buffer usage hint +// GL buffer usage hint #define RL_STREAM_DRAW 0x88E0 // GL_STREAM_DRAW #define RL_STREAM_READ 0x88E1 // GL_STREAM_READ #define RL_STREAM_COPY 0x88E2 // GL_STREAM_COPY @@ -280,6 +280,37 @@ #define RL_VERTEX_SHADER 0x8B31 // GL_VERTEX_SHADER #define RL_COMPUTE_SHADER 0x91B9 // GL_COMPUTE_SHADER +// GL blending factors +#define RL_ZERO 0 // GL_ZERO +#define RL_ONE 1 // GL_ONE +#define RL_SRC_COLOR 0x0300 // GL_SRC_COLOR +#define RL_ONE_MINUS_SRC_COLOR 0x0301 // GL_ONE_MINUS_SRC_COLOR +#define RL_SRC_ALPHA 0x0302 // GL_SRC_ALPHA +#define RL_ONE_MINUS_SRC_ALPHA 0x0303 // GL_ONE_MINUS_SRC_ALPHA +#define RL_DST_ALPHA 0x0304 // GL_DST_ALPHA +#define RL_ONE_MINUS_DST_ALPHA 0x0305 // GL_ONE_MINUS_DST_ALPHA +#define RL_DST_COLOR 0x0306 // GL_DST_COLOR +#define RL_ONE_MINUS_DST_COLOR 0x0307 // GL_ONE_MINUS_DST_COLOR +#define RL_SRC_ALPHA_SATURATE 0x0308 // GL_SRC_ALPHA_SATURATE +#define RL_CONSTANT_COLOR 0x8001 // GL_CONSTANT_COLOR +#define RL_ONE_MINUS_CONSTANT_COLOR 0x8002 // GL_ONE_MINUS_CONSTANT_COLOR +#define RL_CONSTANT_ALPHA 0x8003 // GL_CONSTANT_ALPHA +#define RL_ONE_MINUS_CONSTANT_ALPHA 0x8004 // GL_ONE_MINUS_CONSTANT_ALPHA + +// GL blending functions/equations +#define RL_FUNC_ADD 0x8006 // GL_FUNC_ADD +#define RL_FUNC_SUBTRACT 0x800A // GL_FUNC_SUBTRACT +#define RL_FUNC_REVERSE_SUBTRACT 0x800B // GL_FUNC_REVERSE_SUBTRACT +#define RL_BLEND_EQUATION 0x8009 // GL_BLEND_EQUATION +#define RL_BLEND_EQUATION_RGB 0x8009 // GL_BLEND_EQUATION_RGB // (Same as BLEND_EQUATION) +#define RL_BLEND_EQUATION_ALPHA 0x883D // GL_BLEND_EQUATION_ALPHA +#define RL_BLEND_DST_RGB 0x80C8 // GL_BLEND_DST_RGB +#define RL_BLEND_SRC_RGB 0x80C9 // GL_BLEND_SRC_RGB +#define RL_BLEND_DST_ALPHA 0x80CA // GL_BLEND_DST_ALPHA +#define RL_BLEND_SRC_ALPHA 0x80CB // GL_BLEND_SRC_ALPHA +#define RL_BLEND_COLOR 0x8005 // GL_BLEND_COLOR + + //---------------------------------------------------------------------------------- // Types and Structures Definition //---------------------------------------------------------------------------------- From f1368c36dd38dd912782485ce827fb8b35b86365 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 5 Dec 2022 00:24:55 +0100 Subject: [PATCH 004/192] ADDED: `ColorBrightness()` --- src/raylib.h | 1 + src/rtextures.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/src/raylib.h b/src/raylib.h index c48380d828d6..6642bc8d39a9 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1331,6 +1331,7 @@ RLAPI Vector4 ColorNormalize(Color color); // G RLAPI Color ColorFromNormalized(Vector4 normalized); // Get Color from normalized values [0..1] RLAPI Vector3 ColorToHSV(Color color); // Get HSV values for a Color, hue [0..360], saturation/value [0..1] RLAPI Color ColorFromHSV(float hue, float saturation, float value); // Get a Color from HSV values, hue [0..360], saturation/value [0..1] +RLAPI Color ColorBrightness(Color color, float factor); // Get color with brightness correction, brightness factor goes from 0.0f to 1.0f RLAPI Color ColorAlpha(Color color, float alpha); // Get color with alpha applied, alpha goes from 0.0f to 1.0f RLAPI Color ColorAlphaBlend(Color dst, Color src, Color tint); // Get src alpha-blended into dst color with tint RLAPI Color GetColor(unsigned int hexValue); // Get Color structure from hexadecimal value diff --git a/src/rtextures.c b/src/rtextures.c index 82de04785eac..66434c116bc9 100644 --- a/src/rtextures.c +++ b/src/rtextures.c @@ -3944,6 +3944,39 @@ Color ColorFromHSV(float hue, float saturation, float value) return color; } +// Get color with brightness correction, brightness factor goes from 0.0f to 1.0f +Color ColorBrightness(Color color, float factor) +{ + Color result = color; + + if (factor > 1.0f) factor = 1.0f; + else if (factor < -1.0f) factor = -1.0f; + + float red = (float)color.r; + float green = (float)color.g; + float blue = (float)color.b; + + if (factor < 0.0f) + { + factor = 1.0f + factor; + red *= factor; + green *= factor; + blue *= factor; + } + else + { + red = (255 - red)*factor + red; + green = (255 - green)*factor + green; + blue = (255 - blue)*factor + blue; + } + + result.r = (unsigned char)red; + result.g = (unsigned char)green; + result.b = (unsigned char)blue; + + return result; +} + // Get color with alpha applied, alpha goes from 0.0f to 1.0f Color ColorAlpha(Color color, float alpha) { From 2c9d116a5ce835328dc3267313f1b34b2e7ad8c9 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 7 Dec 2022 12:52:42 +0100 Subject: [PATCH 005/192] ADDED: `ColorTint()`, `ColorContrast()` --- src/raylib.h | 4 ++- src/rtextures.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 70 insertions(+), 2 deletions(-) diff --git a/src/raylib.h b/src/raylib.h index 6642bc8d39a9..dc71af847dda 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1331,7 +1331,9 @@ RLAPI Vector4 ColorNormalize(Color color); // G RLAPI Color ColorFromNormalized(Vector4 normalized); // Get Color from normalized values [0..1] RLAPI Vector3 ColorToHSV(Color color); // Get HSV values for a Color, hue [0..360], saturation/value [0..1] RLAPI Color ColorFromHSV(float hue, float saturation, float value); // Get a Color from HSV values, hue [0..360], saturation/value [0..1] -RLAPI Color ColorBrightness(Color color, float factor); // Get color with brightness correction, brightness factor goes from 0.0f to 1.0f +RLAPI Color ColorTint(Color color, Color tint); // Get color multiplied with another color +RLAPI Color ColorBrightness(Color color, float factor); // Get color with brightness correction, brightness factor goes from -1.0f to 1.0f +RLAPI Color ColorContrast(Color color, float contrast); // Get color with contrast correction, contrast values between -1.0f and 1.0f RLAPI Color ColorAlpha(Color color, float alpha); // Get color with alpha applied, alpha goes from 0.0f to 1.0f RLAPI Color ColorAlphaBlend(Color dst, Color src, Color tint); // Get src alpha-blended into dst color with tint RLAPI Color GetColor(unsigned int hexValue); // Get Color structure from hexadecimal value diff --git a/src/rtextures.c b/src/rtextures.c index 66434c116bc9..3313a06f1341 100644 --- a/src/rtextures.c +++ b/src/rtextures.c @@ -3944,7 +3944,30 @@ Color ColorFromHSV(float hue, float saturation, float value) return color; } -// Get color with brightness correction, brightness factor goes from 0.0f to 1.0f +// Get color multiplied with another color +Color ColorTint(Color color, Color tint) +{ + Color result = color; + + float cR = (float)tint.r/255; + float cG = (float)tint.g/255; + float cB = (float)tint.b/255; + float cA = (float)tint.a/255; + + unsigned char r = (unsigned char)(((float)color.r/255*cR)*255.0f); + unsigned char g = (unsigned char)(((float)color.g/255*cG)*255.0f); + unsigned char b = (unsigned char)(((float)color.b/255*cB)*255.0f); + unsigned char a = (unsigned char)(((float)color.a/255*cA)*255.0f); + + result.r = r; + result.g = g; + result.b = b; + result.a = a; + + return result; +} + +// Get color with brightness correction, brightness factor goes from -1.0f to 1.0f Color ColorBrightness(Color color, float factor) { Color result = color; @@ -3977,6 +4000,49 @@ Color ColorBrightness(Color color, float factor) return result; } +// Get color with contrast correction +// NOTE: Contrast values between -1.0f and 1.0f +Color ColorContrast(Color color, float contrast) +{ + Color result = color; + + if (contrast < -1.0f) contrast = -1.0f; + else if (contrast > 1.0f) contrast = 1.0f; + + contrast = (1.0f + contrast); + contrast *= contrast; + + float pR = (float)color.r/255.0f; + pR -= 0.5f; + pR *= contrast; + pR += 0.5f; + pR *= 255; + if (pR < 0) pR = 0; + else if (pR > 255) pR = 255; + + float pG = (float)color.g/255.0f; + pG -= 0.5f; + pG *= contrast; + pG += 0.5f; + pG *= 255; + if (pG < 0) pG = 0; + else if (pG > 255) pG = 255; + + float pB = (float)color.b/255.0f; + pB -= 0.5f; + pB *= contrast; + pB += 0.5f; + pB *= 255; + if (pB < 0) pB = 0; + else if (pB > 255) pB = 255; + + result.r = (unsigned char)pR; + result.g = (unsigned char)pG; + result.b = (unsigned char)pB; + + return result; +} + // Get color with alpha applied, alpha goes from 0.0f to 1.0f Color ColorAlpha(Color color, float alpha) { From 935a306b29ea53cba1633c1b82e9280a51307dcc Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 10 Dec 2022 12:44:25 +0100 Subject: [PATCH 006/192] Update windows.yml --- .github/workflows/windows.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 55a2410d0f2e..ff6fdb8f79fd 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -74,7 +74,7 @@ jobs: # Setup MSBuild.exe path if required - name: Setup MSBuild - uses: microsoft/setup-msbuild@v1.0.2 + uses: microsoft/setup-msbuild@v1.1 if: matrix.compiler == 'msvc16' - name: Build Library (MinGW-w64) From 6d59a21e99d73f6467d481875c0e6e4e843e087b Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 10 Dec 2022 13:01:57 +0100 Subject: [PATCH 007/192] Update windows.yml --- .github/workflows/windows.yml | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index ff6fdb8f79fd..4bd4a5801b4e 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -77,7 +77,22 @@ jobs: uses: microsoft/setup-msbuild@v1.1 if: matrix.compiler == 'msvc16' - - name: Build Library (MinGW-w64) + - name: Build Library (MinGW-w64 32bit) + run: | + cd src + x86_64-w64-mingw32-gcc.exe --version + windres.exe --version + dir C:\msys64\mingw64\bin + make PLATFORM=PLATFORM_DESKTOP CC=x86_64-w64-mingw32-gcc.exe RAYLIB_LIBTYPE=STATIC RAYLIB_RELEASE_PATH="../build/${{ env.RELEASE_NAME }}/lib" CFLAGS=-m32 + //windres.exe -i raylib.dll.rc -o raylib.dll.rc.data -O coff --target=${{ matrix.WINDRES_ARCH }} + //make PLATFORM=PLATFORM_DESKTOP CC=${{ matrix.ARCH }}-w64-mingw32-gcc.exe RAYLIB_LIBTYPE=SHARED RAYLIB_RELEASE_PATH="../build/${{ env.RELEASE_NAME }}/lib" -B + cd .. + shell: cmd + if: | + matrix.compiler == 'mingw-w64' && + matrix.bits == 32 + + - name: Build Library (MinGW-w64 64bit) run: | cd src ${{ matrix.ARCH }}-w64-mingw32-gcc.exe --version @@ -88,7 +103,9 @@ jobs: make PLATFORM=PLATFORM_DESKTOP CC=${{ matrix.ARCH }}-w64-mingw32-gcc.exe RAYLIB_LIBTYPE=SHARED RAYLIB_RELEASE_PATH="../build/${{ env.RELEASE_NAME }}/lib" -B cd .. shell: cmd - if: matrix.compiler == 'mingw-w64' + if: | + matrix.compiler == 'mingw-w64' && + matrix.bits == 64 - name: Build Library (MSVC16) run: | From 855a5f3701aaab854a50ef962e4b1432f6b52f34 Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 10 Dec 2022 13:06:13 +0100 Subject: [PATCH 008/192] Update windows.yml --- .github/workflows/windows.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 4bd4a5801b4e..17a8518681a6 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -83,7 +83,7 @@ jobs: x86_64-w64-mingw32-gcc.exe --version windres.exe --version dir C:\msys64\mingw64\bin - make PLATFORM=PLATFORM_DESKTOP CC=x86_64-w64-mingw32-gcc.exe RAYLIB_LIBTYPE=STATIC RAYLIB_RELEASE_PATH="../build/${{ env.RELEASE_NAME }}/lib" CFLAGS=-m32 + make PLATFORM=PLATFORM_DESKTOP CC=x86_64-w64-mingw32-gcc.exe RAYLIB_LIBTYPE=STATIC RAYLIB_RELEASE_PATH="../build/${{ env.RELEASE_NAME }}/lib" EXTERNAL_CONFIG_FLAGS=-m32 //windres.exe -i raylib.dll.rc -o raylib.dll.rc.data -O coff --target=${{ matrix.WINDRES_ARCH }} //make PLATFORM=PLATFORM_DESKTOP CC=${{ matrix.ARCH }}-w64-mingw32-gcc.exe RAYLIB_LIBTYPE=SHARED RAYLIB_RELEASE_PATH="../build/${{ env.RELEASE_NAME }}/lib" -B cd .. From c04c3668cbcdabac492532ede7b251d1a86ed8e9 Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 10 Dec 2022 13:09:05 +0100 Subject: [PATCH 009/192] Update windows.yml --- .github/workflows/windows.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 17a8518681a6..cf9a9f33e5cd 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -83,7 +83,7 @@ jobs: x86_64-w64-mingw32-gcc.exe --version windres.exe --version dir C:\msys64\mingw64\bin - make PLATFORM=PLATFORM_DESKTOP CC=x86_64-w64-mingw32-gcc.exe RAYLIB_LIBTYPE=STATIC RAYLIB_RELEASE_PATH="../build/${{ env.RELEASE_NAME }}/lib" EXTERNAL_CONFIG_FLAGS=-m32 + make PLATFORM=PLATFORM_DESKTOP CC=x86_64-w64-mingw32-gcc.exe RAYLIB_LIBTYPE=STATIC RAYLIB_RELEASE_PATH="../build/${{ env.RELEASE_NAME }}/lib" CUSTOM_CFLAGS=-m32 //windres.exe -i raylib.dll.rc -o raylib.dll.rc.data -O coff --target=${{ matrix.WINDRES_ARCH }} //make PLATFORM=PLATFORM_DESKTOP CC=${{ matrix.ARCH }}-w64-mingw32-gcc.exe RAYLIB_LIBTYPE=SHARED RAYLIB_RELEASE_PATH="../build/${{ env.RELEASE_NAME }}/lib" -B cd .. From 884d30b85acae99f74ba072bda52172dc5757ef1 Mon Sep 17 00:00:00 2001 From: simendsjo Date: Sun, 11 Dec 2022 13:37:38 +0100 Subject: [PATCH 010/192] Use GLVND also for old cmake versions (#2826) Use GLVND also when legacy implementations exist for old cmake versions <= 3.10. This is a breaking change for old cmake versions (prior to around 2017-10-05) which will now use GLVND rather than defaulting to libGL. This fixes the following warning when building: CMake Warning (dev) at /gnu/store/qv13zgbmyx0vjav8iiqp772kp6rxvwnd-cmake-3.24.2/share/cmake-3.24/Modules/FindOpenGL.cmake:315 (message): Policy CMP0072 is not set: FindOpenGL prefers GLVND by default when available. Run "cmake --help-policy CMP0072" for policy details. Use the cmake_policy command to set the policy and suppress this warning. FindOpenGL found both a legacy GL library: OPENGL_gl_LIBRARY: /home/simendsjo/.guix-profile/lib/libGL.so and GLVND libraries for OpenGL and GLX: OPENGL_opengl_LIBRARY: /home/simendsjo/.guix-profile/lib/libOpenGL.so OPENGL_glx_LIBRARY: /home/simendsjo/.guix-profile/lib/libGLX.so OpenGL_GL_PREFERENCE has not been set to "GLVND" or "LEGACY", so for compatibility with CMake 3.10 and below the legacy GL library will be used. Call Stack (most recent call first): cmake/LibraryConfigurations.cmake:21 (find_package) src/CMakeLists.txt:46 (include) This warning is for project developers. Use -Wno-dev to suppress it. See https://cmake.org/cmake/help/latest/policy/CMP0072.html Closes #2825 --- cmake/LibraryConfigurations.cmake | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/cmake/LibraryConfigurations.cmake b/cmake/LibraryConfigurations.cmake index cc0f01e40e91..a16bde69d6b0 100644 --- a/cmake/LibraryConfigurations.cmake +++ b/cmake/LibraryConfigurations.cmake @@ -1,3 +1,12 @@ +# Set OpenGL_GL_PREFERENCE to new "GLVND" even when legacy library exists and +# cmake is <= 3.10 +# +# See https://cmake.org/cmake/help/latest/policy/CMP0072.html for more +# information. +if(POLICY CMP0072) + cmake_policy(SET CMP0072 NEW) +endif() + if (${PLATFORM} MATCHES "Desktop") set(PLATFORM_CPP "PLATFORM_DESKTOP") From 445ce51e510bc3733e6ab7db618ad3d53de8943c Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 13 Dec 2022 10:46:49 +0100 Subject: [PATCH 011/192] Update Makefile --- examples/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/Makefile b/examples/Makefile index edfbab118e5b..76a33149f559 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -52,8 +52,8 @@ USE_EXTERNAL_GLFW ?= FALSE USE_WAYLAND_DISPLAY ?= FALSE # PLATFORM_WEB: Default properties -BUILD_WEB_ASYNCIFY ?= FALSE -BUILD_WEB_SHELL ?= minshell.html +BUILD_WEB_ASYNCIFY ?= TRUE +BUILD_WEB_SHELL ?= $(RAYLIB_PATH)/src/minshell.html BUILD_WEB_HEAP_SIZE ?= 134217728 BUILD_WEB_RESOURCES ?= TRUE BUILD_WEB_RESOURCES_PATH ?= $(dir $<)resources@resources From 3419aef6778d5b1d9ed61e6d63d11c44f29ef8e1 Mon Sep 17 00:00:00 2001 From: Alexander Heinrich Date: Tue, 13 Dec 2022 18:59:00 +0100 Subject: [PATCH 012/192] Fix Vector2Angle() (#2829) With this fix the function still returns negative values, which is wrong. But we keep this behaviour to maintain backwards compatibility. --- src/raymath.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/raymath.h b/src/raymath.h index fbe4ceadc593..34db2d8858fb 100644 --- a/src/raymath.h +++ b/src/raymath.h @@ -309,7 +309,7 @@ RMAPI float Vector2DistanceSqr(Vector2 v1, Vector2 v2) // Calculate angle from two vectors RMAPI float Vector2Angle(Vector2 v1, Vector2 v2) { - float result = atan2f(v2.y, v2.x) - atan2f(v1.y, v1.x); + float result = -acos(v1.x*v2.x + v1.y*v2.y); return result; } From 619331f4a7e146a122e45214f40c32bdce25c650 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 14 Dec 2022 12:57:39 +0100 Subject: [PATCH 013/192] REVIEWED: Issue with depth textures on WebGL #2824 --- src/rlgl.h | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/rlgl.h b/src/rlgl.h index 301bd976d1ef..8afe1fdcf48d 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -987,7 +987,8 @@ typedef struct rlglData { bool vao; // VAO support (OpenGL ES2 could not support VAO extension) (GL_ARB_vertex_array_object) bool instancing; // Instancing supported (GL_ANGLE_instanced_arrays, GL_EXT_draw_instanced + GL_EXT_instanced_arrays) bool texNPOT; // NPOT textures full support (GL_ARB_texture_non_power_of_two, GL_OES_texture_npot) - bool texDepth; // Depth textures supported (GL_ARB_depth_texture, GL_WEBGL_depth_texture, GL_OES_depth_texture) + bool texDepth; // Depth textures supported (GL_ARB_depth_texture, GL_OES_depth_texture) + bool texDepthWebGL; // Depth textures supported WebGL specific (GL_WEBGL_depth_texture) bool texFloat32; // float textures support (32 bit per channel) (GL_OES_texture_float) bool texCompDXT; // DDS texture compression support (GL_EXT_texture_compression_s3tc, GL_WEBGL_compressed_texture_s3tc, GL_WEBKIT_WEBGL_compressed_texture_s3tc) bool texCompETC1; // ETC1 texture compression support (GL_OES_compressed_ETC1_RGB8_texture, GL_WEBGL_compressed_texture_etc1) @@ -2218,11 +2219,12 @@ void rlLoadExtensions(void *loader) if (strcmp(extList[i], (const char *)"GL_OES_texture_float") == 0) RLGL.ExtSupported.texFloat32 = true; // Check depth texture support - if ((strcmp(extList[i], (const char *)"GL_OES_depth_texture") == 0) || - (strcmp(extList[i], (const char *)"GL_WEBGL_depth_texture") == 0)) RLGL.ExtSupported.texDepth = true; + if (strcmp(extList[i], (const char *)"GL_OES_depth_texture") == 0) RLGL.ExtSupported.texDepth = true; + if (strcmp(extList[i], (const char *)"GL_WEBGL_depth_texture") == 0) RLGL.ExtSupported.texDepthWebGL = true; // WebGL requires unsized internal format + if (RLGL.ExtSupported.texDepthWebGL) RLGL.ExtSupported.texDepth = true; - if (strcmp(extList[i], (const char *)"GL_OES_depth24") == 0) RLGL.ExtSupported.maxDepthBits = 24; - if (strcmp(extList[i], (const char *)"GL_OES_depth32") == 0) RLGL.ExtSupported.maxDepthBits = 32; + if (strcmp(extList[i], (const char *)"GL_OES_depth24") == 0) RLGL.ExtSupported.maxDepthBits = 24; // Not available on WebGL + if (strcmp(extList[i], (const char *)"GL_OES_depth32") == 0) RLGL.ExtSupported.maxDepthBits = 32; // Not available on WebGL // Check texture compression support: DXT if ((strcmp(extList[i], (const char *)"GL_EXT_texture_compression_s3tc") == 0) || @@ -2975,7 +2977,7 @@ unsigned int rlLoadTexture(const void *data, int width, int height, int format, } // Load depth texture/renderbuffer (to be attached to fbo) -// WARNING: OpenGL ES 2.0 requires GL_OES_depth_texture/WEBGL_depth_texture extensions +// WARNING: OpenGL ES 2.0 requires GL_OES_depth_texture and WebGL requires WEBGL_depth_texture extensions unsigned int rlLoadTextureDepth(int width, int height, bool useRenderBuffer) { unsigned int id = 0; @@ -2983,15 +2985,20 @@ unsigned int rlLoadTextureDepth(int width, int height, bool useRenderBuffer) #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) // In case depth textures not supported, we force renderbuffer usage if (!RLGL.ExtSupported.texDepth) useRenderBuffer = true; - + // NOTE: We let the implementation to choose the best bit-depth // Possible formats: GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT32 and GL_DEPTH_COMPONENT32F unsigned int glInternalFormat = GL_DEPTH_COMPONENT; #if defined(GRAPHICS_API_OPENGL_ES2) - if (RLGL.ExtSupported.maxDepthBits == 32) glInternalFormat = GL_DEPTH_COMPONENT32_OES; - else if (RLGL.ExtSupported.maxDepthBits == 24) glInternalFormat = GL_DEPTH_COMPONENT24_OES; - else glInternalFormat = GL_DEPTH_COMPONENT16; + // WARNING: WebGL platform requires unsized internal format definition (GL_DEPTH_COMPONENT) + // while other platforms using OpenGL ES 2.0 require/support sized internal formats depending on the GPU capabilities + if (!RLGL.ExtSupported.texDepthWebGL) + { + if (RLGL.ExtSupported.maxDepthBits == 32) glInternalFormat = GL_DEPTH_COMPONENT32_OES; + else if (RLGL.ExtSupported.maxDepthBits == 24) glInternalFormat = GL_DEPTH_COMPONENT24_OES; + else glInternalFormat = GL_DEPTH_COMPONENT16; + } #endif if (!useRenderBuffer && RLGL.ExtSupported.texDepth) From d1a104bba46d2918c2a521e255edee07ea2e5f3f Mon Sep 17 00:00:00 2001 From: Antonis Geralis <43617260+planetis-m@users.noreply.github.com> Date: Sat, 17 Dec 2022 13:13:40 +0200 Subject: [PATCH 014/192] Fix vector2angle (#2832) * Fix vector2angle * Fix ; * use acosf * need a break * add comments --- src/raymath.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/raymath.h b/src/raymath.h index 34db2d8858fb..d3130750c01b 100644 --- a/src/raymath.h +++ b/src/raymath.h @@ -307,9 +307,15 @@ RMAPI float Vector2DistanceSqr(Vector2 v1, Vector2 v2) } // Calculate angle from two vectors +// Parameters need to be normalized RMAPI float Vector2Angle(Vector2 v1, Vector2 v2) { - float result = -acos(v1.x*v2.x + v1.y*v2.y); + float dotProduct = v1.x*v2.x + v1.y*v2.y; // Dot product + + float t = dotProduct < -1 ? -1 : dotProduct; // Clamp + if (t > 1) t = 1; + + float result = acosf(t); return result; } From 72b9f3c5def47fe6bf840466e464485878d93967 Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 17 Dec 2022 12:15:19 +0100 Subject: [PATCH 015/192] Minor tweaks --- src/rcore.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/rcore.c b/src/rcore.c index 118a5736bdcd..e1fcd0de8c1f 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -151,7 +151,7 @@ #include "external/sdefl.h" // Deflate (RFC 1951) compressor #endif -#if (defined(__linux__) || defined(PLATFORM_WEB)) && _POSIX_C_SOURCE < 199309L +#if (defined(__linux__) || defined(PLATFORM_WEB)) && (_POSIX_C_SOURCE < 199309L) #undef _POSIX_C_SOURCE #define _POSIX_C_SOURCE 199309L // Required for: CLOCK_MONOTONIC if compiled with c99 without gnu ext. #endif @@ -2813,6 +2813,9 @@ void TakeScreenshot(const char *fileName) } // Get a random value between min and max (both included) +// WARNING: Ranges higher than RAND_MAX will return invalid results +// More specifically, if (max - min) > INT_MAX there will be an overflow, +// and otherwise if (max - min) > RAND_MAX the random value will incorrectly never exceed a certain threshold int GetRandomValue(int min, int max) { if (min > max) @@ -2821,9 +2824,6 @@ int GetRandomValue(int min, int max) max = min; min = tmp; } - - // WARNING: Ranges higher than RAND_MAX will return invalid results. More specifically, if (max - min) > INT_MAX there will - // be an overflow, and otherwise if (max - min) > RAND_MAX the random value will incorrectly never exceed a certain threshold. if ((unsigned int)(max - min) > (unsigned int)RAND_MAX) { TRACELOG(LOG_WARNING, "Invalid GetRandomValue arguments. Range should not be higher than %i.", RAND_MAX); From d7f7c94c4d44df89f6104dcda93eb330fc8534f3 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 18 Dec 2022 18:00:14 +0100 Subject: [PATCH 016/192] REVIEWED: `Vector2Angle()` --- src/raymath.h | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/raymath.h b/src/raymath.h index d3130750c01b..ea3085a54629 100644 --- a/src/raymath.h +++ b/src/raymath.h @@ -307,15 +307,23 @@ RMAPI float Vector2DistanceSqr(Vector2 v1, Vector2 v2) } // Calculate angle from two vectors -// Parameters need to be normalized +// NOTE: Parameters need to be normalized +// Current implementation should be aligned with glm::angle RMAPI float Vector2Angle(Vector2 v1, Vector2 v2) { - float dotProduct = v1.x*v2.x + v1.y*v2.y; // Dot product - - float t = dotProduct < -1 ? -1 : dotProduct; // Clamp - if (t > 1) t = 1; - - float result = acosf(t); + float result = 0.0f; + + float dot = v1.x*v2.x + v1.y*v2.y; // Dot product + + float dotClamp = (dot < -1.0f)? -1.0f : dot; // Clamp + if (dotClamp > 1.0f) dotClamp = 1.0f; + + result = acosf(dotClamp); + + // Alternative implementation, more costly + //float v1Length = sqrtf((v1.x*v1.x) + (v1.y*v1.y)); + //float v2Length = sqrtf((v2.x*v2.x) + (v2.y*v2.y)); + //float result = -acosf((v1.x*v2.x + v1.y*v2.y)/(v1Length*v2Length)); return result; } From 03cc540d5f1df71bd7ad8118d0e11b492fa5cc18 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 18 Dec 2022 18:00:21 +0100 Subject: [PATCH 017/192] Minor tweak --- src/rcore.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/rcore.c b/src/rcore.c index e1fcd0de8c1f..12fe73512a95 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -2824,9 +2824,10 @@ int GetRandomValue(int min, int max) max = min; min = tmp; } + if ((unsigned int)(max - min) > (unsigned int)RAND_MAX) { - TRACELOG(LOG_WARNING, "Invalid GetRandomValue arguments. Range should not be higher than %i.", RAND_MAX); + TRACELOG(LOG_WARNING, "Invalid GetRandomValue() arguments, range should not be higher than %i", RAND_MAX); } return (rand()%(abs(max - min) + 1) + min); From dbdbbea47193ed19cd188dccbe694970387f810d Mon Sep 17 00:00:00 2001 From: turborium <45082001+turborium@users.noreply.github.com> Date: Wed, 28 Dec 2022 14:04:55 +0400 Subject: [PATCH 018/192] Add new Delphi/Lazarus bindings (#2838) TurboRaylib - dynamic bindings of ray lib for Delphi/Lazarus --- BINDINGS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/BINDINGS.md b/BINDINGS.md index 6d1b00f2ebb4..39a333e51907 100644 --- a/BINDINGS.md +++ b/BINDINGS.md @@ -43,6 +43,7 @@ Some people ported raylib to other languages in form of bindings or wrappers to | raylib_odin_bindings | 4.0-dev | [Odin](https://odin-lang.org/) | MIT | https://github.com/Deathbat2190/raylib_odin_bindings | | raylib-odin | **4.0** | [Odin](https://odin-lang.org/) | BSD-3Clause | https://github.com/odin-lang/Odin/tree/master/vendor/raylib | | raylib-ocaml | **4.0** | [OCaml](https://ocaml.org/) | MIT | https://github.com/tjammer/raylib-ocaml | +| TurboRaylib | **4.2** | [Object Pascal](https://en.wikipedia.org/wiki/Object_Pascal) | MIT | https://github.com/turborium/TurboRaylib | | Ray4Laz | **4.2** | [Free Pascal](https://en.wikipedia.org/wiki/Free_Pascal)| Zlib | https://github.com/GuvaCode/Ray4Laz | | Raylib.4.0.Pascal | **4.0** | [Free Pascal](https://en.wikipedia.org/wiki/Free_Pascal)| Zlib | https://github.com/sysrpl/Raylib.4.0.Pascal | | pyraylib | 3.7 | [Python](https://www.python.org/) | Zlib | https://github.com/Ho011/pyraylib | From ba38fe5b97c2401830d612376d198f1d3c811969 Mon Sep 17 00:00:00 2001 From: Antonis Geralis <43617260+planetis-m@users.noreply.github.com> Date: Sat, 31 Dec 2022 20:25:35 +0200 Subject: [PATCH 019/192] core_loading_thread example join thread on completion (#2845) * core_loading_thread example join thread on completion * error checking --- examples/core/core_loading_thread.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/examples/core/core_loading_thread.c b/examples/core/core_loading_thread.c index 09ec76460514..5ab8bbc3a888 100644 --- a/examples/core/core_loading_thread.c +++ b/examples/core/core_loading_thread.c @@ -72,6 +72,10 @@ int main(void) if (atomic_load(&dataLoaded)) { framesCounter = 0; + int error = pthread_join(threadId, NULL); + if (error != 0) TraceLog(LOG_ERROR, "Error joining loading thread"); + else TraceLog(LOG_INFO, "Loading thread terminated successfully"); + state = STATE_FINISHED; } } break; From 713e26332f15209a9b8f2315a909858a21fa5fd4 Mon Sep 17 00:00:00 2001 From: Wytek01 <101928745+Wytekol@users.noreply.github.com> Date: Sun, 1 Jan 2023 12:55:49 +0100 Subject: [PATCH 020/192] Update year to 2023 (#2846) * Update year to 2023 * Update raylib.h year to 2023 --- LICENSE | 2 +- src/raylib.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/LICENSE b/LICENSE index 2694b47485d7..91da62ed9248 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2013-2022 Ramon Santamaria (@raysan5) +Copyright (c) 2013-2023 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. diff --git a/src/raylib.h b/src/raylib.h index dc71af847dda..5a230a3acf6b 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -57,7 +57,7 @@ * raylib is 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) 2013-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2013-2023 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. From b59fab7ee6035886554778e8adc540deb3f29f4a Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 1 Jan 2023 16:00:56 +0100 Subject: [PATCH 021/192] Update year to 2023 --- examples/audio/audio_module_playing.c | 2 +- examples/audio/audio_multichannel_sound.c | 2 +- examples/audio/audio_music_stream.c | 2 +- examples/audio/audio_raw_stream.c | 2 +- examples/audio/audio_sound_loading.c | 2 +- examples/audio/audio_stream_effects.c | 2 +- examples/core/core_2d_camera.c | 2 +- examples/core/core_2d_camera_platformer.c | 2 +- examples/core/core_3d_camera_first_person.c | 2 +- examples/core/core_3d_camera_free.c | 2 +- examples/core/core_3d_camera_mode.c | 2 +- examples/core/core_3d_picking.c | 2 +- examples/core/core_basic_screen_manager.c | 2 +- examples/core/core_basic_window.c | 2 +- examples/core/core_basic_window_web.c | 2 +- examples/core/core_custom_frame_control.c | 2 +- examples/core/core_custom_logging.c | 2 +- examples/core/core_drop_files.c | 2 +- examples/core/core_input_gamepad.c | 2 +- examples/core/core_input_gestures.c | 2 +- examples/core/core_input_keys.c | 2 +- examples/core/core_input_mouse.c | 2 +- examples/core/core_input_mouse_wheel.c | 2 +- examples/core/core_input_multitouch.c | 2 +- examples/core/core_loading_thread.c | 2 +- examples/core/core_random_values.c | 2 +- examples/core/core_scissor_test.c | 2 +- examples/core/core_smooth_pixelperfect.c | 2 +- examples/core/core_split_screen.c | 2 +- examples/core/core_storage_values.c | 2 +- examples/core/core_vr_simulator.c | 2 +- examples/core/core_window_flags.c | 2 +- examples/core/core_window_letterbox.c | 2 +- examples/core/core_window_should_close.c | 2 +- examples/core/core_world_screen.c | 2 +- examples/examples_template.c | 2 +- examples/models/models_animation.c | 2 +- examples/models/models_billboard.c | 2 +- examples/models/models_box_collisions.c | 2 +- examples/models/models_cubicmap.c | 2 +- examples/models/models_first_person_maze.c | 2 +- examples/models/models_geometric_shapes.c | 2 +- examples/models/models_heightmap.c | 2 +- examples/models/models_loading.c | 2 +- examples/models/models_loading_gltf.c | 2 +- examples/models/models_loading_vox.c | 2 +- examples/models/models_mesh_generation.c | 2 +- examples/models/models_mesh_picking.c | 2 +- examples/models/models_orthographic_projection.c | 2 +- examples/models/models_rlgl_solar_system.c | 2 +- examples/models/models_skybox.c | 2 +- examples/models/models_waving_cubes.c | 2 +- examples/models/models_yaw_pitch_roll.c | 2 +- examples/others/easings_testbed.c | 2 +- examples/others/embedded_files_loading.c | 2 +- examples/others/raylib_opengl_interop.c | 2 +- examples/others/reasings.h | 2 +- examples/others/rlgl_compute_shader.c | 2 +- examples/others/rlgl_standalone.c | 2 +- examples/shaders/rlights.h | 2 +- examples/shaders/shaders_basic_lighting.c | 2 +- examples/shaders/shaders_custom_uniform.c | 2 +- examples/shaders/shaders_eratosthenes.c | 2 +- examples/shaders/shaders_fog.c | 2 +- examples/shaders/shaders_hot_reloading.c | 2 +- examples/shaders/shaders_julia_set.c | 2 +- examples/shaders/shaders_mesh_instancing.c | 2 +- examples/shaders/shaders_model_shader.c | 2 +- examples/shaders/shaders_multi_sample2d.c | 2 +- examples/shaders/shaders_palette_switch.c | 2 +- examples/shaders/shaders_postprocessing.c | 2 +- examples/shaders/shaders_raymarching.c | 2 +- examples/shaders/shaders_shapes_textures.c | 2 +- examples/shaders/shaders_simple_mask.c | 2 +- examples/shaders/shaders_spotlight.c | 2 +- examples/shaders/shaders_texture_drawing.c | 2 +- examples/shaders/shaders_texture_outline.c | 2 +- examples/shaders/shaders_texture_waves.c | 2 +- examples/shapes/shapes_basic_shapes.c | 2 +- examples/shapes/shapes_bouncing_ball.c | 2 +- examples/shapes/shapes_collision_area.c | 2 +- examples/shapes/shapes_colors_palette.c | 2 +- examples/shapes/shapes_draw_circle_sector.c | 2 +- examples/shapes/shapes_draw_rectangle_rounded.c | 2 +- examples/shapes/shapes_draw_ring.c | 2 +- examples/shapes/shapes_easings_ball_anim.c | 2 +- examples/shapes/shapes_easings_box_anim.c | 2 +- examples/shapes/shapes_easings_rectangle_array.c | 2 +- examples/shapes/shapes_following_eyes.c | 2 +- examples/shapes/shapes_lines_bezier.c | 2 +- examples/shapes/shapes_logo_raylib.c | 2 +- examples/shapes/shapes_logo_raylib_anim.c | 2 +- examples/shapes/shapes_rectangle_scaling.c | 2 +- examples/text/text_draw_3d.c | 2 +- examples/text/text_font_filters.c | 2 +- examples/text/text_font_loading.c | 2 +- examples/text/text_font_sdf.c | 2 +- examples/text/text_font_spritefont.c | 2 +- examples/text/text_format_text.c | 2 +- examples/text/text_input_box.c | 2 +- examples/text/text_raylib_fonts.c | 2 +- examples/text/text_rectangle_bounds.c | 2 +- examples/text/text_unicode.c | 2 +- examples/text/text_writing_anim.c | 2 +- examples/textures/textures_background_scrolling.c | 2 +- examples/textures/textures_blend_modes.c | 2 +- examples/textures/textures_bunnymark.c | 2 +- examples/textures/textures_draw_tiled.c | 2 +- examples/textures/textures_fog_of_war.c | 2 +- examples/textures/textures_gif_player.c | 2 +- examples/textures/textures_image_drawing.c | 2 +- examples/textures/textures_image_generation.c | 2 +- examples/textures/textures_image_loading.c | 2 +- examples/textures/textures_image_processing.c | 2 +- examples/textures/textures_image_text.c | 2 +- examples/textures/textures_logo_raylib.c | 2 +- examples/textures/textures_mouse_painting.c | 2 +- examples/textures/textures_npatch_drawing.c | 2 +- examples/textures/textures_particles_blending.c | 2 +- examples/textures/textures_polygon.c | 2 +- examples/textures/textures_raw_data.c | 2 +- examples/textures/textures_sprite_anim.c | 2 +- examples/textures/textures_sprite_button.c | 2 +- examples/textures/textures_sprite_explosion.c | 2 +- examples/textures/textures_srcrec_dstrec.c | 2 +- examples/textures/textures_to_image.c | 2 +- parser/raylib_parser.c | 4 ++-- projects/Geany/core_basic_window.c | 2 +- projects/VSCode/main.c | 2 +- src/config.h | 2 +- src/raudio.c | 4 ++-- src/raymath.h | 2 +- src/rcamera.h | 2 +- src/rcore.c | 2 +- src/rgestures.h | 2 +- src/rglfw.c | 2 +- src/rlgl.h | 2 +- src/rmodels.c | 4 ++-- src/rshapes.c | 2 +- src/rtextures.c | 4 ++-- 140 files changed, 144 insertions(+), 144 deletions(-) diff --git a/examples/audio/audio_module_playing.c b/examples/audio/audio_module_playing.c index e47db592b0cc..b8482aa572d3 100644 --- a/examples/audio/audio_module_playing.c +++ b/examples/audio/audio_module_playing.c @@ -7,7 +7,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) 2016-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2016-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/audio/audio_multichannel_sound.c b/examples/audio/audio_multichannel_sound.c index 3e6a612c8efc..1d549a055a02 100644 --- a/examples/audio/audio_multichannel_sound.c +++ b/examples/audio/audio_multichannel_sound.c @@ -9,7 +9,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) 2019-2022 Chris Camacho (@chriscamacho) and Ramon Santamaria (@raysan5) +* Copyright (c) 2019-2023 Chris Camacho (@chriscamacho) and Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/audio/audio_music_stream.c b/examples/audio/audio_music_stream.c index f4819eb137ec..4cf29973d092 100644 --- a/examples/audio/audio_music_stream.c +++ b/examples/audio/audio_music_stream.c @@ -7,7 +7,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) 2015-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2015-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/audio/audio_raw_stream.c b/examples/audio/audio_raw_stream.c index afee42962053..142450e83d76 100644 --- a/examples/audio/audio_raw_stream.c +++ b/examples/audio/audio_raw_stream.c @@ -9,7 +9,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) 2015-2022 Ramon Santamaria (@raysan5) and James Hofmann (@triplefox) +* Copyright (c) 2015-2023 Ramon Santamaria (@raysan5) and James Hofmann (@triplefox) * ********************************************************************************************/ diff --git a/examples/audio/audio_sound_loading.c b/examples/audio/audio_sound_loading.c index 6a267043975e..dae6516eef2a 100644 --- a/examples/audio/audio_sound_loading.c +++ b/examples/audio/audio_sound_loading.c @@ -7,7 +7,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) 2014-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/audio/audio_stream_effects.c b/examples/audio/audio_stream_effects.c index ddaeb7fb0ce7..21930505724c 100644 --- a/examples/audio/audio_stream_effects.c +++ b/examples/audio/audio_stream_effects.c @@ -7,7 +7,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) 2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2022-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/core/core_2d_camera.c b/examples/core/core_2d_camera.c index edc67a0a8d21..24cca698515b 100644 --- a/examples/core/core_2d_camera.c +++ b/examples/core/core_2d_camera.c @@ -7,7 +7,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) 2016-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2016-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/core/core_2d_camera_platformer.c b/examples/core/core_2d_camera_platformer.c index 5750e7a80b21..1ae9e0fcb41b 100644 --- a/examples/core/core_2d_camera_platformer.c +++ b/examples/core/core_2d_camera_platformer.c @@ -9,7 +9,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) 2019-2022 arvyy (@arvyy) +* Copyright (c) 2019-2023 arvyy (@arvyy) * ********************************************************************************************/ diff --git a/examples/core/core_3d_camera_first_person.c b/examples/core/core_3d_camera_first_person.c index 3af829e25bfd..a7aa5f49a6e7 100644 --- a/examples/core/core_3d_camera_first_person.c +++ b/examples/core/core_3d_camera_first_person.c @@ -7,7 +7,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) 2015-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2015-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/core/core_3d_camera_free.c b/examples/core/core_3d_camera_free.c index b3b0b9b0b33e..af7ab8d72dc2 100644 --- a/examples/core/core_3d_camera_free.c +++ b/examples/core/core_3d_camera_free.c @@ -7,7 +7,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) 2015-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2015-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/core/core_3d_camera_mode.c b/examples/core/core_3d_camera_mode.c index ffa1acd6d5cc..cb83a4a2bf11 100644 --- a/examples/core/core_3d_camera_mode.c +++ b/examples/core/core_3d_camera_mode.c @@ -7,7 +7,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) 2014-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/core/core_3d_picking.c b/examples/core/core_3d_picking.c index 8cd3a3fe10c8..8c0df9663fe9 100644 --- a/examples/core/core_3d_picking.c +++ b/examples/core/core_3d_picking.c @@ -7,7 +7,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) 2015-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2015-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/core/core_basic_screen_manager.c b/examples/core/core_basic_screen_manager.c index 1364982e879d..a805729881c1 100644 --- a/examples/core/core_basic_screen_manager.c +++ b/examples/core/core_basic_screen_manager.c @@ -9,7 +9,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) 2021-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2021-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/core/core_basic_window.c b/examples/core/core_basic_window.c index be7a449ab22e..5bfd186da775 100644 --- a/examples/core/core_basic_window.c +++ b/examples/core/core_basic_window.c @@ -17,7 +17,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) 2013-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2013-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/core/core_basic_window_web.c b/examples/core/core_basic_window_web.c index 7dc47f9c9e6d..7d83254a1cb0 100644 --- a/examples/core/core_basic_window_web.c +++ b/examples/core/core_basic_window_web.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) 2015-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2015-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/core/core_custom_frame_control.c b/examples/core/core_custom_frame_control.c index 016c6c4483d1..ed0dbc661cd0 100644 --- a/examples/core/core_custom_frame_control.c +++ b/examples/core/core_custom_frame_control.c @@ -22,7 +22,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) 2021-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2021-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/core/core_custom_logging.c b/examples/core/core_custom_logging.c index 9794d14b9c81..b4da2d5751f0 100644 --- a/examples/core/core_custom_logging.c +++ b/examples/core/core_custom_logging.c @@ -9,7 +9,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-2022 Pablo Marcos Oltra (@pamarcos) and Ramon Santamaria (@raysan5) +* Copyright (c) 2018-2023 Pablo Marcos Oltra (@pamarcos) and Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/core/core_drop_files.c b/examples/core/core_drop_files.c index 35ebc7689924..9ebe0f957d2d 100644 --- a/examples/core/core_drop_files.c +++ b/examples/core/core_drop_files.c @@ -9,7 +9,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) 2015-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2015-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/core/core_input_gamepad.c b/examples/core/core_input_gamepad.c index 02ac170538de..411472b34058 100644 --- a/examples/core/core_input_gamepad.c +++ b/examples/core/core_input_gamepad.c @@ -13,7 +13,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) 2013-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2013-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/core/core_input_gestures.c b/examples/core/core_input_gestures.c index 012204ddddfd..312e78ffde59 100644 --- a/examples/core/core_input_gestures.c +++ b/examples/core/core_input_gestures.c @@ -7,7 +7,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) 2016-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2016-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/core/core_input_keys.c b/examples/core/core_input_keys.c index 6020d577f3cb..ccff24005d96 100644 --- a/examples/core/core_input_keys.c +++ b/examples/core/core_input_keys.c @@ -7,7 +7,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) 2014-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/core/core_input_mouse.c b/examples/core/core_input_mouse.c index 6e164f50b64c..874e16c300b2 100644 --- a/examples/core/core_input_mouse.c +++ b/examples/core/core_input_mouse.c @@ -7,7 +7,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) 2014-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/core/core_input_mouse_wheel.c b/examples/core/core_input_mouse_wheel.c index 1f384cd0c0bf..826bad3a1198 100644 --- a/examples/core/core_input_mouse_wheel.c +++ b/examples/core/core_input_mouse_wheel.c @@ -7,7 +7,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) 2014-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/core/core_input_multitouch.c b/examples/core/core_input_multitouch.c index 1eb6905b544d..980af3801ad6 100644 --- a/examples/core/core_input_multitouch.c +++ b/examples/core/core_input_multitouch.c @@ -9,7 +9,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) 2019-2022 Berni (@Berni8k) and Ramon Santamaria (@raysan5) +* Copyright (c) 2019-2023 Berni (@Berni8k) and Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/core/core_loading_thread.c b/examples/core/core_loading_thread.c index 5ab8bbc3a888..d5c00fc5607a 100644 --- a/examples/core/core_loading_thread.c +++ b/examples/core/core_loading_thread.c @@ -9,7 +9,7 @@ * * Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, * -* Copyright (c) 2014-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/core/core_random_values.c b/examples/core/core_random_values.c index 9150b9f45885..c2225bcaf5bd 100644 --- a/examples/core/core_random_values.c +++ b/examples/core/core_random_values.c @@ -7,7 +7,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) 2014-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/core/core_scissor_test.c b/examples/core/core_scissor_test.c index f296a3acb75d..c2b853c05aa1 100644 --- a/examples/core/core_scissor_test.c +++ b/examples/core/core_scissor_test.c @@ -9,7 +9,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) 2019-2022 Chris Dill (@MysteriousSpace) +* Copyright (c) 2019-2023 Chris Dill (@MysteriousSpace) * ********************************************************************************************/ diff --git a/examples/core/core_smooth_pixelperfect.c b/examples/core/core_smooth_pixelperfect.c index 36fb09c58756..776706c0051b 100644 --- a/examples/core/core_smooth_pixelperfect.c +++ b/examples/core/core_smooth_pixelperfect.c @@ -10,7 +10,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) 2021-2022 Giancamillo Alessandroni (@NotManyIdeasDev) and Ramon Santamaria (@raysan5) +* Copyright (c) 2021-2023 Giancamillo Alessandroni (@NotManyIdeasDev) and Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/core/core_split_screen.c b/examples/core/core_split_screen.c index 1f1f3967bc76..50cfcf7ac613 100644 --- a/examples/core/core_split_screen.c +++ b/examples/core/core_split_screen.c @@ -9,7 +9,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) 2021-2022 Jeffery Myers (@JeffM2501) +* Copyright (c) 2021-2023 Jeffery Myers (@JeffM2501) * ********************************************************************************************/ diff --git a/examples/core/core_storage_values.c b/examples/core/core_storage_values.c index c6f01217b5ae..127399123ee6 100644 --- a/examples/core/core_storage_values.c +++ b/examples/core/core_storage_values.c @@ -7,7 +7,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) 2015-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2015-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/core/core_vr_simulator.c b/examples/core/core_vr_simulator.c index f5dc4d55d547..5914897b0974 100644 --- a/examples/core/core_vr_simulator.c +++ b/examples/core/core_vr_simulator.c @@ -7,7 +7,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) 2017-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2017-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/core/core_window_flags.c b/examples/core/core_window_flags.c index 27a6e7b65577..b1cbb1b64ea3 100644 --- a/examples/core/core_window_flags.c +++ b/examples/core/core_window_flags.c @@ -7,7 +7,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) 2020-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2020-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/core/core_window_letterbox.c b/examples/core/core_window_letterbox.c index 774e8d99fd08..751fb14ab9dd 100644 --- a/examples/core/core_window_letterbox.c +++ b/examples/core/core_window_letterbox.c @@ -9,7 +9,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) 2019-2022 Anata (@anatagawa) and Ramon Santamaria (@raysan5) +* Copyright (c) 2019-2023 Anata (@anatagawa) and Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/core/core_window_should_close.c b/examples/core/core_window_should_close.c index fa6b9b97b7cc..f0392b013731 100644 --- a/examples/core/core_window_should_close.c +++ b/examples/core/core_window_should_close.c @@ -7,7 +7,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) 2013-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2013-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/core/core_world_screen.c b/examples/core/core_world_screen.c index 80d9cf918641..d86adf877160 100644 --- a/examples/core/core_world_screen.c +++ b/examples/core/core_world_screen.c @@ -7,7 +7,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) 2015-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2015-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/examples_template.c b/examples/examples_template.c index 1ea615d4a434..3d8332e67c10 100644 --- a/examples/examples_template.c +++ b/examples/examples_template.c @@ -48,7 +48,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) 2022 (@) +* Copyright (c) 2023 (@) * ********************************************************************************************/ diff --git a/examples/models/models_animation.c b/examples/models/models_animation.c index 161b21995d42..b9216b21f960 100644 --- a/examples/models/models_animation.c +++ b/examples/models/models_animation.c @@ -9,7 +9,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) 2019-2022 Culacant (@culacant) and Ramon Santamaria (@raysan5) +* Copyright (c) 2019-2023 Culacant (@culacant) and Ramon Santamaria (@raysan5) * ******************************************************************************************** * diff --git a/examples/models/models_billboard.c b/examples/models/models_billboard.c index 0b5a42d57494..ce313949bcf5 100644 --- a/examples/models/models_billboard.c +++ b/examples/models/models_billboard.c @@ -7,7 +7,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) 2015-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2015-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/models/models_box_collisions.c b/examples/models/models_box_collisions.c index db8eb1f2dc61..9cff5e05809b 100644 --- a/examples/models/models_box_collisions.c +++ b/examples/models/models_box_collisions.c @@ -7,7 +7,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) 2015-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2015-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/models/models_cubicmap.c b/examples/models/models_cubicmap.c index e9da0482fa6e..4953a99fcbd2 100644 --- a/examples/models/models_cubicmap.c +++ b/examples/models/models_cubicmap.c @@ -7,7 +7,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) 2015-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2015-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/models/models_first_person_maze.c b/examples/models/models_first_person_maze.c index b2211c57ea05..b5e35b585023 100644 --- a/examples/models/models_first_person_maze.c +++ b/examples/models/models_first_person_maze.c @@ -7,7 +7,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) 2019-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2019-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/models/models_geometric_shapes.c b/examples/models/models_geometric_shapes.c index 90261ad21249..33c406347505 100644 --- a/examples/models/models_geometric_shapes.c +++ b/examples/models/models_geometric_shapes.c @@ -7,7 +7,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) 2014-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/models/models_heightmap.c b/examples/models/models_heightmap.c index 189d07d75d95..a5d17b02eeeb 100644 --- a/examples/models/models_heightmap.c +++ b/examples/models/models_heightmap.c @@ -7,7 +7,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) 2015-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2015-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/models/models_loading.c b/examples/models/models_loading.c index d40661412824..7bdf1772f9fc 100644 --- a/examples/models/models_loading.c +++ b/examples/models/models_loading.c @@ -20,7 +20,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) 2014-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/models/models_loading_gltf.c b/examples/models/models_loading_gltf.c index 01a08406964a..68228a3f0f96 100644 --- a/examples/models/models_loading_gltf.c +++ b/examples/models/models_loading_gltf.c @@ -7,7 +7,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) 2020-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2020-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/models/models_loading_vox.c b/examples/models/models_loading_vox.c index 80226d0a4b9f..49477cd9c0e8 100644 --- a/examples/models/models_loading_vox.c +++ b/examples/models/models_loading_vox.c @@ -9,7 +9,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) 2021-2022 Johann Nadalutti (@procfxgen) and Ramon Santamaria (@raysan5) +* Copyright (c) 2021-2023 Johann Nadalutti (@procfxgen) and Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/models/models_mesh_generation.c b/examples/models/models_mesh_generation.c index 35586c811614..b4ff018cc5f7 100644 --- a/examples/models/models_mesh_generation.c +++ b/examples/models/models_mesh_generation.c @@ -7,7 +7,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) 2017-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2017-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/models/models_mesh_picking.c b/examples/models/models_mesh_picking.c index 64aba2624b75..52f9974d3770 100644 --- a/examples/models/models_mesh_picking.c +++ b/examples/models/models_mesh_picking.c @@ -9,7 +9,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) 2017-2022 Joel Davis (@joeld42) and Ramon Santamaria (@raysan5) +* Copyright (c) 2017-2023 Joel Davis (@joeld42) and Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/models/models_orthographic_projection.c b/examples/models/models_orthographic_projection.c index cfdeb859bef9..098e4b20a3a0 100644 --- a/examples/models/models_orthographic_projection.c +++ b/examples/models/models_orthographic_projection.c @@ -9,7 +9,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-2022 Max Danielsson (@autious) and Ramon Santamaria (@raysan5) +* Copyright (c) 2018-2023 Max Danielsson (@autious) and Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/models/models_rlgl_solar_system.c b/examples/models/models_rlgl_solar_system.c index a49b37d06b53..903752f76138 100644 --- a/examples/models/models_rlgl_solar_system.c +++ b/examples/models/models_rlgl_solar_system.c @@ -9,7 +9,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-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2018-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/models/models_skybox.c b/examples/models/models_skybox.c index b6ce72b2a605..1b9923334b05 100644 --- a/examples/models/models_skybox.c +++ b/examples/models/models_skybox.c @@ -7,7 +7,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) 2017-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2017-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/models/models_waving_cubes.c b/examples/models/models_waving_cubes.c index f0737de3a93f..31ed4ff419f2 100644 --- a/examples/models/models_waving_cubes.c +++ b/examples/models/models_waving_cubes.c @@ -9,7 +9,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) 2019-2022 Codecat (@codecat) and Ramon Santamaria (@raysan5) +* Copyright (c) 2019-2023 Codecat (@codecat) and Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/models/models_yaw_pitch_roll.c b/examples/models/models_yaw_pitch_roll.c index d3db9d063078..611ee31460c4 100644 --- a/examples/models/models_yaw_pitch_roll.c +++ b/examples/models/models_yaw_pitch_roll.c @@ -9,7 +9,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) 2017-2022 Berni (@Berni8k) and Ramon Santamaria (@raysan5) +* Copyright (c) 2017-2023 Berni (@Berni8k) and Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/others/easings_testbed.c b/examples/others/easings_testbed.c index 38f47dd094fe..227efd231ef0 100644 --- a/examples/others/easings_testbed.c +++ b/examples/others/easings_testbed.c @@ -9,7 +9,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) 2019-2022 Juan Miguel López (@flashback-fx ) and Ramon Santamaria (@raysan5) +* Copyright (c) 2019-2023 Juan Miguel López (@flashback-fx ) and Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/others/embedded_files_loading.c b/examples/others/embedded_files_loading.c index 3e3bc7d44a68..64023539c87f 100644 --- a/examples/others/embedded_files_loading.c +++ b/examples/others/embedded_files_loading.c @@ -9,7 +9,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) 2020-2022 Kristian Holmgren (@defutura) and Ramon Santamaria (@raysan5) +* Copyright (c) 2020-2023 Kristian Holmgren (@defutura) and Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/others/raylib_opengl_interop.c b/examples/others/raylib_opengl_interop.c index 2acb62193ac4..bda301a7e33e 100644 --- a/examples/others/raylib_opengl_interop.c +++ b/examples/others/raylib_opengl_interop.c @@ -9,7 +9,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) 2021-2022 Stephan Soller (@arkanis) and Ramon Santamaria (@raysan5) +* Copyright (c) 2021-2023 Stephan Soller (@arkanis) and Ramon Santamaria (@raysan5) * ******************************************************************************************** * diff --git a/examples/others/reasings.h b/examples/others/reasings.h index 8b14ba6aa9e0..657ea242eba8 100644 --- a/examples/others/reasings.h +++ b/examples/others/reasings.h @@ -60,7 +60,7 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. * --------------------------------------------------------------------------------- * -* Copyright (c) 2015-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2015-2023 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. diff --git a/examples/others/rlgl_compute_shader.c b/examples/others/rlgl_compute_shader.c index b74ed932fef9..e19a6c2f51ad 100644 --- a/examples/others/rlgl_compute_shader.c +++ b/examples/others/rlgl_compute_shader.c @@ -12,7 +12,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) 2021-2022 Teddy Astie (@tsnake41) +* Copyright (c) 2021-2023 Teddy Astie (@tsnake41) * ********************************************************************************************/ diff --git a/examples/others/rlgl_standalone.c b/examples/others/rlgl_standalone.c index 3086999927c8..43cc3288ebe6 100644 --- a/examples/others/rlgl_standalone.c +++ b/examples/others/rlgl_standalone.c @@ -29,7 +29,7 @@ * This example is 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) 2014-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2023 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. diff --git a/examples/shaders/rlights.h b/examples/shaders/rlights.h index cf0f7629ab5f..d17bf7c2ea20 100644 --- a/examples/shaders/rlights.h +++ b/examples/shaders/rlights.h @@ -11,7 +11,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2017-2022 Victor Fisac (@victorfisac) and Ramon Santamaria (@raysan5) +* Copyright (c) 2017-2023 Victor Fisac (@victorfisac) and 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. diff --git a/examples/shaders/shaders_basic_lighting.c b/examples/shaders/shaders_basic_lighting.c index c557ecf733b6..1b29b8522ca0 100644 --- a/examples/shaders/shaders_basic_lighting.c +++ b/examples/shaders/shaders_basic_lighting.c @@ -14,7 +14,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) 2019-2022 Chris Camacho (@codifies) and Ramon Santamaria (@raysan5) +* Copyright (c) 2019-2023 Chris Camacho (@codifies) and Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/shaders/shaders_custom_uniform.c b/examples/shaders/shaders_custom_uniform.c index 401328e0f4f3..75f6112e5023 100644 --- a/examples/shaders/shaders_custom_uniform.c +++ b/examples/shaders/shaders_custom_uniform.c @@ -14,7 +14,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) 2015-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2015-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/shaders/shaders_eratosthenes.c b/examples/shaders/shaders_eratosthenes.c index a1f4101ac403..a481f3008b00 100644 --- a/examples/shaders/shaders_eratosthenes.c +++ b/examples/shaders/shaders_eratosthenes.c @@ -21,7 +21,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) 2019-2022 ProfJski and Ramon Santamaria (@raysan5) +* Copyright (c) 2019-2023 ProfJski and Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/shaders/shaders_fog.c b/examples/shaders/shaders_fog.c index de5c23df5131..ac84a018047d 100644 --- a/examples/shaders/shaders_fog.c +++ b/examples/shaders/shaders_fog.c @@ -14,7 +14,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) 2019-2022 Chris Camacho (@chriscamacho) and Ramon Santamaria (@raysan5) +* Copyright (c) 2019-2023 Chris Camacho (@chriscamacho) and Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/shaders/shaders_hot_reloading.c b/examples/shaders/shaders_hot_reloading.c index e9aae34961bc..e58c45f3c1c0 100644 --- a/examples/shaders/shaders_hot_reloading.c +++ b/examples/shaders/shaders_hot_reloading.c @@ -10,7 +10,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) 2020-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2020-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/shaders/shaders_julia_set.c b/examples/shaders/shaders_julia_set.c index 962c723b16bb..ee1988058e16 100644 --- a/examples/shaders/shaders_julia_set.c +++ b/examples/shaders/shaders_julia_set.c @@ -14,7 +14,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) 2019-2022 eggmund (@eggmund) and Ramon Santamaria (@raysan5) +* Copyright (c) 2019-2023 eggmund (@eggmund) and Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/shaders/shaders_mesh_instancing.c b/examples/shaders/shaders_mesh_instancing.c index ce0855d942b1..f4e6b40b0cb9 100644 --- a/examples/shaders/shaders_mesh_instancing.c +++ b/examples/shaders/shaders_mesh_instancing.c @@ -9,7 +9,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) 2020-2022 @seanpringle, Max (@moliad) and Ramon Santamaria (@raysan5) +* Copyright (c) 2020-2023 @seanpringle, Max (@moliad) and Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/shaders/shaders_model_shader.c b/examples/shaders/shaders_model_shader.c index 29c1948c9700..de3cb5f8d48f 100644 --- a/examples/shaders/shaders_model_shader.c +++ b/examples/shaders/shaders_model_shader.c @@ -14,7 +14,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) 2014-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/shaders/shaders_multi_sample2d.c b/examples/shaders/shaders_multi_sample2d.c index ae5470fff90f..d6f8803b799a 100644 --- a/examples/shaders/shaders_multi_sample2d.c +++ b/examples/shaders/shaders_multi_sample2d.c @@ -14,7 +14,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) 2020-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2020-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/shaders/shaders_palette_switch.c b/examples/shaders/shaders_palette_switch.c index b47bbf16fce4..bb1eda4e0835 100644 --- a/examples/shaders/shaders_palette_switch.c +++ b/examples/shaders/shaders_palette_switch.c @@ -16,7 +16,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) 2019-2022 Marco Lizza (@MarcoLizza) and Ramon Santamaria (@raysan5) +* Copyright (c) 2019-2023 Marco Lizza (@MarcoLizza) and Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/shaders/shaders_postprocessing.c b/examples/shaders/shaders_postprocessing.c index 758250f1976a..d0555f219e30 100644 --- a/examples/shaders/shaders_postprocessing.c +++ b/examples/shaders/shaders_postprocessing.c @@ -14,7 +14,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) 2015-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2015-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/shaders/shaders_raymarching.c b/examples/shaders/shaders_raymarching.c index 8be45fb9ff2d..9b8bc30cd789 100644 --- a/examples/shaders/shaders_raymarching.c +++ b/examples/shaders/shaders_raymarching.c @@ -10,7 +10,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-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2018-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/shaders/shaders_shapes_textures.c b/examples/shaders/shaders_shapes_textures.c index ca6677fbd2e2..d3ec8daf0414 100644 --- a/examples/shaders/shaders_shapes_textures.c +++ b/examples/shaders/shaders_shapes_textures.c @@ -14,7 +14,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) 2015-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2015-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/shaders/shaders_simple_mask.c b/examples/shaders/shaders_simple_mask.c index d10878d771fc..ce3fc8bb91e4 100644 --- a/examples/shaders/shaders_simple_mask.c +++ b/examples/shaders/shaders_simple_mask.c @@ -9,7 +9,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) 2019-2022 Chris Camacho (@chriscamacho) and Ramon Santamaria (@raysan5) +* Copyright (c) 2019-2023 Chris Camacho (@chriscamacho) and Ramon Santamaria (@raysan5) * ******************************************************************************************** * diff --git a/examples/shaders/shaders_spotlight.c b/examples/shaders/shaders_spotlight.c index 6ddcd42f60a5..a21e3c82a48e 100644 --- a/examples/shaders/shaders_spotlight.c +++ b/examples/shaders/shaders_spotlight.c @@ -9,7 +9,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) 2019-2022 Chris Camacho (@chriscamacho) and Ramon Santamaria (@raysan5) +* Copyright (c) 2019-2023 Chris Camacho (@chriscamacho) and Ramon Santamaria (@raysan5) * ******************************************************************************************** * diff --git a/examples/shaders/shaders_texture_drawing.c b/examples/shaders/shaders_texture_drawing.c index 6b82915b5b4a..006168d57e52 100644 --- a/examples/shaders/shaders_texture_drawing.c +++ b/examples/shaders/shaders_texture_drawing.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) 2019-2022 Michał Ciesielski and Ramon Santamaria (@raysan5) +* Copyright (c) 2019-2023 Michał Ciesielski and Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/shaders/shaders_texture_outline.c b/examples/shaders/shaders_texture_outline.c index c81d3ff16a0e..a28ab80e424c 100644 --- a/examples/shaders/shaders_texture_outline.c +++ b/examples/shaders/shaders_texture_outline.c @@ -12,7 +12,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) 2021-2022 Samuel SKiff (@GoldenThumbs) and Ramon Santamaria (@raysan5) +* Copyright (c) 2021-2023 Samuel SKiff (@GoldenThumbs) and Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/shaders/shaders_texture_waves.c b/examples/shaders/shaders_texture_waves.c index cc250f1b9c35..a087ec4d0e87 100644 --- a/examples/shaders/shaders_texture_waves.c +++ b/examples/shaders/shaders_texture_waves.c @@ -16,7 +16,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) 2019-2022 Anata (@anatagawa) and Ramon Santamaria (@raysan5) +* Copyright (c) 2019-2023 Anata (@anatagawa) and Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/shapes/shapes_basic_shapes.c b/examples/shapes/shapes_basic_shapes.c index edc0b0c6bb3c..40056b4e73ec 100644 --- a/examples/shapes/shapes_basic_shapes.c +++ b/examples/shapes/shapes_basic_shapes.c @@ -7,7 +7,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) 2014-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/shapes/shapes_bouncing_ball.c b/examples/shapes/shapes_bouncing_ball.c index 19f58da6518e..5e43b80da2cf 100644 --- a/examples/shapes/shapes_bouncing_ball.c +++ b/examples/shapes/shapes_bouncing_ball.c @@ -7,7 +7,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) 2013-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2013-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/shapes/shapes_collision_area.c b/examples/shapes/shapes_collision_area.c index e83f83834c6e..34d04811d48b 100644 --- a/examples/shapes/shapes_collision_area.c +++ b/examples/shapes/shapes_collision_area.c @@ -7,7 +7,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) 2013-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2013-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/shapes/shapes_colors_palette.c b/examples/shapes/shapes_colors_palette.c index 49aad8a371d2..d5578255057b 100644 --- a/examples/shapes/shapes_colors_palette.c +++ b/examples/shapes/shapes_colors_palette.c @@ -7,7 +7,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) 2014-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/shapes/shapes_draw_circle_sector.c b/examples/shapes/shapes_draw_circle_sector.c index 1fcd8aa48b7a..c95f436432c8 100644 --- a/examples/shapes/shapes_draw_circle_sector.c +++ b/examples/shapes/shapes_draw_circle_sector.c @@ -9,7 +9,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-2022 Vlad Adrian (@demizdor) and Ramon Santamaria (@raysan5) +* Copyright (c) 2018-2023 Vlad Adrian (@demizdor) and Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/shapes/shapes_draw_rectangle_rounded.c b/examples/shapes/shapes_draw_rectangle_rounded.c index 9c527e5ef95d..8150e0946af9 100644 --- a/examples/shapes/shapes_draw_rectangle_rounded.c +++ b/examples/shapes/shapes_draw_rectangle_rounded.c @@ -9,7 +9,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-2022 Vlad Adrian (@demizdor) and Ramon Santamaria (@raysan5) +* Copyright (c) 2018-2023 Vlad Adrian (@demizdor) and Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/shapes/shapes_draw_ring.c b/examples/shapes/shapes_draw_ring.c index 6225d473cf3c..b001b9216765 100644 --- a/examples/shapes/shapes_draw_ring.c +++ b/examples/shapes/shapes_draw_ring.c @@ -9,7 +9,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-2022 Vlad Adrian (@demizdor) and Ramon Santamaria (@raysan5) +* Copyright (c) 2018-2023 Vlad Adrian (@demizdor) and Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/shapes/shapes_easings_ball_anim.c b/examples/shapes/shapes_easings_ball_anim.c index e6b595c32e10..866ec0971fcf 100644 --- a/examples/shapes/shapes_easings_ball_anim.c +++ b/examples/shapes/shapes_easings_ball_anim.c @@ -7,7 +7,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) 2014-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/shapes/shapes_easings_box_anim.c b/examples/shapes/shapes_easings_box_anim.c index 05cba19594eb..a854bf6c3893 100644 --- a/examples/shapes/shapes_easings_box_anim.c +++ b/examples/shapes/shapes_easings_box_anim.c @@ -7,7 +7,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) 2014-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/shapes/shapes_easings_rectangle_array.c b/examples/shapes/shapes_easings_rectangle_array.c index a2ab6397d861..03916f5b456b 100644 --- a/examples/shapes/shapes_easings_rectangle_array.c +++ b/examples/shapes/shapes_easings_rectangle_array.c @@ -10,7 +10,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) 2014-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/shapes/shapes_following_eyes.c b/examples/shapes/shapes_following_eyes.c index 43a50a79dc01..2137d797a4fc 100644 --- a/examples/shapes/shapes_following_eyes.c +++ b/examples/shapes/shapes_following_eyes.c @@ -7,7 +7,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) 2013-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2013-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/shapes/shapes_lines_bezier.c b/examples/shapes/shapes_lines_bezier.c index 76c232792876..195281be30e6 100644 --- a/examples/shapes/shapes_lines_bezier.c +++ b/examples/shapes/shapes_lines_bezier.c @@ -7,7 +7,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) 2017-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2017-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/shapes/shapes_logo_raylib.c b/examples/shapes/shapes_logo_raylib.c index 48005c7aef70..4f625c2c8953 100644 --- a/examples/shapes/shapes_logo_raylib.c +++ b/examples/shapes/shapes_logo_raylib.c @@ -7,7 +7,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) 2014-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/shapes/shapes_logo_raylib_anim.c b/examples/shapes/shapes_logo_raylib_anim.c index 60e839f51ddc..5d6dd35389b4 100644 --- a/examples/shapes/shapes_logo_raylib_anim.c +++ b/examples/shapes/shapes_logo_raylib_anim.c @@ -7,7 +7,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) 2014-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/shapes/shapes_rectangle_scaling.c b/examples/shapes/shapes_rectangle_scaling.c index 0faeee2f3ba1..18104b120ae9 100644 --- a/examples/shapes/shapes_rectangle_scaling.c +++ b/examples/shapes/shapes_rectangle_scaling.c @@ -9,7 +9,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-2022 Vlad Adrian (@demizdor) and Ramon Santamaria (@raysan5) +* Copyright (c) 2018-2023 Vlad Adrian (@demizdor) and Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/text/text_draw_3d.c b/examples/text/text_draw_3d.c index f03ad7849c34..0711d54cde6f 100644 --- a/examples/text/text_draw_3d.c +++ b/examples/text/text_draw_3d.c @@ -22,7 +22,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) 2021-2022 Vlad Adrian (@demizdor) +* Copyright (c) 2021-2023 Vlad Adrian (@demizdor) * ********************************************************************************************/ diff --git a/examples/text/text_font_filters.c b/examples/text/text_font_filters.c index 7d9082b5d8cf..e6756713c0cd 100644 --- a/examples/text/text_font_filters.c +++ b/examples/text/text_font_filters.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) 2015-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2015-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/text/text_font_loading.c b/examples/text/text_font_loading.c index 6ebdbbcddf12..2ded64f09f20 100644 --- a/examples/text/text_font_loading.c +++ b/examples/text/text_font_loading.c @@ -16,7 +16,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) 2016-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2016-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/text/text_font_sdf.c b/examples/text/text_font_sdf.c index 9e7465019ce0..6a223ae5c0db 100644 --- a/examples/text/text_font_sdf.c +++ b/examples/text/text_font_sdf.c @@ -7,7 +7,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) 2015-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2015-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/text/text_font_spritefont.c b/examples/text/text_font_spritefont.c index 109ab486b2ae..b5df2d0dc445 100644 --- a/examples/text/text_font_spritefont.c +++ b/examples/text/text_font_spritefont.c @@ -17,7 +17,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) 2014-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/text/text_format_text.c b/examples/text/text_format_text.c index dbdbb0fdb9fa..6b1b0456fc2d 100644 --- a/examples/text/text_format_text.c +++ b/examples/text/text_format_text.c @@ -7,7 +7,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) 2014-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/text/text_input_box.c b/examples/text/text_input_box.c index 4d2eee442fc1..f3923c1e9290 100644 --- a/examples/text/text_input_box.c +++ b/examples/text/text_input_box.c @@ -7,7 +7,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) 2017-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2017-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/text/text_raylib_fonts.c b/examples/text/text_raylib_fonts.c index f08569a2e2d7..8ef67c71d6f7 100644 --- a/examples/text/text_raylib_fonts.c +++ b/examples/text/text_raylib_fonts.c @@ -10,7 +10,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) 2017-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2017-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/text/text_rectangle_bounds.c b/examples/text/text_rectangle_bounds.c index 9ae2ba938cb0..886c348d5ae1 100644 --- a/examples/text/text_rectangle_bounds.c +++ b/examples/text/text_rectangle_bounds.c @@ -9,7 +9,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-2022 Vlad Adrian (@demizdor) and Ramon Santamaria (@raysan5) +* Copyright (c) 2018-2023 Vlad Adrian (@demizdor) and Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/text/text_unicode.c b/examples/text/text_unicode.c index 4af542655b11..eb2a7843c1f3 100644 --- a/examples/text/text_unicode.c +++ b/examples/text/text_unicode.c @@ -9,7 +9,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) 2019-2022 Vlad Adrian (@demizdor) and Ramon Santamaria (@raysan5) +* Copyright (c) 2019-2023 Vlad Adrian (@demizdor) and Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/text/text_writing_anim.c b/examples/text/text_writing_anim.c index 6beb3e5527b1..4ee67700e87a 100644 --- a/examples/text/text_writing_anim.c +++ b/examples/text/text_writing_anim.c @@ -7,7 +7,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) 2016-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2016-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/textures/textures_background_scrolling.c b/examples/textures/textures_background_scrolling.c index 70b67c3de8f7..55fa2115e3af 100644 --- a/examples/textures/textures_background_scrolling.c +++ b/examples/textures/textures_background_scrolling.c @@ -7,7 +7,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) 2019-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2019-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/textures/textures_blend_modes.c b/examples/textures/textures_blend_modes.c index b8131354a196..246a98e47309 100644 --- a/examples/textures/textures_blend_modes.c +++ b/examples/textures/textures_blend_modes.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) 2020-2022 Karlo Licudine (@accidentalrebel) +* Copyright (c) 2020-2023 Karlo Licudine (@accidentalrebel) * ********************************************************************************************/ diff --git a/examples/textures/textures_bunnymark.c b/examples/textures/textures_bunnymark.c index 2cca8b48f8ba..ede3036fa8da 100644 --- a/examples/textures/textures_bunnymark.c +++ b/examples/textures/textures_bunnymark.c @@ -7,7 +7,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) 2014-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/textures/textures_draw_tiled.c b/examples/textures/textures_draw_tiled.c index f68f236690be..34fe82ce46a1 100644 --- a/examples/textures/textures_draw_tiled.c +++ b/examples/textures/textures_draw_tiled.c @@ -9,7 +9,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) 2020-2022 Vlad Adrian (@demizdor) and Ramon Santamaria (@raysan5) +* Copyright (c) 2020-2023 Vlad Adrian (@demizdor) and Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/textures/textures_fog_of_war.c b/examples/textures/textures_fog_of_war.c index d89386c86715..7c3d666424ad 100644 --- a/examples/textures/textures_fog_of_war.c +++ b/examples/textures/textures_fog_of_war.c @@ -7,7 +7,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-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2018-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/textures/textures_gif_player.c b/examples/textures/textures_gif_player.c index 099a712686ba..108522835deb 100644 --- a/examples/textures/textures_gif_player.c +++ b/examples/textures/textures_gif_player.c @@ -7,7 +7,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) 2021-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2021-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/textures/textures_image_drawing.c b/examples/textures/textures_image_drawing.c index 190fb859477b..967cb52a4ae2 100644 --- a/examples/textures/textures_image_drawing.c +++ b/examples/textures/textures_image_drawing.c @@ -9,7 +9,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) 2016-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2016-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/textures/textures_image_generation.c b/examples/textures/textures_image_generation.c index ed67be036d3e..1ab08ae84145 100644 --- a/examples/textures/textures_image_generation.c +++ b/examples/textures/textures_image_generation.c @@ -7,7 +7,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) 2O17-2022 Wilhem Barbier (@nounoursheureux) and Ramon Santamaria (@raysan5) +* Copyright (c) 2O17-2023 Wilhem Barbier (@nounoursheureux) and Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/textures/textures_image_loading.c b/examples/textures/textures_image_loading.c index 1e5cb6c5a6ab..b1bfe09f70b2 100644 --- a/examples/textures/textures_image_loading.c +++ b/examples/textures/textures_image_loading.c @@ -9,7 +9,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) 2015-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2015-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/textures/textures_image_processing.c b/examples/textures/textures_image_processing.c index 49aacfc75cc6..6e6c85482697 100644 --- a/examples/textures/textures_image_processing.c +++ b/examples/textures/textures_image_processing.c @@ -9,7 +9,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) 2016-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2016-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/textures/textures_image_text.c b/examples/textures/textures_image_text.c index f4c919d536fd..50db688decb2 100644 --- a/examples/textures/textures_image_text.c +++ b/examples/textures/textures_image_text.c @@ -7,7 +7,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) 2017-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2017-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/textures/textures_logo_raylib.c b/examples/textures/textures_logo_raylib.c index 5afd1475367c..8bd86581166f 100644 --- a/examples/textures/textures_logo_raylib.c +++ b/examples/textures/textures_logo_raylib.c @@ -7,7 +7,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) 2014-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/textures/textures_mouse_painting.c b/examples/textures/textures_mouse_painting.c index eb6dc480a637..e985cee0c99e 100644 --- a/examples/textures/textures_mouse_painting.c +++ b/examples/textures/textures_mouse_painting.c @@ -9,7 +9,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) 2019-2022 Chris Dill (@MysteriousSpace) and Ramon Santamaria (@raysan5) +* Copyright (c) 2019-2023 Chris Dill (@MysteriousSpace) and Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/textures/textures_npatch_drawing.c b/examples/textures/textures_npatch_drawing.c index 515ad9b52cc0..f85aaa129bd2 100644 --- a/examples/textures/textures_npatch_drawing.c +++ b/examples/textures/textures_npatch_drawing.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-2022 Jorge A. Gomes (@overdev) and Ramon Santamaria (@raysan5) +* Copyright (c) 2018-2023 Jorge A. Gomes (@overdev) and Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/textures/textures_particles_blending.c b/examples/textures/textures_particles_blending.c index 7f1952f0590c..ec144ff4b018 100644 --- a/examples/textures/textures_particles_blending.c +++ b/examples/textures/textures_particles_blending.c @@ -7,7 +7,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) 2017-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2017-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/textures/textures_polygon.c b/examples/textures/textures_polygon.c index 287029f7366e..18fc952490fc 100644 --- a/examples/textures/textures_polygon.c +++ b/examples/textures/textures_polygon.c @@ -9,7 +9,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) 2021-2022 Chris Camacho (@codifies) and Ramon Santamaria (@raysan5) +* Copyright (c) 2021-2023 Chris Camacho (@codifies) and Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/textures/textures_raw_data.c b/examples/textures/textures_raw_data.c index cd0c9bf0ec51..22d7cc06f3c6 100644 --- a/examples/textures/textures_raw_data.c +++ b/examples/textures/textures_raw_data.c @@ -9,7 +9,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) 2015-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2015-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/textures/textures_sprite_anim.c b/examples/textures/textures_sprite_anim.c index aa9f18aeb463..99efe2eabf7f 100644 --- a/examples/textures/textures_sprite_anim.c +++ b/examples/textures/textures_sprite_anim.c @@ -7,7 +7,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) 2014-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/textures/textures_sprite_button.c b/examples/textures/textures_sprite_button.c index 5e2a4011cbd0..bd9891826f54 100644 --- a/examples/textures/textures_sprite_button.c +++ b/examples/textures/textures_sprite_button.c @@ -7,7 +7,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) 2019-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2019-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/textures/textures_sprite_explosion.c b/examples/textures/textures_sprite_explosion.c index 32c69849ce3a..a6cbd3e5b2cd 100644 --- a/examples/textures/textures_sprite_explosion.c +++ b/examples/textures/textures_sprite_explosion.c @@ -7,7 +7,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) 2019-2022 Anata and Ramon Santamaria (@raysan5) +* Copyright (c) 2019-2023 Anata and Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/textures/textures_srcrec_dstrec.c b/examples/textures/textures_srcrec_dstrec.c index 1839fc7802fb..caf8f64b3a3a 100644 --- a/examples/textures/textures_srcrec_dstrec.c +++ b/examples/textures/textures_srcrec_dstrec.c @@ -7,7 +7,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) 2015-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2015-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/textures/textures_to_image.c b/examples/textures/textures_to_image.c index 9acdf2334f5b..fd3c848e8b21 100644 --- a/examples/textures/textures_to_image.c +++ b/examples/textures/textures_to_image.c @@ -9,7 +9,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) 2015-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2015-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/parser/raylib_parser.c b/parser/raylib_parser.c index 5ca186d7196f..97e1e79a9748 100644 --- a/parser/raylib_parser.c +++ b/parser/raylib_parser.c @@ -54,7 +54,7 @@ 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: - Copyright (c) 2021-2022 Ramon Santamaria (@raysan5) + Copyright (c) 2021-2023 Ramon Santamaria (@raysan5) **********************************************************************************************/ @@ -1073,7 +1073,7 @@ static void ShowCommandLineInfo(void) printf("// //\n"); printf("// more info and bugs-report: github.com/raysan5/raylib/parser //\n"); printf("// //\n"); - printf("// Copyright (c) 2021-2022 Ramon Santamaria (@raysan5) //\n"); + printf("// Copyright (c) 2021-2023 Ramon Santamaria (@raysan5) //\n"); printf("// //\n"); printf("//////////////////////////////////////////////////////////////////////////////////\n\n"); diff --git a/projects/Geany/core_basic_window.c b/projects/Geany/core_basic_window.c index dc1bba141614..c4dd584a57b2 100644 --- a/projects/Geany/core_basic_window.c +++ b/projects/Geany/core_basic_window.c @@ -5,7 +5,7 @@ * This example has been created using raylib 1.0 (www.raylib.com) * raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) * -* Copyright (c) 2013-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2013-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/projects/VSCode/main.c b/projects/VSCode/main.c index 2d7b121f9728..0794672d0610 100644 --- a/projects/VSCode/main.c +++ b/projects/VSCode/main.c @@ -15,7 +15,7 @@ * This example has been created using raylib 1.0 (www.raylib.com) * raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) * -* Copyright (c) 2013-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2013-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/src/config.h b/src/config.h index d5f59a3728d6..17334b8acb61 100644 --- a/src/config.h +++ b/src/config.h @@ -6,7 +6,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2018-2022 Ahmad Fatoum & Ramon Santamaria (@raysan5) +* Copyright (c) 2018-2023 Ahmad Fatoum & 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. diff --git a/src/raudio.c b/src/raudio.c index d1b47f64a991..40b89106ac9f 100644 --- a/src/raudio.c +++ b/src/raudio.c @@ -50,7 +50,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2013-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2013-2023 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. @@ -974,7 +974,7 @@ bool ExportWaveAsCode(Wave wave, const char *fileName) byteCount += sprintf(txtData + byteCount, "// more info and bugs-report: github.com/raysan5/raylib //\n"); byteCount += sprintf(txtData + byteCount, "// feedback and support: ray[at]raylib.com //\n"); byteCount += sprintf(txtData + byteCount, "// //\n"); - byteCount += sprintf(txtData + byteCount, "// Copyright (c) 2018-2022 Ramon Santamaria (@raysan5) //\n"); + byteCount += sprintf(txtData + byteCount, "// Copyright (c) 2018-2023 Ramon Santamaria (@raysan5) //\n"); byteCount += sprintf(txtData + byteCount, "// //\n"); byteCount += sprintf(txtData + byteCount, "//////////////////////////////////////////////////////////////////////////////////\n\n"); diff --git a/src/raymath.h b/src/raymath.h index ea3085a54629..435ea3c6e076 100644 --- a/src/raymath.h +++ b/src/raymath.h @@ -25,7 +25,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2015-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2015-2023 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. diff --git a/src/rcamera.h b/src/rcamera.h index 37ea13a6792c..92c3c49a977f 100644 --- a/src/rcamera.h +++ b/src/rcamera.h @@ -22,7 +22,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2015-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2015-2023 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. diff --git a/src/rcore.c b/src/rcore.c index 12fe73512a95..b88d6e9f27d1 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -89,7 +89,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2013-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2013-2023 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. diff --git a/src/rgestures.h b/src/rgestures.h index 1703dbd0d4c0..b63ac9678d80 100644 --- a/src/rgestures.h +++ b/src/rgestures.h @@ -24,7 +24,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2014-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2023 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. diff --git a/src/rglfw.c b/src/rglfw.c index 61922604c206..940257ab1993 100644 --- a/src/rglfw.c +++ b/src/rglfw.c @@ -7,7 +7,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2017-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2017-2023 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. diff --git a/src/rlgl.h b/src/rlgl.h index 8afe1fdcf48d..072925551ffa 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -85,7 +85,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2014-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2023 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. diff --git a/src/rmodels.c b/src/rmodels.c index 290d6e2953b2..9bb54961a118 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -22,7 +22,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2013-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2013-2023 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. @@ -1795,7 +1795,7 @@ bool ExportMesh(Mesh mesh, const char *fileName) byteCount += sprintf(txtData + byteCount, "# // more info and bugs-report: github.com/raysan5/raylib //\n"); byteCount += sprintf(txtData + byteCount, "# // feedback and support: ray[at]raylib.com //\n"); byteCount += sprintf(txtData + byteCount, "# // //\n"); - byteCount += sprintf(txtData + byteCount, "# // Copyright (c) 2018-2022 Ramon Santamaria (@raysan5) //\n"); + byteCount += sprintf(txtData + byteCount, "# // Copyright (c) 2018-2023 Ramon Santamaria (@raysan5) //\n"); byteCount += sprintf(txtData + byteCount, "# // //\n"); byteCount += sprintf(txtData + byteCount, "# //////////////////////////////////////////////////////////////////////////////////\n\n"); byteCount += sprintf(txtData + byteCount, "# Vertex Count: %i\n", mesh.vertexCount); diff --git a/src/rshapes.c b/src/rshapes.c index 2262ae978458..371abe2c72a2 100644 --- a/src/rshapes.c +++ b/src/rshapes.c @@ -26,7 +26,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2013-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2013-2023 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. diff --git a/src/rtextures.c b/src/rtextures.c index 3313a06f1341..5d17184897dc 100644 --- a/src/rtextures.c +++ b/src/rtextures.c @@ -43,7 +43,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2013-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2013-2023 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. @@ -609,7 +609,7 @@ bool ExportImageAsCode(Image image, const char *fileName) byteCount += sprintf(txtData + byteCount, "// more info and bugs-report: github.com/raysan5/raylib //\n"); byteCount += sprintf(txtData + byteCount, "// feedback and support: ray[at]raylib.com //\n"); byteCount += sprintf(txtData + byteCount, "// //\n"); - byteCount += sprintf(txtData + byteCount, "// Copyright (c) 2018-2022 Ramon Santamaria (@raysan5) //\n"); + byteCount += sprintf(txtData + byteCount, "// Copyright (c) 2018-2023 Ramon Santamaria (@raysan5) //\n"); byteCount += sprintf(txtData + byteCount, "// //\n"); byteCount += sprintf(txtData + byteCount, "////////////////////////////////////////////////////////////////////////////////////////\n\n"); From e2a8066fca67fe39ab2b5113d748bb04cd310f6c Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 1 Jan 2023 16:07:51 +0100 Subject: [PATCH 022/192] Update year to 2023 --- examples/core/core_2d_camera_mouse_zoom.c | 2 +- examples/models/models_draw_cube_texture.c | 2 +- examples/models/models_loading_m3d.c | 2 +- examples/shapes/reasings.h | 2 +- examples/shapes/shapes_top_down_lights.c | 2 +- examples/text/text_codepoints_loading.c | 2 +- examples/textures/textures_textured_curve.c | 2 +- src/raylib.dll.rc | 10 +++++----- src/raylib.rc | 10 +++++----- src/rtext.c | 4 ++-- src/utils.c | 4 ++-- src/utils.h | 2 +- 12 files changed, 22 insertions(+), 22 deletions(-) diff --git a/examples/core/core_2d_camera_mouse_zoom.c b/examples/core/core_2d_camera_mouse_zoom.c index 74ac76499a96..2e94d37a5d9e 100644 --- a/examples/core/core_2d_camera_mouse_zoom.c +++ b/examples/core/core_2d_camera_mouse_zoom.c @@ -7,7 +7,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) 2022 Jeffery Myers (@JeffM2501) +* Copyright (c) 2022-2023 Jeffery Myers (@JeffM2501) * ********************************************************************************************/ diff --git a/examples/models/models_draw_cube_texture.c b/examples/models/models_draw_cube_texture.c index b36e968f402d..e43c3c844d7f 100644 --- a/examples/models/models_draw_cube_texture.c +++ b/examples/models/models_draw_cube_texture.c @@ -7,7 +7,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) 2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2022-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/models/models_loading_m3d.c b/examples/models/models_loading_m3d.c index 81968407355a..52dc952269cc 100644 --- a/examples/models/models_loading_m3d.c +++ b/examples/models/models_loading_m3d.c @@ -13,7 +13,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) 2022 bzt (@bztsrc) +* Copyright (c) 2022-2023 bzt (@bztsrc) * ********************************************************************************************/ diff --git a/examples/shapes/reasings.h b/examples/shapes/reasings.h index 8b14ba6aa9e0..657ea242eba8 100644 --- a/examples/shapes/reasings.h +++ b/examples/shapes/reasings.h @@ -60,7 +60,7 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. * --------------------------------------------------------------------------------- * -* Copyright (c) 2015-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2015-2023 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. diff --git a/examples/shapes/shapes_top_down_lights.c b/examples/shapes/shapes_top_down_lights.c index d75d46d74e71..b09137cba02f 100644 --- a/examples/shapes/shapes_top_down_lights.c +++ b/examples/shapes/shapes_top_down_lights.c @@ -9,7 +9,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) 2022 Jeffery Myers (@JeffM2501) +* Copyright (c) 2022-2023 Jeffery Myers (@JeffM2501) * ********************************************************************************************/ diff --git a/examples/text/text_codepoints_loading.c b/examples/text/text_codepoints_loading.c index c68544030efc..1f3db0cf3d93 100644 --- a/examples/text/text_codepoints_loading.c +++ b/examples/text/text_codepoints_loading.c @@ -7,7 +7,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) 2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2022-2023 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/textures/textures_textured_curve.c b/examples/textures/textures_textured_curve.c index 276670972abc..201b01fecfb6 100644 --- a/examples/textures/textures_textured_curve.c +++ b/examples/textures/textures_textured_curve.c @@ -9,7 +9,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) 2022 Jeffery Myers and Ramon Santamaria (@raysan5) +* Copyright (c) 2022-2023 Jeffery Myers and Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/src/raylib.dll.rc b/src/raylib.dll.rc index 4380d9784581..c2a42dca2ed6 100644 --- a/src/raylib.dll.rc +++ b/src/raylib.dll.rc @@ -1,8 +1,8 @@ GLFW_ICON ICON "raylib.ico" 1 VERSIONINFO -FILEVERSION 4,2,0,0 -PRODUCTVERSION 4,2,0,0 +FILEVERSION 4,5,0,0 +PRODUCTVERSION 4,5,0,0 BEGIN BLOCK "StringFileInfo" BEGIN @@ -11,12 +11,12 @@ BEGIN BEGIN //VALUE "CompanyName", "raylib technologies" VALUE "FileDescription", "raylib dynamic library (www.raylib.com)" - VALUE "FileVersion", "4.2.0" + VALUE "FileVersion", "4.5.0" VALUE "InternalName", "raylib.dll" - VALUE "LegalCopyright", "(c) 2022 Ramon Santamaria (@raysan5)" + VALUE "LegalCopyright", "(c) 2023 Ramon Santamaria (@raysan5)" VALUE "OriginalFilename", "raylib.dll" VALUE "ProductName", "raylib" - VALUE "ProductVersion", "4.2.0" + VALUE "ProductVersion", "4.5.0" END END BLOCK "VarFileInfo" diff --git a/src/raylib.rc b/src/raylib.rc index 984017055d5b..6a9546537d01 100644 --- a/src/raylib.rc +++ b/src/raylib.rc @@ -1,8 +1,8 @@ GLFW_ICON ICON "raylib.ico" 1 VERSIONINFO -FILEVERSION 4,2,0,0 -PRODUCTVERSION 4,2,0,0 +FILEVERSION 4,5,0,0 +PRODUCTVERSION 4,5,0,0 BEGIN BLOCK "StringFileInfo" BEGIN @@ -11,12 +11,12 @@ BEGIN BEGIN //VALUE "CompanyName", "raylib technologies" VALUE "FileDescription", "raylib application (www.raylib.com)" - VALUE "FileVersion", "4.2.0" + VALUE "FileVersion", "4.5.0" VALUE "InternalName", "raylib app" - VALUE "LegalCopyright", "(c) 2022 Ramon Santamaria (@raysan5)" + VALUE "LegalCopyright", "(c) 2023 Ramon Santamaria (@raysan5)" //VALUE "OriginalFilename", "raylib_app.exe" VALUE "ProductName", "raylib app" - VALUE "ProductVersion", "4.2.0" + VALUE "ProductVersion", "4.5.0" END END BLOCK "VarFileInfo" diff --git a/src/rtext.c b/src/rtext.c index 1eb8f45320a3..f98386702747 100644 --- a/src/rtext.c +++ b/src/rtext.c @@ -30,7 +30,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2013-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2013-2023 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. @@ -867,7 +867,7 @@ bool ExportFontAsCode(Font font, const char *fileName) byteCount += sprintf(txtData + byteCount, "// more info and bugs-report: github.com/raysan5/raylib //\n"); byteCount += sprintf(txtData + byteCount, "// feedback and support: ray[at]raylib.com //\n"); byteCount += sprintf(txtData + byteCount, "// //\n"); - byteCount += sprintf(txtData + byteCount, "// Copyright (c) 2018-2022 Ramon Santamaria (@raysan5) //\n"); + byteCount += sprintf(txtData + byteCount, "// Copyright (c) 2018-2023 Ramon Santamaria (@raysan5) //\n"); byteCount += sprintf(txtData + byteCount, "// //\n"); byteCount += sprintf(txtData + byteCount, "// ---------------------------------------------------------------------------------- //\n"); byteCount += sprintf(txtData + byteCount, "// //\n"); diff --git a/src/utils.c b/src/utils.c index b165449b4dcd..030e59734718 100644 --- a/src/utils.c +++ b/src/utils.c @@ -11,7 +11,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2014-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2023 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. @@ -290,7 +290,7 @@ bool ExportDataAsCode(const unsigned char *data, unsigned int size, const char * byteCount += sprintf(txtData + byteCount, "// more info and bugs-report: github.com/raysan5/raylib //\n"); byteCount += sprintf(txtData + byteCount, "// feedback and support: ray[at]raylib.com //\n"); byteCount += sprintf(txtData + byteCount, "// //\n"); - byteCount += sprintf(txtData + byteCount, "// Copyright (c) 2022 Ramon Santamaria (@raysan5) //\n"); + byteCount += sprintf(txtData + byteCount, "// Copyright (c) 2022-2023 Ramon Santamaria (@raysan5) //\n"); byteCount += sprintf(txtData + byteCount, "// //\n"); byteCount += sprintf(txtData + byteCount, "////////////////////////////////////////////////////////////////////////////////////////\n\n"); diff --git a/src/utils.h b/src/utils.h index a2b3e03c53cc..ff8246a7b68a 100644 --- a/src/utils.h +++ b/src/utils.h @@ -5,7 +5,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2014-2022 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2023 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. From 30b75702df9d5d8f1ce2b9c7911b05e992b777f5 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 1 Jan 2023 18:09:22 +0100 Subject: [PATCH 023/192] Update year to 2023 --- parser/LICENSE | 2 +- parser/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/parser/LICENSE b/parser/LICENSE index fac92d37bee2..125d7dbae71f 100644 --- a/parser/LICENSE +++ b/parser/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2021-2022 Ramon Santamaria (@raysan5) +Copyright (c) 2021-2023 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. diff --git a/parser/README.md b/parser/README.md index 4d00fde06051..0c55f20eaac6 100644 --- a/parser/README.md +++ b/parser/README.md @@ -19,7 +19,7 @@ Check `raylib_parser.c` for details about those structs. // // // more info and bugs-report: github.com/raysan5/raylib/parser // // // -// Copyright (c) 2021-2022 Ramon Santamaria (@raysan5) // +// Copyright (c) 2021-2023 Ramon Santamaria (@raysan5) // // // ////////////////////////////////////////////////////////////////////////////////// From 3cfb9a6e83af9a94a2d1d57dd6bbfba738c09b2a Mon Sep 17 00:00:00 2001 From: BugraAlptekinSari <94199723+BugraAlptekinSari@users.noreply.github.com> Date: Sun, 1 Jan 2023 20:17:28 +0300 Subject: [PATCH 024/192] [example] Writing into the depth buffer (#2836) * Add a depth buffer example. * Fixed a typo --- examples/Makefile | 3 +- .../resources/shaders/glsl100/write_depth.fs | 15 ++ .../resources/shaders/glsl330/write_depth.fs | 13 ++ examples/shaders/shaders_write_depth.c | 149 ++++++++++++++++++ 4 files changed, 179 insertions(+), 1 deletion(-) create mode 100644 examples/shaders/resources/shaders/glsl100/write_depth.fs create mode 100644 examples/shaders/resources/shaders/glsl330/write_depth.fs create mode 100644 examples/shaders/shaders_write_depth.c diff --git a/examples/Makefile b/examples/Makefile index 76a33149f559..7beff293416f 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -520,7 +520,8 @@ SHADERS = \ shaders/shaders_spotlight \ shaders/shaders_hot_reloading \ shaders/shaders_mesh_instancing \ - shaders/shaders_multi_sample2d + shaders/shaders_multi_sample2d \ + shaders/shaders_write_depth AUDIO = \ audio/audio_module_playing \ diff --git a/examples/shaders/resources/shaders/glsl100/write_depth.fs b/examples/shaders/resources/shaders/glsl100/write_depth.fs new file mode 100644 index 000000000000..5167efb8e026 --- /dev/null +++ b/examples/shaders/resources/shaders/glsl100/write_depth.fs @@ -0,0 +1,15 @@ +#version 100 +#extension GL_EXT_frag_depth : enable +precision mediump float; // Precision required for OpenGL ES2 (WebGL) + +varying vec2 fragTexCoord; +varying vec4 fragColor; + +uniform sampler2D texture0; +uniform vec4 colDiffuse; +void main() +{ + vec4 texelColor = texture2D(texture0, fragTexCoord); + gl_FragColor = texelColor*colDiffuse*fragColor; + gl_FragDepthEXT = 1.0 - gl_FragCoord.z; +} \ No newline at end of file diff --git a/examples/shaders/resources/shaders/glsl330/write_depth.fs b/examples/shaders/resources/shaders/glsl330/write_depth.fs new file mode 100644 index 000000000000..36c70fe41a6c --- /dev/null +++ b/examples/shaders/resources/shaders/glsl330/write_depth.fs @@ -0,0 +1,13 @@ +#version 330 + +in vec2 fragTexCoord; +in vec4 fragColor; + +uniform sampler2D texture0; +uniform vec4 colDiffuse; +void main() +{ + vec4 texelColor = texture2D(texture0, fragTexCoord); + gl_FragColor = texelColor*colDiffuse*fragColor; + gl_FragDepth = 1.0 - gl_FragCoord.z; +} \ No newline at end of file diff --git a/examples/shaders/shaders_write_depth.c b/examples/shaders/shaders_write_depth.c new file mode 100644 index 000000000000..28c605c70bdb --- /dev/null +++ b/examples/shaders/shaders_write_depth.c @@ -0,0 +1,149 @@ +/******************************************************************************************* +* +* raylib [core] example - Basic window +* +* Example originally created with raylib 4.2, last time updated with raylib 4.2 +* +* Example contributed by Buğra Alptekin Sarı (@BugraAlptekinSari) 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) 2022 Buğra Alptekin Sarı (@BugraAlptekinSari) +* +********************************************************************************************/ + +#include "raylib.h" +#include "rlgl.h" + +#if defined(PLATFORM_DESKTOP) +#define GLSL_VERSION 330 +#else // PLATFORM_RPI, PLATFORM_ANDROID, PLATFORM_WEB +#define GLSL_VERSION 100 +#endif +//------------------------------------------------------------------------------------ +// Customized render texture function to create a writable render buffer +RenderTexture2D LoadRenderTextureMOD(int width, int height) +{ + RenderTexture2D target = { 0 }; + + target.id = rlLoadFramebuffer(width, height); // Load an empty framebuffer + + if (target.id > 0) + { + rlEnableFramebuffer(target.id); + + // Create color texture (default to RGBA) + target.texture.id = rlLoadTexture(0, width, height, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, 1); + target.texture.width = width; + target.texture.height = height; + target.texture.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; + target.texture.mipmaps = 1; + + // Create depth rendertexture + target.depth.id = rlLoadTextureDepth(width, height, false); + target.depth.width = width; + target.depth.height = height; + target.depth.format = 19; //DEPTH_COMPONENT_24BIT? + target.depth.mipmaps = 1; + + // Attach color texture and depth renderbuffer/texture to FBO + rlFramebufferAttach(target.id, target.texture.id, RL_ATTACHMENT_COLOR_CHANNEL0, RL_ATTACHMENT_TEXTURE2D, 0); + rlFramebufferAttach(target.id, target.depth.id, RL_ATTACHMENT_DEPTH, RL_ATTACHMENT_TEXTURE2D, 0); + + // Check if fbo is complete with attachments (valid) + if (rlFramebufferComplete(target.id)) TRACELOG(LOG_INFO, "FBO: [ID %i] Framebuffer object created successfully", target.id); + + rlDisableFramebuffer(); + } + else TRACELOG(LOG_WARNING, "FBO: Framebuffer object can not be created"); + + return target; +} + +// Unload render texture from GPU memory (VRAM) +void UnloadRenderTextureMOD(RenderTexture2D target) +{ + if (target.id > 0) + { + // Color texture attached to FBO is deleted + rlUnloadTexture(target.texture.id); + rlUnloadTexture(target.depth.id); + + // NOTE: Depth texture/renderbuffer is automatically + // queried and deleted before deleting framebuffer + rlUnloadFramebuffer(target.id); + } +} +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [core] example - basic window"); + + // The shader inverst the depth buffer by writing into it by `gl_FragDepth = 1 - gl_FragCoord.z;` + Shader shader = LoadShader(0, TextFormat("resources/shaders/glsl%i/write_depth.fs", GLSL_VERSION)); + + //Use Customized function to create writable depth buffer + RenderTexture2D target = LoadRenderTextureMOD(screenWidth, screenHeight); + + Camera camera = { // Define the camera to look into our 3d world + .position = (Vector3){ 2.0f, 2.0f, 3.0f }, // Camera position + .target = (Vector3){ 0.0f, 0.5f, 0.0f }, // Camera looking at point + .up = (Vector3){ 0.0f, 1.0f, 0.0f }, // Camera up vector (rotation towards target) + .fovy = 45.0f, // Camera field-of-view Y + .projection = CAMERA_PERSPECTIVE // Camera mode type + }; + SetCameraMode(camera, CAMERA_ORBITAL); + SetTargetFPS(60); + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + UpdateCamera(&camera); + // Draw + //---------------------------------------------------------------------------------- + // Draw FBO + BeginTextureMode(target); + ClearBackground(WHITE); + BeginMode3D(camera); + BeginShaderMode(shader); + DrawCubeWiresV((Vector3) { 0.0f, 0.5f, 1.0f }, (Vector3) { 1.0f, 1.0f, 1.0f }, RED); + DrawCubeV((Vector3) { 0.0f, 0.5f, 1.0f }, (Vector3) { 1.0f, 1.0f, 1.0f }, PURPLE); + DrawCubeWiresV((Vector3) { 0.0f, 0.5f, -1.0f }, (Vector3) { 1.0f, 1.0f, 1.0f }, DARKGREEN); + DrawCubeV((Vector3) { 0.0f, 0.5f, -1.0f }, (Vector3) { 1.0f, 1.0f, 1.0f }, YELLOW); + DrawGrid(10, 1.0f); + EndShaderMode(); + EndMode3D(); + EndTextureMode(); + + // Draw Screen + BeginDrawing(); + + ClearBackground(RAYWHITE); + DrawTextureRec(target.texture, (Rectangle) { 0, 0, screenWidth, -screenHeight }, (Vector2) { 0, 0 }, WHITE); + DrawFPS(0, 0); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + UnloadRenderTextureMOD(target); + UnloadShader(shader); + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} From 5ba41e4f7fc2af29c59705e2179e7333ff68b92f Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 1 Jan 2023 18:31:03 +0100 Subject: [PATCH 025/192] REVIEWED: `shaders_write_depth` example --- .../resources/shaders/glsl100/write_depth.fs | 4 +- .../resources/shaders/glsl330/write_depth.fs | 6 +- examples/shaders/shaders_write_depth.c | 173 ++++++++++-------- 3 files changed, 103 insertions(+), 80 deletions(-) diff --git a/examples/shaders/resources/shaders/glsl100/write_depth.fs b/examples/shaders/resources/shaders/glsl100/write_depth.fs index 5167efb8e026..341c6115f0a3 100644 --- a/examples/shaders/resources/shaders/glsl100/write_depth.fs +++ b/examples/shaders/resources/shaders/glsl100/write_depth.fs @@ -7,9 +7,11 @@ varying vec4 fragColor; uniform sampler2D texture0; uniform vec4 colDiffuse; + void main() { vec4 texelColor = texture2D(texture0, fragTexCoord); + gl_FragColor = texelColor*colDiffuse*fragColor; - gl_FragDepthEXT = 1.0 - gl_FragCoord.z; + gl_FragDepthEXT = 1.0 - gl_FragCoord.z; } \ No newline at end of file diff --git a/examples/shaders/resources/shaders/glsl330/write_depth.fs b/examples/shaders/resources/shaders/glsl330/write_depth.fs index 36c70fe41a6c..88a4113ff698 100644 --- a/examples/shaders/resources/shaders/glsl330/write_depth.fs +++ b/examples/shaders/resources/shaders/glsl330/write_depth.fs @@ -5,9 +5,11 @@ in vec4 fragColor; uniform sampler2D texture0; uniform vec4 colDiffuse; + void main() { vec4 texelColor = texture2D(texture0, fragTexCoord); + gl_FragColor = texelColor*colDiffuse*fragColor; - gl_FragDepth = 1.0 - gl_FragCoord.z; -} \ No newline at end of file + gl_FragDepth = 1.0 - gl_FragCoord.z; +} diff --git a/examples/shaders/shaders_write_depth.c b/examples/shaders/shaders_write_depth.c index 28c605c70bdb..317f6ac7585c 100644 --- a/examples/shaders/shaders_write_depth.c +++ b/examples/shaders/shaders_write_depth.c @@ -1,6 +1,6 @@ /******************************************************************************************* * -* raylib [core] example - Basic window +* raylib [shaders] example - Depth buffer writing * * Example originally created with raylib 4.2, last time updated with raylib 4.2 * @@ -9,7 +9,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) 2022 Buğra Alptekin Sarı (@BugraAlptekinSari) +* Copyright (c) 2022-2023 Buğra Alptekin Sarı (@BugraAlptekinSari) * ********************************************************************************************/ @@ -21,60 +21,16 @@ #else // PLATFORM_RPI, PLATFORM_ANDROID, PLATFORM_WEB #define GLSL_VERSION 100 #endif -//------------------------------------------------------------------------------------ -// Customized render texture function to create a writable render buffer -RenderTexture2D LoadRenderTextureMOD(int width, int height) -{ - RenderTexture2D target = { 0 }; - - target.id = rlLoadFramebuffer(width, height); // Load an empty framebuffer - - if (target.id > 0) - { - rlEnableFramebuffer(target.id); - - // Create color texture (default to RGBA) - target.texture.id = rlLoadTexture(0, width, height, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, 1); - target.texture.width = width; - target.texture.height = height; - target.texture.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; - target.texture.mipmaps = 1; - - // Create depth rendertexture - target.depth.id = rlLoadTextureDepth(width, height, false); - target.depth.width = width; - target.depth.height = height; - target.depth.format = 19; //DEPTH_COMPONENT_24BIT? - target.depth.mipmaps = 1; - - // Attach color texture and depth renderbuffer/texture to FBO - rlFramebufferAttach(target.id, target.texture.id, RL_ATTACHMENT_COLOR_CHANNEL0, RL_ATTACHMENT_TEXTURE2D, 0); - rlFramebufferAttach(target.id, target.depth.id, RL_ATTACHMENT_DEPTH, RL_ATTACHMENT_TEXTURE2D, 0); - - // Check if fbo is complete with attachments (valid) - if (rlFramebufferComplete(target.id)) TRACELOG(LOG_INFO, "FBO: [ID %i] Framebuffer object created successfully", target.id); - - rlDisableFramebuffer(); - } - else TRACELOG(LOG_WARNING, "FBO: Framebuffer object can not be created"); - - return target; -} +//------------------------------------------------------------------------------------ +// Declare custom functions required for the example +//------------------------------------------------------------------------------------ +// Load custom render texture, create a writable depth texture buffer +static RenderTexture2D LoadRenderTextureDepthTex(int width, int height); // Unload render texture from GPU memory (VRAM) -void UnloadRenderTextureMOD(RenderTexture2D target) -{ - if (target.id > 0) - { - // Color texture attached to FBO is deleted - rlUnloadTexture(target.texture.id); - rlUnloadTexture(target.depth.id); +static void UnloadRenderTextureDepthTex(RenderTexture2D target); + - // NOTE: Depth texture/renderbuffer is automatically - // queried and deleted before deleting framebuffer - rlUnloadFramebuffer(target.id); - } -} //------------------------------------------------------------------------------------ // Program main entry point //------------------------------------------------------------------------------------ @@ -85,22 +41,25 @@ int main(void) const int screenWidth = 800; const int screenHeight = 450; - InitWindow(screenWidth, screenHeight, "raylib [core] example - basic window"); + InitWindow(screenWidth, screenHeight, "raylib [shaders] example - write depth buffer"); - // The shader inverst the depth buffer by writing into it by `gl_FragDepth = 1 - gl_FragCoord.z;` + // The shader inverts the depth buffer by writing into it by `gl_FragDepth = 1 - gl_FragCoord.z;` Shader shader = LoadShader(0, TextFormat("resources/shaders/glsl%i/write_depth.fs", GLSL_VERSION)); - //Use Customized function to create writable depth buffer - RenderTexture2D target = LoadRenderTextureMOD(screenWidth, screenHeight); + // Use Customized function to create writable depth texture buffer + RenderTexture2D target = LoadRenderTextureDepthTex(screenWidth, screenHeight); - Camera camera = { // Define the camera to look into our 3d world + // Define the camera to look into our 3d world + Camera camera = { .position = (Vector3){ 2.0f, 2.0f, 3.0f }, // Camera position .target = (Vector3){ 0.0f, 0.5f, 0.0f }, // Camera looking at point .up = (Vector3){ 0.0f, 1.0f, 0.0f }, // Camera up vector (rotation towards target) .fovy = 45.0f, // Camera field-of-view Y - .projection = CAMERA_PERSPECTIVE // Camera mode type + .projection = CAMERA_PERSPECTIVE // Camera mode type }; + SetCameraMode(camera, CAMERA_ORBITAL); + SetTargetFPS(60); //-------------------------------------------------------------------------------------- @@ -110,36 +69,39 @@ int main(void) // Update //---------------------------------------------------------------------------------- UpdateCamera(&camera); + //---------------------------------------------------------------------------------- + // Draw //---------------------------------------------------------------------------------- - // Draw FBO + + // Draw into our custom render texture (framebuffer) BeginTextureMode(target); - ClearBackground(WHITE); - BeginMode3D(camera); - BeginShaderMode(shader); - DrawCubeWiresV((Vector3) { 0.0f, 0.5f, 1.0f }, (Vector3) { 1.0f, 1.0f, 1.0f }, RED); - DrawCubeV((Vector3) { 0.0f, 0.5f, 1.0f }, (Vector3) { 1.0f, 1.0f, 1.0f }, PURPLE); - DrawCubeWiresV((Vector3) { 0.0f, 0.5f, -1.0f }, (Vector3) { 1.0f, 1.0f, 1.0f }, DARKGREEN); - DrawCubeV((Vector3) { 0.0f, 0.5f, -1.0f }, (Vector3) { 1.0f, 1.0f, 1.0f }, YELLOW); - DrawGrid(10, 1.0f); - EndShaderMode(); - EndMode3D(); + ClearBackground(WHITE); + + BeginMode3D(camera); + BeginShaderMode(shader); + DrawCubeWiresV((Vector3){ 0.0f, 0.5f, 1.0f }, (Vector3){ 1.0f, 1.0f, 1.0f }, RED); + DrawCubeV((Vector3){ 0.0f, 0.5f, 1.0f }, (Vector3){ 1.0f, 1.0f, 1.0f }, PURPLE); + DrawCubeWiresV((Vector3){ 0.0f, 0.5f, -1.0f }, (Vector3){ 1.0f, 1.0f, 1.0f }, DARKGREEN); + DrawCubeV((Vector3) { 0.0f, 0.5f, -1.0f }, (Vector3){ 1.0f, 1.0f, 1.0f }, YELLOW); + DrawGrid(10, 1.0f); + EndShaderMode(); + EndMode3D(); EndTextureMode(); - // Draw Screen + // Draw into screen our custom render texture BeginDrawing(); - - ClearBackground(RAYWHITE); - DrawTextureRec(target.texture, (Rectangle) { 0, 0, screenWidth, -screenHeight }, (Vector2) { 0, 0 }, WHITE); - DrawFPS(0, 0); - + ClearBackground(RAYWHITE); + + DrawTextureRec(target.texture, (Rectangle) { 0, 0, screenWidth, -screenHeight }, (Vector2) { 0, 0 }, WHITE); + DrawFPS(10, 10); EndDrawing(); //---------------------------------------------------------------------------------- } // De-Initialization //-------------------------------------------------------------------------------------- - UnloadRenderTextureMOD(target); + UnloadRenderTextureDepthTex(target); UnloadShader(shader); CloseWindow(); // Close window and OpenGL context @@ -147,3 +109,60 @@ int main(void) return 0; } + +//------------------------------------------------------------------------------------ +// Define custom functions required for the example +//------------------------------------------------------------------------------------ +// Load custom render texture, create a writable depth texture buffer +RenderTexture2D LoadRenderTextureDepthTex(int width, int height) +{ + RenderTexture2D target = { 0 }; + + target.id = rlLoadFramebuffer(width, height); // Load an empty framebuffer + + if (target.id > 0) + { + rlEnableFramebuffer(target.id); + + // Create color texture (default to RGBA) + target.texture.id = rlLoadTexture(0, width, height, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, 1); + target.texture.width = width; + target.texture.height = height; + target.texture.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; + target.texture.mipmaps = 1; + + // Create depth texture buffer (instead of raylib default renderbuffer) + target.depth.id = rlLoadTextureDepth(width, height, false); + target.depth.width = width; + target.depth.height = height; + target.depth.format = 19; //DEPTH_COMPONENT_24BIT? + target.depth.mipmaps = 1; + + // Attach color texture and depth texture to FBO + rlFramebufferAttach(target.id, target.texture.id, RL_ATTACHMENT_COLOR_CHANNEL0, RL_ATTACHMENT_TEXTURE2D, 0); + rlFramebufferAttach(target.id, target.depth.id, RL_ATTACHMENT_DEPTH, RL_ATTACHMENT_TEXTURE2D, 0); + + // Check if fbo is complete with attachments (valid) + if (rlFramebufferComplete(target.id)) TRACELOG(LOG_INFO, "FBO: [ID %i] Framebuffer object created successfully", target.id); + + rlDisableFramebuffer(); + } + else TRACELOG(LOG_WARNING, "FBO: Framebuffer object can not be created"); + + return target; +} + +// Unload render texture from GPU memory (VRAM) +void UnloadRenderTextureDepthTex(RenderTexture2D target) +{ + if (target.id > 0) + { + // Color texture attached to FBO is deleted + rlUnloadTexture(target.texture.id); + rlUnloadTexture(target.depth.id); + + // NOTE: Depth texture is automatically + // queried and deleted before deleting framebuffer + rlUnloadFramebuffer(target.id); + } +} \ No newline at end of file From 0ccc1d3686f7c9eeafd88c7385d908b23812231e Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 1 Jan 2023 19:07:58 +0100 Subject: [PATCH 026/192] Update year to 2023 --- examples/Makefile | 2 +- examples/Makefile.Android | 2 +- examples/Makefile.Web | 2 +- projects/4coder/Makefile | 2 +- src/Makefile | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/Makefile b/examples/Makefile index 7beff293416f..bc2c8d711838 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -2,7 +2,7 @@ # # raylib makefile for Desktop platforms, Raspberry Pi, Android and HTML5 # -# Copyright (c) 2013-2022 Ramon Santamaria (@raysan5) +# Copyright (c) 2013-2023 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. diff --git a/examples/Makefile.Android b/examples/Makefile.Android index 0570d8b231a8..267c4aa57c7c 100644 --- a/examples/Makefile.Android +++ b/examples/Makefile.Android @@ -2,7 +2,7 @@ # # raylib makefile for Android project (APK building) # -# Copyright (c) 2017-2022 Ramon Santamaria (@raysan5) +# Copyright (c) 2017-2023 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. diff --git a/examples/Makefile.Web b/examples/Makefile.Web index d7e640862ce4..a55a76b8c7cb 100644 --- a/examples/Makefile.Web +++ b/examples/Makefile.Web @@ -2,7 +2,7 @@ # # raylib makefile for Desktop platforms, Raspberry Pi, Android and HTML5 # -# Copyright (c) 2013-2022 Ramon Santamaria (@raysan5) +# Copyright (c) 2013-2023 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. diff --git a/projects/4coder/Makefile b/projects/4coder/Makefile index 4178920bbb26..0d254e340ebc 100644 --- a/projects/4coder/Makefile +++ b/projects/4coder/Makefile @@ -2,7 +2,7 @@ # # raylib makefile for Desktop platforms, Raspberry Pi, Android and HTML5 # -# Copyright (c) 2013-2022 Ramon Santamaria (@raysan5) +# Copyright (c) 2013-2023 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. diff --git a/src/Makefile b/src/Makefile index 40a509bd48c3..fdc52a8396e5 100644 --- a/src/Makefile +++ b/src/Makefile @@ -15,7 +15,7 @@ # Many thanks to Milan Nikolic (@gen2brain) for implementing Android platform pipeline. # Many thanks to Emanuele Petriglia for his contribution on GNU/Linux pipeline. # -# Copyright (c) 2013-2022 Ramon Santamaria (@raysan5) +# Copyright (c) 2013-2023 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. From 1dbcce8b56933aa9983b81f33a2f6db64e93d5af Mon Sep 17 00:00:00 2001 From: Antonis Geralis <43617260+planetis-m@users.noreply.github.com> Date: Mon, 2 Jan 2023 17:48:53 +0200 Subject: [PATCH 027/192] Use explicit atomics (#2849) * Use explicit atomics * missed one * use relaced ordering --- examples/core/core_loading_thread.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/examples/core/core_loading_thread.c b/examples/core/core_loading_thread.c index d5c00fc5607a..5a988bb27b8c 100644 --- a/examples/core/core_loading_thread.c +++ b/examples/core/core_loading_thread.c @@ -23,10 +23,10 @@ // Using C11 atomics for synchronization // NOTE: A plain bool (or any plain data type for that matter) can't be used for inter-thread synchronization -static atomic_bool dataLoaded = ATOMIC_VAR_INIT(false); // Data Loaded completion indicator +static atomic_bool dataLoaded = false; // Data Loaded completion indicator static void *LoadDataThread(void *arg); // Loading data thread function declaration -static int dataProgress = 0; // Data progress accumulator +static atomic_int dataProgress = 0; // Data progress accumulator //------------------------------------------------------------------------------------ // Program main entry point @@ -69,7 +69,7 @@ int main(void) case STATE_LOADING: { framesCounter++; - if (atomic_load(&dataLoaded)) + if (atomic_load_explicit(&dataLoaded, memory_order_relaxed)) { framesCounter = 0; int error = pthread_join(threadId, NULL); @@ -84,8 +84,8 @@ int main(void) if (IsKeyPressed(KEY_ENTER)) { // Reset everything to launch again - atomic_store(&dataLoaded, false); - dataProgress = 0; + atomic_store_explicit(&dataLoaded, false, memory_order_relaxed); + atomic_store_explicit(&dataProgress, 0, memory_order_relaxed); state = STATE_WAITING; } } break; @@ -104,7 +104,7 @@ int main(void) case STATE_WAITING: DrawText("PRESS ENTER to START LOADING DATA", 150, 170, 20, DARKGRAY); break; case STATE_LOADING: { - DrawRectangle(150, 200, dataProgress, 60, SKYBLUE); + DrawRectangle(150, 200, atomic_load_explicit(&dataProgress, memory_order_relaxed), 60, SKYBLUE); if ((framesCounter/15)%2) DrawText("LOADING DATA...", 240, 210, 40, DARKBLUE); } break; @@ -145,11 +145,11 @@ static void *LoadDataThread(void *arg) // We accumulate time over a global variable to be used in // main thread as a progress bar - dataProgress = timeCounter/10; + atomic_store_explicit(&dataProgress, timeCounter/10, memory_order_relaxed); } // When data has finished loading, we set global variable - atomic_store(&dataLoaded, true); + atomic_store_explicit(&dataLoaded, true, memory_order_relaxed); return NULL; } From 62f63f9e485fdffa1e981ae4ae58f5eb8ccfff8e Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 2 Jan 2023 17:06:52 +0100 Subject: [PATCH 028/192] REVIEWED: Avoid possible gamepad index as `-1` #2839 WARNING: It could require further review of `GamepadThread()` function where `js_event gamepadEvent.number` detecting current pressed button could generate a missmatch with index 0 (reserved for button unknow). Or maybe `0` could just be `GAMEPAD_BUTTON_NONE`? In that case, consistency with other inputs should be carefully considered... --- src/raylib.h | 4 ++-- src/rcore.c | 11 ++++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/raylib.h b/src/raylib.h index 5a230a3acf6b..1c3f77669ada 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -716,7 +716,7 @@ typedef enum { // Material map index typedef enum { - MATERIAL_MAP_ALBEDO = 0, // Albedo material (same as: MATERIAL_MAP_DIFFUSE) + MATERIAL_MAP_ALBEDO = 0, // Albedo material (same as: MATERIAL_MAP_DIFFUSE) MATERIAL_MAP_METALNESS, // Metalness material (same as: MATERIAL_MAP_SPECULAR) MATERIAL_MAP_NORMAL, // Normal material MATERIAL_MAP_ROUGHNESS, // Roughness material @@ -862,7 +862,7 @@ typedef enum { } BlendMode; // Gesture -// NOTE: It could be used as flags to enable only some gestures +// NOTE: Provided as bit-wise flags to enable only desired gestures typedef enum { GESTURE_NONE = 0, // No gesture GESTURE_TAP = 1, // Tap gesture diff --git a/src/rcore.c b/src/rcore.c index b88d6e9f27d1..0e9aa76ec0b6 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -765,7 +765,7 @@ void InitWindow(int width, int height, const char *title) CORE.Input.Keyboard.exitKey = KEY_ESCAPE; CORE.Input.Mouse.scale = (Vector2){ 1.0f, 1.0f }; CORE.Input.Mouse.cursor = MOUSE_CURSOR_ARROW; - CORE.Input.Gamepad.lastButtonPressed = -1; + CORE.Input.Gamepad.lastButtonPressed = 0; // GAMEPAD_BUTTON_UNKNOWN #if defined(SUPPORT_EVENTS_WAITING) CORE.Window.eventWaiting = true; #endif @@ -4871,7 +4871,7 @@ void PollInputEvents(void) #if !(defined(PLATFORM_RPI) || defined(PLATFORM_DRM)) // Reset last gamepad button/axis registered state - CORE.Input.Gamepad.lastButtonPressed = -1; + CORE.Input.Gamepad.lastButtonPressed = 0; // GAMEPAD_BUTTON_UNKNOWN CORE.Input.Gamepad.axisCount = 0; #endif @@ -5714,14 +5714,15 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event) CORE.Input.Gamepad.ready[0] = true; GamepadButton button = AndroidTranslateGamepadButton(keycode); - if (button == GAMEPAD_BUTTON_UNKNOWN) - return 1; + + if (button == GAMEPAD_BUTTON_UNKNOWN) return 1; if (AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_DOWN) { CORE.Input.Gamepad.currentButtonState[0][button] = 1; } else CORE.Input.Gamepad.currentButtonState[0][button] = 0; // Key up + return 1; // Handled gamepad button } @@ -6685,7 +6686,7 @@ static void *GamepadThread(void *arg) CORE.Input.Gamepad.currentButtonState[i][gamepadEvent.number] = (int)gamepadEvent.value; if ((int)gamepadEvent.value == 1) CORE.Input.Gamepad.lastButtonPressed = gamepadEvent.number; - else CORE.Input.Gamepad.lastButtonPressed = -1; + else CORE.Input.Gamepad.lastButtonPressed = 0; // GAMEPAD_BUTTON_UNKNOWN } } else if (gamepadEvent.type == JS_EVENT_AXIS) From f2e3d6eca724ee88794b20934aa9bf9d818280a9 Mon Sep 17 00:00:00 2001 From: Charles Date: Mon, 2 Jan 2023 14:23:48 -0500 Subject: [PATCH 029/192] [models] Add GLTF animation support (#2844) * add GLTF animation support * use correct index when allocating animVertices and animNormals * early exit LoadModelAnimationsGLTF if the gtlf file fails to parse * update models/models_loading_gltf.c to play gltf animation Updated the .blend file to use weights rather than bone parents so it fits into the framework. Exported with weights to the .glb file. * fix order of operations for bone scale in UpdateModelAnimation * minor doc cleanup and improvements * fix formatting * fix float formatting * fix brace alignment and replace asserts with log messages --- examples/models/models_loading_gltf.c | 23 +- .../models/resources/models/gltf/robot.blend | Bin 1899312 -> 2107372 bytes .../models/resources/models/gltf/robot.glb | Bin 1477024 -> 1602604 bytes src/rmodels.c | 320 +++++++++++++++++- 4 files changed, 324 insertions(+), 19 deletions(-) diff --git a/examples/models/models_loading_gltf.c b/examples/models/models_loading_gltf.c index 68228a3f0f96..8797159066d5 100644 --- a/examples/models/models_loading_gltf.c +++ b/examples/models/models_loading_gltf.c @@ -35,6 +35,10 @@ int main(void) // Loaf gltf model Model model = LoadModel("resources/models/gltf/robot.glb"); + unsigned int animsCount = 0; + ModelAnimation *modelAnimations = LoadModelAnimations("resources/models/gltf/robot.glb", &animsCount); + + unsigned int animIndex = 0; Vector3 position = { 0.0f, 0.0f, 0.0f }; // Set model position @@ -43,11 +47,26 @@ int main(void) SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- + unsigned int currentFrame = 0; + // Main game loop while (!WindowShouldClose()) // Detect window close button or ESC key { // Update //---------------------------------------------------------------------------------- + ModelAnimation anim = modelAnimations[animIndex]; + if (IsKeyPressed(KEY_UP)) + { + animIndex = (animIndex + 1) % animsCount; + } + + if (IsKeyPressed(KEY_DOWN)) + { + animIndex = (animIndex + animsCount - 1) % animsCount; + } + + currentFrame = (currentFrame + 1) % anim.frameCount; + UpdateModelAnimation(model, anim, currentFrame); UpdateCamera(&camera); //---------------------------------------------------------------------------------- @@ -64,6 +83,8 @@ int main(void) EndMode3D(); + DrawText("Use the up/down arrow keys to switch animation.", 10, 10, 20, WHITE); + EndDrawing(); //---------------------------------------------------------------------------------- } @@ -71,7 +92,7 @@ int main(void) // De-Initialization //-------------------------------------------------------------------------------------- UnloadModel(model); // Unload model and meshes/material - + CloseWindow(); // Close window and OpenGL context //-------------------------------------------------------------------------------------- diff --git a/examples/models/resources/models/gltf/robot.blend b/examples/models/resources/models/gltf/robot.blend index d3bdac23721927c385d17f0c3dc32bd899dc6169..efe43c5e591d2b6edf1a52539aa598ad5a1e0be7 100644 GIT binary patch literal 2107372 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

E2@h_q`VbeY@rQdzc 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�@!foEF3?le5pa*Z^|GdsLz?lZ^n z=k$BldU#8BJ)?$a)JjejXY~8c znd$2p-fyNaXZqRpXf5WMKXYA;JnJtl&oi&Sd(VhG^U9q}om0p&S7~Gl-fs@=nLcZn z=WbY@*(vaBas%_MGqh*k^VwhZ=h>B4=yxMf{zMj3}+(r2}n592KY{i5ma{U$X$qpre;&(FO288tkk zt`Y~HY5ls>@J!1!QtG-$&stO9nccD9vmfvEsCz!6hG*1DSe|EI{fru(QCEor&$NEs zX?UjP8flPcb_zTje_p?5A6cm1hd>R_sFkqXGp~L|4bP~n#DQm8zwR_V({hb8$g|EA zc-DG;zh^gk?>DL88MP9Yd*;>8sNorPl{oNB>(`xzXIie226<+-9CSTPKcVq@Ho8;4 zXLG-{)V<%NhG*1DSniouKcj|c)K%iZGp%2D8lGvnMjGT^Z&JfEY9&lF z!ZWXaMh(xXtHgn4T0j4N4Pk?4)K%ipv(6NF)_FmHo;{=AZ*G;op5guGeieQmFtKyY zGk@l~8hO@VTApWKefORbdFGWnnL5XjXRgvzyx$z!GkuS4U$|j;W{37n-#d-JXv6ZX zGXMC*InbyyL9w2P+jJir3dS-|A zOh0p+jCi*HOMD%LGp~L|4bP~n#DQm8zwR_V({hb8D9<`Wd#3lz&S-z0 zUGKf$q=skIN?4v}Uj2+3o>5nc1JAU6{#lT)!87VAahPYOe#t$5y0qJ3TE6kWdk@#M z^t(;Ho=xo9@7X=x&o`;z8Fdv#u$nwGx)+nO8rfhG*1O;=nVlUw0awX}Lxk?K+tnE6z<F(B#0s3+w$NQCtV{{Vk(=Zdg9m{ygaKG2=d&y*4bLT0{CY8TIKI zy#Ch<($5jyzcWmId4XQvJAb|5_dB|&k+-QZ&;q$De%nhvtfDG8QL>FH^=ww z_iVS@#@y#T)Oe1d*86(-vzJ#tqsDUtb(J`Hj?nsbr}4b1Wh6Gin~gHpPhNRj+$M=%O^V!gzdCzADZdjh#De%nB-mpCDOo3Sxrr2T)gugL{D1uRD!MC*Inbxm64bQY(BMtJbH3goH9^CKQm`e(3ct*`**rph9 z-}LHd)bNbDN*s8m_3KWaJ(h@Qhjs%RTezXVmbF zx=I{)ruFMi!!s?{NP|2xFCK6`tMGoab4Y)l{q`rveVG*0@Qj+ruuU-{&%F8>H9VuP z5(l1X{kqfeOv^P=isw-IZnM_#p1Hp>oS571*^k;Uao;&b4bP~Ru-r4Rent(?sH?<* zXIj7RG(6LCjWozJJG^J^a}C?*_w4#F-RZ7p)bNa23Clh6>SxsOjJir3c&7F9pOFh2 zJfp4>hk4eS0?)?B`aP@Pa=N>oQNuIpDvUTcz4{q7Jfp4>2cBvDy3_DX%Qe!VJTtqb zuV?(boYWH41dd7gRoGirE7T_p}Y)B1I%;hC0eq(Ppw zrogk&X1`~v?);Fu2T;Q^Y9%c9%&VVK!!znCap0NOuR9ITv|J+%^2|41dxo2Mej2fO%SBV49w0_-bc&6nVX^>}~De!DE;@OSAJ>Pjo4bP~Ru-r4R zent(?sH?<*XIel1yBuMIXVg{V@E%}ZGU$4ien8{(taE68p8fQm7rJK+YIsIng%S4v zuYN`i�@!foEF3?le5pa*Z@7&stO9*~DS}o*lOGAoshn)bNa23Cr`$tDjNBGwLdF z;F;F1I}OjYTq6zg%ua!4_V9ksuKoBY-SZhWJfl{^a?iZ_88tkkt`Y~HY5ls>@J!1! z(jd<|Q{dV75&fP$qkkSSn!cWOzXu}qbf%wcv|2IGbl#|tXVm^SHLtjydG*}yhau0r zawk)9kY}#aRQz4e(4OhfP)3j3uspLvd*=P_|I0Tl&pJbUrg=6Q@ofCQ|Zs zd)AFmZIhXVdroxqFXJ4bP~R zu-r4Rent(?sH?<*XIel1u0~;lXVg{VFwg81cxGSG@7al;nB~q*YIsIng%S5nuYN`i z�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

    7k6Ga;RtDh79`V2=nIZ=d6*j*=b2v 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%0A7_gK{4XRwp!EU=LTtuB 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 V`;`8w#?4|g*KS;^2A=Nv`wyBwBJBVG diff --git a/examples/models/resources/models/gltf/robot.glb b/examples/models/resources/models/gltf/robot.glb index 73f5bf44ec1fff629b4ed949bf4ba29a5cbfd78a..549011e75ee4ab8cd69b99743df72020d685b7f9 100644 GIT binary patch literal 1602604 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 z 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%0D1Lm(5^wA`BLP&KScWwx!Y5a!G03$N#uFoLyq^) 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�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

    rU*2;-DQMN>*C4G=a^bfvUXUr9okq%>5@ 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�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 0) + { + if (bones[i].parent > i) + { + TRACELOG(LOG_WARNING, "Assumes bones are toplogically sorted, but bone %d has parent %d. Skipping.", i, bones[i].parent); + continue; + } + transforms[i].rotation = QuaternionMultiply(transforms[bones[i].parent].rotation, transforms[i].rotation); + 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); + } + } +} + //---------------------------------------------------------------------------------- // Module specific Functions Definition //---------------------------------------------------------------------------------- @@ -4370,17 +4389,7 @@ static Model LoadIQM(const char *fileName) model.bindPose[i].scale.z = ijoint[i].scale[2]; } - // Build bind pose from parent joints - for (int i = 0; i < model.boneCount; i++) - { - if (model.bones[i].parent >= 0) - { - model.bindPose[i].rotation = QuaternionMultiply(model.bindPose[model.bones[i].parent].rotation, model.bindPose[i].rotation); - model.bindPose[i].translation = Vector3RotateByQuaternion(model.bindPose[i].translation, model.bindPose[model.bones[i].parent].rotation); - model.bindPose[i].translation = Vector3Add(model.bindPose[i].translation, model.bindPose[model.bones[i].parent].translation); - model.bindPose[i].scale = Vector3Multiply(model.bindPose[i].scale, model.bindPose[model.bones[i].parent].scale); - } - } + BuildPoseFromParentJoints(model.bones, model.boneCount, model.bindPose); RL_FREE(fileData); @@ -4681,6 +4690,33 @@ static Image LoadImageFromCgltfImage(cgltf_image *cgltfImage, const char *texPat return image; } +static BoneInfo *LoadGLTFBoneInfo(cgltf_skin skin, int *boneCount) +{ + *boneCount = skin.joints_count; + BoneInfo *bones = RL_MALLOC(skin.joints_count*sizeof(BoneInfo)); + + for (unsigned int i = 0; i < skin.joints_count; i++) + { + cgltf_node node = *skin.joints[i]; + strncpy(bones[i].name, node.name, sizeof(bones[i].name)); + + // find parent bone index + unsigned int parentIndex = -1; + for (unsigned int j = 0; j < skin.joints_count; j++) + { + if (skin.joints[j] == node.parent) + { + parentIndex = j; + break; + } + } + + bones[i].parent = parentIndex; + } + + return bones; +} + // Load glTF file into model struct, .gltf and .glb supported static Model LoadGLTF(const char *fileName) { @@ -4695,6 +4731,7 @@ static Model LoadGLTF(const char *fileName) - Supports PBR metallic/roughness flow, loads material textures, values and colors PBR specular/glossiness flow and extended texture flows not supported - Supports multiple meshes per model (every primitives is loaded as a separate mesh) + - Supports basic animation RESTRICTIONS: - Only triangle meshes supported @@ -5039,11 +5076,41 @@ static Model LoadGLTF(const char *fileName) } } -/* - // TODO: Load glTF meshes animation data + // Load glTF meshes animation data // REF: https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#skins // REF: https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#skinned-mesh-attributes //---------------------------------------------------------------------------------------------------- + + if (data->skins_count == 1) + { + cgltf_skin skin = data->skins[0]; + model.bones = LoadGLTFBoneInfo(skin, &model.boneCount); + model.bindPose = RL_MALLOC(model.boneCount*sizeof(Transform)); + + for (unsigned int i = 0; i < model.boneCount; i++) + { + cgltf_node node = *skin.joints[i]; + model.bindPose[i].translation.x = node.translation[0]; + model.bindPose[i].translation.y = node.translation[1]; + model.bindPose[i].translation.z = node.translation[2]; + + model.bindPose[i].rotation.x = node.rotation[0]; + model.bindPose[i].rotation.y = node.rotation[1]; + model.bindPose[i].rotation.z = node.rotation[2]; + model.bindPose[i].rotation.w = node.rotation[3]; + + model.bindPose[i].scale.x = node.scale[0]; + model.bindPose[i].scale.y = node.scale[1]; + model.bindPose[i].scale.z = node.scale[2]; + } + + BuildPoseFromParentJoints(model.bones, model.boneCount, model.bindPose); + } + else if (data->skins_count > 1) + { + TRACELOG(LOG_ERROR, "MODEL: [%s] can only load one skin (armature) per model, but gltf skins_count == %i", fileName, data->skins_count); + } + for (unsigned int i = 0, meshIndex = 0; i < data->meshes_count; i++) { for (unsigned int p = 0; p < data->meshes[i].primitives_count; p++) @@ -5065,7 +5132,6 @@ static Model LoadGLTF(const char *fileName) model.meshes[meshIndex].boneIds = RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(unsigned char)); // Load 4 components of unsigned char data type into mesh.boneIds - // TODO: It seems LOAD_ATTRIBUTE() macro does not work as expected in some cases, // for cgltf_attribute_type_joints we have: // - data.meshes[0] (256 vertices) // - 256 values, provided as cgltf_type_vec4 of bytes (4 byte per joint, stride 4) @@ -5092,10 +5158,17 @@ static Model LoadGLTF(const char *fileName) } } + // Animated vertex data + model.meshes[meshIndex].animVertices = RL_CALLOC(model.meshes[meshIndex].vertexCount*3, sizeof(float)); + memcpy(model.meshes[meshIndex].animVertices, model.meshes[meshIndex].vertices, model.meshes[meshIndex].vertexCount*3*sizeof(float)); + model.meshes[meshIndex].animNormals = RL_CALLOC(model.meshes[meshIndex].vertexCount*3, sizeof(float)); + memcpy(model.meshes[meshIndex].animNormals, model.meshes[meshIndex].normals, model.meshes[meshIndex].vertexCount*3*sizeof(float)); + meshIndex++; // Move to next mesh } + } -*/ + // Free all cgltf loaded data cgltf_free(data); } @@ -5106,6 +5179,217 @@ static Model LoadGLTF(const char *fileName) return model; } + +// Get interpolated pose for bone sampler at a specific time. Returns true on success. +static bool GetGLTFPoseAtTime(cgltf_accessor* input, cgltf_accessor *output, float time, void *data) +{ + // input and output should have the same count + + float tstart = 0.0f; + float tend = 0.0f; + + int keyframe = 0; // defaults to first pose + for (int i = 0; i < input->count - 1; i++) + { + cgltf_bool r1 = cgltf_accessor_read_float(input, i, &tstart, 1); + if (!r1) return false; + cgltf_bool r2 = cgltf_accessor_read_float(input, i+1, &tend, 1); + if (!r2) return false; + + if ((tstart <= time) && (time < tend)) + { + keyframe = i; + break; + } + } + + float t = (time - tstart)/(tend - tstart); + t = (t < 0.0f)? 0.0f : t; + t = (t > 1.0f)? 1.0f : t; + + if (output->component_type != cgltf_component_type_r_32f) return false; + + if (output->type == cgltf_type_vec3) + { + float tmp[3] = { 0.0f }; + cgltf_accessor_read_float(output, keyframe, tmp, 3); + 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; + *r = Vector3Lerp(v1, v2, t); + } + else if (output->type == cgltf_type_vec4) + { + float tmp[4] = { 0.0f }; + cgltf_accessor_read_float(output, keyframe, tmp, 4); + 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; + // only v4 is for rotations, so we know it's a quat. + *r = QuaternionSlerp(v1, v2, t); + } + return true; +} + +#define GLTF_ANIMDELAY 17 // that's roughly ~1000 msec / 60 FPS (16.666666* msec) +static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, unsigned int *animCount) +{ + // glTF file loading + unsigned int dataSize = 0; + unsigned char *fileData = LoadFileData(fileName, &dataSize); + + ModelAnimation *animations = NULL; + // glTF data loading + cgltf_options options = { 0 }; + cgltf_data *data = NULL; + cgltf_result result = cgltf_parse(&options, fileData, dataSize, &data); + if (result != cgltf_result_success) + { + TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load glTF data", fileName); + *animCount = 0; + return NULL; + } + + result = cgltf_load_buffers(&options, data, fileName); + if (result != cgltf_result_success) TRACELOG(LOG_INFO, "MODEL: [%s] Failed to load animation buffers", fileName); + + if (result == cgltf_result_success) + { + if (data->skins_count == 1) + { + cgltf_skin skin = data->skins[0]; + *animCount = data->animations_count; + animations = RL_MALLOC(data->animations_count*sizeof(ModelAnimation)); + for (unsigned int i = 0; i < data->animations_count; i++) + { + animations[i].bones = LoadGLTFBoneInfo(skin, &animations[i].boneCount); + + cgltf_animation animData = data->animations[i]; + + struct Channels { + cgltf_animation_channel *translate; + cgltf_animation_channel *rotate; + cgltf_animation_channel *scale; + }; + + struct Channels *boneChannels = RL_CALLOC(animations[i].boneCount, sizeof(struct Channels)); + float animDuration = 0.0f; + for (unsigned int j = 0; j < animData.channels_count; j++) + { + cgltf_animation_channel channel = animData.channels[j]; + int boneIndex = -1; + for (unsigned int k = 0; k < skin.joints_count; k++) + { + if (animData.channels[j].target_node == skin.joints[k]) + { + boneIndex = k; + break; + } + } + + if (boneIndex == -1) + { + // animation channel for a node not in the armature. + continue; + } + + if (animData.channels[j].sampler->interpolation == cgltf_interpolation_type_linear) + { + if (channel.target_path == cgltf_animation_path_type_translation) + { + boneChannels[boneIndex].translate = &animData.channels[j]; + } + else if (channel.target_path == cgltf_animation_path_type_rotation) + { + boneChannels[boneIndex].rotate = &animData.channels[j]; + } + else if (channel.target_path == cgltf_animation_path_type_scale) + { + boneChannels[boneIndex].scale = &animData.channels[j]; + } + else + { + TRACELOG(LOG_WARNING, "MODEL: [%s] Unsupported target_path on channel %d's sampler for animation %d. Skipping.", fileName, j, i); + } + } else TRACELOG(LOG_WARNING, "MODEL: [%s] Only linear interpolation curves are supported for GLTF animation.", fileName); + + float t = 0.0f; + cgltf_bool r = cgltf_accessor_read_float(channel.sampler->input, channel.sampler->input->count - 1, &t, 1); + if (!r) + { + TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load input time", fileName); + continue; + } + + animDuration = (t > animDuration)? t : animDuration; + } + + animations[i].frameCount = (int)(animDuration*1000.0f/GLTF_ANIMDELAY); + animations[i].framePoses = RL_MALLOC(animations[i].frameCount*sizeof(Transform *)); + + for (unsigned int j = 0; j < animations[i].frameCount; j++) + { + animations[i].framePoses[j] = RL_MALLOC(animations[i].boneCount*sizeof(Transform)); + float time = ((float) j*GLTF_ANIMDELAY)/1000.0f; + for (unsigned int k = 0; k < animations[i].boneCount; k++) + { + Vector3 translation = {0, 0, 0}; + Quaternion rotation = {0, 0, 0, 1}; + Vector3 scale = {1, 1, 1}; + if (boneChannels[k].translate) + { + if (!GetGLTFPoseAtTime(boneChannels[k].translate->sampler->input, + boneChannels[k].translate->sampler->output, + time, + &translation)) + { + TRACELOG(LOG_INFO, "MODEL: [%s] Failed to load translate pose data for bone %s", fileName, animations[i].bones[k].name); + } + } + + if (boneChannels[k].rotate) + { + if (!GetGLTFPoseAtTime(boneChannels[k].rotate->sampler->input, + boneChannels[k].rotate->sampler->output, + time, + &rotation)) + { + TRACELOG(LOG_INFO, "MODEL: [%s] Failed to load rotate pose data for bone %s", fileName, animations[i].bones[k].name); + } + } + + if (boneChannels[k].scale) + { + if (!GetGLTFPoseAtTime(boneChannels[k].scale->sampler->input, + boneChannels[k].scale->sampler->output, + time, + &scale)) + { + TRACELOG(LOG_INFO, "MODEL: [%s] Failed to load scale pose data for bone %s", fileName, animations[i].bones[k].name); + } + } + + animations[i].framePoses[j][k] = (Transform){ + .translation = translation, + .rotation = rotation, + .scale = scale}; + } + + BuildPoseFromParentJoints(animations[i].bones, animations[i].boneCount, animations[i].framePoses[j]); + } + + TRACELOG(LOG_INFO, "MODEL: [%s] Loaded animation: %s (%d frames, %fs)", fileName, animData.name, animations[i].frameCount, animDuration); + RL_FREE(boneChannels); + } + } else TRACELOG(LOG_ERROR, "MODEL: [%s] expected exactly one skin to load animation data from, but found %i", fileName, data->skins_count); + + cgltf_free(data); + } + + return animations; +} #endif #if defined(SUPPORT_FILEFORMAT_VOX) From d3c1a04983ee8fdc5dc3bbad5f77c572dd20c36c Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 2 Jan 2023 20:46:33 +0100 Subject: [PATCH 030/192] REVIEWED: GLTF animations support #2844 --- examples/models/models_loading_gltf.c | 43 ++++---- examples/models/models_loading_gltf.png | Bin 21286 -> 25896 bytes src/rmodels.c | 135 ++++++++++++++---------- 3 files changed, 98 insertions(+), 80 deletions(-) diff --git a/examples/models/models_loading_gltf.c b/examples/models/models_loading_gltf.c index 8797159066d5..c19df3f5b641 100644 --- a/examples/models/models_loading_gltf.c +++ b/examples/models/models_loading_gltf.c @@ -27,46 +27,43 @@ int main(void) // Define the camera to look into our 3d world Camera camera = { 0 }; - camera.position = (Vector3){ 10.0f, 10.0f, 10.0f }; // Camera position - camera.target = (Vector3){ 0.0f, 0.0f, 0.0f }; // Camera looking at point + 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 mode type - // Loaf gltf model + // Load gltf model Model model = LoadModel("resources/models/gltf/robot.glb"); + + // Load gltf model animations unsigned int animsCount = 0; - ModelAnimation *modelAnimations = LoadModelAnimations("resources/models/gltf/robot.glb", &animsCount); - unsigned int animIndex = 0; + unsigned int animCurrentFrame = 0; + ModelAnimation *modelAnimations = LoadModelAnimations("resources/models/gltf/robot.glb", &animsCount); Vector3 position = { 0.0f, 0.0f, 0.0f }; // Set model position - SetCameraMode(camera, CAMERA_FREE); // Set free camera mode + SetCameraMode(camera, CAMERA_FREE); // Set free camera mode - SetTargetFPS(60); // Set our game to run at 60 frames-per-second + SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- - unsigned int currentFrame = 0; + // Main game loop - while (!WindowShouldClose()) // Detect window close button or ESC key + while (!WindowShouldClose()) // Detect window close button or ESC key { // Update //---------------------------------------------------------------------------------- ModelAnimation anim = modelAnimations[animIndex]; - if (IsKeyPressed(KEY_UP)) - { - animIndex = (animIndex + 1) % animsCount; - } - - if (IsKeyPressed(KEY_DOWN)) - { - animIndex = (animIndex + animsCount - 1) % animsCount; - } - - currentFrame = (currentFrame + 1) % anim.frameCount; - UpdateModelAnimation(model, anim, currentFrame); + + if (IsKeyPressed(KEY_UP)) animIndex = (animIndex + 1)%animsCount; + else if (IsKeyPressed(KEY_DOWN)) animIndex = (animIndex + animsCount - 1)%animsCount; + + animCurrentFrame = (animCurrentFrame + 1)%anim.frameCount; + UpdateModelAnimation(model, anim, animCurrentFrame); + UpdateCamera(&camera); //---------------------------------------------------------------------------------- @@ -74,7 +71,7 @@ int main(void) //---------------------------------------------------------------------------------- BeginDrawing(); - ClearBackground(SKYBLUE); + ClearBackground(RAYWHITE); BeginMode3D(camera); @@ -83,7 +80,7 @@ int main(void) EndMode3D(); - DrawText("Use the up/down arrow keys to switch animation.", 10, 10, 20, WHITE); + DrawText("Use the UP/DOWN arrow keys to switch animation", 10, 10, 20, GRAY); EndDrawing(); //---------------------------------------------------------------------------------- diff --git a/examples/models/models_loading_gltf.png b/examples/models/models_loading_gltf.png index 654444b848342eff35d72b5243671f1a1243cbf3..34748a22e587a86dc297238c939fbbe148fb5153 100644 GIT binary patch literal 25896 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 literal 21286 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 diff --git a/src/rmodels.c b/src/rmodels.c index ed32751c3902..786e5ac79bcf 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -142,18 +142,18 @@ static Model LoadOBJ(const char *fileName); // Load OBJ mesh data #endif #if defined(SUPPORT_FILEFORMAT_IQM) static Model LoadIQM(const char *fileName); // Load IQM mesh data -static ModelAnimation *LoadModelAnimationsIQM(const char *fileName, unsigned int *animCount); // Load IQM animation data +static ModelAnimation *LoadModelAnimationsIQM(const char *fileName, unsigned int *animCount); // Load IQM animation data #endif #if defined(SUPPORT_FILEFORMAT_GLTF) static Model LoadGLTF(const char *fileName); // Load GLTF mesh data -static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, unsigned int *animCount); // Load GLTF animation data +static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, unsigned int *animCount); // Load GLTF animation data #endif #if defined(SUPPORT_FILEFORMAT_VOX) static Model LoadVOX(const char *filename); // Load VOX mesh data #endif #if defined(SUPPORT_FILEFORMAT_M3D) static Model LoadM3D(const char *filename); // Load M3D mesh data -static ModelAnimation *LoadModelAnimationsM3D(const char *fileName, unsigned int *animCount); // Load M3D animation data +static ModelAnimation *LoadModelAnimationsM3D(const char *fileName, unsigned int *animCount); // Load M3D animation data #endif //---------------------------------------------------------------------------------- @@ -3829,6 +3829,12 @@ RayCollision GetRayCollisionQuad(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3, Ve return collision; } +//---------------------------------------------------------------------------------- +// Module specific Functions Definition +//---------------------------------------------------------------------------------- +#if defined(SUPPORT_FILEFORMAT_IQM) || defined(SUPPORT_FILEFORMAT_GLTF) +// Build pose from parent joints +// NOTE: Required for animations loading (required by IQM and GLTF) static void BuildPoseFromParentJoints(BoneInfo *bones, int boneCount, Transform *transforms) { for (int i = 0; i < boneCount; i++) @@ -3847,10 +3853,8 @@ static void BuildPoseFromParentJoints(BoneInfo *bones, int boneCount, Transform } } } +#endif -//---------------------------------------------------------------------------------- -// Module specific Functions Definition -//---------------------------------------------------------------------------------- #if defined(SUPPORT_FILEFORMAT_OBJ) // Load OBJ mesh data // @@ -4690,7 +4694,8 @@ static Image LoadImageFromCgltfImage(cgltf_image *cgltfImage, const char *texPat return image; } -static BoneInfo *LoadGLTFBoneInfo(cgltf_skin skin, int *boneCount) +// Load bone info from GLTF skin data +static BoneInfo *LoadBoneInfoGLTF(cgltf_skin skin, int *boneCount) { *boneCount = skin.joints_count; BoneInfo *bones = RL_MALLOC(skin.joints_count*sizeof(BoneInfo)); @@ -4700,8 +4705,9 @@ static BoneInfo *LoadGLTFBoneInfo(cgltf_skin skin, int *boneCount) cgltf_node node = *skin.joints[i]; strncpy(bones[i].name, node.name, sizeof(bones[i].name)); - // find parent bone index + // Find parent bone index unsigned int parentIndex = -1; + for (unsigned int j = 0; j < skin.joints_count; j++) { if (skin.joints[j] == node.parent) @@ -4731,7 +4737,7 @@ static Model LoadGLTF(const char *fileName) - Supports PBR metallic/roughness flow, loads material textures, values and colors PBR specular/glossiness flow and extended texture flows not supported - Supports multiple meshes per model (every primitives is loaded as a separate mesh) - - Supports basic animation + - Supports basic animations RESTRICTIONS: - Only triangle meshes supported @@ -5079,12 +5085,16 @@ static Model LoadGLTF(const char *fileName) // Load glTF meshes animation data // REF: https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#skins // REF: https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#skinned-mesh-attributes + // + // LIMITATIONS: + // - Only supports 1 armature per file, and skips loading it if there are multiple armatures + // - Only supports linear interpolation (default method in Blender when checked "Always Sample Animations" when exporting a GLTF file) + // - Only supports translation/rotation/scale animation channel.path, weights not considered (i.e. morph targets) //---------------------------------------------------------------------------------------------------- - if (data->skins_count == 1) { cgltf_skin skin = data->skins[0]; - model.bones = LoadGLTFBoneInfo(skin, &model.boneCount); + model.bones = LoadBoneInfoGLTF(skin, &model.boneCount); model.bindPose = RL_MALLOC(model.boneCount*sizeof(Transform)); for (unsigned int i = 0; i < model.boneCount; i++) @@ -5181,19 +5191,19 @@ static Model LoadGLTF(const char *fileName) } // Get interpolated pose for bone sampler at a specific time. Returns true on success. -static bool GetGLTFPoseAtTime(cgltf_accessor* input, cgltf_accessor *output, float time, void *data) +static bool GetPoseAtTimeGLTF(cgltf_accessor *input, cgltf_accessor *output, float time, void *data) { - // input and output should have the same count - + // Input and output should have the same count float tstart = 0.0f; float tend = 0.0f; - - int keyframe = 0; // defaults to first pose + int keyframe = 0; // Defaults to first pose + for (int i = 0; i < input->count - 1; i++) { cgltf_bool r1 = cgltf_accessor_read_float(input, i, &tstart, 1); if (!r1) return false; - cgltf_bool r2 = cgltf_accessor_read_float(input, i+1, &tend, 1); + + cgltf_bool r2 = cgltf_accessor_read_float(input, i + 1, &tend, 1); if (!r2) return false; if ((tstart <= time) && (time < tend)) @@ -5227,13 +5237,16 @@ static bool GetGLTFPoseAtTime(cgltf_accessor* input, cgltf_accessor *output, flo cgltf_accessor_read_float(output, keyframe+1, tmp, 4); Vector4 v2 = {tmp[0], tmp[1], tmp[2], tmp[3]}; Vector4 *r = data; - // only v4 is for rotations, so we know it's a quat. + + // Only v4 is for rotations, so we know it's a quat *r = QuaternionSlerp(v1, v2, t); } + return true; } -#define GLTF_ANIMDELAY 17 // that's roughly ~1000 msec / 60 FPS (16.666666* msec) +#define GLTF_ANIMDELAY 17 // Animation frames delay, (~1000 ms/60 FPS = 16.666666* ms) + static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, unsigned int *animCount) { // glTF file loading @@ -5241,10 +5254,12 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, unsigned in unsigned char *fileData = LoadFileData(fileName, &dataSize); ModelAnimation *animations = NULL; + // glTF data loading cgltf_options options = { 0 }; cgltf_data *data = NULL; cgltf_result result = cgltf_parse(&options, fileData, dataSize, &data); + if (result != cgltf_result_success) { TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load glTF data", fileName); @@ -5262,9 +5277,10 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, unsigned in cgltf_skin skin = data->skins[0]; *animCount = data->animations_count; animations = RL_MALLOC(data->animations_count*sizeof(ModelAnimation)); + for (unsigned int i = 0; i < data->animations_count; i++) { - animations[i].bones = LoadGLTFBoneInfo(skin, &animations[i].boneCount); + animations[i].bones = LoadBoneInfoGLTF(skin, &animations[i].boneCount); cgltf_animation animData = data->animations[i]; @@ -5276,10 +5292,12 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, unsigned in struct Channels *boneChannels = RL_CALLOC(animations[i].boneCount, sizeof(struct Channels)); float animDuration = 0.0f; + for (unsigned int j = 0; j < animData.channels_count; j++) { cgltf_animation_channel channel = animData.channels[j]; int boneIndex = -1; + for (unsigned int k = 0; k < skin.joints_count; k++) { if (animData.channels[j].target_node == skin.joints[k]) @@ -5291,7 +5309,7 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, unsigned in if (boneIndex == -1) { - // animation channel for a node not in the armature. + // Animation channel for a node not in the armature continue; } @@ -5313,10 +5331,12 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, unsigned in { TRACELOG(LOG_WARNING, "MODEL: [%s] Unsupported target_path on channel %d's sampler for animation %d. Skipping.", fileName, j, i); } - } else TRACELOG(LOG_WARNING, "MODEL: [%s] Only linear interpolation curves are supported for GLTF animation.", fileName); + } + else TRACELOG(LOG_WARNING, "MODEL: [%s] Only linear interpolation curves are supported for GLTF animation.", fileName); float t = 0.0f; cgltf_bool r = cgltf_accessor_read_float(channel.sampler->input, channel.sampler->input->count - 1, &t, 1); + if (!r) { TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load input time", fileName); @@ -5333,17 +5353,16 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, unsigned in { animations[i].framePoses[j] = RL_MALLOC(animations[i].boneCount*sizeof(Transform)); float time = ((float) j*GLTF_ANIMDELAY)/1000.0f; + for (unsigned int k = 0; k < animations[i].boneCount; k++) { Vector3 translation = {0, 0, 0}; Quaternion rotation = {0, 0, 0, 1}; Vector3 scale = {1, 1, 1}; + if (boneChannels[k].translate) { - if (!GetGLTFPoseAtTime(boneChannels[k].translate->sampler->input, - boneChannels[k].translate->sampler->output, - time, - &translation)) + if (!GetPoseAtTimeGLTF(boneChannels[k].translate->sampler->input, boneChannels[k].translate->sampler->output, time, &translation)) { TRACELOG(LOG_INFO, "MODEL: [%s] Failed to load translate pose data for bone %s", fileName, animations[i].bones[k].name); } @@ -5351,10 +5370,7 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, unsigned in if (boneChannels[k].rotate) { - if (!GetGLTFPoseAtTime(boneChannels[k].rotate->sampler->input, - boneChannels[k].rotate->sampler->output, - time, - &rotation)) + if (!GetPoseAtTimeGLTF(boneChannels[k].rotate->sampler->input, boneChannels[k].rotate->sampler->output, time, &rotation)) { TRACELOG(LOG_INFO, "MODEL: [%s] Failed to load rotate pose data for bone %s", fileName, animations[i].bones[k].name); } @@ -5362,10 +5378,7 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, unsigned in if (boneChannels[k].scale) { - if (!GetGLTFPoseAtTime(boneChannels[k].scale->sampler->input, - boneChannels[k].scale->sampler->output, - time, - &scale)) + if (!GetPoseAtTimeGLTF(boneChannels[k].scale->sampler->input, boneChannels[k].scale->sampler->output, time, &scale)) { TRACELOG(LOG_INFO, "MODEL: [%s] Failed to load scale pose data for bone %s", fileName, animations[i].bones[k].name); } @@ -5374,7 +5387,8 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, unsigned in animations[i].framePoses[j][k] = (Transform){ .translation = translation, .rotation = rotation, - .scale = scale}; + .scale = scale + }; } BuildPoseFromParentJoints(animations[i].bones, animations[i].boneCount, animations[i].framePoses[j]); @@ -5383,7 +5397,8 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, unsigned in TRACELOG(LOG_INFO, "MODEL: [%s] Loaded animation: %s (%d frames, %fs)", fileName, animData.name, animations[i].frameCount, animDuration); RL_FREE(boneChannels); } - } else TRACELOG(LOG_ERROR, "MODEL: [%s] expected exactly one skin to load animation data from, but found %i", fileName, data->skins_count); + } + else TRACELOG(LOG_ERROR, "MODEL: [%s] expected exactly one skin to load animation data from, but found %i", fileName, data->skins_count); cgltf_free(data); } @@ -5576,12 +5591,14 @@ static Model LoadM3D(const char *fileName) model.meshes[k].vertices = (float *)RL_CALLOC(model.meshes[k].vertexCount*3, sizeof(float)); model.meshes[k].texcoords = (float *)RL_CALLOC(model.meshes[k].vertexCount*2, sizeof(float)); model.meshes[k].normals = (float *)RL_CALLOC(model.meshes[k].vertexCount*3, sizeof(float)); + // without material, we rely on vertex colors if (mi == M3D_UNDEF && model.meshes[k].colors == NULL) { model.meshes[k].colors = RL_CALLOC(model.meshes[k].vertexCount*4, sizeof(unsigned char)); for (j = 0; j < model.meshes[k].vertexCount*4; j += 4) memcpy(&model.meshes[k].colors[j], &WHITE, 4); } + if (m3d->numbone && m3d->numskin) { model.meshes[k].boneIds = (unsigned char *)RL_CALLOC(model.meshes[k].vertexCount*4, sizeof(unsigned char)); @@ -5589,6 +5606,7 @@ static Model LoadM3D(const char *fileName) model.meshes[k].animVertices = (float *)RL_CALLOC(model.meshes[k].vertexCount*3, sizeof(float)); model.meshes[k].animNormals = (float *)RL_CALLOC(model.meshes[k].vertexCount*3, sizeof(float)); } + model.meshMaterial[k] = mi + 1; l = 0; } @@ -5617,25 +5635,25 @@ static Model LoadM3D(const char *fileName) if (m3d->face[i].texcoord[0] != M3D_UNDEF) { - model.meshes[k].texcoords[l * 6 + 0] = m3d->tmap[m3d->face[i].texcoord[0]].u; - model.meshes[k].texcoords[l * 6 + 1] = 1.0 - m3d->tmap[m3d->face[i].texcoord[0]].v; - model.meshes[k].texcoords[l * 6 + 2] = m3d->tmap[m3d->face[i].texcoord[1]].u; - model.meshes[k].texcoords[l * 6 + 3] = 1.0 - m3d->tmap[m3d->face[i].texcoord[1]].v; - model.meshes[k].texcoords[l * 6 + 4] = m3d->tmap[m3d->face[i].texcoord[2]].u; - model.meshes[k].texcoords[l * 6 + 5] = 1.0 - m3d->tmap[m3d->face[i].texcoord[2]].v; + model.meshes[k].texcoords[l*6 + 0] = m3d->tmap[m3d->face[i].texcoord[0]].u; + model.meshes[k].texcoords[l*6 + 1] = 1.0 - m3d->tmap[m3d->face[i].texcoord[0]].v; + model.meshes[k].texcoords[l*6 + 2] = m3d->tmap[m3d->face[i].texcoord[1]].u; + model.meshes[k].texcoords[l*6 + 3] = 1.0 - m3d->tmap[m3d->face[i].texcoord[1]].v; + model.meshes[k].texcoords[l*6 + 4] = m3d->tmap[m3d->face[i].texcoord[2]].u; + model.meshes[k].texcoords[l*6 + 5] = 1.0 - m3d->tmap[m3d->face[i].texcoord[2]].v; } if (m3d->face[i].normal[0] != M3D_UNDEF) { - model.meshes[k].normals[l * 9 + 0] = m3d->vertex[m3d->face[i].normal[0]].x; - model.meshes[k].normals[l * 9 + 1] = m3d->vertex[m3d->face[i].normal[0]].y; - model.meshes[k].normals[l * 9 + 2] = m3d->vertex[m3d->face[i].normal[0]].z; - model.meshes[k].normals[l * 9 + 3] = m3d->vertex[m3d->face[i].normal[1]].x; - model.meshes[k].normals[l * 9 + 4] = m3d->vertex[m3d->face[i].normal[1]].y; - model.meshes[k].normals[l * 9 + 5] = m3d->vertex[m3d->face[i].normal[1]].z; - model.meshes[k].normals[l * 9 + 6] = m3d->vertex[m3d->face[i].normal[2]].x; - model.meshes[k].normals[l * 9 + 7] = m3d->vertex[m3d->face[i].normal[2]].y; - model.meshes[k].normals[l * 9 + 8] = m3d->vertex[m3d->face[i].normal[2]].z; + model.meshes[k].normals[l*9 + 0] = m3d->vertex[m3d->face[i].normal[0]].x; + model.meshes[k].normals[l*9 + 1] = m3d->vertex[m3d->face[i].normal[0]].y; + model.meshes[k].normals[l*9 + 2] = m3d->vertex[m3d->face[i].normal[0]].z; + model.meshes[k].normals[l*9 + 3] = m3d->vertex[m3d->face[i].normal[1]].x; + model.meshes[k].normals[l*9 + 4] = m3d->vertex[m3d->face[i].normal[1]].y; + model.meshes[k].normals[l*9 + 5] = m3d->vertex[m3d->face[i].normal[1]].z; + model.meshes[k].normals[l*9 + 6] = m3d->vertex[m3d->face[i].normal[2]].x; + model.meshes[k].normals[l*9 + 7] = m3d->vertex[m3d->face[i].normal[2]].y; + model.meshes[k].normals[l*9 + 8] = m3d->vertex[m3d->face[i].normal[2]].z; } // Add skin (vertex / bone weight pairs) @@ -5658,8 +5676,8 @@ static Model LoadM3D(const char *fileName) { // raylib does not handle boneless meshes with skeletal animations, so // we put all vertices without a bone into a special "no bone" bone - model.meshes[k].boneIds[l * 12 + n * 4] = m3d->numbone; - model.meshes[k].boneWeights[l * 12 + n * 4] = 1.0f; + model.meshes[k].boneIds[l*12 + n*4] = m3d->numbone; + model.meshes[k].boneWeights[l*12 + n*4] = 1.0f; } } } @@ -5754,6 +5772,7 @@ static Model LoadM3D(const char *fileName) model.bindPose[i].rotation.y = m3d->vertex[m3d->bone[i].ori].y; model.bindPose[i].rotation.z = m3d->vertex[m3d->bone[i].ori].z; model.bindPose[i].rotation.w = m3d->vertex[m3d->bone[i].ori].w; + // TODO: if the orientation quaternion not normalized, then that's encoding scaling model.bindPose[i].rotation = QuaternionNormalize(model.bindPose[i].rotation); model.bindPose[i].scale.x = model.bindPose[i].scale.y = model.bindPose[i].scale.z = 1.0f; @@ -5799,15 +5818,16 @@ static Model LoadM3D(const char *fileName) return model; } +#define M3D_ANIMDELAY 17 // Animation frames delay, (~1000 ms/60 FPS = 16.666666* ms) + // Load M3D animation data -#define M3D_ANIMDELAY 17 // that's roughly ~1000 msec / 60 FPS (16.666666* msec) static ModelAnimation *LoadModelAnimationsM3D(const char *fileName, unsigned int *animCount) { m3d_t *m3d = NULL; unsigned int bytesRead = 0; unsigned char *fileData = LoadFileData(fileName, &bytesRead); ModelAnimation *animations = NULL; - int i, j; + int i = 0, j = 0; *animCount = 0; @@ -5824,7 +5844,7 @@ static ModelAnimation *LoadModelAnimationsM3D(const char *fileName, unsigned int else TRACELOG(LOG_INFO, "MODEL: [%s] M3D data loaded successfully: %i animations, %i bones, %i skins", fileName, m3d->numaction, m3d->numbone, m3d->numskin); - // no animation or bone+skin? + // No animation or bone+skin? if (!m3d->numaction || !m3d->numbone || !m3d->numskin) { m3d_free(m3d); @@ -5860,7 +5880,8 @@ static ModelAnimation *LoadModelAnimationsM3D(const char *fileName, unsigned int { animations[a].framePoses[i] = RL_MALLOC((m3d->numbone + 1)*sizeof(Transform)); - m3db_t *pose = m3d_pose(m3d, a, i * M3D_ANIMDELAY); + m3db_t *pose = m3d_pose(m3d, a, i*M3D_ANIMDELAY); + if (pose != NULL) { for (j = 0; j < m3d->numbone; j++) From b85490980339cab5cbdde4d674624deaabff783c Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 2 Jan 2023 20:48:02 +0100 Subject: [PATCH 031/192] Update models_loading_gltf.c --- examples/models/models_loading_gltf.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/examples/models/models_loading_gltf.c b/examples/models/models_loading_gltf.c index c19df3f5b641..fcd469493162 100644 --- a/examples/models/models_loading_gltf.c +++ b/examples/models/models_loading_gltf.c @@ -1,6 +1,13 @@ /******************************************************************************************* * -* raylib [models] example - loading gltf +* raylib [models] example - loading gltf with animations +* +* LIMITATIONS: +* - Only supports 1 armature per file, and skips loading it if there are multiple armatures +* - Only supports linear interpolation (default method in Blender when checked +* "Always Sample Animations" when exporting a GLTF file) +* - Only supports translation/rotation/scale animation channel.path, +* weights not considered (i.e. morph targets) * * Example originally created with raylib 3.7, last time updated with raylib 4.2 * From 39f9045703268f0b844916b07643d3801d2212cf Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 2 Jan 2023 20:59:25 +0100 Subject: [PATCH 032/192] Update models_loading_gltf.c --- examples/models/models_loading_gltf.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/models/models_loading_gltf.c b/examples/models/models_loading_gltf.c index fcd469493162..92b517a1c772 100644 --- a/examples/models/models_loading_gltf.c +++ b/examples/models/models_loading_gltf.c @@ -56,21 +56,21 @@ int main(void) 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 //---------------------------------------------------------------------------------- - ModelAnimation anim = modelAnimations[animIndex]; - + // Select current animation if (IsKeyPressed(KEY_UP)) animIndex = (animIndex + 1)%animsCount; else if (IsKeyPressed(KEY_DOWN)) animIndex = (animIndex + animsCount - 1)%animsCount; - + + // Update model animation + ModelAnimation anim = modelAnimations[animIndex]; animCurrentFrame = (animCurrentFrame + 1)%anim.frameCount; UpdateModelAnimation(model, anim, animCurrentFrame); + // Update camera UpdateCamera(&camera); //---------------------------------------------------------------------------------- @@ -82,8 +82,8 @@ int main(void) BeginMode3D(camera); - DrawModel(model, position, 1.0f, WHITE); - DrawGrid(10, 1.0f); // Draw a grid + DrawModel(model, position, 1.0f, WHITE); // Draw animated model + DrawGrid(10, 1.0f); EndMode3D(); From 73234d2a28166ca65cd10c01b0233a667e5290c1 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 3 Jan 2023 17:44:06 +0100 Subject: [PATCH 033/192] Avoid trying to setup uniform for invalid locations --- src/rcore.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/rcore.c b/src/rcore.c index 0e9aa76ec0b6..d17632942850 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -2525,25 +2525,34 @@ void SetShaderValue(Shader shader, int locIndex, const void *value, int uniformT // Set shader uniform value vector void SetShaderValueV(Shader shader, int locIndex, const void *value, int uniformType, int count) { - rlEnableShader(shader.id); - rlSetUniform(locIndex, value, uniformType, count); - //rlDisableShader(); // Avoid reseting current shader program, in case other uniforms are set + if (locIndex > -1) + { + rlEnableShader(shader.id); + rlSetUniform(locIndex, value, uniformType, count); + //rlDisableShader(); // Avoid reseting current shader program, in case other uniforms are set + } } // Set shader uniform value (matrix 4x4) void SetShaderValueMatrix(Shader shader, int locIndex, Matrix mat) { - rlEnableShader(shader.id); - rlSetUniformMatrix(locIndex, mat); - //rlDisableShader(); + if (locIndex > -1) + { + rlEnableShader(shader.id); + rlSetUniformMatrix(locIndex, mat); + //rlDisableShader(); + } } // Set shader uniform value for texture void SetShaderValueTexture(Shader shader, int locIndex, Texture2D texture) { - rlEnableShader(shader.id); - rlSetUniformSampler(locIndex, texture.id); - //rlDisableShader(); + if (locIndex > -1) + { + rlEnableShader(shader.id); + rlSetUniformSampler(locIndex, texture.id); + //rlDisableShader(); + } } // Get a ray trace from mouse position From 89755e52bf066e66dcfac2f2f52f6806ff02a693 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 4 Jan 2023 17:35:51 +0100 Subject: [PATCH 034/192] REVIEWED: `rLoadTextureDepth()` fixed issue --- src/rlgl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rlgl.h b/src/rlgl.h index 072925551ffa..a7226a818d31 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -2993,7 +2993,7 @@ unsigned int rlLoadTextureDepth(int width, int height, bool useRenderBuffer) #if defined(GRAPHICS_API_OPENGL_ES2) // WARNING: WebGL platform requires unsized internal format definition (GL_DEPTH_COMPONENT) // while other platforms using OpenGL ES 2.0 require/support sized internal formats depending on the GPU capabilities - if (!RLGL.ExtSupported.texDepthWebGL) + if (!RLGL.ExtSupported.texDepthWebGL || useRenderBuffer) { if (RLGL.ExtSupported.maxDepthBits == 32) glInternalFormat = GL_DEPTH_COMPONENT32_OES; else if (RLGL.ExtSupported.maxDepthBits == 24) glInternalFormat = GL_DEPTH_COMPONENT24_OES; From ce8000ee7e3c1e07bd747e71872200311038d090 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 4 Jan 2023 20:13:44 +0100 Subject: [PATCH 035/192] REVIEWED: `GetClipboardText()` on `PLATFORM_WEB` --- src/rcore.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/rcore.c b/src/rcore.c index d17632942850..da9436573f13 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -1945,7 +1945,21 @@ const char *GetClipboardText(void) return glfwGetClipboardString(CORE.Window.handle); #endif #if defined(PLATFORM_WEB) - return emscripten_run_script_string("navigator.clipboard.readText()"); + // Accessing clipboard data from browser is tricky due to security reasons + // The method to use is navigator.clipboard.readText() but this is an asynchronous method + // that will return at some moment after the function is called with the required data + emscripten_run_script_string("navigator.clipboard.readText() \ + .then(text => { document.getElementById('clipboard').innerText = text; console.log('Pasted content: ', text); }) \ + .catch(err => { console.error('Failed to read clipboard contents: ', err); });" + ); + + // The main issue is getting that data, one approach could be using ASYNCIFY and wait + // for the data but it requires adding Asyncify emscripten library on compilation + + // Another approach could be just copy the data in a HTML text field and try to retrieve it + // later on if available... and clean it for future accesses + + return NULL; #endif return NULL; } From bba6ae562238299f07b7f83f1278fc279eb21fd5 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 10 Jan 2023 12:16:42 +0100 Subject: [PATCH 036/192] RENAME: type to projection #2851 --- src/rcamera.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rcamera.h b/src/rcamera.h index 92c3c49a977f..1b77e19a96ff 100644 --- a/src/rcamera.h +++ b/src/rcamera.h @@ -73,7 +73,7 @@ Vector3 target; // Camera target it looks-at Vector3 up; // Camera up vector (rotation over its axis) float fovy; // Camera field-of-view apperture in Y (degrees) in perspective, used as near plane width in orthographic - int type; // Camera type, defines projection type: CAMERA_PERSPECTIVE or CAMERA_ORTHOGRAPHIC + int projection; // Camera type, defines projection type: CAMERA_PERSPECTIVE or CAMERA_ORTHOGRAPHIC } Camera3D; typedef Camera3D Camera; // Camera type fallback, defaults to Camera3D From 6dd1d2d9316c2d665c02d45bd0677150352ed9d3 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 10 Jan 2023 12:20:45 +0100 Subject: [PATCH 037/192] ADDED: Required define on Linux #2729 --- src/rcore.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/rcore.c b/src/rcore.c index da9436573f13..2d68606d8673 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -155,6 +155,9 @@ #undef _POSIX_C_SOURCE #define _POSIX_C_SOURCE 199309L // Required for: CLOCK_MONOTONIC if compiled with c99 without gnu ext. #endif +#if defined(__linux__) && !defined(_GNU_SOURCE) + #define _GNU_SOURCE +#endif // Platform specific defines to handle GetApplicationDirectory() #if defined (PLATFORM_DESKTOP) From f549f67be9e1cc1256d35c86637ac807ec2e6823 Mon Sep 17 00:00:00 2001 From: Go Watanabe <1570475+wtnbgo@users.noreply.github.com> Date: Tue, 10 Jan 2023 20:34:06 +0900 Subject: [PATCH 038/192] OpenGLES 2.0 support on PLATFORM_DESKTOP (#2840) * OpenGLES 2.0 support on PLATFORM_DESKTOP * exmples raylib_opengl_interop desktop GLES2 support * rename gles2.h -> glad_gles2.h --- cmake/LibraryConfigurations.cmake | 2 +- examples/others/external/include/glad_gles2.h | 4774 +++++++++++++++++ examples/others/raylib_opengl_interop.c | 30 +- src/external/glad_gles2.h | 4774 +++++++++++++++++ src/rlgl.h | 12 + 5 files changed, 9581 insertions(+), 11 deletions(-) create mode 100644 examples/others/external/include/glad_gles2.h create mode 100644 src/external/glad_gles2.h diff --git a/cmake/LibraryConfigurations.cmake b/cmake/LibraryConfigurations.cmake index a16bde69d6b0..ffb1a047d979 100644 --- a/cmake/LibraryConfigurations.cmake +++ b/cmake/LibraryConfigurations.cmake @@ -93,7 +93,7 @@ elseif ("${PLATFORM}" MATCHES "DRM") endif () -if (${OPENGL_VERSION}) +if (NOT ${OPENGL_VERSION}) set(${SUGGESTED_GRAPHICS} "${GRAPHICS}") if (${OPENGL_VERSION} MATCHES "4.3") set(GRAPHICS "GRAPHICS_API_OPENGL_43") diff --git a/examples/others/external/include/glad_gles2.h b/examples/others/external/include/glad_gles2.h new file mode 100644 index 000000000000..6c753d0a4d50 --- /dev/null +++ b/examples/others/external/include/glad_gles2.h @@ -0,0 +1,4774 @@ +/** + * Loader generated by glad 2.0.2 on Wed Dec 28 13:28:51 2022 + * + * SPDX-License-Identifier: (WTFPL OR CC0-1.0) AND Apache-2.0 + * + * Generator: C/C++ + * Specification: gl + * Extensions: 170 + * + * APIs: + * - gles2=2.0 + * + * Options: + * - ALIAS = False + * - DEBUG = False + * - HEADER_ONLY = True + * - LOADER = False + * - MX = False + * - ON_DEMAND = False + * + * Commandline: + * --api='gles2=2.0' --extensions='GL_EXT_EGL_image_array,GL_EXT_EGL_image_storage,GL_EXT_EGL_image_storage_compression,GL_EXT_YUV_target,GL_EXT_base_instance,GL_EXT_blend_func_extended,GL_EXT_blend_minmax,GL_EXT_buffer_storage,GL_EXT_clear_texture,GL_EXT_clip_control,GL_EXT_clip_cull_distance,GL_EXT_color_buffer_float,GL_EXT_color_buffer_half_float,GL_EXT_conservative_depth,GL_EXT_copy_image,GL_EXT_debug_label,GL_EXT_debug_marker,GL_EXT_depth_clamp,GL_EXT_discard_framebuffer,GL_EXT_disjoint_timer_query,GL_EXT_draw_buffers,GL_EXT_draw_buffers_indexed,GL_EXT_draw_elements_base_vertex,GL_EXT_draw_instanced,GL_EXT_draw_transform_feedback,GL_EXT_external_buffer,GL_EXT_float_blend,GL_EXT_fragment_shading_rate,GL_EXT_geometry_point_size,GL_EXT_geometry_shader,GL_EXT_gpu_shader5,GL_EXT_instanced_arrays,GL_EXT_map_buffer_range,GL_EXT_memory_object,GL_EXT_memory_object_fd,GL_EXT_memory_object_win32,GL_EXT_multi_draw_arrays,GL_EXT_multi_draw_indirect,GL_EXT_multisampled_compatibility,GL_EXT_multisampled_render_to_texture,GL_EXT_multisampled_render_to_texture2,GL_EXT_multiview_draw_buffers,GL_EXT_multiview_tessellation_geometry_shader,GL_EXT_multiview_texture_multisample,GL_EXT_multiview_timer_query,GL_EXT_occlusion_query_boolean,GL_EXT_polygon_offset_clamp,GL_EXT_post_depth_coverage,GL_EXT_primitive_bounding_box,GL_EXT_protected_textures,GL_EXT_pvrtc_sRGB,GL_EXT_raster_multisample,GL_EXT_read_format_bgra,GL_EXT_render_snorm,GL_EXT_robustness,GL_EXT_sRGB,GL_EXT_sRGB_write_control,GL_EXT_semaphore,GL_EXT_semaphore_fd,GL_EXT_semaphore_win32,GL_EXT_separate_depth_stencil,GL_EXT_separate_shader_objects,GL_EXT_shader_framebuffer_fetch,GL_EXT_shader_framebuffer_fetch_non_coherent,GL_EXT_shader_group_vote,GL_EXT_shader_implicit_conversions,GL_EXT_shader_integer_mix,GL_EXT_shader_io_blocks,GL_EXT_shader_non_constant_global_initializers,GL_EXT_shader_pixel_local_storage,GL_EXT_shader_pixel_local_storage2,GL_EXT_shader_samples_identical,GL_EXT_shader_texture_lod,GL_EXT_shadow_samplers,GL_EXT_sparse_texture,GL_EXT_sparse_texture2,GL_EXT_tessellation_point_size,GL_EXT_tessellation_shader,GL_EXT_texture_border_clamp,GL_EXT_texture_buffer,GL_EXT_texture_compression_astc_decode_mode,GL_EXT_texture_compression_bptc,GL_EXT_texture_compression_dxt1,GL_EXT_texture_compression_rgtc,GL_EXT_texture_compression_s3tc,GL_EXT_texture_compression_s3tc_srgb,GL_EXT_texture_cube_map_array,GL_EXT_texture_filter_anisotropic,GL_EXT_texture_filter_minmax,GL_EXT_texture_format_BGRA8888,GL_EXT_texture_format_sRGB_override,GL_EXT_texture_mirror_clamp_to_edge,GL_EXT_texture_norm16,GL_EXT_texture_query_lod,GL_EXT_texture_rg,GL_EXT_texture_sRGB_R8,GL_EXT_texture_sRGB_RG8,GL_EXT_texture_sRGB_decode,GL_EXT_texture_shadow_lod,GL_EXT_texture_storage,GL_EXT_texture_storage_compression,GL_EXT_texture_type_2_10_10_10_REV,GL_EXT_texture_view,GL_EXT_unpack_subimage,GL_EXT_win32_keyed_mutex,GL_EXT_window_rectangles,GL_KHR_blend_equation_advanced,GL_KHR_blend_equation_advanced_coherent,GL_KHR_context_flush_control,GL_KHR_debug,GL_KHR_no_error,GL_KHR_parallel_shader_compile,GL_KHR_robust_buffer_access_behavior,GL_KHR_robustness,GL_KHR_shader_subgroup,GL_KHR_texture_compression_astc_hdr,GL_KHR_texture_compression_astc_ldr,GL_KHR_texture_compression_astc_sliced_3d,GL_OES_EGL_image,GL_OES_EGL_image_external,GL_OES_EGL_image_external_essl3,GL_OES_compressed_ETC1_RGB8_sub_texture,GL_OES_compressed_ETC1_RGB8_texture,GL_OES_compressed_paletted_texture,GL_OES_copy_image,GL_OES_depth24,GL_OES_depth32,GL_OES_depth_texture,GL_OES_draw_buffers_indexed,GL_OES_draw_elements_base_vertex,GL_OES_element_index_uint,GL_OES_fbo_render_mipmap,GL_OES_fragment_precision_high,GL_OES_geometry_point_size,GL_OES_geometry_shader,GL_OES_get_program_binary,GL_OES_gpu_shader5,GL_OES_mapbuffer,GL_OES_packed_depth_stencil,GL_OES_primitive_bounding_box,GL_OES_required_internalformat,GL_OES_rgb8_rgba8,GL_OES_sample_shading,GL_OES_sample_variables,GL_OES_shader_image_atomic,GL_OES_shader_io_blocks,GL_OES_shader_multisample_interpolation,GL_OES_standard_derivatives,GL_OES_stencil1,GL_OES_stencil4,GL_OES_surfaceless_context,GL_OES_tessellation_point_size,GL_OES_tessellation_shader,GL_OES_texture_3D,GL_OES_texture_border_clamp,GL_OES_texture_buffer,GL_OES_texture_compression_astc,GL_OES_texture_cube_map_array,GL_OES_texture_float,GL_OES_texture_float_linear,GL_OES_texture_half_float,GL_OES_texture_half_float_linear,GL_OES_texture_npot,GL_OES_texture_stencil8,GL_OES_texture_storage_multisample_2d_array,GL_OES_texture_view,GL_OES_vertex_array_object,GL_OES_vertex_half_float,GL_OES_vertex_type_10_10_10_2,GL_OES_viewport_array' c --header-only + * + * Online: + * http://glad.sh/#api=gles2%3D2.0&generator=c&options=HEADER_ONLY + * + */ + +#ifndef GLAD_GLES2_H_ +#define GLAD_GLES2_H_ + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wreserved-id-macro" +#endif +#ifdef __gl2_h_ + #error OpenGL ES 2 header already included (API: gles2), remove previous include! +#endif +#define __gl2_h_ 1 +#ifdef __gles2_gl2_h_ + #error OpenGL ES 2 header already included (API: gles2), remove previous include! +#endif +#define __gles2_gl2_h_ 1 +#ifdef __gl3_h_ + #error OpenGL ES 3 header already included (API: gles2), remove previous include! +#endif +#define __gl3_h_ 1 +#ifdef __gles2_gl3_h_ + #error OpenGL ES 3 header already included (API: gles2), remove previous include! +#endif +#define __gles2_gl3_h_ 1 +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#define GLAD_GLES2 +#define GLAD_OPTION_GLES2_HEADER_ONLY + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef GLAD_PLATFORM_H_ +#define GLAD_PLATFORM_H_ + +#ifndef GLAD_PLATFORM_WIN32 + #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(__MINGW32__) + #define GLAD_PLATFORM_WIN32 1 + #else + #define GLAD_PLATFORM_WIN32 0 + #endif +#endif + +#ifndef GLAD_PLATFORM_APPLE + #ifdef __APPLE__ + #define GLAD_PLATFORM_APPLE 1 + #else + #define GLAD_PLATFORM_APPLE 0 + #endif +#endif + +#ifndef GLAD_PLATFORM_EMSCRIPTEN + #ifdef __EMSCRIPTEN__ + #define GLAD_PLATFORM_EMSCRIPTEN 1 + #else + #define GLAD_PLATFORM_EMSCRIPTEN 0 + #endif +#endif + +#ifndef GLAD_PLATFORM_UWP + #if defined(_MSC_VER) && !defined(GLAD_INTERNAL_HAVE_WINAPIFAMILY) + #ifdef __has_include + #if __has_include() + #define GLAD_INTERNAL_HAVE_WINAPIFAMILY 1 + #endif + #elif _MSC_VER >= 1700 && !_USING_V110_SDK71_ + #define GLAD_INTERNAL_HAVE_WINAPIFAMILY 1 + #endif + #endif + + #ifdef GLAD_INTERNAL_HAVE_WINAPIFAMILY + #include + #if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) + #define GLAD_PLATFORM_UWP 1 + #endif + #endif + + #ifndef GLAD_PLATFORM_UWP + #define GLAD_PLATFORM_UWP 0 + #endif +#endif + +#ifdef __GNUC__ + #define GLAD_GNUC_EXTENSION __extension__ +#else + #define GLAD_GNUC_EXTENSION +#endif + +#define GLAD_UNUSED(x) (void)(x) + +#ifndef GLAD_API_CALL + #if defined(GLAD_API_CALL_EXPORT) + #if GLAD_PLATFORM_WIN32 || defined(__CYGWIN__) + #if defined(GLAD_API_CALL_EXPORT_BUILD) + #if defined(__GNUC__) + #define GLAD_API_CALL __attribute__ ((dllexport)) extern + #else + #define GLAD_API_CALL __declspec(dllexport) extern + #endif + #else + #if defined(__GNUC__) + #define GLAD_API_CALL __attribute__ ((dllimport)) extern + #else + #define GLAD_API_CALL __declspec(dllimport) extern + #endif + #endif + #elif defined(__GNUC__) && defined(GLAD_API_CALL_EXPORT_BUILD) + #define GLAD_API_CALL __attribute__ ((visibility ("default"))) extern + #else + #define GLAD_API_CALL extern + #endif + #else + #define GLAD_API_CALL extern + #endif +#endif + +#ifdef APIENTRY + #define GLAD_API_PTR APIENTRY +#elif GLAD_PLATFORM_WIN32 + #define GLAD_API_PTR __stdcall +#else + #define GLAD_API_PTR +#endif + +#ifndef GLAPI +#define GLAPI GLAD_API_CALL +#endif + +#ifndef GLAPIENTRY +#define GLAPIENTRY GLAD_API_PTR +#endif + +#define GLAD_MAKE_VERSION(major, minor) (major * 10000 + minor) +#define GLAD_VERSION_MAJOR(version) (version / 10000) +#define GLAD_VERSION_MINOR(version) (version % 10000) + +#define GLAD_GENERATOR_VERSION "2.0.2" + +typedef void (*GLADapiproc)(void); + +typedef GLADapiproc (*GLADloadfunc)(const char *name); +typedef GLADapiproc (*GLADuserptrloadfunc)(void *userptr, const char *name); + +typedef void (*GLADprecallback)(const char *name, GLADapiproc apiproc, int len_args, ...); +typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apiproc, int len_args, ...); + +#endif /* GLAD_PLATFORM_H_ */ + +#define GL_ACTIVE_ATTRIBUTES 0x8B89 +#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A +#define GL_ACTIVE_PROGRAM_EXT 0x8259 +#define GL_ACTIVE_TEXTURE 0x84E0 +#define GL_ACTIVE_UNIFORMS 0x8B86 +#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 +#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E +#define GL_ALIASED_POINT_SIZE_RANGE 0x846D +#define GL_ALL_SHADER_BITS_EXT 0xFFFFFFFF +#define GL_ALPHA 0x1906 +#define GL_ALPHA16F_EXT 0x881C +#define GL_ALPHA32F_EXT 0x8816 +#define GL_ALPHA8_EXT 0x803C +#define GL_ALPHA8_OES 0x803C +#define GL_ALPHA_BITS 0x0D55 +#define GL_ALWAYS 0x0207 +#define GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT 0x8D6A +#define GL_ANY_SAMPLES_PASSED_EXT 0x8C2F +#define GL_ARRAY_BUFFER 0x8892 +#define GL_ARRAY_BUFFER_BINDING 0x8894 +#define GL_ATTACHED_SHADERS 0x8B85 +#define GL_BACK 0x0405 +#define GL_BGRA8_EXT 0x93A1 +#define GL_BGRA_EXT 0x80E1 +#define GL_BLEND 0x0BE2 +#define GL_BLEND_ADVANCED_COHERENT_KHR 0x9285 +#define GL_BLEND_COLOR 0x8005 +#define GL_BLEND_DST_ALPHA 0x80CA +#define GL_BLEND_DST_RGB 0x80C8 +#define GL_BLEND_EQUATION 0x8009 +#define GL_BLEND_EQUATION_ALPHA 0x883D +#define GL_BLEND_EQUATION_RGB 0x8009 +#define GL_BLEND_SRC_ALPHA 0x80CB +#define GL_BLEND_SRC_RGB 0x80C9 +#define GL_BLUE_BITS 0x0D54 +#define GL_BOOL 0x8B56 +#define GL_BOOL_VEC2 0x8B57 +#define GL_BOOL_VEC3 0x8B58 +#define GL_BOOL_VEC4 0x8B59 +#define GL_BUFFER_ACCESS_OES 0x88BB +#define GL_BUFFER_IMMUTABLE_STORAGE_EXT 0x821F +#define GL_BUFFER_KHR 0x82E0 +#define GL_BUFFER_MAPPED_OES 0x88BC +#define GL_BUFFER_MAP_POINTER_OES 0x88BD +#define GL_BUFFER_OBJECT_EXT 0x9151 +#define GL_BUFFER_SIZE 0x8764 +#define GL_BUFFER_STORAGE_FLAGS_EXT 0x8220 +#define GL_BUFFER_USAGE 0x8765 +#define GL_BYTE 0x1400 +#define GL_CCW 0x0901 +#define GL_CLAMP_TO_BORDER_EXT 0x812D +#define GL_CLAMP_TO_BORDER_OES 0x812D +#define GL_CLAMP_TO_EDGE 0x812F +#define GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT_EXT 0x00004000 +#define GL_CLIENT_STORAGE_BIT_EXT 0x0200 +#define GL_CLIP_DEPTH_MODE 0x935D +#define GL_CLIP_DEPTH_MODE_EXT 0x935D +#define GL_CLIP_DISTANCE0_EXT 0x3000 +#define GL_CLIP_DISTANCE1_EXT 0x3001 +#define GL_CLIP_DISTANCE2_EXT 0x3002 +#define GL_CLIP_DISTANCE3_EXT 0x3003 +#define GL_CLIP_DISTANCE4_EXT 0x3004 +#define GL_CLIP_DISTANCE5_EXT 0x3005 +#define GL_CLIP_DISTANCE6 0x3006 +#define GL_CLIP_DISTANCE6_EXT 0x3006 +#define GL_CLIP_DISTANCE7 0x3007 +#define GL_CLIP_DISTANCE7_EXT 0x3007 +#define GL_CLIP_ORIGIN 0x935C +#define GL_CLIP_ORIGIN_EXT 0x935C +#define GL_CLIP_PLANE0 0x3000 +#define GL_CLIP_PLANE1 0x3001 +#define GL_CLIP_PLANE2 0x3002 +#define GL_CLIP_PLANE3 0x3003 +#define GL_CLIP_PLANE4 0x3004 +#define GL_CLIP_PLANE5 0x3005 +#define GL_COLORBURN_KHR 0x929A +#define GL_COLORDODGE_KHR 0x9299 +#define GL_COLOR_ATTACHMENT0 0x8CE0 +#define GL_COLOR_ATTACHMENT0_EXT 0x8CE0 +#define GL_COLOR_ATTACHMENT10_EXT 0x8CEA +#define GL_COLOR_ATTACHMENT11_EXT 0x8CEB +#define GL_COLOR_ATTACHMENT12_EXT 0x8CEC +#define GL_COLOR_ATTACHMENT13_EXT 0x8CED +#define GL_COLOR_ATTACHMENT14_EXT 0x8CEE +#define GL_COLOR_ATTACHMENT15_EXT 0x8CEF +#define GL_COLOR_ATTACHMENT1_EXT 0x8CE1 +#define GL_COLOR_ATTACHMENT2_EXT 0x8CE2 +#define GL_COLOR_ATTACHMENT3_EXT 0x8CE3 +#define GL_COLOR_ATTACHMENT4_EXT 0x8CE4 +#define GL_COLOR_ATTACHMENT5_EXT 0x8CE5 +#define GL_COLOR_ATTACHMENT6_EXT 0x8CE6 +#define GL_COLOR_ATTACHMENT7_EXT 0x8CE7 +#define GL_COLOR_ATTACHMENT8_EXT 0x8CE8 +#define GL_COLOR_ATTACHMENT9_EXT 0x8CE9 +#define GL_COLOR_ATTACHMENT_EXT 0x90F0 +#define GL_COLOR_BUFFER_BIT 0x00004000 +#define GL_COLOR_CLEAR_VALUE 0x0C22 +#define GL_COLOR_EXT 0x1800 +#define GL_COLOR_WRITEMASK 0x0C23 +#define GL_COMPARE_REF_TO_TEXTURE_EXT 0x884E +#define GL_COMPILE_STATUS 0x8B81 +#define GL_COMPLETION_STATUS_KHR 0x91B1 +#define GL_COMPRESSED_RED_GREEN_RGTC2_EXT 0x8DBD +#define GL_COMPRESSED_RED_RGTC1_EXT 0x8DBB +#define GL_COMPRESSED_RGBA_ASTC_10x10_KHR 0x93BB +#define GL_COMPRESSED_RGBA_ASTC_10x5_KHR 0x93B8 +#define GL_COMPRESSED_RGBA_ASTC_10x6_KHR 0x93B9 +#define GL_COMPRESSED_RGBA_ASTC_10x8_KHR 0x93BA +#define GL_COMPRESSED_RGBA_ASTC_12x10_KHR 0x93BC +#define GL_COMPRESSED_RGBA_ASTC_12x12_KHR 0x93BD +#define GL_COMPRESSED_RGBA_ASTC_3x3x3_OES 0x93C0 +#define GL_COMPRESSED_RGBA_ASTC_4x3x3_OES 0x93C1 +#define GL_COMPRESSED_RGBA_ASTC_4x4_KHR 0x93B0 +#define GL_COMPRESSED_RGBA_ASTC_4x4x3_OES 0x93C2 +#define GL_COMPRESSED_RGBA_ASTC_4x4x4_OES 0x93C3 +#define GL_COMPRESSED_RGBA_ASTC_5x4_KHR 0x93B1 +#define GL_COMPRESSED_RGBA_ASTC_5x4x4_OES 0x93C4 +#define GL_COMPRESSED_RGBA_ASTC_5x5_KHR 0x93B2 +#define GL_COMPRESSED_RGBA_ASTC_5x5x4_OES 0x93C5 +#define GL_COMPRESSED_RGBA_ASTC_5x5x5_OES 0x93C6 +#define GL_COMPRESSED_RGBA_ASTC_6x5_KHR 0x93B3 +#define GL_COMPRESSED_RGBA_ASTC_6x5x5_OES 0x93C7 +#define GL_COMPRESSED_RGBA_ASTC_6x6_KHR 0x93B4 +#define GL_COMPRESSED_RGBA_ASTC_6x6x5_OES 0x93C8 +#define GL_COMPRESSED_RGBA_ASTC_6x6x6_OES 0x93C9 +#define GL_COMPRESSED_RGBA_ASTC_8x5_KHR 0x93B5 +#define GL_COMPRESSED_RGBA_ASTC_8x6_KHR 0x93B6 +#define GL_COMPRESSED_RGBA_ASTC_8x8_KHR 0x93B7 +#define GL_COMPRESSED_RGBA_BPTC_UNORM_EXT 0x8E8C +#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 +#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2 +#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3 +#define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT 0x8E8E +#define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT 0x8E8F +#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0 +#define GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT 0x8DBE +#define GL_COMPRESSED_SIGNED_RED_RGTC1_EXT 0x8DBC +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR 0x93DB +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR 0x93D8 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR 0x93D9 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR 0x93DA +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR 0x93DC +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR 0x93DD +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_3x3x3_OES 0x93E0 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x3x3_OES 0x93E1 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR 0x93D0 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4x3_OES 0x93E2 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4x4_OES 0x93E3 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR 0x93D1 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4x4_OES 0x93E4 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR 0x93D2 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5x4_OES 0x93E5 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5x5_OES 0x93E6 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR 0x93D3 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5x5_OES 0x93E7 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR 0x93D4 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6x5_OES 0x93E8 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6x6_OES 0x93E9 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR 0x93D5 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR 0x93D6 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR 0x93D7 +#define GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT 0x8E8D +#define GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1_EXT 0x8A56 +#define GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV2_IMG 0x93F0 +#define GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1_EXT 0x8A57 +#define GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV2_IMG 0x93F1 +#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT 0x8C4D +#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT 0x8C4E +#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT 0x8C4F +#define GL_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT 0x8A54 +#define GL_COMPRESSED_SRGB_PVRTC_4BPPV1_EXT 0x8A55 +#define GL_COMPRESSED_SRGB_S3TC_DXT1_EXT 0x8C4C +#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 +#define GL_CONSTANT_ALPHA 0x8003 +#define GL_CONSTANT_COLOR 0x8001 +#define GL_CONTEXT_FLAG_DEBUG_BIT_KHR 0x00000002 +#define GL_CONTEXT_FLAG_NO_ERROR_BIT 0x00000008 +#define GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR 0x00000008 +#define GL_CONTEXT_FLAG_PROTECTED_CONTENT_BIT_EXT 0x00000010 +#define GL_CONTEXT_LOST_KHR 0x0507 +#define GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR 0x82FC +#define GL_CONTEXT_RELEASE_BEHAVIOR_KHR 0x82FB +#define GL_CONTEXT_ROBUST_ACCESS_EXT 0x90F3 +#define GL_CONTEXT_ROBUST_ACCESS_KHR 0x90F3 +#define GL_CULL_FACE 0x0B44 +#define GL_CULL_FACE_MODE 0x0B45 +#define GL_CURRENT_PROGRAM 0x8B8D +#define GL_CURRENT_QUERY_EXT 0x8865 +#define GL_CURRENT_VERTEX_ATTRIB 0x8626 +#define GL_CW 0x0900 +#define GL_D3D12_FENCE_VALUE_EXT 0x9595 +#define GL_DARKEN_KHR 0x9297 +#define GL_DEBUG_CALLBACK_FUNCTION_KHR 0x8244 +#define GL_DEBUG_CALLBACK_USER_PARAM_KHR 0x8245 +#define GL_DEBUG_GROUP_STACK_DEPTH_KHR 0x826D +#define GL_DEBUG_LOGGED_MESSAGES_KHR 0x9145 +#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_KHR 0x8243 +#define GL_DEBUG_OUTPUT_KHR 0x92E0 +#define GL_DEBUG_OUTPUT_SYNCHRONOUS_KHR 0x8242 +#define GL_DEBUG_SEVERITY_HIGH_KHR 0x9146 +#define GL_DEBUG_SEVERITY_LOW_KHR 0x9148 +#define GL_DEBUG_SEVERITY_MEDIUM_KHR 0x9147 +#define GL_DEBUG_SEVERITY_NOTIFICATION_KHR 0x826B +#define GL_DEBUG_SOURCE_API_KHR 0x8246 +#define GL_DEBUG_SOURCE_APPLICATION_KHR 0x824A +#define GL_DEBUG_SOURCE_OTHER_KHR 0x824B +#define GL_DEBUG_SOURCE_SHADER_COMPILER_KHR 0x8248 +#define GL_DEBUG_SOURCE_THIRD_PARTY_KHR 0x8249 +#define GL_DEBUG_SOURCE_WINDOW_SYSTEM_KHR 0x8247 +#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_KHR 0x824D +#define GL_DEBUG_TYPE_ERROR_KHR 0x824C +#define GL_DEBUG_TYPE_MARKER_KHR 0x8268 +#define GL_DEBUG_TYPE_OTHER_KHR 0x8251 +#define GL_DEBUG_TYPE_PERFORMANCE_KHR 0x8250 +#define GL_DEBUG_TYPE_POP_GROUP_KHR 0x826A +#define GL_DEBUG_TYPE_PORTABILITY_KHR 0x824F +#define GL_DEBUG_TYPE_PUSH_GROUP_KHR 0x8269 +#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_KHR 0x824E +#define GL_DECODE_EXT 0x8A49 +#define GL_DECR 0x1E03 +#define GL_DECR_WRAP 0x8508 +#define GL_DEDICATED_MEMORY_OBJECT_EXT 0x9581 +#define GL_DELETE_STATUS 0x8B80 +#define GL_DEPTH24_STENCIL8_OES 0x88F0 +#define GL_DEPTH_ATTACHMENT 0x8D00 +#define GL_DEPTH_BITS 0x0D56 +#define GL_DEPTH_BUFFER_BIT 0x00000100 +#define GL_DEPTH_CLAMP_EXT 0x864F +#define GL_DEPTH_CLEAR_VALUE 0x0B73 +#define GL_DEPTH_COMPONENT 0x1902 +#define GL_DEPTH_COMPONENT16 0x81A5 +#define GL_DEPTH_COMPONENT16_OES 0x81A5 +#define GL_DEPTH_COMPONENT24_OES 0x81A6 +#define GL_DEPTH_COMPONENT32_OES 0x81A7 +#define GL_DEPTH_EXT 0x1801 +#define GL_DEPTH_FUNC 0x0B74 +#define GL_DEPTH_RANGE 0x0B70 +#define GL_DEPTH_STENCIL_OES 0x84F9 +#define GL_DEPTH_TEST 0x0B71 +#define GL_DEPTH_WRITEMASK 0x0B72 +#define GL_DEVICE_LUID_EXT 0x9599 +#define GL_DEVICE_NODE_MASK_EXT 0x959A +#define GL_DEVICE_UUID_EXT 0x9597 +#define GL_DIFFERENCE_KHR 0x929E +#define GL_DITHER 0x0BD0 +#define GL_DONT_CARE 0x1100 +#define GL_DRAW_BUFFER0_EXT 0x8825 +#define GL_DRAW_BUFFER10_EXT 0x882F +#define GL_DRAW_BUFFER11_EXT 0x8830 +#define GL_DRAW_BUFFER12_EXT 0x8831 +#define GL_DRAW_BUFFER13_EXT 0x8832 +#define GL_DRAW_BUFFER14_EXT 0x8833 +#define GL_DRAW_BUFFER15_EXT 0x8834 +#define GL_DRAW_BUFFER1_EXT 0x8826 +#define GL_DRAW_BUFFER2_EXT 0x8827 +#define GL_DRAW_BUFFER3_EXT 0x8828 +#define GL_DRAW_BUFFER4_EXT 0x8829 +#define GL_DRAW_BUFFER5_EXT 0x882A +#define GL_DRAW_BUFFER6_EXT 0x882B +#define GL_DRAW_BUFFER7_EXT 0x882C +#define GL_DRAW_BUFFER8_EXT 0x882D +#define GL_DRAW_BUFFER9_EXT 0x882E +#define GL_DRAW_BUFFER_EXT 0x0C01 +#define GL_DRIVER_UUID_EXT 0x9598 +#define GL_DST_ALPHA 0x0304 +#define GL_DST_COLOR 0x0306 +#define GL_DYNAMIC_DRAW 0x88E8 +#define GL_DYNAMIC_STORAGE_BIT_EXT 0x0100 +#define GL_EFFECTIVE_RASTER_SAMPLES_EXT 0x932C +#define GL_ELEMENT_ARRAY_BUFFER 0x8893 +#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 +#define GL_EQUAL 0x0202 +#define GL_ETC1_RGB8_OES 0x8D64 +#define GL_EXCLUSION_KHR 0x92A0 +#define GL_EXCLUSIVE_EXT 0x8F11 +#define GL_EXTENSIONS 0x1F03 +#define GL_FALSE 0 +#define GL_FASTEST 0x1101 +#define GL_FIRST_VERTEX_CONVENTION_EXT 0x8E4D +#define GL_FIRST_VERTEX_CONVENTION_OES 0x8E4D +#define GL_FIXED 0x140C +#define GL_FLOAT 0x1406 +#define GL_FLOAT_MAT2 0x8B5A +#define GL_FLOAT_MAT3 0x8B5B +#define GL_FLOAT_MAT4 0x8B5C +#define GL_FLOAT_VEC2 0x8B50 +#define GL_FLOAT_VEC3 0x8B51 +#define GL_FLOAT_VEC4 0x8B52 +#define GL_FRACTIONAL_EVEN_EXT 0x8E7C +#define GL_FRACTIONAL_EVEN_OES 0x8E7C +#define GL_FRACTIONAL_ODD_EXT 0x8E7B +#define GL_FRACTIONAL_ODD_OES 0x8E7B +#define GL_FRAGMENT_INTERPOLATION_OFFSET_BITS_OES 0x8E5D +#define GL_FRAGMENT_SHADER 0x8B30 +#define GL_FRAGMENT_SHADER_BIT_EXT 0x00000002 +#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES 0x8B8B +#define GL_FRAGMENT_SHADER_DISCARDS_SAMPLES_EXT 0x8A52 +#define GL_FRAGMENT_SHADING_RATE_ATTACHMENT_WITH_DEFAULT_FRAMEBUFFER_SUPPORTED_EXT 0x96DF +#define GL_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_EXT 0x96D2 +#define GL_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_EXT 0x96D5 +#define GL_FRAGMENT_SHADING_RATE_COMBINER_OP_MIN_EXT 0x96D4 +#define GL_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL_EXT 0x96D6 +#define GL_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_EXT 0x96D3 +#define GL_FRAGMENT_SHADING_RATE_NON_TRIVIAL_COMBINERS_SUPPORTED_EXT 0x8F6F +#define GL_FRAGMENT_SHADING_RATE_WITH_SAMPLE_MASK_SUPPORTED_EXT 0x96DE +#define GL_FRAGMENT_SHADING_RATE_WITH_SHADER_DEPTH_STENCIL_WRITES_SUPPORTED_EXT 0x96DD +#define GL_FRAMEBUFFER 0x8D40 +#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT 0x8210 +#define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT 0x8211 +#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED_EXT 0x8DA7 +#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED_OES 0x8DA7 +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1 +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_OES 0x8CD4 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SAMPLES_EXT 0x8D6C +#define GL_FRAMEBUFFER_BINDING 0x8CA6 +#define GL_FRAMEBUFFER_COMPLETE 0x8CD5 +#define GL_FRAMEBUFFER_DEFAULT_LAYERS_EXT 0x9312 +#define GL_FRAMEBUFFER_DEFAULT_LAYERS_OES 0x9312 +#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 +#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS 0x8CD9 +#define GL_FRAMEBUFFER_INCOMPLETE_INSUFFICIENT_SHADER_COMBINED_LOCAL_STORAGE_EXT 0x9652 +#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT 0x8DA8 +#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_OES 0x8DA8 +#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 +#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT 0x8D56 +#define GL_FRAMEBUFFER_SRGB_EXT 0x8DB9 +#define GL_FRAMEBUFFER_UNDEFINED_OES 0x8219 +#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD +#define GL_FRONT 0x0404 +#define GL_FRONT_AND_BACK 0x0408 +#define GL_FRONT_FACE 0x0B46 +#define GL_FUNC_ADD 0x8006 +#define GL_FUNC_REVERSE_SUBTRACT 0x800B +#define GL_FUNC_SUBTRACT 0x800A +#define GL_GENERATE_MIPMAP_HINT 0x8192 +#define GL_GEOMETRY_LINKED_INPUT_TYPE_EXT 0x8917 +#define GL_GEOMETRY_LINKED_INPUT_TYPE_OES 0x8917 +#define GL_GEOMETRY_LINKED_OUTPUT_TYPE_EXT 0x8918 +#define GL_GEOMETRY_LINKED_OUTPUT_TYPE_OES 0x8918 +#define GL_GEOMETRY_LINKED_VERTICES_OUT_EXT 0x8916 +#define GL_GEOMETRY_LINKED_VERTICES_OUT_OES 0x8916 +#define GL_GEOMETRY_SHADER_BIT_EXT 0x00000004 +#define GL_GEOMETRY_SHADER_BIT_OES 0x00000004 +#define GL_GEOMETRY_SHADER_EXT 0x8DD9 +#define GL_GEOMETRY_SHADER_INVOCATIONS_EXT 0x887F +#define GL_GEOMETRY_SHADER_INVOCATIONS_OES 0x887F +#define GL_GEOMETRY_SHADER_OES 0x8DD9 +#define GL_GEQUAL 0x0206 +#define GL_GPU_DISJOINT_EXT 0x8FBB +#define GL_GREATER 0x0204 +#define GL_GREEN_BITS 0x0D53 +#define GL_GUILTY_CONTEXT_RESET_EXT 0x8253 +#define GL_GUILTY_CONTEXT_RESET_KHR 0x8253 +#define GL_HALF_FLOAT_OES 0x8D61 +#define GL_HANDLE_TYPE_D3D11_IMAGE_EXT 0x958B +#define GL_HANDLE_TYPE_D3D11_IMAGE_KMT_EXT 0x958C +#define GL_HANDLE_TYPE_D3D12_FENCE_EXT 0x9594 +#define GL_HANDLE_TYPE_D3D12_RESOURCE_EXT 0x958A +#define GL_HANDLE_TYPE_D3D12_TILEPOOL_EXT 0x9589 +#define GL_HANDLE_TYPE_OPAQUE_FD_EXT 0x9586 +#define GL_HANDLE_TYPE_OPAQUE_WIN32_EXT 0x9587 +#define GL_HANDLE_TYPE_OPAQUE_WIN32_KMT_EXT 0x9588 +#define GL_HARDLIGHT_KHR 0x929B +#define GL_HIGH_FLOAT 0x8DF2 +#define GL_HIGH_INT 0x8DF5 +#define GL_HSL_COLOR_KHR 0x92AF +#define GL_HSL_HUE_KHR 0x92AD +#define GL_HSL_LUMINOSITY_KHR 0x92B0 +#define GL_HSL_SATURATION_KHR 0x92AE +#define GL_IMAGE_BUFFER_EXT 0x9051 +#define GL_IMAGE_BUFFER_OES 0x9051 +#define GL_IMAGE_CUBE_MAP_ARRAY_EXT 0x9054 +#define GL_IMAGE_CUBE_MAP_ARRAY_OES 0x9054 +#define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B +#define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A +#define GL_INCLUSIVE_EXT 0x8F10 +#define GL_INCR 0x1E02 +#define GL_INCR_WRAP 0x8507 +#define GL_INFO_LOG_LENGTH 0x8B84 +#define GL_INNOCENT_CONTEXT_RESET_EXT 0x8254 +#define GL_INNOCENT_CONTEXT_RESET_KHR 0x8254 +#define GL_INT 0x1404 +#define GL_INT_10_10_10_2_OES 0x8DF7 +#define GL_INT_IMAGE_BUFFER_EXT 0x905C +#define GL_INT_IMAGE_BUFFER_OES 0x905C +#define GL_INT_IMAGE_CUBE_MAP_ARRAY_EXT 0x905F +#define GL_INT_IMAGE_CUBE_MAP_ARRAY_OES 0x905F +#define GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY_OES 0x910C +#define GL_INT_SAMPLER_BUFFER_EXT 0x8DD0 +#define GL_INT_SAMPLER_BUFFER_OES 0x8DD0 +#define GL_INT_SAMPLER_CUBE_MAP_ARRAY_EXT 0x900E +#define GL_INT_SAMPLER_CUBE_MAP_ARRAY_OES 0x900E +#define GL_INT_VEC2 0x8B53 +#define GL_INT_VEC3 0x8B54 +#define GL_INT_VEC4 0x8B55 +#define GL_INVALID_ENUM 0x0500 +#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 +#define GL_INVALID_OPERATION 0x0502 +#define GL_INVALID_VALUE 0x0501 +#define GL_INVERT 0x150A +#define GL_ISOLINES_EXT 0x8E7A +#define GL_ISOLINES_OES 0x8E7A +#define GL_IS_PER_PATCH_EXT 0x92E7 +#define GL_IS_PER_PATCH_OES 0x92E7 +#define GL_KEEP 0x1E00 +#define GL_LAST_VERTEX_CONVENTION_EXT 0x8E4E +#define GL_LAST_VERTEX_CONVENTION_OES 0x8E4E +#define GL_LAYER_PROVOKING_VERTEX_EXT 0x825E +#define GL_LAYER_PROVOKING_VERTEX_OES 0x825E +#define GL_LAYOUT_COLOR_ATTACHMENT_EXT 0x958E +#define GL_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_EXT 0x9531 +#define GL_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_EXT 0x9530 +#define GL_LAYOUT_DEPTH_STENCIL_ATTACHMENT_EXT 0x958F +#define GL_LAYOUT_DEPTH_STENCIL_READ_ONLY_EXT 0x9590 +#define GL_LAYOUT_GENERAL_EXT 0x958D +#define GL_LAYOUT_SHADER_READ_ONLY_EXT 0x9591 +#define GL_LAYOUT_TRANSFER_DST_EXT 0x9593 +#define GL_LAYOUT_TRANSFER_SRC_EXT 0x9592 +#define GL_LEQUAL 0x0203 +#define GL_LESS 0x0201 +#define GL_LIGHTEN_KHR 0x9298 +#define GL_LINEAR 0x2601 +#define GL_LINEAR_MIPMAP_LINEAR 0x2703 +#define GL_LINEAR_MIPMAP_NEAREST 0x2701 +#define GL_LINEAR_TILING_EXT 0x9585 +#define GL_LINES 0x0001 +#define GL_LINES_ADJACENCY_EXT 0x000A +#define GL_LINES_ADJACENCY_OES 0x000A +#define GL_LINE_LOOP 0x0002 +#define GL_LINE_STRIP 0x0003 +#define GL_LINE_STRIP_ADJACENCY_EXT 0x000B +#define GL_LINE_STRIP_ADJACENCY_OES 0x000B +#define GL_LINE_WIDTH 0x0B21 +#define GL_LINK_STATUS 0x8B82 +#define GL_LOCATION_INDEX_EXT 0x930F +#define GL_LOSE_CONTEXT_ON_RESET_EXT 0x8252 +#define GL_LOSE_CONTEXT_ON_RESET_KHR 0x8252 +#define GL_LOWER_LEFT 0x8CA1 +#define GL_LOWER_LEFT_EXT 0x8CA1 +#define GL_LOW_FLOAT 0x8DF0 +#define GL_LOW_INT 0x8DF3 +#define GL_LUID_SIZE_EXT 8 +#define GL_LUMINANCE 0x1909 +#define GL_LUMINANCE16F_EXT 0x881E +#define GL_LUMINANCE32F_EXT 0x8818 +#define GL_LUMINANCE4_ALPHA4_OES 0x8043 +#define GL_LUMINANCE8_ALPHA8_EXT 0x8045 +#define GL_LUMINANCE8_ALPHA8_OES 0x8045 +#define GL_LUMINANCE8_EXT 0x8040 +#define GL_LUMINANCE8_OES 0x8040 +#define GL_LUMINANCE_ALPHA 0x190A +#define GL_LUMINANCE_ALPHA16F_EXT 0x881F +#define GL_LUMINANCE_ALPHA32F_EXT 0x8819 +#define GL_MAP_COHERENT_BIT_EXT 0x0080 +#define GL_MAP_FLUSH_EXPLICIT_BIT_EXT 0x0010 +#define GL_MAP_INVALIDATE_BUFFER_BIT_EXT 0x0008 +#define GL_MAP_INVALIDATE_RANGE_BIT_EXT 0x0004 +#define GL_MAP_PERSISTENT_BIT_EXT 0x0040 +#define GL_MAP_READ_BIT 0x0001 +#define GL_MAP_READ_BIT_EXT 0x0001 +#define GL_MAP_UNSYNCHRONIZED_BIT_EXT 0x0020 +#define GL_MAP_WRITE_BIT 0x0002 +#define GL_MAP_WRITE_BIT_EXT 0x0002 +#define GL_MAX 0x8008 +#define GL_MAX_3D_TEXTURE_SIZE_OES 0x8073 +#define GL_MAX_CLIP_DISTANCES_EXT 0x0D32 +#define GL_MAX_CLIP_PLANES 0x0D32 +#define GL_MAX_COLOR_ATTACHMENTS_EXT 0x8CDF +#define GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES 0x82FA +#define GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES_EXT 0x82FA +#define GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS_EXT 0x8A32 +#define GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS_OES 0x8A32 +#define GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS_EXT 0x8E1E +#define GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS_OES 0x8E1E +#define GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS_EXT 0x8E1F +#define GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS_OES 0x8E1F +#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D +#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C +#define GL_MAX_CULL_DISTANCES 0x82F9 +#define GL_MAX_CULL_DISTANCES_EXT 0x82F9 +#define GL_MAX_DEBUG_GROUP_STACK_DEPTH_KHR 0x826C +#define GL_MAX_DEBUG_LOGGED_MESSAGES_KHR 0x9144 +#define GL_MAX_DEBUG_MESSAGE_LENGTH_KHR 0x9143 +#define GL_MAX_DRAW_BUFFERS_EXT 0x8824 +#define GL_MAX_DUAL_SOURCE_DRAW_BUFFERS_EXT 0x88FC +#define GL_MAX_EXT 0x8008 +#define GL_MAX_FRAGMENT_INTERPOLATION_OFFSET_OES 0x8E5C +#define GL_MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_LAYERS_EXT 0x96DC +#define GL_MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_ASPECT_RATIO_EXT 0x96DB +#define GL_MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_HEIGHT_EXT 0x96DA +#define GL_MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_WIDTH_EXT 0x96D8 +#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD +#define GL_MAX_FRAMEBUFFER_LAYERS_EXT 0x9317 +#define GL_MAX_FRAMEBUFFER_LAYERS_OES 0x9317 +#define GL_MAX_GEOMETRY_ATOMIC_COUNTERS_EXT 0x92D5 +#define GL_MAX_GEOMETRY_ATOMIC_COUNTERS_OES 0x92D5 +#define GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS_EXT 0x92CF +#define GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS_OES 0x92CF +#define GL_MAX_GEOMETRY_IMAGE_UNIFORMS_EXT 0x90CD +#define GL_MAX_GEOMETRY_IMAGE_UNIFORMS_OES 0x90CD +#define GL_MAX_GEOMETRY_INPUT_COMPONENTS_EXT 0x9123 +#define GL_MAX_GEOMETRY_INPUT_COMPONENTS_OES 0x9123 +#define GL_MAX_GEOMETRY_OUTPUT_COMPONENTS_EXT 0x9124 +#define GL_MAX_GEOMETRY_OUTPUT_COMPONENTS_OES 0x9124 +#define GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT 0x8DE0 +#define GL_MAX_GEOMETRY_OUTPUT_VERTICES_OES 0x8DE0 +#define GL_MAX_GEOMETRY_SHADER_INVOCATIONS_EXT 0x8E5A +#define GL_MAX_GEOMETRY_SHADER_INVOCATIONS_OES 0x8E5A +#define GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS_EXT 0x90D7 +#define GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS_OES 0x90D7 +#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT 0x8C29 +#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_OES 0x8C29 +#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_EXT 0x8DE1 +#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_OES 0x8DE1 +#define GL_MAX_GEOMETRY_UNIFORM_BLOCKS_EXT 0x8A2C +#define GL_MAX_GEOMETRY_UNIFORM_BLOCKS_OES 0x8A2C +#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_EXT 0x8DDF +#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_OES 0x8DDF +#define GL_MAX_LABEL_LENGTH_KHR 0x82E8 +#define GL_MAX_MULTIVIEW_BUFFERS_EXT 0x90F2 +#define GL_MAX_PATCH_VERTICES_EXT 0x8E7D +#define GL_MAX_PATCH_VERTICES_OES 0x8E7D +#define GL_MAX_RASTER_SAMPLES_EXT 0x9329 +#define GL_MAX_RENDERBUFFER_SIZE 0x84E8 +#define GL_MAX_SAMPLES_EXT 0x8D57 +#define GL_MAX_SHADER_COMBINED_LOCAL_STORAGE_FAST_SIZE_EXT 0x9650 +#define GL_MAX_SHADER_COMBINED_LOCAL_STORAGE_SIZE_EXT 0x9651 +#define GL_MAX_SHADER_COMPILER_THREADS_KHR 0x91B0 +#define GL_MAX_SHADER_PIXEL_LOCAL_STORAGE_FAST_SIZE_EXT 0x8F63 +#define GL_MAX_SHADER_PIXEL_LOCAL_STORAGE_SIZE_EXT 0x8F67 +#define GL_MAX_SPARSE_3D_TEXTURE_SIZE_EXT 0x9199 +#define GL_MAX_SPARSE_ARRAY_TEXTURE_LAYERS_EXT 0x919A +#define GL_MAX_SPARSE_TEXTURE_SIZE_EXT 0x9198 +#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS_EXT 0x92D3 +#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS_OES 0x92D3 +#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS_EXT 0x92CD +#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS_OES 0x92CD +#define GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS_EXT 0x90CB +#define GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS_OES 0x90CB +#define GL_MAX_TESS_CONTROL_INPUT_COMPONENTS_EXT 0x886C +#define GL_MAX_TESS_CONTROL_INPUT_COMPONENTS_OES 0x886C +#define GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS_EXT 0x8E83 +#define GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS_OES 0x8E83 +#define GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS_EXT 0x90D8 +#define GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS_OES 0x90D8 +#define GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS_EXT 0x8E81 +#define GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS_OES 0x8E81 +#define GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS_EXT 0x8E85 +#define GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS_OES 0x8E85 +#define GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS_EXT 0x8E89 +#define GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS_OES 0x8E89 +#define GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS_EXT 0x8E7F +#define GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS_OES 0x8E7F +#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS_EXT 0x92D4 +#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS_OES 0x92D4 +#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS_EXT 0x92CE +#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS_OES 0x92CE +#define GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS_EXT 0x90CC +#define GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS_OES 0x90CC +#define GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS_EXT 0x886D +#define GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS_OES 0x886D +#define GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS_EXT 0x8E86 +#define GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS_OES 0x8E86 +#define GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS_EXT 0x90D9 +#define GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS_OES 0x90D9 +#define GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS_EXT 0x8E82 +#define GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS_OES 0x8E82 +#define GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS_EXT 0x8E8A +#define GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS_OES 0x8E8A +#define GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS_EXT 0x8E80 +#define GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS_OES 0x8E80 +#define GL_MAX_TESS_GEN_LEVEL_EXT 0x8E7E +#define GL_MAX_TESS_GEN_LEVEL_OES 0x8E7E +#define GL_MAX_TESS_PATCH_COMPONENTS_EXT 0x8E84 +#define GL_MAX_TESS_PATCH_COMPONENTS_OES 0x8E84 +#define GL_MAX_TEXTURE_BUFFER_SIZE_EXT 0x8C2B +#define GL_MAX_TEXTURE_BUFFER_SIZE_OES 0x8C2B +#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 +#define GL_MAX_TEXTURE_MAX_ANISOTROPY 0x84FF +#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF +#define GL_MAX_TEXTURE_SIZE 0x0D33 +#define GL_MAX_VARYING_VECTORS 0x8DFC +#define GL_MAX_VERTEX_ATTRIBS 0x8869 +#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C +#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB +#define GL_MAX_VIEWPORTS_OES 0x825B +#define GL_MAX_VIEWPORT_DIMS 0x0D3A +#define GL_MAX_WINDOW_RECTANGLES_EXT 0x8F14 +#define GL_MEDIUM_FLOAT 0x8DF1 +#define GL_MEDIUM_INT 0x8DF4 +#define GL_MIN 0x8007 +#define GL_MIN_EXT 0x8007 +#define GL_MIN_FRAGMENT_INTERPOLATION_OFFSET_OES 0x8E5B +#define GL_MIN_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_HEIGHT_EXT 0x96D9 +#define GL_MIN_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_WIDTH_EXT 0x96D7 +#define GL_MIN_SAMPLE_SHADING_VALUE_OES 0x8C37 +#define GL_MIRRORED_REPEAT 0x8370 +#define GL_MIRROR_CLAMP_TO_EDGE_EXT 0x8743 +#define GL_MULTIPLY_KHR 0x9294 +#define GL_MULTISAMPLE_EXT 0x809D +#define GL_MULTISAMPLE_RASTERIZATION_ALLOWED_EXT 0x932B +#define GL_MULTIVIEW_EXT 0x90F1 +#define GL_NEAREST 0x2600 +#define GL_NEAREST_MIPMAP_LINEAR 0x2702 +#define GL_NEAREST_MIPMAP_NEAREST 0x2700 +#define GL_NEGATIVE_ONE_TO_ONE 0x935E +#define GL_NEGATIVE_ONE_TO_ONE_EXT 0x935E +#define GL_NEVER 0x0200 +#define GL_NICEST 0x1102 +#define GL_NONE 0 +#define GL_NOTEQUAL 0x0205 +#define GL_NO_ERROR 0 +#define GL_NO_RESET_NOTIFICATION_EXT 0x8261 +#define GL_NO_RESET_NOTIFICATION_KHR 0x8261 +#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 +#define GL_NUM_DEVICE_UUIDS_EXT 0x9596 +#define GL_NUM_PROGRAM_BINARY_FORMATS_OES 0x87FE +#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9 +#define GL_NUM_SPARSE_LEVELS_EXT 0x91AA +#define GL_NUM_SURFACE_COMPRESSION_FIXED_RATES_EXT 0x8F6E +#define GL_NUM_TILING_TYPES_EXT 0x9582 +#define GL_NUM_VIRTUAL_PAGE_SIZES_EXT 0x91A8 +#define GL_NUM_WINDOW_RECTANGLES_EXT 0x8F15 +#define GL_ONE 1 +#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 +#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 +#define GL_ONE_MINUS_DST_ALPHA 0x0305 +#define GL_ONE_MINUS_DST_COLOR 0x0307 +#define GL_ONE_MINUS_SRC1_ALPHA_EXT 0x88FB +#define GL_ONE_MINUS_SRC1_COLOR_EXT 0x88FA +#define GL_ONE_MINUS_SRC_ALPHA 0x0303 +#define GL_ONE_MINUS_SRC_COLOR 0x0301 +#define GL_OPTIMAL_TILING_EXT 0x9584 +#define GL_OUT_OF_MEMORY 0x0505 +#define GL_OVERLAY_KHR 0x9296 +#define GL_PACK_ALIGNMENT 0x0D05 +#define GL_PALETTE4_R5_G6_B5_OES 0x8B92 +#define GL_PALETTE4_RGB5_A1_OES 0x8B94 +#define GL_PALETTE4_RGB8_OES 0x8B90 +#define GL_PALETTE4_RGBA4_OES 0x8B93 +#define GL_PALETTE4_RGBA8_OES 0x8B91 +#define GL_PALETTE8_R5_G6_B5_OES 0x8B97 +#define GL_PALETTE8_RGB5_A1_OES 0x8B99 +#define GL_PALETTE8_RGB8_OES 0x8B95 +#define GL_PALETTE8_RGBA4_OES 0x8B98 +#define GL_PALETTE8_RGBA8_OES 0x8B96 +#define GL_PATCHES_EXT 0x000E +#define GL_PATCHES_OES 0x000E +#define GL_PATCH_VERTICES_EXT 0x8E72 +#define GL_PATCH_VERTICES_OES 0x8E72 +#define GL_POINTS 0x0000 +#define GL_POLYGON_OFFSET_CLAMP 0x8E1B +#define GL_POLYGON_OFFSET_CLAMP_EXT 0x8E1B +#define GL_POLYGON_OFFSET_FACTOR 0x8038 +#define GL_POLYGON_OFFSET_FILL 0x8037 +#define GL_POLYGON_OFFSET_UNITS 0x2A00 +#define GL_PRIMITIVES_GENERATED_EXT 0x8C87 +#define GL_PRIMITIVES_GENERATED_OES 0x8C87 +#define GL_PRIMITIVE_BOUNDING_BOX_EXT 0x92BE +#define GL_PRIMITIVE_BOUNDING_BOX_OES 0x92BE +#define GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED 0x8221 +#define GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED_OES 0x8221 +#define GL_PROGRAM_BINARY_FORMATS_OES 0x87FF +#define GL_PROGRAM_BINARY_LENGTH_OES 0x8741 +#define GL_PROGRAM_KHR 0x82E2 +#define GL_PROGRAM_OBJECT_EXT 0x8B40 +#define GL_PROGRAM_PIPELINE_BINDING_EXT 0x825A +#define GL_PROGRAM_PIPELINE_KHR 0x82E4 +#define GL_PROGRAM_PIPELINE_OBJECT_EXT 0x8A4F +#define GL_PROGRAM_SEPARABLE_EXT 0x8258 +#define GL_PROTECTED_MEMORY_OBJECT_EXT 0x959B +#define GL_QUADS_EXT 0x0007 +#define GL_QUADS_OES 0x0007 +#define GL_QUERY_COUNTER_BITS_EXT 0x8864 +#define GL_QUERY_KHR 0x82E3 +#define GL_QUERY_OBJECT_EXT 0x9153 +#define GL_QUERY_RESULT_AVAILABLE_EXT 0x8867 +#define GL_QUERY_RESULT_EXT 0x8866 +#define GL_R16F_EXT 0x822D +#define GL_R16_EXT 0x822A +#define GL_R16_SNORM_EXT 0x8F98 +#define GL_R32F_EXT 0x822E +#define GL_R8_EXT 0x8229 +#define GL_R8_SNORM 0x8F94 +#define GL_RASTER_FIXED_SAMPLE_LOCATIONS_EXT 0x932A +#define GL_RASTER_MULTISAMPLE_EXT 0x9327 +#define GL_RASTER_SAMPLES_EXT 0x9328 +#define GL_READ_BUFFER_EXT 0x0C02 +#define GL_RED_BITS 0x0D52 +#define GL_RED_EXT 0x1903 +#define GL_REFERENCED_BY_GEOMETRY_SHADER_EXT 0x9309 +#define GL_REFERENCED_BY_GEOMETRY_SHADER_OES 0x9309 +#define GL_REFERENCED_BY_TESS_CONTROL_SHADER_EXT 0x9307 +#define GL_REFERENCED_BY_TESS_CONTROL_SHADER_OES 0x9307 +#define GL_REFERENCED_BY_TESS_EVALUATION_SHADER_EXT 0x9308 +#define GL_REFERENCED_BY_TESS_EVALUATION_SHADER_OES 0x9308 +#define GL_RENDERBUFFER 0x8D41 +#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53 +#define GL_RENDERBUFFER_BINDING 0x8CA7 +#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52 +#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54 +#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51 +#define GL_RENDERBUFFER_HEIGHT 0x8D43 +#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44 +#define GL_RENDERBUFFER_RED_SIZE 0x8D50 +#define GL_RENDERBUFFER_SAMPLES_EXT 0x8CAB +#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55 +#define GL_RENDERBUFFER_WIDTH 0x8D42 +#define GL_RENDERER 0x1F01 +#define GL_REPEAT 0x2901 +#define GL_REPLACE 0x1E01 +#define GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES 0x8D68 +#define GL_RESET_NOTIFICATION_STRATEGY_EXT 0x8256 +#define GL_RESET_NOTIFICATION_STRATEGY_KHR 0x8256 +#define GL_RG16F_EXT 0x822F +#define GL_RG16_EXT 0x822C +#define GL_RG16_SNORM_EXT 0x8F99 +#define GL_RG32F_EXT 0x8230 +#define GL_RG8_EXT 0x822B +#define GL_RG8_SNORM 0x8F95 +#define GL_RGB 0x1907 +#define GL_RGB10_A2_EXT 0x8059 +#define GL_RGB10_EXT 0x8052 +#define GL_RGB16F_EXT 0x881B +#define GL_RGB16_EXT 0x8054 +#define GL_RGB16_SNORM_EXT 0x8F9A +#define GL_RGB32F_EXT 0x8815 +#define GL_RGB565 0x8D62 +#define GL_RGB565_OES 0x8D62 +#define GL_RGB5_A1 0x8057 +#define GL_RGB5_A1_OES 0x8057 +#define GL_RGB8_OES 0x8051 +#define GL_RGBA 0x1908 +#define GL_RGBA16F_EXT 0x881A +#define GL_RGBA16_EXT 0x805B +#define GL_RGBA16_SNORM_EXT 0x8F9B +#define GL_RGBA32F_EXT 0x8814 +#define GL_RGBA4 0x8056 +#define GL_RGBA4_OES 0x8056 +#define GL_RGBA8_OES 0x8058 +#define GL_RGBA8_SNORM 0x8F97 +#define GL_RG_EXT 0x8227 +#define GL_SAMPLER 0x82E6 +#define GL_SAMPLER_2D 0x8B5E +#define GL_SAMPLER_2D_MULTISAMPLE_ARRAY_OES 0x910B +#define GL_SAMPLER_2D_SHADOW_EXT 0x8B62 +#define GL_SAMPLER_3D_OES 0x8B5F +#define GL_SAMPLER_BUFFER_EXT 0x8DC2 +#define GL_SAMPLER_BUFFER_OES 0x8DC2 +#define GL_SAMPLER_CUBE 0x8B60 +#define GL_SAMPLER_CUBE_MAP_ARRAY_EXT 0x900C +#define GL_SAMPLER_CUBE_MAP_ARRAY_OES 0x900C +#define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW_EXT 0x900D +#define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW_OES 0x900D +#define GL_SAMPLER_EXTERNAL_2D_Y2Y_EXT 0x8BE7 +#define GL_SAMPLER_EXTERNAL_OES 0x8D66 +#define GL_SAMPLER_KHR 0x82E6 +#define GL_SAMPLES 0x80A9 +#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E +#define GL_SAMPLE_ALPHA_TO_ONE_EXT 0x809F +#define GL_SAMPLE_BUFFERS 0x80A8 +#define GL_SAMPLE_COVERAGE 0x80A0 +#define GL_SAMPLE_COVERAGE_INVERT 0x80AB +#define GL_SAMPLE_COVERAGE_VALUE 0x80AA +#define GL_SAMPLE_SHADING_OES 0x8C36 +#define GL_SCISSOR_BOX 0x0C10 +#define GL_SCISSOR_TEST 0x0C11 +#define GL_SCREEN_KHR 0x9295 +#define GL_SHADER_BINARY_FORMATS 0x8DF8 +#define GL_SHADER_COMPILER 0x8DFA +#define GL_SHADER_KHR 0x82E1 +#define GL_SHADER_OBJECT_EXT 0x8B48 +#define GL_SHADER_PIXEL_LOCAL_STORAGE_EXT 0x8F64 +#define GL_SHADER_SOURCE_LENGTH 0x8B88 +#define GL_SHADER_TYPE 0x8B4F +#define GL_SHADING_LANGUAGE_VERSION 0x8B8C +#define GL_SHADING_RATE_1X1_PIXELS_EXT 0x96A6 +#define GL_SHADING_RATE_1X1_PIXELS_QCOM 0x96A6 +#define GL_SHADING_RATE_1X2_PIXELS_EXT 0x96A7 +#define GL_SHADING_RATE_1X2_PIXELS_QCOM 0x96A7 +#define GL_SHADING_RATE_1X4_PIXELS_EXT 0x96AA +#define GL_SHADING_RATE_1X4_PIXELS_QCOM 0x96AA +#define GL_SHADING_RATE_2X1_PIXELS_EXT 0x96A8 +#define GL_SHADING_RATE_2X1_PIXELS_QCOM 0x96A8 +#define GL_SHADING_RATE_2X2_PIXELS_EXT 0x96A9 +#define GL_SHADING_RATE_2X2_PIXELS_QCOM 0x96A9 +#define GL_SHADING_RATE_2X4_PIXELS_EXT 0x96AD +#define GL_SHADING_RATE_2X4_PIXELS_QCOM 0x96AD +#define GL_SHADING_RATE_4X1_PIXELS_EXT 0x96AB +#define GL_SHADING_RATE_4X1_PIXELS_QCOM 0x96AB +#define GL_SHADING_RATE_4X2_PIXELS_EXT 0x96AC +#define GL_SHADING_RATE_4X2_PIXELS_QCOM 0x96AC +#define GL_SHADING_RATE_4X4_PIXELS_EXT 0x96AE +#define GL_SHADING_RATE_4X4_PIXELS_QCOM 0x96AE +#define GL_SHADING_RATE_ATTACHMENT_EXT 0x96D1 +#define GL_SHADING_RATE_EXT 0x96D0 +#define GL_SHORT 0x1402 +#define GL_SKIP_DECODE_EXT 0x8A4A +#define GL_SOFTLIGHT_KHR 0x929C +#define GL_SPARSE_TEXTURE_FULL_ARRAY_CUBE_MIPMAPS_EXT 0x91A9 +#define GL_SR8_EXT 0x8FBD +#define GL_SRC1_ALPHA_EXT 0x8589 +#define GL_SRC1_COLOR_EXT 0x88F9 +#define GL_SRC_ALPHA 0x0302 +#define GL_SRC_ALPHA_SATURATE 0x0308 +#define GL_SRC_ALPHA_SATURATE_EXT 0x0308 +#define GL_SRC_COLOR 0x0300 +#define GL_SRG8_EXT 0x8FBE +#define GL_SRGB8_ALPHA8_EXT 0x8C43 +#define GL_SRGB_ALPHA_EXT 0x8C42 +#define GL_SRGB_EXT 0x8C40 +#define GL_STACK_OVERFLOW_KHR 0x0503 +#define GL_STACK_UNDERFLOW_KHR 0x0504 +#define GL_STATIC_DRAW 0x88E4 +#define GL_STENCIL_ATTACHMENT 0x8D20 +#define GL_STENCIL_BACK_FAIL 0x8801 +#define GL_STENCIL_BACK_FUNC 0x8800 +#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 +#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 +#define GL_STENCIL_BACK_REF 0x8CA3 +#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 +#define GL_STENCIL_BACK_WRITEMASK 0x8CA5 +#define GL_STENCIL_BITS 0x0D57 +#define GL_STENCIL_BUFFER_BIT 0x00000400 +#define GL_STENCIL_CLEAR_VALUE 0x0B91 +#define GL_STENCIL_EXT 0x1802 +#define GL_STENCIL_FAIL 0x0B94 +#define GL_STENCIL_FUNC 0x0B92 +#define GL_STENCIL_INDEX1_OES 0x8D46 +#define GL_STENCIL_INDEX4_OES 0x8D47 +#define GL_STENCIL_INDEX8 0x8D48 +#define GL_STENCIL_INDEX8_OES 0x8D48 +#define GL_STENCIL_INDEX_OES 0x1901 +#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95 +#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96 +#define GL_STENCIL_REF 0x0B97 +#define GL_STENCIL_TEST 0x0B90 +#define GL_STENCIL_VALUE_MASK 0x0B93 +#define GL_STENCIL_WRITEMASK 0x0B98 +#define GL_STREAM_DRAW 0x88E0 +#define GL_SUBGROUP_FEATURE_ARITHMETIC_BIT_KHR 0x00000004 +#define GL_SUBGROUP_FEATURE_BALLOT_BIT_KHR 0x00000008 +#define GL_SUBGROUP_FEATURE_BASIC_BIT_KHR 0x00000001 +#define GL_SUBGROUP_FEATURE_CLUSTERED_BIT_KHR 0x00000040 +#define GL_SUBGROUP_FEATURE_QUAD_BIT_KHR 0x00000080 +#define GL_SUBGROUP_FEATURE_SHUFFLE_BIT_KHR 0x00000010 +#define GL_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT_KHR 0x00000020 +#define GL_SUBGROUP_FEATURE_VOTE_BIT_KHR 0x00000002 +#define GL_SUBGROUP_QUAD_ALL_STAGES_KHR 0x9535 +#define GL_SUBGROUP_SIZE_KHR 0x9532 +#define GL_SUBGROUP_SUPPORTED_FEATURES_KHR 0x9534 +#define GL_SUBGROUP_SUPPORTED_STAGES_KHR 0x9533 +#define GL_SUBPIXEL_BITS 0x0D50 +#define GL_SURFACE_COMPRESSION_EXT 0x96C0 +#define GL_SURFACE_COMPRESSION_FIXED_RATE_10BPC_EXT 0x96CD +#define GL_SURFACE_COMPRESSION_FIXED_RATE_11BPC_EXT 0x96CE +#define GL_SURFACE_COMPRESSION_FIXED_RATE_12BPC_EXT 0x96CF +#define GL_SURFACE_COMPRESSION_FIXED_RATE_1BPC_EXT 0x96C4 +#define GL_SURFACE_COMPRESSION_FIXED_RATE_2BPC_EXT 0x96C5 +#define GL_SURFACE_COMPRESSION_FIXED_RATE_3BPC_EXT 0x96C6 +#define GL_SURFACE_COMPRESSION_FIXED_RATE_4BPC_EXT 0x96C7 +#define GL_SURFACE_COMPRESSION_FIXED_RATE_5BPC_EXT 0x96C8 +#define GL_SURFACE_COMPRESSION_FIXED_RATE_6BPC_EXT 0x96C9 +#define GL_SURFACE_COMPRESSION_FIXED_RATE_7BPC_EXT 0x96CA +#define GL_SURFACE_COMPRESSION_FIXED_RATE_8BPC_EXT 0x96CB +#define GL_SURFACE_COMPRESSION_FIXED_RATE_9BPC_EXT 0x96CC +#define GL_SURFACE_COMPRESSION_FIXED_RATE_DEFAULT_EXT 0x96C2 +#define GL_SURFACE_COMPRESSION_FIXED_RATE_NONE_EXT 0x96C1 +#define GL_TESS_CONTROL_OUTPUT_VERTICES_EXT 0x8E75 +#define GL_TESS_CONTROL_OUTPUT_VERTICES_OES 0x8E75 +#define GL_TESS_CONTROL_SHADER_BIT_EXT 0x00000008 +#define GL_TESS_CONTROL_SHADER_BIT_OES 0x00000008 +#define GL_TESS_CONTROL_SHADER_EXT 0x8E88 +#define GL_TESS_CONTROL_SHADER_OES 0x8E88 +#define GL_TESS_EVALUATION_SHADER_BIT_EXT 0x00000010 +#define GL_TESS_EVALUATION_SHADER_BIT_OES 0x00000010 +#define GL_TESS_EVALUATION_SHADER_EXT 0x8E87 +#define GL_TESS_EVALUATION_SHADER_OES 0x8E87 +#define GL_TESS_GEN_MODE_EXT 0x8E76 +#define GL_TESS_GEN_MODE_OES 0x8E76 +#define GL_TESS_GEN_POINT_MODE_EXT 0x8E79 +#define GL_TESS_GEN_POINT_MODE_OES 0x8E79 +#define GL_TESS_GEN_SPACING_EXT 0x8E77 +#define GL_TESS_GEN_SPACING_OES 0x8E77 +#define GL_TESS_GEN_VERTEX_ORDER_EXT 0x8E78 +#define GL_TESS_GEN_VERTEX_ORDER_OES 0x8E78 +#define GL_TEXTURE 0x1702 +#define GL_TEXTURE0 0x84C0 +#define GL_TEXTURE1 0x84C1 +#define GL_TEXTURE10 0x84CA +#define GL_TEXTURE11 0x84CB +#define GL_TEXTURE12 0x84CC +#define GL_TEXTURE13 0x84CD +#define GL_TEXTURE14 0x84CE +#define GL_TEXTURE15 0x84CF +#define GL_TEXTURE16 0x84D0 +#define GL_TEXTURE17 0x84D1 +#define GL_TEXTURE18 0x84D2 +#define GL_TEXTURE19 0x84D3 +#define GL_TEXTURE2 0x84C2 +#define GL_TEXTURE20 0x84D4 +#define GL_TEXTURE21 0x84D5 +#define GL_TEXTURE22 0x84D6 +#define GL_TEXTURE23 0x84D7 +#define GL_TEXTURE24 0x84D8 +#define GL_TEXTURE25 0x84D9 +#define GL_TEXTURE26 0x84DA +#define GL_TEXTURE27 0x84DB +#define GL_TEXTURE28 0x84DC +#define GL_TEXTURE29 0x84DD +#define GL_TEXTURE3 0x84C3 +#define GL_TEXTURE30 0x84DE +#define GL_TEXTURE31 0x84DF +#define GL_TEXTURE4 0x84C4 +#define GL_TEXTURE5 0x84C5 +#define GL_TEXTURE6 0x84C6 +#define GL_TEXTURE7 0x84C7 +#define GL_TEXTURE8 0x84C8 +#define GL_TEXTURE9 0x84C9 +#define GL_TEXTURE_2D 0x0DE1 +#define GL_TEXTURE_2D_ARRAY 0x8C1A +#define GL_TEXTURE_2D_MULTISAMPLE_ARRAY_OES 0x9102 +#define GL_TEXTURE_3D 0x806F +#define GL_TEXTURE_3D_OES 0x806F +#define GL_TEXTURE_ASTC_DECODE_PRECISION_EXT 0x8F69 +#define GL_TEXTURE_BINDING_2D 0x8069 +#define GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY_OES 0x9105 +#define GL_TEXTURE_BINDING_3D_OES 0x806A +#define GL_TEXTURE_BINDING_BUFFER_EXT 0x8C2C +#define GL_TEXTURE_BINDING_BUFFER_OES 0x8C2C +#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514 +#define GL_TEXTURE_BINDING_CUBE_MAP_ARRAY_EXT 0x900A +#define GL_TEXTURE_BINDING_CUBE_MAP_ARRAY_OES 0x900A +#define GL_TEXTURE_BINDING_EXTERNAL_OES 0x8D67 +#define GL_TEXTURE_BORDER_COLOR_EXT 0x1004 +#define GL_TEXTURE_BORDER_COLOR_OES 0x1004 +#define GL_TEXTURE_BUFFER_BINDING_EXT 0x8C2A +#define GL_TEXTURE_BUFFER_BINDING_OES 0x8C2A +#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING_EXT 0x8C2D +#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING_OES 0x8C2D +#define GL_TEXTURE_BUFFER_EXT 0x8C2A +#define GL_TEXTURE_BUFFER_OES 0x8C2A +#define GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT_EXT 0x919F +#define GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT_OES 0x919F +#define GL_TEXTURE_BUFFER_OFFSET_EXT 0x919D +#define GL_TEXTURE_BUFFER_OFFSET_OES 0x919D +#define GL_TEXTURE_BUFFER_SIZE_EXT 0x919E +#define GL_TEXTURE_BUFFER_SIZE_OES 0x919E +#define GL_TEXTURE_COMPARE_FUNC_EXT 0x884D +#define GL_TEXTURE_COMPARE_MODE_EXT 0x884C +#define GL_TEXTURE_CUBE_MAP 0x8513 +#define GL_TEXTURE_CUBE_MAP_ARRAY_EXT 0x9009 +#define GL_TEXTURE_CUBE_MAP_ARRAY_OES 0x9009 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A +#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 +#define GL_TEXTURE_EXTERNAL_OES 0x8D65 +#define GL_TEXTURE_FORMAT_SRGB_OVERRIDE_EXT 0x8FBF +#define GL_TEXTURE_IMMUTABLE_FORMAT_EXT 0x912F +#define GL_TEXTURE_IMMUTABLE_LEVELS 0x82DF +#define GL_TEXTURE_MAG_FILTER 0x2800 +#define GL_TEXTURE_MAX_ANISOTROPY 0x84FE +#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE +#define GL_TEXTURE_MIN_FILTER 0x2801 +#define GL_TEXTURE_PROTECTED_EXT 0x8BFA +#define GL_TEXTURE_REDUCTION_MODE_ARB 0x9366 +#define GL_TEXTURE_REDUCTION_MODE_EXT 0x9366 +#define GL_TEXTURE_SPARSE_EXT 0x91A6 +#define GL_TEXTURE_SRGB_DECODE_EXT 0x8A48 +#define GL_TEXTURE_TILING_EXT 0x9580 +#define GL_TEXTURE_VIEW_MIN_LAYER_EXT 0x82DD +#define GL_TEXTURE_VIEW_MIN_LAYER_OES 0x82DD +#define GL_TEXTURE_VIEW_MIN_LEVEL_EXT 0x82DB +#define GL_TEXTURE_VIEW_MIN_LEVEL_OES 0x82DB +#define GL_TEXTURE_VIEW_NUM_LAYERS_EXT 0x82DE +#define GL_TEXTURE_VIEW_NUM_LAYERS_OES 0x82DE +#define GL_TEXTURE_VIEW_NUM_LEVELS_EXT 0x82DC +#define GL_TEXTURE_VIEW_NUM_LEVELS_OES 0x82DC +#define GL_TEXTURE_WRAP_R_OES 0x8072 +#define GL_TEXTURE_WRAP_S 0x2802 +#define GL_TEXTURE_WRAP_T 0x2803 +#define GL_TILING_TYPES_EXT 0x9583 +#define GL_TIMESTAMP_EXT 0x8E28 +#define GL_TIME_ELAPSED_EXT 0x88BF +#define GL_TRANSFORM_FEEDBACK 0x8E22 +#define GL_TRIANGLES 0x0004 +#define GL_TRIANGLES_ADJACENCY_EXT 0x000C +#define GL_TRIANGLES_ADJACENCY_OES 0x000C +#define GL_TRIANGLE_FAN 0x0006 +#define GL_TRIANGLE_STRIP 0x0005 +#define GL_TRIANGLE_STRIP_ADJACENCY_EXT 0x000D +#define GL_TRIANGLE_STRIP_ADJACENCY_OES 0x000D +#define GL_TRUE 1 +#define GL_UNDEFINED_VERTEX_EXT 0x8260 +#define GL_UNDEFINED_VERTEX_OES 0x8260 +#define GL_UNKNOWN_CONTEXT_RESET_EXT 0x8255 +#define GL_UNKNOWN_CONTEXT_RESET_KHR 0x8255 +#define GL_UNPACK_ALIGNMENT 0x0CF5 +#define GL_UNPACK_ROW_LENGTH_EXT 0x0CF2 +#define GL_UNPACK_SKIP_PIXELS_EXT 0x0CF4 +#define GL_UNPACK_SKIP_ROWS_EXT 0x0CF3 +#define GL_UNSIGNED_BYTE 0x1401 +#define GL_UNSIGNED_INT 0x1405 +#define GL_UNSIGNED_INT_10_10_10_2_OES 0x8DF6 +#define GL_UNSIGNED_INT_24_8_OES 0x84FA +#define GL_UNSIGNED_INT_2_10_10_10_REV_EXT 0x8368 +#define GL_UNSIGNED_INT_IMAGE_BUFFER_EXT 0x9067 +#define GL_UNSIGNED_INT_IMAGE_BUFFER_OES 0x9067 +#define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY_EXT 0x906A +#define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY_OES 0x906A +#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY_OES 0x910D +#define GL_UNSIGNED_INT_SAMPLER_BUFFER_EXT 0x8DD8 +#define GL_UNSIGNED_INT_SAMPLER_BUFFER_OES 0x8DD8 +#define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY_EXT 0x900F +#define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY_OES 0x900F +#define GL_UNSIGNED_NORMALIZED_EXT 0x8C17 +#define GL_UNSIGNED_SHORT 0x1403 +#define GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT 0x8366 +#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 +#define GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT 0x8365 +#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 +#define GL_UNSIGNED_SHORT_5_6_5 0x8363 +#define GL_UPPER_LEFT 0x8CA2 +#define GL_UPPER_LEFT_EXT 0x8CA2 +#define GL_UUID_SIZE_EXT 16 +#define GL_VALIDATE_STATUS 0x8B83 +#define GL_VENDOR 0x1F00 +#define GL_VERSION 0x1F02 +#define GL_VERTEX_ARRAY_BINDING_OES 0x85B5 +#define GL_VERTEX_ARRAY_KHR 0x8074 +#define GL_VERTEX_ARRAY_OBJECT_EXT 0x9154 +#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F +#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR_EXT 0x88FE +#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 +#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A +#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 +#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 +#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 +#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 +#define GL_VERTEX_SHADER 0x8B31 +#define GL_VERTEX_SHADER_BIT_EXT 0x00000001 +#define GL_VIEWPORT 0x0BA2 +#define GL_VIEWPORT_BOUNDS_RANGE_OES 0x825D +#define GL_VIEWPORT_INDEX_PROVOKING_VERTEX_OES 0x825F +#define GL_VIEWPORT_SUBPIXEL_BITS_OES 0x825C +#define GL_VIRTUAL_PAGE_SIZE_INDEX_EXT 0x91A7 +#define GL_VIRTUAL_PAGE_SIZE_X_EXT 0x9195 +#define GL_VIRTUAL_PAGE_SIZE_Y_EXT 0x9196 +#define GL_VIRTUAL_PAGE_SIZE_Z_EXT 0x9197 +#define GL_WEIGHTED_AVERAGE_ARB 0x9367 +#define GL_WEIGHTED_AVERAGE_EXT 0x9367 +#define GL_WINDOW_RECTANGLE_EXT 0x8F12 +#define GL_WINDOW_RECTANGLE_MODE_EXT 0x8F13 +#define GL_WRITE_ONLY_OES 0x88B9 +#define GL_ZERO 0 +#define GL_ZERO_TO_ONE 0x935F +#define GL_ZERO_TO_ONE_EXT 0x935F + + +#ifndef __khrplatform_h_ +#define __khrplatform_h_ + +/* +** Copyright (c) 2008-2018 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are 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 Materials. +** +** THE MATERIALS ARE 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 +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +/* Khronos platform-specific types and definitions. + * + * The master copy of khrplatform.h is maintained in the Khronos EGL + * Registry repository at https://github.com/KhronosGroup/EGL-Registry + * The last semantic modification to khrplatform.h was at commit ID: + * 67a3e0864c2d75ea5287b9f3d2eb74a745936692 + * + * Adopters may modify this file to suit their platform. Adopters are + * encouraged to submit platform specific modifications to the Khronos + * group so that they can be included in future versions of this file. + * Please submit changes by filing pull requests or issues on + * the EGL Registry repository linked above. + * + * + * See the Implementer's Guidelines for information about where this file + * should be located on your system and for more details of its use: + * http://www.khronos.org/registry/implementers_guide.pdf + * + * This file should be included as + * #include + * by Khronos client API header files that use its types and defines. + * + * The types in khrplatform.h should only be used to define API-specific types. + * + * Types defined in khrplatform.h: + * khronos_int8_t signed 8 bit + * khronos_uint8_t unsigned 8 bit + * khronos_int16_t signed 16 bit + * khronos_uint16_t unsigned 16 bit + * khronos_int32_t signed 32 bit + * khronos_uint32_t unsigned 32 bit + * khronos_int64_t signed 64 bit + * khronos_uint64_t unsigned 64 bit + * khronos_intptr_t signed same number of bits as a pointer + * khronos_uintptr_t unsigned same number of bits as a pointer + * khronos_ssize_t signed size + * khronos_usize_t unsigned size + * khronos_float_t signed 32 bit floating point + * khronos_time_ns_t unsigned 64 bit time in nanoseconds + * khronos_utime_nanoseconds_t unsigned time interval or absolute time in + * nanoseconds + * khronos_stime_nanoseconds_t signed time interval in nanoseconds + * khronos_boolean_enum_t enumerated boolean type. This should + * only be used as a base type when a client API's boolean type is + * an enum. Client APIs which use an integer or other type for + * booleans cannot use this as the base type for their boolean. + * + * Tokens defined in khrplatform.h: + * + * KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values. + * + * KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0. + * KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0. + * + * Calling convention macros defined in this file: + * KHRONOS_APICALL + * KHRONOS_GLAD_API_PTR + * KHRONOS_APIATTRIBUTES + * + * These may be used in function prototypes as: + * + * KHRONOS_APICALL void KHRONOS_GLAD_API_PTR funcname( + * int arg1, + * int arg2) KHRONOS_APIATTRIBUTES; + */ + +#if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC) +# define KHRONOS_STATIC 1 +#endif + +/*------------------------------------------------------------------------- + * Definition of KHRONOS_APICALL + *------------------------------------------------------------------------- + * This precedes the return type of the function in the function prototype. + */ +#if defined(KHRONOS_STATIC) + /* If the preprocessor constant KHRONOS_STATIC is defined, make the + * header compatible with static linking. */ +# define KHRONOS_APICALL +#elif defined(_WIN32) +# define KHRONOS_APICALL __declspec(dllimport) +#elif defined (__SYMBIAN32__) +# define KHRONOS_APICALL IMPORT_C +#elif defined(__ANDROID__) +# define KHRONOS_APICALL __attribute__((visibility("default"))) +#else +# define KHRONOS_APICALL +#endif + +/*------------------------------------------------------------------------- + * Definition of KHRONOS_GLAD_API_PTR + *------------------------------------------------------------------------- + * This follows the return type of the function and precedes the function + * name in the function prototype. + */ +#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__) + /* Win32 but not WinCE */ +# define KHRONOS_GLAD_API_PTR __stdcall +#else +# define KHRONOS_GLAD_API_PTR +#endif + +/*------------------------------------------------------------------------- + * Definition of KHRONOS_APIATTRIBUTES + *------------------------------------------------------------------------- + * This follows the closing parenthesis of the function prototype arguments. + */ +#if defined (__ARMCC_2__) +#define KHRONOS_APIATTRIBUTES __softfp +#else +#define KHRONOS_APIATTRIBUTES +#endif + +/*------------------------------------------------------------------------- + * basic type definitions + *-----------------------------------------------------------------------*/ +#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__) + + +/* + * Using + */ +#include +typedef int32_t khronos_int32_t; +typedef uint32_t khronos_uint32_t; +typedef int64_t khronos_int64_t; +typedef uint64_t khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 +/* + * To support platform where unsigned long cannot be used interchangeably with + * inptr_t (e.g. CHERI-extended ISAs), we can use the stdint.h intptr_t. + * Ideally, we could just use (u)intptr_t everywhere, but this could result in + * ABI breakage if khronos_uintptr_t is changed from unsigned long to + * unsigned long long or similar (this results in different C++ name mangling). + * To avoid changes for existing platforms, we restrict usage of intptr_t to + * platforms where the size of a pointer is larger than the size of long. + */ +#if defined(__SIZEOF_LONG__) && defined(__SIZEOF_POINTER__) +#if __SIZEOF_POINTER__ > __SIZEOF_LONG__ +#define KHRONOS_USE_INTPTR_T +#endif +#endif + +#elif defined(__VMS ) || defined(__sgi) + +/* + * Using + */ +#include +typedef int32_t khronos_int32_t; +typedef uint32_t khronos_uint32_t; +typedef int64_t khronos_int64_t; +typedef uint64_t khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif defined(_WIN32) && !defined(__SCITECH_SNAP__) + +/* + * Win32 + */ +typedef __int32 khronos_int32_t; +typedef unsigned __int32 khronos_uint32_t; +typedef __int64 khronos_int64_t; +typedef unsigned __int64 khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif defined(__sun__) || defined(__digital__) + +/* + * Sun or Digital + */ +typedef int khronos_int32_t; +typedef unsigned int khronos_uint32_t; +#if defined(__arch64__) || defined(_LP64) +typedef long int khronos_int64_t; +typedef unsigned long int khronos_uint64_t; +#else +typedef long long int khronos_int64_t; +typedef unsigned long long int khronos_uint64_t; +#endif /* __arch64__ */ +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif 0 + +/* + * Hypothetical platform with no float or int64 support + */ +typedef int khronos_int32_t; +typedef unsigned int khronos_uint32_t; +#define KHRONOS_SUPPORT_INT64 0 +#define KHRONOS_SUPPORT_FLOAT 0 + +#else + +/* + * Generic fallback + */ +#include +typedef int32_t khronos_int32_t; +typedef uint32_t khronos_uint32_t; +typedef int64_t khronos_int64_t; +typedef uint64_t khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#endif + + +/* + * Types that are (so far) the same on all platforms + */ +typedef signed char khronos_int8_t; +typedef unsigned char khronos_uint8_t; +typedef signed short int khronos_int16_t; +typedef unsigned short int khronos_uint16_t; + +/* + * Types that differ between LLP64 and LP64 architectures - in LLP64, + * pointers are 64 bits, but 'long' is still 32 bits. Win64 appears + * to be the only LLP64 architecture in current use. + */ +#ifdef KHRONOS_USE_INTPTR_T +typedef intptr_t khronos_intptr_t; +typedef uintptr_t khronos_uintptr_t; +#elif defined(_WIN64) +typedef signed long long int khronos_intptr_t; +typedef unsigned long long int khronos_uintptr_t; +#else +typedef signed long int khronos_intptr_t; +typedef unsigned long int khronos_uintptr_t; +#endif + +#if defined(_WIN64) +typedef signed long long int khronos_ssize_t; +typedef unsigned long long int khronos_usize_t; +#else +typedef signed long int khronos_ssize_t; +typedef unsigned long int khronos_usize_t; +#endif + +#if KHRONOS_SUPPORT_FLOAT +/* + * Float type + */ +typedef float khronos_float_t; +#endif + +#if KHRONOS_SUPPORT_INT64 +/* Time types + * + * These types can be used to represent a time interval in nanoseconds or + * an absolute Unadjusted System Time. Unadjusted System Time is the number + * of nanoseconds since some arbitrary system event (e.g. since the last + * time the system booted). The Unadjusted System Time is an unsigned + * 64 bit value that wraps back to 0 every 584 years. Time intervals + * may be either signed or unsigned. + */ +typedef khronos_uint64_t khronos_utime_nanoseconds_t; +typedef khronos_int64_t khronos_stime_nanoseconds_t; +#endif + +/* + * Dummy value used to pad enum types to 32 bits. + */ +#ifndef KHRONOS_MAX_ENUM +#define KHRONOS_MAX_ENUM 0x7FFFFFFF +#endif + +/* + * Enumerated boolean type + * + * Values other than zero should be considered to be true. Therefore + * comparisons should not be made against KHRONOS_TRUE. + */ +typedef enum { + KHRONOS_FALSE = 0, + KHRONOS_TRUE = 1, + KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM +} khronos_boolean_enum_t; + +#endif /* __khrplatform_h_ */ +typedef unsigned int GLenum; +typedef unsigned char GLboolean; +typedef unsigned int GLbitfield; +typedef void GLvoid; +typedef khronos_int8_t GLbyte; +typedef khronos_uint8_t GLubyte; +typedef khronos_int16_t GLshort; +typedef khronos_uint16_t GLushort; +typedef int GLint; +typedef unsigned int GLuint; +typedef khronos_int32_t GLclampx; +typedef int GLsizei; +typedef khronos_float_t GLfloat; +typedef khronos_float_t GLclampf; +typedef double GLdouble; +typedef double GLclampd; +typedef void *GLeglClientBufferEXT; +typedef void *GLeglImageOES; +typedef char GLchar; +typedef char GLcharARB; +#ifdef __APPLE__ +typedef void *GLhandleARB; +#else +typedef unsigned int GLhandleARB; +#endif +typedef khronos_uint16_t GLhalf; +typedef khronos_uint16_t GLhalfARB; +typedef khronos_int32_t GLfixed; +#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060) +typedef khronos_intptr_t GLintptr; +#else +typedef khronos_intptr_t GLintptr; +#endif +#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060) +typedef khronos_intptr_t GLintptrARB; +#else +typedef khronos_intptr_t GLintptrARB; +#endif +#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060) +typedef khronos_ssize_t GLsizeiptr; +#else +typedef khronos_ssize_t GLsizeiptr; +#endif +#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060) +typedef khronos_ssize_t GLsizeiptrARB; +#else +typedef khronos_ssize_t GLsizeiptrARB; +#endif +typedef khronos_int64_t GLint64; +typedef khronos_int64_t GLint64EXT; +typedef khronos_uint64_t GLuint64; +typedef khronos_uint64_t GLuint64EXT; +typedef struct __GLsync *GLsync; +struct _cl_context; +struct _cl_event; +typedef void (GLAD_API_PTR *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); +typedef void (GLAD_API_PTR *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); +typedef void (GLAD_API_PTR *GLDEBUGPROCKHR)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); +typedef void (GLAD_API_PTR *GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenum severity,GLsizei length,const GLchar *message,void *userParam); +typedef unsigned short GLhalfNV; +typedef GLintptr GLvdpauSurfaceNV; +typedef void (GLAD_API_PTR *GLVULKANPROCNV)(void); + + +#define GL_ES_VERSION_2_0 1 +GLAD_API_CALL int GLAD_GL_ES_VERSION_2_0; +#define GL_EXT_EGL_image_array 1 +GLAD_API_CALL int GLAD_GL_EXT_EGL_image_array; +#define GL_EXT_EGL_image_storage 1 +GLAD_API_CALL int GLAD_GL_EXT_EGL_image_storage; +#define GL_EXT_EGL_image_storage_compression 1 +GLAD_API_CALL int GLAD_GL_EXT_EGL_image_storage_compression; +#define GL_EXT_YUV_target 1 +GLAD_API_CALL int GLAD_GL_EXT_YUV_target; +#define GL_EXT_base_instance 1 +GLAD_API_CALL int GLAD_GL_EXT_base_instance; +#define GL_EXT_blend_func_extended 1 +GLAD_API_CALL int GLAD_GL_EXT_blend_func_extended; +#define GL_EXT_blend_minmax 1 +GLAD_API_CALL int GLAD_GL_EXT_blend_minmax; +#define GL_EXT_buffer_storage 1 +GLAD_API_CALL int GLAD_GL_EXT_buffer_storage; +#define GL_EXT_clear_texture 1 +GLAD_API_CALL int GLAD_GL_EXT_clear_texture; +#define GL_EXT_clip_control 1 +GLAD_API_CALL int GLAD_GL_EXT_clip_control; +#define GL_EXT_clip_cull_distance 1 +GLAD_API_CALL int GLAD_GL_EXT_clip_cull_distance; +#define GL_EXT_color_buffer_float 1 +GLAD_API_CALL int GLAD_GL_EXT_color_buffer_float; +#define GL_EXT_color_buffer_half_float 1 +GLAD_API_CALL int GLAD_GL_EXT_color_buffer_half_float; +#define GL_EXT_conservative_depth 1 +GLAD_API_CALL int GLAD_GL_EXT_conservative_depth; +#define GL_EXT_copy_image 1 +GLAD_API_CALL int GLAD_GL_EXT_copy_image; +#define GL_EXT_debug_label 1 +GLAD_API_CALL int GLAD_GL_EXT_debug_label; +#define GL_EXT_debug_marker 1 +GLAD_API_CALL int GLAD_GL_EXT_debug_marker; +#define GL_EXT_depth_clamp 1 +GLAD_API_CALL int GLAD_GL_EXT_depth_clamp; +#define GL_EXT_discard_framebuffer 1 +GLAD_API_CALL int GLAD_GL_EXT_discard_framebuffer; +#define GL_EXT_disjoint_timer_query 1 +GLAD_API_CALL int GLAD_GL_EXT_disjoint_timer_query; +#define GL_EXT_draw_buffers 1 +GLAD_API_CALL int GLAD_GL_EXT_draw_buffers; +#define GL_EXT_draw_buffers_indexed 1 +GLAD_API_CALL int GLAD_GL_EXT_draw_buffers_indexed; +#define GL_EXT_draw_elements_base_vertex 1 +GLAD_API_CALL int GLAD_GL_EXT_draw_elements_base_vertex; +#define GL_EXT_draw_instanced 1 +GLAD_API_CALL int GLAD_GL_EXT_draw_instanced; +#define GL_EXT_draw_transform_feedback 1 +GLAD_API_CALL int GLAD_GL_EXT_draw_transform_feedback; +#define GL_EXT_external_buffer 1 +GLAD_API_CALL int GLAD_GL_EXT_external_buffer; +#define GL_EXT_float_blend 1 +GLAD_API_CALL int GLAD_GL_EXT_float_blend; +#define GL_EXT_fragment_shading_rate 1 +GLAD_API_CALL int GLAD_GL_EXT_fragment_shading_rate; +#define GL_EXT_geometry_point_size 1 +GLAD_API_CALL int GLAD_GL_EXT_geometry_point_size; +#define GL_EXT_geometry_shader 1 +GLAD_API_CALL int GLAD_GL_EXT_geometry_shader; +#define GL_EXT_gpu_shader5 1 +GLAD_API_CALL int GLAD_GL_EXT_gpu_shader5; +#define GL_EXT_instanced_arrays 1 +GLAD_API_CALL int GLAD_GL_EXT_instanced_arrays; +#define GL_EXT_map_buffer_range 1 +GLAD_API_CALL int GLAD_GL_EXT_map_buffer_range; +#define GL_EXT_memory_object 1 +GLAD_API_CALL int GLAD_GL_EXT_memory_object; +#define GL_EXT_memory_object_fd 1 +GLAD_API_CALL int GLAD_GL_EXT_memory_object_fd; +#define GL_EXT_memory_object_win32 1 +GLAD_API_CALL int GLAD_GL_EXT_memory_object_win32; +#define GL_EXT_multi_draw_arrays 1 +GLAD_API_CALL int GLAD_GL_EXT_multi_draw_arrays; +#define GL_EXT_multi_draw_indirect 1 +GLAD_API_CALL int GLAD_GL_EXT_multi_draw_indirect; +#define GL_EXT_multisampled_compatibility 1 +GLAD_API_CALL int GLAD_GL_EXT_multisampled_compatibility; +#define GL_EXT_multisampled_render_to_texture 1 +GLAD_API_CALL int GLAD_GL_EXT_multisampled_render_to_texture; +#define GL_EXT_multisampled_render_to_texture2 1 +GLAD_API_CALL int GLAD_GL_EXT_multisampled_render_to_texture2; +#define GL_EXT_multiview_draw_buffers 1 +GLAD_API_CALL int GLAD_GL_EXT_multiview_draw_buffers; +#define GL_EXT_multiview_tessellation_geometry_shader 1 +GLAD_API_CALL int GLAD_GL_EXT_multiview_tessellation_geometry_shader; +#define GL_EXT_multiview_texture_multisample 1 +GLAD_API_CALL int GLAD_GL_EXT_multiview_texture_multisample; +#define GL_EXT_multiview_timer_query 1 +GLAD_API_CALL int GLAD_GL_EXT_multiview_timer_query; +#define GL_EXT_occlusion_query_boolean 1 +GLAD_API_CALL int GLAD_GL_EXT_occlusion_query_boolean; +#define GL_EXT_polygon_offset_clamp 1 +GLAD_API_CALL int GLAD_GL_EXT_polygon_offset_clamp; +#define GL_EXT_post_depth_coverage 1 +GLAD_API_CALL int GLAD_GL_EXT_post_depth_coverage; +#define GL_EXT_primitive_bounding_box 1 +GLAD_API_CALL int GLAD_GL_EXT_primitive_bounding_box; +#define GL_EXT_protected_textures 1 +GLAD_API_CALL int GLAD_GL_EXT_protected_textures; +#define GL_EXT_pvrtc_sRGB 1 +GLAD_API_CALL int GLAD_GL_EXT_pvrtc_sRGB; +#define GL_EXT_raster_multisample 1 +GLAD_API_CALL int GLAD_GL_EXT_raster_multisample; +#define GL_EXT_read_format_bgra 1 +GLAD_API_CALL int GLAD_GL_EXT_read_format_bgra; +#define GL_EXT_render_snorm 1 +GLAD_API_CALL int GLAD_GL_EXT_render_snorm; +#define GL_EXT_robustness 1 +GLAD_API_CALL int GLAD_GL_EXT_robustness; +#define GL_EXT_sRGB 1 +GLAD_API_CALL int GLAD_GL_EXT_sRGB; +#define GL_EXT_sRGB_write_control 1 +GLAD_API_CALL int GLAD_GL_EXT_sRGB_write_control; +#define GL_EXT_semaphore 1 +GLAD_API_CALL int GLAD_GL_EXT_semaphore; +#define GL_EXT_semaphore_fd 1 +GLAD_API_CALL int GLAD_GL_EXT_semaphore_fd; +#define GL_EXT_semaphore_win32 1 +GLAD_API_CALL int GLAD_GL_EXT_semaphore_win32; +#define GL_EXT_separate_depth_stencil 1 +GLAD_API_CALL int GLAD_GL_EXT_separate_depth_stencil; +#define GL_EXT_separate_shader_objects 1 +GLAD_API_CALL int GLAD_GL_EXT_separate_shader_objects; +#define GL_EXT_shader_framebuffer_fetch 1 +GLAD_API_CALL int GLAD_GL_EXT_shader_framebuffer_fetch; +#define GL_EXT_shader_framebuffer_fetch_non_coherent 1 +GLAD_API_CALL int GLAD_GL_EXT_shader_framebuffer_fetch_non_coherent; +#define GL_EXT_shader_group_vote 1 +GLAD_API_CALL int GLAD_GL_EXT_shader_group_vote; +#define GL_EXT_shader_implicit_conversions 1 +GLAD_API_CALL int GLAD_GL_EXT_shader_implicit_conversions; +#define GL_EXT_shader_integer_mix 1 +GLAD_API_CALL int GLAD_GL_EXT_shader_integer_mix; +#define GL_EXT_shader_io_blocks 1 +GLAD_API_CALL int GLAD_GL_EXT_shader_io_blocks; +#define GL_EXT_shader_non_constant_global_initializers 1 +GLAD_API_CALL int GLAD_GL_EXT_shader_non_constant_global_initializers; +#define GL_EXT_shader_pixel_local_storage 1 +GLAD_API_CALL int GLAD_GL_EXT_shader_pixel_local_storage; +#define GL_EXT_shader_pixel_local_storage2 1 +GLAD_API_CALL int GLAD_GL_EXT_shader_pixel_local_storage2; +#define GL_EXT_shader_samples_identical 1 +GLAD_API_CALL int GLAD_GL_EXT_shader_samples_identical; +#define GL_EXT_shader_texture_lod 1 +GLAD_API_CALL int GLAD_GL_EXT_shader_texture_lod; +#define GL_EXT_shadow_samplers 1 +GLAD_API_CALL int GLAD_GL_EXT_shadow_samplers; +#define GL_EXT_sparse_texture 1 +GLAD_API_CALL int GLAD_GL_EXT_sparse_texture; +#define GL_EXT_sparse_texture2 1 +GLAD_API_CALL int GLAD_GL_EXT_sparse_texture2; +#define GL_EXT_tessellation_point_size 1 +GLAD_API_CALL int GLAD_GL_EXT_tessellation_point_size; +#define GL_EXT_tessellation_shader 1 +GLAD_API_CALL int GLAD_GL_EXT_tessellation_shader; +#define GL_EXT_texture_border_clamp 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_border_clamp; +#define GL_EXT_texture_buffer 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_buffer; +#define GL_EXT_texture_compression_astc_decode_mode 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_compression_astc_decode_mode; +#define GL_EXT_texture_compression_bptc 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_compression_bptc; +#define GL_EXT_texture_compression_dxt1 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_compression_dxt1; +#define GL_EXT_texture_compression_rgtc 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_compression_rgtc; +#define GL_EXT_texture_compression_s3tc 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_compression_s3tc; +#define GL_EXT_texture_compression_s3tc_srgb 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_compression_s3tc_srgb; +#define GL_EXT_texture_cube_map_array 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_cube_map_array; +#define GL_EXT_texture_filter_anisotropic 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_filter_anisotropic; +#define GL_EXT_texture_filter_minmax 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_filter_minmax; +#define GL_EXT_texture_format_BGRA8888 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_format_BGRA8888; +#define GL_EXT_texture_format_sRGB_override 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_format_sRGB_override; +#define GL_EXT_texture_mirror_clamp_to_edge 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_mirror_clamp_to_edge; +#define GL_EXT_texture_norm16 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_norm16; +#define GL_EXT_texture_query_lod 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_query_lod; +#define GL_EXT_texture_rg 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_rg; +#define GL_EXT_texture_sRGB_R8 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_sRGB_R8; +#define GL_EXT_texture_sRGB_RG8 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_sRGB_RG8; +#define GL_EXT_texture_sRGB_decode 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_sRGB_decode; +#define GL_EXT_texture_shadow_lod 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_shadow_lod; +#define GL_EXT_texture_storage 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_storage; +#define GL_EXT_texture_storage_compression 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_storage_compression; +#define GL_EXT_texture_type_2_10_10_10_REV 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_type_2_10_10_10_REV; +#define GL_EXT_texture_view 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_view; +#define GL_EXT_unpack_subimage 1 +GLAD_API_CALL int GLAD_GL_EXT_unpack_subimage; +#define GL_EXT_win32_keyed_mutex 1 +GLAD_API_CALL int GLAD_GL_EXT_win32_keyed_mutex; +#define GL_EXT_window_rectangles 1 +GLAD_API_CALL int GLAD_GL_EXT_window_rectangles; +#define GL_KHR_blend_equation_advanced 1 +GLAD_API_CALL int GLAD_GL_KHR_blend_equation_advanced; +#define GL_KHR_blend_equation_advanced_coherent 1 +GLAD_API_CALL int GLAD_GL_KHR_blend_equation_advanced_coherent; +#define GL_KHR_context_flush_control 1 +GLAD_API_CALL int GLAD_GL_KHR_context_flush_control; +#define GL_KHR_debug 1 +GLAD_API_CALL int GLAD_GL_KHR_debug; +#define GL_KHR_no_error 1 +GLAD_API_CALL int GLAD_GL_KHR_no_error; +#define GL_KHR_parallel_shader_compile 1 +GLAD_API_CALL int GLAD_GL_KHR_parallel_shader_compile; +#define GL_KHR_robust_buffer_access_behavior 1 +GLAD_API_CALL int GLAD_GL_KHR_robust_buffer_access_behavior; +#define GL_KHR_robustness 1 +GLAD_API_CALL int GLAD_GL_KHR_robustness; +#define GL_KHR_shader_subgroup 1 +GLAD_API_CALL int GLAD_GL_KHR_shader_subgroup; +#define GL_KHR_texture_compression_astc_hdr 1 +GLAD_API_CALL int GLAD_GL_KHR_texture_compression_astc_hdr; +#define GL_KHR_texture_compression_astc_ldr 1 +GLAD_API_CALL int GLAD_GL_KHR_texture_compression_astc_ldr; +#define GL_KHR_texture_compression_astc_sliced_3d 1 +GLAD_API_CALL int GLAD_GL_KHR_texture_compression_astc_sliced_3d; +#define GL_OES_EGL_image 1 +GLAD_API_CALL int GLAD_GL_OES_EGL_image; +#define GL_OES_EGL_image_external 1 +GLAD_API_CALL int GLAD_GL_OES_EGL_image_external; +#define GL_OES_EGL_image_external_essl3 1 +GLAD_API_CALL int GLAD_GL_OES_EGL_image_external_essl3; +#define GL_OES_compressed_ETC1_RGB8_sub_texture 1 +GLAD_API_CALL int GLAD_GL_OES_compressed_ETC1_RGB8_sub_texture; +#define GL_OES_compressed_ETC1_RGB8_texture 1 +GLAD_API_CALL int GLAD_GL_OES_compressed_ETC1_RGB8_texture; +#define GL_OES_compressed_paletted_texture 1 +GLAD_API_CALL int GLAD_GL_OES_compressed_paletted_texture; +#define GL_OES_copy_image 1 +GLAD_API_CALL int GLAD_GL_OES_copy_image; +#define GL_OES_depth24 1 +GLAD_API_CALL int GLAD_GL_OES_depth24; +#define GL_OES_depth32 1 +GLAD_API_CALL int GLAD_GL_OES_depth32; +#define GL_OES_depth_texture 1 +GLAD_API_CALL int GLAD_GL_OES_depth_texture; +#define GL_OES_draw_buffers_indexed 1 +GLAD_API_CALL int GLAD_GL_OES_draw_buffers_indexed; +#define GL_OES_draw_elements_base_vertex 1 +GLAD_API_CALL int GLAD_GL_OES_draw_elements_base_vertex; +#define GL_OES_element_index_uint 1 +GLAD_API_CALL int GLAD_GL_OES_element_index_uint; +#define GL_OES_fbo_render_mipmap 1 +GLAD_API_CALL int GLAD_GL_OES_fbo_render_mipmap; +#define GL_OES_fragment_precision_high 1 +GLAD_API_CALL int GLAD_GL_OES_fragment_precision_high; +#define GL_OES_geometry_point_size 1 +GLAD_API_CALL int GLAD_GL_OES_geometry_point_size; +#define GL_OES_geometry_shader 1 +GLAD_API_CALL int GLAD_GL_OES_geometry_shader; +#define GL_OES_get_program_binary 1 +GLAD_API_CALL int GLAD_GL_OES_get_program_binary; +#define GL_OES_gpu_shader5 1 +GLAD_API_CALL int GLAD_GL_OES_gpu_shader5; +#define GL_OES_mapbuffer 1 +GLAD_API_CALL int GLAD_GL_OES_mapbuffer; +#define GL_OES_packed_depth_stencil 1 +GLAD_API_CALL int GLAD_GL_OES_packed_depth_stencil; +#define GL_OES_primitive_bounding_box 1 +GLAD_API_CALL int GLAD_GL_OES_primitive_bounding_box; +#define GL_OES_required_internalformat 1 +GLAD_API_CALL int GLAD_GL_OES_required_internalformat; +#define GL_OES_rgb8_rgba8 1 +GLAD_API_CALL int GLAD_GL_OES_rgb8_rgba8; +#define GL_OES_sample_shading 1 +GLAD_API_CALL int GLAD_GL_OES_sample_shading; +#define GL_OES_sample_variables 1 +GLAD_API_CALL int GLAD_GL_OES_sample_variables; +#define GL_OES_shader_image_atomic 1 +GLAD_API_CALL int GLAD_GL_OES_shader_image_atomic; +#define GL_OES_shader_io_blocks 1 +GLAD_API_CALL int GLAD_GL_OES_shader_io_blocks; +#define GL_OES_shader_multisample_interpolation 1 +GLAD_API_CALL int GLAD_GL_OES_shader_multisample_interpolation; +#define GL_OES_standard_derivatives 1 +GLAD_API_CALL int GLAD_GL_OES_standard_derivatives; +#define GL_OES_stencil1 1 +GLAD_API_CALL int GLAD_GL_OES_stencil1; +#define GL_OES_stencil4 1 +GLAD_API_CALL int GLAD_GL_OES_stencil4; +#define GL_OES_surfaceless_context 1 +GLAD_API_CALL int GLAD_GL_OES_surfaceless_context; +#define GL_OES_tessellation_point_size 1 +GLAD_API_CALL int GLAD_GL_OES_tessellation_point_size; +#define GL_OES_tessellation_shader 1 +GLAD_API_CALL int GLAD_GL_OES_tessellation_shader; +#define GL_OES_texture_3D 1 +GLAD_API_CALL int GLAD_GL_OES_texture_3D; +#define GL_OES_texture_border_clamp 1 +GLAD_API_CALL int GLAD_GL_OES_texture_border_clamp; +#define GL_OES_texture_buffer 1 +GLAD_API_CALL int GLAD_GL_OES_texture_buffer; +#define GL_OES_texture_compression_astc 1 +GLAD_API_CALL int GLAD_GL_OES_texture_compression_astc; +#define GL_OES_texture_cube_map_array 1 +GLAD_API_CALL int GLAD_GL_OES_texture_cube_map_array; +#define GL_OES_texture_float 1 +GLAD_API_CALL int GLAD_GL_OES_texture_float; +#define GL_OES_texture_float_linear 1 +GLAD_API_CALL int GLAD_GL_OES_texture_float_linear; +#define GL_OES_texture_half_float 1 +GLAD_API_CALL int GLAD_GL_OES_texture_half_float; +#define GL_OES_texture_half_float_linear 1 +GLAD_API_CALL int GLAD_GL_OES_texture_half_float_linear; +#define GL_OES_texture_npot 1 +GLAD_API_CALL int GLAD_GL_OES_texture_npot; +#define GL_OES_texture_stencil8 1 +GLAD_API_CALL int GLAD_GL_OES_texture_stencil8; +#define GL_OES_texture_storage_multisample_2d_array 1 +GLAD_API_CALL int GLAD_GL_OES_texture_storage_multisample_2d_array; +#define GL_OES_texture_view 1 +GLAD_API_CALL int GLAD_GL_OES_texture_view; +#define GL_OES_vertex_array_object 1 +GLAD_API_CALL int GLAD_GL_OES_vertex_array_object; +#define GL_OES_vertex_half_float 1 +GLAD_API_CALL int GLAD_GL_OES_vertex_half_float; +#define GL_OES_vertex_type_10_10_10_2 1 +GLAD_API_CALL int GLAD_GL_OES_vertex_type_10_10_10_2; +#define GL_OES_viewport_array 1 +GLAD_API_CALL int GLAD_GL_OES_viewport_array; + + +typedef GLboolean (GLAD_API_PTR *PFNGLACQUIREKEYEDMUTEXWIN32EXTPROC)(GLuint memory, GLuint64 key, GLuint timeout); +typedef void (GLAD_API_PTR *PFNGLACTIVESHADERPROGRAMEXTPROC)(GLuint pipeline, GLuint program); +typedef void (GLAD_API_PTR *PFNGLACTIVETEXTUREPROC)(GLenum texture); +typedef void (GLAD_API_PTR *PFNGLATTACHSHADERPROC)(GLuint program, GLuint shader); +typedef void (GLAD_API_PTR *PFNGLBEGINQUERYEXTPROC)(GLenum target, GLuint id); +typedef void (GLAD_API_PTR *PFNGLBINDATTRIBLOCATIONPROC)(GLuint program, GLuint index, const GLchar * name); +typedef void (GLAD_API_PTR *PFNGLBINDBUFFERPROC)(GLenum target, GLuint buffer); +typedef void (GLAD_API_PTR *PFNGLBINDFRAGDATALOCATIONEXTPROC)(GLuint program, GLuint color, const GLchar * name); +typedef void (GLAD_API_PTR *PFNGLBINDFRAGDATALOCATIONINDEXEDEXTPROC)(GLuint program, GLuint colorNumber, GLuint index, const GLchar * name); +typedef void (GLAD_API_PTR *PFNGLBINDFRAMEBUFFERPROC)(GLenum target, GLuint framebuffer); +typedef void (GLAD_API_PTR *PFNGLBINDPROGRAMPIPELINEEXTPROC)(GLuint pipeline); +typedef void (GLAD_API_PTR *PFNGLBINDRENDERBUFFERPROC)(GLenum target, GLuint renderbuffer); +typedef void (GLAD_API_PTR *PFNGLBINDTEXTUREPROC)(GLenum target, GLuint texture); +typedef void (GLAD_API_PTR *PFNGLBINDVERTEXARRAYOESPROC)(GLuint array); +typedef void (GLAD_API_PTR *PFNGLBLENDBARRIERKHRPROC)(void); +typedef void (GLAD_API_PTR *PFNGLBLENDCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +typedef void (GLAD_API_PTR *PFNGLBLENDEQUATIONPROC)(GLenum mode); +typedef void (GLAD_API_PTR *PFNGLBLENDEQUATIONSEPARATEPROC)(GLenum modeRGB, GLenum modeAlpha); +typedef void (GLAD_API_PTR *PFNGLBLENDEQUATIONSEPARATEIEXTPROC)(GLuint buf, GLenum modeRGB, GLenum modeAlpha); +typedef void (GLAD_API_PTR *PFNGLBLENDEQUATIONSEPARATEIOESPROC)(GLuint buf, GLenum modeRGB, GLenum modeAlpha); +typedef void (GLAD_API_PTR *PFNGLBLENDEQUATIONIEXTPROC)(GLuint buf, GLenum mode); +typedef void (GLAD_API_PTR *PFNGLBLENDEQUATIONIOESPROC)(GLuint buf, GLenum mode); +typedef void (GLAD_API_PTR *PFNGLBLENDFUNCPROC)(GLenum sfactor, GLenum dfactor); +typedef void (GLAD_API_PTR *PFNGLBLENDFUNCSEPARATEPROC)(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); +typedef void (GLAD_API_PTR *PFNGLBLENDFUNCSEPARATEIEXTPROC)(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); +typedef void (GLAD_API_PTR *PFNGLBLENDFUNCSEPARATEIOESPROC)(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); +typedef void (GLAD_API_PTR *PFNGLBLENDFUNCIEXTPROC)(GLuint buf, GLenum src, GLenum dst); +typedef void (GLAD_API_PTR *PFNGLBLENDFUNCIOESPROC)(GLuint buf, GLenum src, GLenum dst); +typedef void (GLAD_API_PTR *PFNGLBUFFERDATAPROC)(GLenum target, GLsizeiptr size, const void * data, GLenum usage); +typedef void (GLAD_API_PTR *PFNGLBUFFERSTORAGEEXTPROC)(GLenum target, GLsizeiptr size, const void * data, GLbitfield flags); +typedef void (GLAD_API_PTR *PFNGLBUFFERSTORAGEEXTERNALEXTPROC)(GLenum target, GLintptr offset, GLsizeiptr size, GLeglClientBufferEXT clientBuffer, GLbitfield flags); +typedef void (GLAD_API_PTR *PFNGLBUFFERSTORAGEMEMEXTPROC)(GLenum target, GLsizeiptr size, GLuint memory, GLuint64 offset); +typedef void (GLAD_API_PTR *PFNGLBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, const void * data); +typedef GLenum (GLAD_API_PTR *PFNGLCHECKFRAMEBUFFERSTATUSPROC)(GLenum target); +typedef void (GLAD_API_PTR *PFNGLCLEARPROC)(GLbitfield mask); +typedef void (GLAD_API_PTR *PFNGLCLEARCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +typedef void (GLAD_API_PTR *PFNGLCLEARDEPTHFPROC)(GLfloat d); +typedef void (GLAD_API_PTR *PFNGLCLEARPIXELLOCALSTORAGEUIEXTPROC)(GLsizei offset, GLsizei n, const GLuint * values); +typedef void (GLAD_API_PTR *PFNGLCLEARSTENCILPROC)(GLint s); +typedef void (GLAD_API_PTR *PFNGLCLEARTEXIMAGEEXTPROC)(GLuint texture, GLint level, GLenum format, GLenum type, const void * data); +typedef void (GLAD_API_PTR *PFNGLCLEARTEXSUBIMAGEEXTPROC)(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void * data); +typedef void (GLAD_API_PTR *PFNGLCLIPCONTROLEXTPROC)(GLenum origin, GLenum depth); +typedef void (GLAD_API_PTR *PFNGLCOLORMASKPROC)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); +typedef void (GLAD_API_PTR *PFNGLCOLORMASKIEXTPROC)(GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); +typedef void (GLAD_API_PTR *PFNGLCOLORMASKIOESPROC)(GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); +typedef void (GLAD_API_PTR *PFNGLCOMPILESHADERPROC)(GLuint shader); +typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void * data); +typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXIMAGE3DOESPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void * data); +typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void * data); +typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXSUBIMAGE3DOESPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void * data); +typedef void (GLAD_API_PTR *PFNGLCOPYIMAGESUBDATAEXTPROC)(GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth); +typedef void (GLAD_API_PTR *PFNGLCOPYIMAGESUBDATAOESPROC)(GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth); +typedef void (GLAD_API_PTR *PFNGLCOPYTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +typedef void (GLAD_API_PTR *PFNGLCOPYTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (GLAD_API_PTR *PFNGLCOPYTEXSUBIMAGE3DOESPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (GLAD_API_PTR *PFNGLCREATEMEMORYOBJECTSEXTPROC)(GLsizei n, GLuint * memoryObjects); +typedef GLuint (GLAD_API_PTR *PFNGLCREATEPROGRAMPROC)(void); +typedef GLuint (GLAD_API_PTR *PFNGLCREATESHADERPROC)(GLenum type); +typedef GLuint (GLAD_API_PTR *PFNGLCREATESHADERPROGRAMVEXTPROC)(GLenum type, GLsizei count, const GLchar *const* strings); +typedef void (GLAD_API_PTR *PFNGLCULLFACEPROC)(GLenum mode); +typedef void (GLAD_API_PTR *PFNGLDEBUGMESSAGECALLBACKKHRPROC)(GLDEBUGPROCKHR callback, const void * userParam); +typedef void (GLAD_API_PTR *PFNGLDEBUGMESSAGECONTROLKHRPROC)(GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint * ids, GLboolean enabled); +typedef void (GLAD_API_PTR *PFNGLDEBUGMESSAGEINSERTKHRPROC)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar * buf); +typedef void (GLAD_API_PTR *PFNGLDELETEBUFFERSPROC)(GLsizei n, const GLuint * buffers); +typedef void (GLAD_API_PTR *PFNGLDELETEFRAMEBUFFERSPROC)(GLsizei n, const GLuint * framebuffers); +typedef void (GLAD_API_PTR *PFNGLDELETEMEMORYOBJECTSEXTPROC)(GLsizei n, const GLuint * memoryObjects); +typedef void (GLAD_API_PTR *PFNGLDELETEPROGRAMPROC)(GLuint program); +typedef void (GLAD_API_PTR *PFNGLDELETEPROGRAMPIPELINESEXTPROC)(GLsizei n, const GLuint * pipelines); +typedef void (GLAD_API_PTR *PFNGLDELETEQUERIESEXTPROC)(GLsizei n, const GLuint * ids); +typedef void (GLAD_API_PTR *PFNGLDELETERENDERBUFFERSPROC)(GLsizei n, const GLuint * renderbuffers); +typedef void (GLAD_API_PTR *PFNGLDELETESEMAPHORESEXTPROC)(GLsizei n, const GLuint * semaphores); +typedef void (GLAD_API_PTR *PFNGLDELETESHADERPROC)(GLuint shader); +typedef void (GLAD_API_PTR *PFNGLDELETETEXTURESPROC)(GLsizei n, const GLuint * textures); +typedef void (GLAD_API_PTR *PFNGLDELETEVERTEXARRAYSOESPROC)(GLsizei n, const GLuint * arrays); +typedef void (GLAD_API_PTR *PFNGLDEPTHFUNCPROC)(GLenum func); +typedef void (GLAD_API_PTR *PFNGLDEPTHMASKPROC)(GLboolean flag); +typedef void (GLAD_API_PTR *PFNGLDEPTHRANGEARRAYFVOESPROC)(GLuint first, GLsizei count, const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLDEPTHRANGEINDEXEDFOESPROC)(GLuint index, GLfloat n, GLfloat f); +typedef void (GLAD_API_PTR *PFNGLDEPTHRANGEFPROC)(GLfloat n, GLfloat f); +typedef void (GLAD_API_PTR *PFNGLDETACHSHADERPROC)(GLuint program, GLuint shader); +typedef void (GLAD_API_PTR *PFNGLDISABLEPROC)(GLenum cap); +typedef void (GLAD_API_PTR *PFNGLDISABLEVERTEXATTRIBARRAYPROC)(GLuint index); +typedef void (GLAD_API_PTR *PFNGLDISABLEIEXTPROC)(GLenum target, GLuint index); +typedef void (GLAD_API_PTR *PFNGLDISABLEIOESPROC)(GLenum target, GLuint index); +typedef void (GLAD_API_PTR *PFNGLDISCARDFRAMEBUFFEREXTPROC)(GLenum target, GLsizei numAttachments, const GLenum * attachments); +typedef void (GLAD_API_PTR *PFNGLDRAWARRAYSPROC)(GLenum mode, GLint first, GLsizei count); +typedef void (GLAD_API_PTR *PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEEXTPROC)(GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance); +typedef void (GLAD_API_PTR *PFNGLDRAWARRAYSINSTANCEDEXTPROC)(GLenum mode, GLint start, GLsizei count, GLsizei primcount); +typedef void (GLAD_API_PTR *PFNGLDRAWBUFFERSEXTPROC)(GLsizei n, const GLenum * bufs); +typedef void (GLAD_API_PTR *PFNGLDRAWBUFFERSINDEXEDEXTPROC)(GLint n, const GLenum * location, const GLint * indices); +typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices); +typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSBASEVERTEXEXTPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices, GLint basevertex); +typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSBASEVERTEXOESPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices, GLint basevertex); +typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEEXTPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices, GLsizei instancecount, GLuint baseinstance); +typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEEXTPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance); +typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXEXTPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices, GLsizei instancecount, GLint basevertex); +typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXOESPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices, GLsizei instancecount, GLint basevertex); +typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSINSTANCEDEXTPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices, GLsizei primcount); +typedef void (GLAD_API_PTR *PFNGLDRAWRANGEELEMENTSBASEVERTEXEXTPROC)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void * indices, GLint basevertex); +typedef void (GLAD_API_PTR *PFNGLDRAWRANGEELEMENTSBASEVERTEXOESPROC)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void * indices, GLint basevertex); +typedef void (GLAD_API_PTR *PFNGLDRAWTRANSFORMFEEDBACKEXTPROC)(GLenum mode, GLuint id); +typedef void (GLAD_API_PTR *PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDEXTPROC)(GLenum mode, GLuint id, GLsizei instancecount); +typedef void (GLAD_API_PTR *PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC)(GLenum target, GLeglImageOES image); +typedef void (GLAD_API_PTR *PFNGLEGLIMAGETARGETTEXSTORAGEEXTPROC)(GLenum target, GLeglImageOES image, const GLint * attrib_list); +typedef void (GLAD_API_PTR *PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)(GLenum target, GLeglImageOES image); +typedef void (GLAD_API_PTR *PFNGLEGLIMAGETARGETTEXTURESTORAGEEXTPROC)(GLuint texture, GLeglImageOES image, const GLint * attrib_list); +typedef void (GLAD_API_PTR *PFNGLENABLEPROC)(GLenum cap); +typedef void (GLAD_API_PTR *PFNGLENABLEVERTEXATTRIBARRAYPROC)(GLuint index); +typedef void (GLAD_API_PTR *PFNGLENABLEIEXTPROC)(GLenum target, GLuint index); +typedef void (GLAD_API_PTR *PFNGLENABLEIOESPROC)(GLenum target, GLuint index); +typedef void (GLAD_API_PTR *PFNGLENDQUERYEXTPROC)(GLenum target); +typedef void (GLAD_API_PTR *PFNGLFINISHPROC)(void); +typedef void (GLAD_API_PTR *PFNGLFLUSHPROC)(void); +typedef void (GLAD_API_PTR *PFNGLFLUSHMAPPEDBUFFERRANGEEXTPROC)(GLenum target, GLintptr offset, GLsizeiptr length); +typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERFETCHBARRIEREXTPROC)(void); +typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC)(GLuint target, GLsizei size); +typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERRENDERBUFFERPROC)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERSHADINGRATEEXTPROC)(GLenum target, GLenum attachment, GLuint texture, GLint baseLayer, GLsizei numLayers, GLsizei texelWidth, GLsizei texelHeight); +typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURE2DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples); +typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURE3DOESPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); +typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTUREEXTPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level); +typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTUREOESPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level); +typedef void (GLAD_API_PTR *PFNGLFRONTFACEPROC)(GLenum mode); +typedef void (GLAD_API_PTR *PFNGLGENBUFFERSPROC)(GLsizei n, GLuint * buffers); +typedef void (GLAD_API_PTR *PFNGLGENFRAMEBUFFERSPROC)(GLsizei n, GLuint * framebuffers); +typedef void (GLAD_API_PTR *PFNGLGENPROGRAMPIPELINESEXTPROC)(GLsizei n, GLuint * pipelines); +typedef void (GLAD_API_PTR *PFNGLGENQUERIESEXTPROC)(GLsizei n, GLuint * ids); +typedef void (GLAD_API_PTR *PFNGLGENRENDERBUFFERSPROC)(GLsizei n, GLuint * renderbuffers); +typedef void (GLAD_API_PTR *PFNGLGENSEMAPHORESEXTPROC)(GLsizei n, GLuint * semaphores); +typedef void (GLAD_API_PTR *PFNGLGENTEXTURESPROC)(GLsizei n, GLuint * textures); +typedef void (GLAD_API_PTR *PFNGLGENVERTEXARRAYSOESPROC)(GLsizei n, GLuint * arrays); +typedef void (GLAD_API_PTR *PFNGLGENERATEMIPMAPPROC)(GLenum target); +typedef void (GLAD_API_PTR *PFNGLGETACTIVEATTRIBPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei * length, GLint * size, GLenum * type, GLchar * name); +typedef void (GLAD_API_PTR *PFNGLGETACTIVEUNIFORMPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei * length, GLint * size, GLenum * type, GLchar * name); +typedef void (GLAD_API_PTR *PFNGLGETATTACHEDSHADERSPROC)(GLuint program, GLsizei maxCount, GLsizei * count, GLuint * shaders); +typedef GLint (GLAD_API_PTR *PFNGLGETATTRIBLOCATIONPROC)(GLuint program, const GLchar * name); +typedef void (GLAD_API_PTR *PFNGLGETBOOLEANVPROC)(GLenum pname, GLboolean * data); +typedef void (GLAD_API_PTR *PFNGLGETBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETBUFFERPOINTERVOESPROC)(GLenum target, GLenum pname, void ** params); +typedef GLuint (GLAD_API_PTR *PFNGLGETDEBUGMESSAGELOGKHRPROC)(GLuint count, GLsizei bufSize, GLenum * sources, GLenum * types, GLuint * ids, GLenum * severities, GLsizei * lengths, GLchar * messageLog); +typedef GLenum (GLAD_API_PTR *PFNGLGETERRORPROC)(void); +typedef void (GLAD_API_PTR *PFNGLGETFLOATI_VOESPROC)(GLenum target, GLuint index, GLfloat * data); +typedef void (GLAD_API_PTR *PFNGLGETFLOATVPROC)(GLenum pname, GLfloat * data); +typedef GLint (GLAD_API_PTR *PFNGLGETFRAGDATAINDEXEXTPROC)(GLuint program, const GLchar * name); +typedef void (GLAD_API_PTR *PFNGLGETFRAGMENTSHADINGRATESEXTPROC)(GLsizei samples, GLsizei maxCount, GLsizei * count, GLenum * shadingRates); +typedef void (GLAD_API_PTR *PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)(GLenum target, GLenum attachment, GLenum pname, GLint * params); +typedef GLsizei (GLAD_API_PTR *PFNGLGETFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC)(GLuint target); +typedef GLenum (GLAD_API_PTR *PFNGLGETGRAPHICSRESETSTATUSEXTPROC)(void); +typedef GLenum (GLAD_API_PTR *PFNGLGETGRAPHICSRESETSTATUSKHRPROC)(void); +typedef void (GLAD_API_PTR *PFNGLGETINTEGER64VEXTPROC)(GLenum pname, GLint64 * data); +typedef void (GLAD_API_PTR *PFNGLGETINTEGERI_VEXTPROC)(GLenum target, GLuint index, GLint * data); +typedef void (GLAD_API_PTR *PFNGLGETINTEGERVPROC)(GLenum pname, GLint * data); +typedef void (GLAD_API_PTR *PFNGLGETMEMORYOBJECTPARAMETERIVEXTPROC)(GLuint memoryObject, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETOBJECTLABELEXTPROC)(GLenum type, GLuint object, GLsizei bufSize, GLsizei * length, GLchar * label); +typedef void (GLAD_API_PTR *PFNGLGETOBJECTLABELKHRPROC)(GLenum identifier, GLuint name, GLsizei bufSize, GLsizei * length, GLchar * label); +typedef void (GLAD_API_PTR *PFNGLGETOBJECTPTRLABELKHRPROC)(const void * ptr, GLsizei bufSize, GLsizei * length, GLchar * label); +typedef void (GLAD_API_PTR *PFNGLGETPOINTERVKHRPROC)(GLenum pname, void ** params); +typedef void (GLAD_API_PTR *PFNGLGETPROGRAMBINARYOESPROC)(GLuint program, GLsizei bufSize, GLsizei * length, GLenum * binaryFormat, void * binary); +typedef void (GLAD_API_PTR *PFNGLGETPROGRAMINFOLOGPROC)(GLuint program, GLsizei bufSize, GLsizei * length, GLchar * infoLog); +typedef void (GLAD_API_PTR *PFNGLGETPROGRAMPIPELINEINFOLOGEXTPROC)(GLuint pipeline, GLsizei bufSize, GLsizei * length, GLchar * infoLog); +typedef void (GLAD_API_PTR *PFNGLGETPROGRAMPIPELINEIVEXTPROC)(GLuint pipeline, GLenum pname, GLint * params); +typedef GLint (GLAD_API_PTR *PFNGLGETPROGRAMRESOURCELOCATIONINDEXEXTPROC)(GLuint program, GLenum programInterface, const GLchar * name); +typedef void (GLAD_API_PTR *PFNGLGETPROGRAMIVPROC)(GLuint program, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETQUERYOBJECTI64VEXTPROC)(GLuint id, GLenum pname, GLint64 * params); +typedef void (GLAD_API_PTR *PFNGLGETQUERYOBJECTIVEXTPROC)(GLuint id, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETQUERYOBJECTUI64VEXTPROC)(GLuint id, GLenum pname, GLuint64 * params); +typedef void (GLAD_API_PTR *PFNGLGETQUERYOBJECTUIVEXTPROC)(GLuint id, GLenum pname, GLuint * params); +typedef void (GLAD_API_PTR *PFNGLGETQUERYIVEXTPROC)(GLenum target, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETRENDERBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETSAMPLERPARAMETERIIVEXTPROC)(GLuint sampler, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETSAMPLERPARAMETERIIVOESPROC)(GLuint sampler, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETSAMPLERPARAMETERIUIVEXTPROC)(GLuint sampler, GLenum pname, GLuint * params); +typedef void (GLAD_API_PTR *PFNGLGETSAMPLERPARAMETERIUIVOESPROC)(GLuint sampler, GLenum pname, GLuint * params); +typedef void (GLAD_API_PTR *PFNGLGETSEMAPHOREPARAMETERUI64VEXTPROC)(GLuint semaphore, GLenum pname, GLuint64 * params); +typedef void (GLAD_API_PTR *PFNGLGETSHADERINFOLOGPROC)(GLuint shader, GLsizei bufSize, GLsizei * length, GLchar * infoLog); +typedef void (GLAD_API_PTR *PFNGLGETSHADERPRECISIONFORMATPROC)(GLenum shadertype, GLenum precisiontype, GLint * range, GLint * precision); +typedef void (GLAD_API_PTR *PFNGLGETSHADERSOURCEPROC)(GLuint shader, GLsizei bufSize, GLsizei * length, GLchar * source); +typedef void (GLAD_API_PTR *PFNGLGETSHADERIVPROC)(GLuint shader, GLenum pname, GLint * params); +typedef const GLubyte * (GLAD_API_PTR *PFNGLGETSTRINGPROC)(GLenum name); +typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERIIVEXTPROC)(GLenum target, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERIIVOESPROC)(GLenum target, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERIUIVEXTPROC)(GLenum target, GLenum pname, GLuint * params); +typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERIUIVOESPROC)(GLenum target, GLenum pname, GLuint * params); +typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERFVPROC)(GLenum target, GLenum pname, GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERIVPROC)(GLenum target, GLenum pname, GLint * params); +typedef GLint (GLAD_API_PTR *PFNGLGETUNIFORMLOCATIONPROC)(GLuint program, const GLchar * name); +typedef void (GLAD_API_PTR *PFNGLGETUNIFORMFVPROC)(GLuint program, GLint location, GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLGETUNIFORMIVPROC)(GLuint program, GLint location, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETUNSIGNEDBYTEI_VEXTPROC)(GLenum target, GLuint index, GLubyte * data); +typedef void (GLAD_API_PTR *PFNGLGETUNSIGNEDBYTEVEXTPROC)(GLenum pname, GLubyte * data); +typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBPOINTERVPROC)(GLuint index, GLenum pname, void ** pointer); +typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBFVPROC)(GLuint index, GLenum pname, GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBIVPROC)(GLuint index, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETNUNIFORMFVEXTPROC)(GLuint program, GLint location, GLsizei bufSize, GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLGETNUNIFORMFVKHRPROC)(GLuint program, GLint location, GLsizei bufSize, GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLGETNUNIFORMIVEXTPROC)(GLuint program, GLint location, GLsizei bufSize, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETNUNIFORMIVKHRPROC)(GLuint program, GLint location, GLsizei bufSize, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETNUNIFORMUIVKHRPROC)(GLuint program, GLint location, GLsizei bufSize, GLuint * params); +typedef void (GLAD_API_PTR *PFNGLHINTPROC)(GLenum target, GLenum mode); +typedef void (GLAD_API_PTR *PFNGLIMPORTMEMORYFDEXTPROC)(GLuint memory, GLuint64 size, GLenum handleType, GLint fd); +typedef void (GLAD_API_PTR *PFNGLIMPORTMEMORYWIN32HANDLEEXTPROC)(GLuint memory, GLuint64 size, GLenum handleType, void * handle); +typedef void (GLAD_API_PTR *PFNGLIMPORTMEMORYWIN32NAMEEXTPROC)(GLuint memory, GLuint64 size, GLenum handleType, const void * name); +typedef void (GLAD_API_PTR *PFNGLIMPORTSEMAPHOREFDEXTPROC)(GLuint semaphore, GLenum handleType, GLint fd); +typedef void (GLAD_API_PTR *PFNGLIMPORTSEMAPHOREWIN32HANDLEEXTPROC)(GLuint semaphore, GLenum handleType, void * handle); +typedef void (GLAD_API_PTR *PFNGLIMPORTSEMAPHOREWIN32NAMEEXTPROC)(GLuint semaphore, GLenum handleType, const void * name); +typedef void (GLAD_API_PTR *PFNGLINSERTEVENTMARKEREXTPROC)(GLsizei length, const GLchar * marker); +typedef GLboolean (GLAD_API_PTR *PFNGLISBUFFERPROC)(GLuint buffer); +typedef GLboolean (GLAD_API_PTR *PFNGLISENABLEDPROC)(GLenum cap); +typedef GLboolean (GLAD_API_PTR *PFNGLISENABLEDIEXTPROC)(GLenum target, GLuint index); +typedef GLboolean (GLAD_API_PTR *PFNGLISENABLEDIOESPROC)(GLenum target, GLuint index); +typedef GLboolean (GLAD_API_PTR *PFNGLISFRAMEBUFFERPROC)(GLuint framebuffer); +typedef GLboolean (GLAD_API_PTR *PFNGLISMEMORYOBJECTEXTPROC)(GLuint memoryObject); +typedef GLboolean (GLAD_API_PTR *PFNGLISPROGRAMPROC)(GLuint program); +typedef GLboolean (GLAD_API_PTR *PFNGLISPROGRAMPIPELINEEXTPROC)(GLuint pipeline); +typedef GLboolean (GLAD_API_PTR *PFNGLISQUERYEXTPROC)(GLuint id); +typedef GLboolean (GLAD_API_PTR *PFNGLISRENDERBUFFERPROC)(GLuint renderbuffer); +typedef GLboolean (GLAD_API_PTR *PFNGLISSEMAPHOREEXTPROC)(GLuint semaphore); +typedef GLboolean (GLAD_API_PTR *PFNGLISSHADERPROC)(GLuint shader); +typedef GLboolean (GLAD_API_PTR *PFNGLISTEXTUREPROC)(GLuint texture); +typedef GLboolean (GLAD_API_PTR *PFNGLISVERTEXARRAYOESPROC)(GLuint array); +typedef void (GLAD_API_PTR *PFNGLLABELOBJECTEXTPROC)(GLenum type, GLuint object, GLsizei length, const GLchar * label); +typedef void (GLAD_API_PTR *PFNGLLINEWIDTHPROC)(GLfloat width); +typedef void (GLAD_API_PTR *PFNGLLINKPROGRAMPROC)(GLuint program); +typedef void * (GLAD_API_PTR *PFNGLMAPBUFFEROESPROC)(GLenum target, GLenum access); +typedef void * (GLAD_API_PTR *PFNGLMAPBUFFERRANGEEXTPROC)(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); +typedef void (GLAD_API_PTR *PFNGLMAXSHADERCOMPILERTHREADSKHRPROC)(GLuint count); +typedef void (GLAD_API_PTR *PFNGLMEMORYOBJECTPARAMETERIVEXTPROC)(GLuint memoryObject, GLenum pname, const GLint * params); +typedef void (GLAD_API_PTR *PFNGLMINSAMPLESHADINGOESPROC)(GLfloat value); +typedef void (GLAD_API_PTR *PFNGLMULTIDRAWARRAYSEXTPROC)(GLenum mode, const GLint * first, const GLsizei * count, GLsizei primcount); +typedef void (GLAD_API_PTR *PFNGLMULTIDRAWARRAYSINDIRECTEXTPROC)(GLenum mode, const void * indirect, GLsizei drawcount, GLsizei stride); +typedef void (GLAD_API_PTR *PFNGLMULTIDRAWELEMENTSBASEVERTEXEXTPROC)(GLenum mode, const GLsizei * count, GLenum type, const void *const* indices, GLsizei drawcount, const GLint * basevertex); +typedef void (GLAD_API_PTR *PFNGLMULTIDRAWELEMENTSEXTPROC)(GLenum mode, const GLsizei * count, GLenum type, const void *const* indices, GLsizei primcount); +typedef void (GLAD_API_PTR *PFNGLMULTIDRAWELEMENTSINDIRECTEXTPROC)(GLenum mode, GLenum type, const void * indirect, GLsizei drawcount, GLsizei stride); +typedef void (GLAD_API_PTR *PFNGLNAMEDBUFFERSTORAGEEXTERNALEXTPROC)(GLuint buffer, GLintptr offset, GLsizeiptr size, GLeglClientBufferEXT clientBuffer, GLbitfield flags); +typedef void (GLAD_API_PTR *PFNGLNAMEDBUFFERSTORAGEMEMEXTPROC)(GLuint buffer, GLsizeiptr size, GLuint memory, GLuint64 offset); +typedef void (GLAD_API_PTR *PFNGLOBJECTLABELKHRPROC)(GLenum identifier, GLuint name, GLsizei length, const GLchar * label); +typedef void (GLAD_API_PTR *PFNGLOBJECTPTRLABELKHRPROC)(const void * ptr, GLsizei length, const GLchar * label); +typedef void (GLAD_API_PTR *PFNGLPATCHPARAMETERIEXTPROC)(GLenum pname, GLint value); +typedef void (GLAD_API_PTR *PFNGLPATCHPARAMETERIOESPROC)(GLenum pname, GLint value); +typedef void (GLAD_API_PTR *PFNGLPIXELSTOREIPROC)(GLenum pname, GLint param); +typedef void (GLAD_API_PTR *PFNGLPOLYGONOFFSETPROC)(GLfloat factor, GLfloat units); +typedef void (GLAD_API_PTR *PFNGLPOLYGONOFFSETCLAMPEXTPROC)(GLfloat factor, GLfloat units, GLfloat clamp); +typedef void (GLAD_API_PTR *PFNGLPOPDEBUGGROUPKHRPROC)(void); +typedef void (GLAD_API_PTR *PFNGLPOPGROUPMARKEREXTPROC)(void); +typedef void (GLAD_API_PTR *PFNGLPRIMITIVEBOUNDINGBOXEXTPROC)(GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW); +typedef void (GLAD_API_PTR *PFNGLPRIMITIVEBOUNDINGBOXOESPROC)(GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW); +typedef void (GLAD_API_PTR *PFNGLPROGRAMBINARYOESPROC)(GLuint program, GLenum binaryFormat, const void * binary, GLint length); +typedef void (GLAD_API_PTR *PFNGLPROGRAMPARAMETERIEXTPROC)(GLuint program, GLenum pname, GLint value); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1FEXTPROC)(GLuint program, GLint location, GLfloat v0); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1FVEXTPROC)(GLuint program, GLint location, GLsizei count, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1IEXTPROC)(GLuint program, GLint location, GLint v0); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1IVEXTPROC)(GLuint program, GLint location, GLsizei count, const GLint * value); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1UIEXTPROC)(GLuint program, GLint location, GLuint v0); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1UIVEXTPROC)(GLuint program, GLint location, GLsizei count, const GLuint * value); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2FEXTPROC)(GLuint program, GLint location, GLfloat v0, GLfloat v1); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2FVEXTPROC)(GLuint program, GLint location, GLsizei count, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2IEXTPROC)(GLuint program, GLint location, GLint v0, GLint v1); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2IVEXTPROC)(GLuint program, GLint location, GLsizei count, const GLint * value); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2UIEXTPROC)(GLuint program, GLint location, GLuint v0, GLuint v1); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2UIVEXTPROC)(GLuint program, GLint location, GLsizei count, const GLuint * value); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3FEXTPROC)(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3FVEXTPROC)(GLuint program, GLint location, GLsizei count, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3IEXTPROC)(GLuint program, GLint location, GLint v0, GLint v1, GLint v2); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3IVEXTPROC)(GLuint program, GLint location, GLsizei count, const GLint * value); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3UIEXTPROC)(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3UIVEXTPROC)(GLuint program, GLint location, GLsizei count, const GLuint * value); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4FEXTPROC)(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4FVEXTPROC)(GLuint program, GLint location, GLsizei count, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4IEXTPROC)(GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4IVEXTPROC)(GLuint program, GLint location, GLsizei count, const GLint * value); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4UIEXTPROC)(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4UIVEXTPROC)(GLuint program, GLint location, GLsizei count, const GLuint * value); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX2FVEXTPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX3FVEXTPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX4FVEXTPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLPUSHDEBUGGROUPKHRPROC)(GLenum source, GLuint id, GLsizei length, const GLchar * message); +typedef void (GLAD_API_PTR *PFNGLPUSHGROUPMARKEREXTPROC)(GLsizei length, const GLchar * marker); +typedef void (GLAD_API_PTR *PFNGLQUERYCOUNTEREXTPROC)(GLuint id, GLenum target); +typedef void (GLAD_API_PTR *PFNGLRASTERSAMPLESEXTPROC)(GLuint samples, GLboolean fixedsamplelocations); +typedef void (GLAD_API_PTR *PFNGLREADBUFFERINDEXEDEXTPROC)(GLenum src, GLint index); +typedef void (GLAD_API_PTR *PFNGLREADPIXELSPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void * pixels); +typedef void (GLAD_API_PTR *PFNGLREADNPIXELSEXTPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void * data); +typedef void (GLAD_API_PTR *PFNGLREADNPIXELSKHRPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void * data); +typedef GLboolean (GLAD_API_PTR *PFNGLRELEASEKEYEDMUTEXWIN32EXTPROC)(GLuint memory, GLuint64 key); +typedef void (GLAD_API_PTR *PFNGLRELEASESHADERCOMPILERPROC)(void); +typedef void (GLAD_API_PTR *PFNGLRENDERBUFFERSTORAGEPROC)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (GLAD_API_PTR *PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (GLAD_API_PTR *PFNGLSAMPLECOVERAGEPROC)(GLfloat value, GLboolean invert); +typedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERIIVEXTPROC)(GLuint sampler, GLenum pname, const GLint * param); +typedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERIIVOESPROC)(GLuint sampler, GLenum pname, const GLint * param); +typedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERIUIVEXTPROC)(GLuint sampler, GLenum pname, const GLuint * param); +typedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERIUIVOESPROC)(GLuint sampler, GLenum pname, const GLuint * param); +typedef void (GLAD_API_PTR *PFNGLSCISSORPROC)(GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (GLAD_API_PTR *PFNGLSCISSORARRAYVOESPROC)(GLuint first, GLsizei count, const GLint * v); +typedef void (GLAD_API_PTR *PFNGLSCISSORINDEXEDOESPROC)(GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height); +typedef void (GLAD_API_PTR *PFNGLSCISSORINDEXEDVOESPROC)(GLuint index, const GLint * v); +typedef void (GLAD_API_PTR *PFNGLSEMAPHOREPARAMETERUI64VEXTPROC)(GLuint semaphore, GLenum pname, const GLuint64 * params); +typedef void (GLAD_API_PTR *PFNGLSHADERBINARYPROC)(GLsizei count, const GLuint * shaders, GLenum binaryFormat, const void * binary, GLsizei length); +typedef void (GLAD_API_PTR *PFNGLSHADERSOURCEPROC)(GLuint shader, GLsizei count, const GLchar *const* string, const GLint * length); +typedef void (GLAD_API_PTR *PFNGLSHADINGRATECOMBINEROPSEXTPROC)(GLenum combinerOp0, GLenum combinerOp1); +typedef void (GLAD_API_PTR *PFNGLSHADINGRATEEXTPROC)(GLenum rate); +typedef void (GLAD_API_PTR *PFNGLSIGNALSEMAPHOREEXTPROC)(GLuint semaphore, GLuint numBufferBarriers, const GLuint * buffers, GLuint numTextureBarriers, const GLuint * textures, const GLenum * dstLayouts); +typedef void (GLAD_API_PTR *PFNGLSTENCILFUNCPROC)(GLenum func, GLint ref, GLuint mask); +typedef void (GLAD_API_PTR *PFNGLSTENCILFUNCSEPARATEPROC)(GLenum face, GLenum func, GLint ref, GLuint mask); +typedef void (GLAD_API_PTR *PFNGLSTENCILMASKPROC)(GLuint mask); +typedef void (GLAD_API_PTR *PFNGLSTENCILMASKSEPARATEPROC)(GLenum face, GLuint mask); +typedef void (GLAD_API_PTR *PFNGLSTENCILOPPROC)(GLenum fail, GLenum zfail, GLenum zpass); +typedef void (GLAD_API_PTR *PFNGLSTENCILOPSEPARATEPROC)(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); +typedef void (GLAD_API_PTR *PFNGLTEXBUFFEREXTPROC)(GLenum target, GLenum internalformat, GLuint buffer); +typedef void (GLAD_API_PTR *PFNGLTEXBUFFEROESPROC)(GLenum target, GLenum internalformat, GLuint buffer); +typedef void (GLAD_API_PTR *PFNGLTEXBUFFERRANGEEXTPROC)(GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); +typedef void (GLAD_API_PTR *PFNGLTEXBUFFERRANGEOESPROC)(GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); +typedef void (GLAD_API_PTR *PFNGLTEXIMAGE2DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void * pixels); +typedef void (GLAD_API_PTR *PFNGLTEXIMAGE3DOESPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void * pixels); +typedef void (GLAD_API_PTR *PFNGLTEXPAGECOMMITMENTEXTPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean commit); +typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIIVEXTPROC)(GLenum target, GLenum pname, const GLint * params); +typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIIVOESPROC)(GLenum target, GLenum pname, const GLint * params); +typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIUIVEXTPROC)(GLenum target, GLenum pname, const GLuint * params); +typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIUIVOESPROC)(GLenum target, GLenum pname, const GLuint * params); +typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERFPROC)(GLenum target, GLenum pname, GLfloat param); +typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERFVPROC)(GLenum target, GLenum pname, const GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIPROC)(GLenum target, GLenum pname, GLint param); +typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIVPROC)(GLenum target, GLenum pname, const GLint * params); +typedef void (GLAD_API_PTR *PFNGLTEXSTORAGE1DEXTPROC)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); +typedef void (GLAD_API_PTR *PFNGLTEXSTORAGE2DEXTPROC)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (GLAD_API_PTR *PFNGLTEXSTORAGE3DEXTPROC)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); +typedef void (GLAD_API_PTR *PFNGLTEXSTORAGE3DMULTISAMPLEOESPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); +typedef void (GLAD_API_PTR *PFNGLTEXSTORAGEATTRIBS2DEXTPROC)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, const GLint * attrib_list); +typedef void (GLAD_API_PTR *PFNGLTEXSTORAGEATTRIBS3DEXTPROC)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, const GLint * attrib_list); +typedef void (GLAD_API_PTR *PFNGLTEXSTORAGEMEM2DEXTPROC)(GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLuint memory, GLuint64 offset); +typedef void (GLAD_API_PTR *PFNGLTEXSTORAGEMEM2DMULTISAMPLEEXTPROC)(GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset); +typedef void (GLAD_API_PTR *PFNGLTEXSTORAGEMEM3DEXTPROC)(GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLuint memory, GLuint64 offset); +typedef void (GLAD_API_PTR *PFNGLTEXSTORAGEMEM3DMULTISAMPLEEXTPROC)(GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset); +typedef void (GLAD_API_PTR *PFNGLTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void * pixels); +typedef void (GLAD_API_PTR *PFNGLTEXSUBIMAGE3DOESPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void * pixels); +typedef void (GLAD_API_PTR *PFNGLTEXTURESTORAGE1DEXTPROC)(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); +typedef void (GLAD_API_PTR *PFNGLTEXTURESTORAGE2DEXTPROC)(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (GLAD_API_PTR *PFNGLTEXTURESTORAGE3DEXTPROC)(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); +typedef void (GLAD_API_PTR *PFNGLTEXTURESTORAGEMEM2DEXTPROC)(GLuint texture, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLuint memory, GLuint64 offset); +typedef void (GLAD_API_PTR *PFNGLTEXTURESTORAGEMEM2DMULTISAMPLEEXTPROC)(GLuint texture, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset); +typedef void (GLAD_API_PTR *PFNGLTEXTURESTORAGEMEM3DEXTPROC)(GLuint texture, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLuint memory, GLuint64 offset); +typedef void (GLAD_API_PTR *PFNGLTEXTURESTORAGEMEM3DMULTISAMPLEEXTPROC)(GLuint texture, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset); +typedef void (GLAD_API_PTR *PFNGLTEXTUREVIEWEXTPROC)(GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers); +typedef void (GLAD_API_PTR *PFNGLTEXTUREVIEWOESPROC)(GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers); +typedef void (GLAD_API_PTR *PFNGLUNIFORM1FPROC)(GLint location, GLfloat v0); +typedef void (GLAD_API_PTR *PFNGLUNIFORM1FVPROC)(GLint location, GLsizei count, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORM1IPROC)(GLint location, GLint v0); +typedef void (GLAD_API_PTR *PFNGLUNIFORM1IVPROC)(GLint location, GLsizei count, const GLint * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORM2FPROC)(GLint location, GLfloat v0, GLfloat v1); +typedef void (GLAD_API_PTR *PFNGLUNIFORM2FVPROC)(GLint location, GLsizei count, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORM2IPROC)(GLint location, GLint v0, GLint v1); +typedef void (GLAD_API_PTR *PFNGLUNIFORM2IVPROC)(GLint location, GLsizei count, const GLint * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORM3FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +typedef void (GLAD_API_PTR *PFNGLUNIFORM3FVPROC)(GLint location, GLsizei count, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORM3IPROC)(GLint location, GLint v0, GLint v1, GLint v2); +typedef void (GLAD_API_PTR *PFNGLUNIFORM3IVPROC)(GLint location, GLsizei count, const GLint * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORM4FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +typedef void (GLAD_API_PTR *PFNGLUNIFORM4FVPROC)(GLint location, GLsizei count, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORM4IPROC)(GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +typedef void (GLAD_API_PTR *PFNGLUNIFORM4IVPROC)(GLint location, GLsizei count, const GLint * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); +typedef GLboolean (GLAD_API_PTR *PFNGLUNMAPBUFFEROESPROC)(GLenum target); +typedef void (GLAD_API_PTR *PFNGLUSEPROGRAMPROC)(GLuint program); +typedef void (GLAD_API_PTR *PFNGLUSEPROGRAMSTAGESEXTPROC)(GLuint pipeline, GLbitfield stages, GLuint program); +typedef void (GLAD_API_PTR *PFNGLVALIDATEPROGRAMPROC)(GLuint program); +typedef void (GLAD_API_PTR *PFNGLVALIDATEPROGRAMPIPELINEEXTPROC)(GLuint pipeline); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1FPROC)(GLuint index, GLfloat x); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1FVPROC)(GLuint index, const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2FPROC)(GLuint index, GLfloat x, GLfloat y); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2FVPROC)(GLuint index, const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3FVPROC)(GLuint index, const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4FVPROC)(GLuint index, const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBDIVISOREXTPROC)(GLuint index, GLuint divisor); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBPOINTERPROC)(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void * pointer); +typedef void (GLAD_API_PTR *PFNGLVIEWPORTPROC)(GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (GLAD_API_PTR *PFNGLVIEWPORTARRAYVOESPROC)(GLuint first, GLsizei count, const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLVIEWPORTINDEXEDFOESPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h); +typedef void (GLAD_API_PTR *PFNGLVIEWPORTINDEXEDFVOESPROC)(GLuint index, const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLWAITSEMAPHOREEXTPROC)(GLuint semaphore, GLuint numBufferBarriers, const GLuint * buffers, GLuint numTextureBarriers, const GLuint * textures, const GLenum * srcLayouts); +typedef void (GLAD_API_PTR *PFNGLWINDOWRECTANGLESEXTPROC)(GLenum mode, GLsizei count, const GLint * box); + +GLAD_API_CALL PFNGLACQUIREKEYEDMUTEXWIN32EXTPROC glad_glAcquireKeyedMutexWin32EXT; +#define glAcquireKeyedMutexWin32EXT glad_glAcquireKeyedMutexWin32EXT +GLAD_API_CALL PFNGLACTIVESHADERPROGRAMEXTPROC glad_glActiveShaderProgramEXT; +#define glActiveShaderProgramEXT glad_glActiveShaderProgramEXT +GLAD_API_CALL PFNGLACTIVETEXTUREPROC glad_glActiveTexture; +#define glActiveTexture glad_glActiveTexture +GLAD_API_CALL PFNGLATTACHSHADERPROC glad_glAttachShader; +#define glAttachShader glad_glAttachShader +GLAD_API_CALL PFNGLBEGINQUERYEXTPROC glad_glBeginQueryEXT; +#define glBeginQueryEXT glad_glBeginQueryEXT +GLAD_API_CALL PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation; +#define glBindAttribLocation glad_glBindAttribLocation +GLAD_API_CALL PFNGLBINDBUFFERPROC glad_glBindBuffer; +#define glBindBuffer glad_glBindBuffer +GLAD_API_CALL PFNGLBINDFRAGDATALOCATIONEXTPROC glad_glBindFragDataLocationEXT; +#define glBindFragDataLocationEXT glad_glBindFragDataLocationEXT +GLAD_API_CALL PFNGLBINDFRAGDATALOCATIONINDEXEDEXTPROC glad_glBindFragDataLocationIndexedEXT; +#define glBindFragDataLocationIndexedEXT glad_glBindFragDataLocationIndexedEXT +GLAD_API_CALL PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer; +#define glBindFramebuffer glad_glBindFramebuffer +GLAD_API_CALL PFNGLBINDPROGRAMPIPELINEEXTPROC glad_glBindProgramPipelineEXT; +#define glBindProgramPipelineEXT glad_glBindProgramPipelineEXT +GLAD_API_CALL PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer; +#define glBindRenderbuffer glad_glBindRenderbuffer +GLAD_API_CALL PFNGLBINDTEXTUREPROC glad_glBindTexture; +#define glBindTexture glad_glBindTexture +GLAD_API_CALL PFNGLBINDVERTEXARRAYOESPROC glad_glBindVertexArrayOES; +#define glBindVertexArrayOES glad_glBindVertexArrayOES +GLAD_API_CALL PFNGLBLENDBARRIERKHRPROC glad_glBlendBarrierKHR; +#define glBlendBarrierKHR glad_glBlendBarrierKHR +GLAD_API_CALL PFNGLBLENDCOLORPROC glad_glBlendColor; +#define glBlendColor glad_glBlendColor +GLAD_API_CALL PFNGLBLENDEQUATIONPROC glad_glBlendEquation; +#define glBlendEquation glad_glBlendEquation +GLAD_API_CALL PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate; +#define glBlendEquationSeparate glad_glBlendEquationSeparate +GLAD_API_CALL PFNGLBLENDEQUATIONSEPARATEIEXTPROC glad_glBlendEquationSeparateiEXT; +#define glBlendEquationSeparateiEXT glad_glBlendEquationSeparateiEXT +GLAD_API_CALL PFNGLBLENDEQUATIONSEPARATEIOESPROC glad_glBlendEquationSeparateiOES; +#define glBlendEquationSeparateiOES glad_glBlendEquationSeparateiOES +GLAD_API_CALL PFNGLBLENDEQUATIONIEXTPROC glad_glBlendEquationiEXT; +#define glBlendEquationiEXT glad_glBlendEquationiEXT +GLAD_API_CALL PFNGLBLENDEQUATIONIOESPROC glad_glBlendEquationiOES; +#define glBlendEquationiOES glad_glBlendEquationiOES +GLAD_API_CALL PFNGLBLENDFUNCPROC glad_glBlendFunc; +#define glBlendFunc glad_glBlendFunc +GLAD_API_CALL PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate; +#define glBlendFuncSeparate glad_glBlendFuncSeparate +GLAD_API_CALL PFNGLBLENDFUNCSEPARATEIEXTPROC glad_glBlendFuncSeparateiEXT; +#define glBlendFuncSeparateiEXT glad_glBlendFuncSeparateiEXT +GLAD_API_CALL PFNGLBLENDFUNCSEPARATEIOESPROC glad_glBlendFuncSeparateiOES; +#define glBlendFuncSeparateiOES glad_glBlendFuncSeparateiOES +GLAD_API_CALL PFNGLBLENDFUNCIEXTPROC glad_glBlendFunciEXT; +#define glBlendFunciEXT glad_glBlendFunciEXT +GLAD_API_CALL PFNGLBLENDFUNCIOESPROC glad_glBlendFunciOES; +#define glBlendFunciOES glad_glBlendFunciOES +GLAD_API_CALL PFNGLBUFFERDATAPROC glad_glBufferData; +#define glBufferData glad_glBufferData +GLAD_API_CALL PFNGLBUFFERSTORAGEEXTPROC glad_glBufferStorageEXT; +#define glBufferStorageEXT glad_glBufferStorageEXT +GLAD_API_CALL PFNGLBUFFERSTORAGEEXTERNALEXTPROC glad_glBufferStorageExternalEXT; +#define glBufferStorageExternalEXT glad_glBufferStorageExternalEXT +GLAD_API_CALL PFNGLBUFFERSTORAGEMEMEXTPROC glad_glBufferStorageMemEXT; +#define glBufferStorageMemEXT glad_glBufferStorageMemEXT +GLAD_API_CALL PFNGLBUFFERSUBDATAPROC glad_glBufferSubData; +#define glBufferSubData glad_glBufferSubData +GLAD_API_CALL PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus; +#define glCheckFramebufferStatus glad_glCheckFramebufferStatus +GLAD_API_CALL PFNGLCLEARPROC glad_glClear; +#define glClear glad_glClear +GLAD_API_CALL PFNGLCLEARCOLORPROC glad_glClearColor; +#define glClearColor glad_glClearColor +GLAD_API_CALL PFNGLCLEARDEPTHFPROC glad_glClearDepthf; +#define glClearDepthf glad_glClearDepthf +GLAD_API_CALL PFNGLCLEARPIXELLOCALSTORAGEUIEXTPROC glad_glClearPixelLocalStorageuiEXT; +#define glClearPixelLocalStorageuiEXT glad_glClearPixelLocalStorageuiEXT +GLAD_API_CALL PFNGLCLEARSTENCILPROC glad_glClearStencil; +#define glClearStencil glad_glClearStencil +GLAD_API_CALL PFNGLCLEARTEXIMAGEEXTPROC glad_glClearTexImageEXT; +#define glClearTexImageEXT glad_glClearTexImageEXT +GLAD_API_CALL PFNGLCLEARTEXSUBIMAGEEXTPROC glad_glClearTexSubImageEXT; +#define glClearTexSubImageEXT glad_glClearTexSubImageEXT +GLAD_API_CALL PFNGLCLIPCONTROLEXTPROC glad_glClipControlEXT; +#define glClipControlEXT glad_glClipControlEXT +GLAD_API_CALL PFNGLCOLORMASKPROC glad_glColorMask; +#define glColorMask glad_glColorMask +GLAD_API_CALL PFNGLCOLORMASKIEXTPROC glad_glColorMaskiEXT; +#define glColorMaskiEXT glad_glColorMaskiEXT +GLAD_API_CALL PFNGLCOLORMASKIOESPROC glad_glColorMaskiOES; +#define glColorMaskiOES glad_glColorMaskiOES +GLAD_API_CALL PFNGLCOMPILESHADERPROC glad_glCompileShader; +#define glCompileShader glad_glCompileShader +GLAD_API_CALL PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D; +#define glCompressedTexImage2D glad_glCompressedTexImage2D +GLAD_API_CALL PFNGLCOMPRESSEDTEXIMAGE3DOESPROC glad_glCompressedTexImage3DOES; +#define glCompressedTexImage3DOES glad_glCompressedTexImage3DOES +GLAD_API_CALL PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D; +#define glCompressedTexSubImage2D glad_glCompressedTexSubImage2D +GLAD_API_CALL PFNGLCOMPRESSEDTEXSUBIMAGE3DOESPROC glad_glCompressedTexSubImage3DOES; +#define glCompressedTexSubImage3DOES glad_glCompressedTexSubImage3DOES +GLAD_API_CALL PFNGLCOPYIMAGESUBDATAEXTPROC glad_glCopyImageSubDataEXT; +#define glCopyImageSubDataEXT glad_glCopyImageSubDataEXT +GLAD_API_CALL PFNGLCOPYIMAGESUBDATAOESPROC glad_glCopyImageSubDataOES; +#define glCopyImageSubDataOES glad_glCopyImageSubDataOES +GLAD_API_CALL PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D; +#define glCopyTexImage2D glad_glCopyTexImage2D +GLAD_API_CALL PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D; +#define glCopyTexSubImage2D glad_glCopyTexSubImage2D +GLAD_API_CALL PFNGLCOPYTEXSUBIMAGE3DOESPROC glad_glCopyTexSubImage3DOES; +#define glCopyTexSubImage3DOES glad_glCopyTexSubImage3DOES +GLAD_API_CALL PFNGLCREATEMEMORYOBJECTSEXTPROC glad_glCreateMemoryObjectsEXT; +#define glCreateMemoryObjectsEXT glad_glCreateMemoryObjectsEXT +GLAD_API_CALL PFNGLCREATEPROGRAMPROC glad_glCreateProgram; +#define glCreateProgram glad_glCreateProgram +GLAD_API_CALL PFNGLCREATESHADERPROC glad_glCreateShader; +#define glCreateShader glad_glCreateShader +GLAD_API_CALL PFNGLCREATESHADERPROGRAMVEXTPROC glad_glCreateShaderProgramvEXT; +#define glCreateShaderProgramvEXT glad_glCreateShaderProgramvEXT +GLAD_API_CALL PFNGLCULLFACEPROC glad_glCullFace; +#define glCullFace glad_glCullFace +GLAD_API_CALL PFNGLDEBUGMESSAGECALLBACKKHRPROC glad_glDebugMessageCallbackKHR; +#define glDebugMessageCallbackKHR glad_glDebugMessageCallbackKHR +GLAD_API_CALL PFNGLDEBUGMESSAGECONTROLKHRPROC glad_glDebugMessageControlKHR; +#define glDebugMessageControlKHR glad_glDebugMessageControlKHR +GLAD_API_CALL PFNGLDEBUGMESSAGEINSERTKHRPROC glad_glDebugMessageInsertKHR; +#define glDebugMessageInsertKHR glad_glDebugMessageInsertKHR +GLAD_API_CALL PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers; +#define glDeleteBuffers glad_glDeleteBuffers +GLAD_API_CALL PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers; +#define glDeleteFramebuffers glad_glDeleteFramebuffers +GLAD_API_CALL PFNGLDELETEMEMORYOBJECTSEXTPROC glad_glDeleteMemoryObjectsEXT; +#define glDeleteMemoryObjectsEXT glad_glDeleteMemoryObjectsEXT +GLAD_API_CALL PFNGLDELETEPROGRAMPROC glad_glDeleteProgram; +#define glDeleteProgram glad_glDeleteProgram +GLAD_API_CALL PFNGLDELETEPROGRAMPIPELINESEXTPROC glad_glDeleteProgramPipelinesEXT; +#define glDeleteProgramPipelinesEXT glad_glDeleteProgramPipelinesEXT +GLAD_API_CALL PFNGLDELETEQUERIESEXTPROC glad_glDeleteQueriesEXT; +#define glDeleteQueriesEXT glad_glDeleteQueriesEXT +GLAD_API_CALL PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers; +#define glDeleteRenderbuffers glad_glDeleteRenderbuffers +GLAD_API_CALL PFNGLDELETESEMAPHORESEXTPROC glad_glDeleteSemaphoresEXT; +#define glDeleteSemaphoresEXT glad_glDeleteSemaphoresEXT +GLAD_API_CALL PFNGLDELETESHADERPROC glad_glDeleteShader; +#define glDeleteShader glad_glDeleteShader +GLAD_API_CALL PFNGLDELETETEXTURESPROC glad_glDeleteTextures; +#define glDeleteTextures glad_glDeleteTextures +GLAD_API_CALL PFNGLDELETEVERTEXARRAYSOESPROC glad_glDeleteVertexArraysOES; +#define glDeleteVertexArraysOES glad_glDeleteVertexArraysOES +GLAD_API_CALL PFNGLDEPTHFUNCPROC glad_glDepthFunc; +#define glDepthFunc glad_glDepthFunc +GLAD_API_CALL PFNGLDEPTHMASKPROC glad_glDepthMask; +#define glDepthMask glad_glDepthMask +GLAD_API_CALL PFNGLDEPTHRANGEARRAYFVOESPROC glad_glDepthRangeArrayfvOES; +#define glDepthRangeArrayfvOES glad_glDepthRangeArrayfvOES +GLAD_API_CALL PFNGLDEPTHRANGEINDEXEDFOESPROC glad_glDepthRangeIndexedfOES; +#define glDepthRangeIndexedfOES glad_glDepthRangeIndexedfOES +GLAD_API_CALL PFNGLDEPTHRANGEFPROC glad_glDepthRangef; +#define glDepthRangef glad_glDepthRangef +GLAD_API_CALL PFNGLDETACHSHADERPROC glad_glDetachShader; +#define glDetachShader glad_glDetachShader +GLAD_API_CALL PFNGLDISABLEPROC glad_glDisable; +#define glDisable glad_glDisable +GLAD_API_CALL PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray; +#define glDisableVertexAttribArray glad_glDisableVertexAttribArray +GLAD_API_CALL PFNGLDISABLEIEXTPROC glad_glDisableiEXT; +#define glDisableiEXT glad_glDisableiEXT +GLAD_API_CALL PFNGLDISABLEIOESPROC glad_glDisableiOES; +#define glDisableiOES glad_glDisableiOES +GLAD_API_CALL PFNGLDISCARDFRAMEBUFFEREXTPROC glad_glDiscardFramebufferEXT; +#define glDiscardFramebufferEXT glad_glDiscardFramebufferEXT +GLAD_API_CALL PFNGLDRAWARRAYSPROC glad_glDrawArrays; +#define glDrawArrays glad_glDrawArrays +GLAD_API_CALL PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEEXTPROC glad_glDrawArraysInstancedBaseInstanceEXT; +#define glDrawArraysInstancedBaseInstanceEXT glad_glDrawArraysInstancedBaseInstanceEXT +GLAD_API_CALL PFNGLDRAWARRAYSINSTANCEDEXTPROC glad_glDrawArraysInstancedEXT; +#define glDrawArraysInstancedEXT glad_glDrawArraysInstancedEXT +GLAD_API_CALL PFNGLDRAWBUFFERSEXTPROC glad_glDrawBuffersEXT; +#define glDrawBuffersEXT glad_glDrawBuffersEXT +GLAD_API_CALL PFNGLDRAWBUFFERSINDEXEDEXTPROC glad_glDrawBuffersIndexedEXT; +#define glDrawBuffersIndexedEXT glad_glDrawBuffersIndexedEXT +GLAD_API_CALL PFNGLDRAWELEMENTSPROC glad_glDrawElements; +#define glDrawElements glad_glDrawElements +GLAD_API_CALL PFNGLDRAWELEMENTSBASEVERTEXEXTPROC glad_glDrawElementsBaseVertexEXT; +#define glDrawElementsBaseVertexEXT glad_glDrawElementsBaseVertexEXT +GLAD_API_CALL PFNGLDRAWELEMENTSBASEVERTEXOESPROC glad_glDrawElementsBaseVertexOES; +#define glDrawElementsBaseVertexOES glad_glDrawElementsBaseVertexOES +GLAD_API_CALL PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEEXTPROC glad_glDrawElementsInstancedBaseInstanceEXT; +#define glDrawElementsInstancedBaseInstanceEXT glad_glDrawElementsInstancedBaseInstanceEXT +GLAD_API_CALL PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEEXTPROC glad_glDrawElementsInstancedBaseVertexBaseInstanceEXT; +#define glDrawElementsInstancedBaseVertexBaseInstanceEXT glad_glDrawElementsInstancedBaseVertexBaseInstanceEXT +GLAD_API_CALL PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXEXTPROC glad_glDrawElementsInstancedBaseVertexEXT; +#define glDrawElementsInstancedBaseVertexEXT glad_glDrawElementsInstancedBaseVertexEXT +GLAD_API_CALL PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXOESPROC glad_glDrawElementsInstancedBaseVertexOES; +#define glDrawElementsInstancedBaseVertexOES glad_glDrawElementsInstancedBaseVertexOES +GLAD_API_CALL PFNGLDRAWELEMENTSINSTANCEDEXTPROC glad_glDrawElementsInstancedEXT; +#define glDrawElementsInstancedEXT glad_glDrawElementsInstancedEXT +GLAD_API_CALL PFNGLDRAWRANGEELEMENTSBASEVERTEXEXTPROC glad_glDrawRangeElementsBaseVertexEXT; +#define glDrawRangeElementsBaseVertexEXT glad_glDrawRangeElementsBaseVertexEXT +GLAD_API_CALL PFNGLDRAWRANGEELEMENTSBASEVERTEXOESPROC glad_glDrawRangeElementsBaseVertexOES; +#define glDrawRangeElementsBaseVertexOES glad_glDrawRangeElementsBaseVertexOES +GLAD_API_CALL PFNGLDRAWTRANSFORMFEEDBACKEXTPROC glad_glDrawTransformFeedbackEXT; +#define glDrawTransformFeedbackEXT glad_glDrawTransformFeedbackEXT +GLAD_API_CALL PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDEXTPROC glad_glDrawTransformFeedbackInstancedEXT; +#define glDrawTransformFeedbackInstancedEXT glad_glDrawTransformFeedbackInstancedEXT +GLAD_API_CALL PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glad_glEGLImageTargetRenderbufferStorageOES; +#define glEGLImageTargetRenderbufferStorageOES glad_glEGLImageTargetRenderbufferStorageOES +GLAD_API_CALL PFNGLEGLIMAGETARGETTEXSTORAGEEXTPROC glad_glEGLImageTargetTexStorageEXT; +#define glEGLImageTargetTexStorageEXT glad_glEGLImageTargetTexStorageEXT +GLAD_API_CALL PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glad_glEGLImageTargetTexture2DOES; +#define glEGLImageTargetTexture2DOES glad_glEGLImageTargetTexture2DOES +GLAD_API_CALL PFNGLEGLIMAGETARGETTEXTURESTORAGEEXTPROC glad_glEGLImageTargetTextureStorageEXT; +#define glEGLImageTargetTextureStorageEXT glad_glEGLImageTargetTextureStorageEXT +GLAD_API_CALL PFNGLENABLEPROC glad_glEnable; +#define glEnable glad_glEnable +GLAD_API_CALL PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray; +#define glEnableVertexAttribArray glad_glEnableVertexAttribArray +GLAD_API_CALL PFNGLENABLEIEXTPROC glad_glEnableiEXT; +#define glEnableiEXT glad_glEnableiEXT +GLAD_API_CALL PFNGLENABLEIOESPROC glad_glEnableiOES; +#define glEnableiOES glad_glEnableiOES +GLAD_API_CALL PFNGLENDQUERYEXTPROC glad_glEndQueryEXT; +#define glEndQueryEXT glad_glEndQueryEXT +GLAD_API_CALL PFNGLFINISHPROC glad_glFinish; +#define glFinish glad_glFinish +GLAD_API_CALL PFNGLFLUSHPROC glad_glFlush; +#define glFlush glad_glFlush +GLAD_API_CALL PFNGLFLUSHMAPPEDBUFFERRANGEEXTPROC glad_glFlushMappedBufferRangeEXT; +#define glFlushMappedBufferRangeEXT glad_glFlushMappedBufferRangeEXT +GLAD_API_CALL PFNGLFRAMEBUFFERFETCHBARRIEREXTPROC glad_glFramebufferFetchBarrierEXT; +#define glFramebufferFetchBarrierEXT glad_glFramebufferFetchBarrierEXT +GLAD_API_CALL PFNGLFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC glad_glFramebufferPixelLocalStorageSizeEXT; +#define glFramebufferPixelLocalStorageSizeEXT glad_glFramebufferPixelLocalStorageSizeEXT +GLAD_API_CALL PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer; +#define glFramebufferRenderbuffer glad_glFramebufferRenderbuffer +GLAD_API_CALL PFNGLFRAMEBUFFERSHADINGRATEEXTPROC glad_glFramebufferShadingRateEXT; +#define glFramebufferShadingRateEXT glad_glFramebufferShadingRateEXT +GLAD_API_CALL PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D; +#define glFramebufferTexture2D glad_glFramebufferTexture2D +GLAD_API_CALL PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC glad_glFramebufferTexture2DMultisampleEXT; +#define glFramebufferTexture2DMultisampleEXT glad_glFramebufferTexture2DMultisampleEXT +GLAD_API_CALL PFNGLFRAMEBUFFERTEXTURE3DOESPROC glad_glFramebufferTexture3DOES; +#define glFramebufferTexture3DOES glad_glFramebufferTexture3DOES +GLAD_API_CALL PFNGLFRAMEBUFFERTEXTUREEXTPROC glad_glFramebufferTextureEXT; +#define glFramebufferTextureEXT glad_glFramebufferTextureEXT +GLAD_API_CALL PFNGLFRAMEBUFFERTEXTUREOESPROC glad_glFramebufferTextureOES; +#define glFramebufferTextureOES glad_glFramebufferTextureOES +GLAD_API_CALL PFNGLFRONTFACEPROC glad_glFrontFace; +#define glFrontFace glad_glFrontFace +GLAD_API_CALL PFNGLGENBUFFERSPROC glad_glGenBuffers; +#define glGenBuffers glad_glGenBuffers +GLAD_API_CALL PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers; +#define glGenFramebuffers glad_glGenFramebuffers +GLAD_API_CALL PFNGLGENPROGRAMPIPELINESEXTPROC glad_glGenProgramPipelinesEXT; +#define glGenProgramPipelinesEXT glad_glGenProgramPipelinesEXT +GLAD_API_CALL PFNGLGENQUERIESEXTPROC glad_glGenQueriesEXT; +#define glGenQueriesEXT glad_glGenQueriesEXT +GLAD_API_CALL PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers; +#define glGenRenderbuffers glad_glGenRenderbuffers +GLAD_API_CALL PFNGLGENSEMAPHORESEXTPROC glad_glGenSemaphoresEXT; +#define glGenSemaphoresEXT glad_glGenSemaphoresEXT +GLAD_API_CALL PFNGLGENTEXTURESPROC glad_glGenTextures; +#define glGenTextures glad_glGenTextures +GLAD_API_CALL PFNGLGENVERTEXARRAYSOESPROC glad_glGenVertexArraysOES; +#define glGenVertexArraysOES glad_glGenVertexArraysOES +GLAD_API_CALL PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap; +#define glGenerateMipmap glad_glGenerateMipmap +GLAD_API_CALL PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib; +#define glGetActiveAttrib glad_glGetActiveAttrib +GLAD_API_CALL PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform; +#define glGetActiveUniform glad_glGetActiveUniform +GLAD_API_CALL PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders; +#define glGetAttachedShaders glad_glGetAttachedShaders +GLAD_API_CALL PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation; +#define glGetAttribLocation glad_glGetAttribLocation +GLAD_API_CALL PFNGLGETBOOLEANVPROC glad_glGetBooleanv; +#define glGetBooleanv glad_glGetBooleanv +GLAD_API_CALL PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv; +#define glGetBufferParameteriv glad_glGetBufferParameteriv +GLAD_API_CALL PFNGLGETBUFFERPOINTERVOESPROC glad_glGetBufferPointervOES; +#define glGetBufferPointervOES glad_glGetBufferPointervOES +GLAD_API_CALL PFNGLGETDEBUGMESSAGELOGKHRPROC glad_glGetDebugMessageLogKHR; +#define glGetDebugMessageLogKHR glad_glGetDebugMessageLogKHR +GLAD_API_CALL PFNGLGETERRORPROC glad_glGetError; +#define glGetError glad_glGetError +GLAD_API_CALL PFNGLGETFLOATI_VOESPROC glad_glGetFloati_vOES; +#define glGetFloati_vOES glad_glGetFloati_vOES +GLAD_API_CALL PFNGLGETFLOATVPROC glad_glGetFloatv; +#define glGetFloatv glad_glGetFloatv +GLAD_API_CALL PFNGLGETFRAGDATAINDEXEXTPROC glad_glGetFragDataIndexEXT; +#define glGetFragDataIndexEXT glad_glGetFragDataIndexEXT +GLAD_API_CALL PFNGLGETFRAGMENTSHADINGRATESEXTPROC glad_glGetFragmentShadingRatesEXT; +#define glGetFragmentShadingRatesEXT glad_glGetFragmentShadingRatesEXT +GLAD_API_CALL PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv; +#define glGetFramebufferAttachmentParameteriv glad_glGetFramebufferAttachmentParameteriv +GLAD_API_CALL PFNGLGETFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC glad_glGetFramebufferPixelLocalStorageSizeEXT; +#define glGetFramebufferPixelLocalStorageSizeEXT glad_glGetFramebufferPixelLocalStorageSizeEXT +GLAD_API_CALL PFNGLGETGRAPHICSRESETSTATUSEXTPROC glad_glGetGraphicsResetStatusEXT; +#define glGetGraphicsResetStatusEXT glad_glGetGraphicsResetStatusEXT +GLAD_API_CALL PFNGLGETGRAPHICSRESETSTATUSKHRPROC glad_glGetGraphicsResetStatusKHR; +#define glGetGraphicsResetStatusKHR glad_glGetGraphicsResetStatusKHR +GLAD_API_CALL PFNGLGETINTEGER64VEXTPROC glad_glGetInteger64vEXT; +#define glGetInteger64vEXT glad_glGetInteger64vEXT +GLAD_API_CALL PFNGLGETINTEGERI_VEXTPROC glad_glGetIntegeri_vEXT; +#define glGetIntegeri_vEXT glad_glGetIntegeri_vEXT +GLAD_API_CALL PFNGLGETINTEGERVPROC glad_glGetIntegerv; +#define glGetIntegerv glad_glGetIntegerv +GLAD_API_CALL PFNGLGETMEMORYOBJECTPARAMETERIVEXTPROC glad_glGetMemoryObjectParameterivEXT; +#define glGetMemoryObjectParameterivEXT glad_glGetMemoryObjectParameterivEXT +GLAD_API_CALL PFNGLGETOBJECTLABELEXTPROC glad_glGetObjectLabelEXT; +#define glGetObjectLabelEXT glad_glGetObjectLabelEXT +GLAD_API_CALL PFNGLGETOBJECTLABELKHRPROC glad_glGetObjectLabelKHR; +#define glGetObjectLabelKHR glad_glGetObjectLabelKHR +GLAD_API_CALL PFNGLGETOBJECTPTRLABELKHRPROC glad_glGetObjectPtrLabelKHR; +#define glGetObjectPtrLabelKHR glad_glGetObjectPtrLabelKHR +GLAD_API_CALL PFNGLGETPOINTERVKHRPROC glad_glGetPointervKHR; +#define glGetPointervKHR glad_glGetPointervKHR +GLAD_API_CALL PFNGLGETPROGRAMBINARYOESPROC glad_glGetProgramBinaryOES; +#define glGetProgramBinaryOES glad_glGetProgramBinaryOES +GLAD_API_CALL PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog; +#define glGetProgramInfoLog glad_glGetProgramInfoLog +GLAD_API_CALL PFNGLGETPROGRAMPIPELINEINFOLOGEXTPROC glad_glGetProgramPipelineInfoLogEXT; +#define glGetProgramPipelineInfoLogEXT glad_glGetProgramPipelineInfoLogEXT +GLAD_API_CALL PFNGLGETPROGRAMPIPELINEIVEXTPROC glad_glGetProgramPipelineivEXT; +#define glGetProgramPipelineivEXT glad_glGetProgramPipelineivEXT +GLAD_API_CALL PFNGLGETPROGRAMRESOURCELOCATIONINDEXEXTPROC glad_glGetProgramResourceLocationIndexEXT; +#define glGetProgramResourceLocationIndexEXT glad_glGetProgramResourceLocationIndexEXT +GLAD_API_CALL PFNGLGETPROGRAMIVPROC glad_glGetProgramiv; +#define glGetProgramiv glad_glGetProgramiv +GLAD_API_CALL PFNGLGETQUERYOBJECTI64VEXTPROC glad_glGetQueryObjecti64vEXT; +#define glGetQueryObjecti64vEXT glad_glGetQueryObjecti64vEXT +GLAD_API_CALL PFNGLGETQUERYOBJECTIVEXTPROC glad_glGetQueryObjectivEXT; +#define glGetQueryObjectivEXT glad_glGetQueryObjectivEXT +GLAD_API_CALL PFNGLGETQUERYOBJECTUI64VEXTPROC glad_glGetQueryObjectui64vEXT; +#define glGetQueryObjectui64vEXT glad_glGetQueryObjectui64vEXT +GLAD_API_CALL PFNGLGETQUERYOBJECTUIVEXTPROC glad_glGetQueryObjectuivEXT; +#define glGetQueryObjectuivEXT glad_glGetQueryObjectuivEXT +GLAD_API_CALL PFNGLGETQUERYIVEXTPROC glad_glGetQueryivEXT; +#define glGetQueryivEXT glad_glGetQueryivEXT +GLAD_API_CALL PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv; +#define glGetRenderbufferParameteriv glad_glGetRenderbufferParameteriv +GLAD_API_CALL PFNGLGETSAMPLERPARAMETERIIVEXTPROC glad_glGetSamplerParameterIivEXT; +#define glGetSamplerParameterIivEXT glad_glGetSamplerParameterIivEXT +GLAD_API_CALL PFNGLGETSAMPLERPARAMETERIIVOESPROC glad_glGetSamplerParameterIivOES; +#define glGetSamplerParameterIivOES glad_glGetSamplerParameterIivOES +GLAD_API_CALL PFNGLGETSAMPLERPARAMETERIUIVEXTPROC glad_glGetSamplerParameterIuivEXT; +#define glGetSamplerParameterIuivEXT glad_glGetSamplerParameterIuivEXT +GLAD_API_CALL PFNGLGETSAMPLERPARAMETERIUIVOESPROC glad_glGetSamplerParameterIuivOES; +#define glGetSamplerParameterIuivOES glad_glGetSamplerParameterIuivOES +GLAD_API_CALL PFNGLGETSEMAPHOREPARAMETERUI64VEXTPROC glad_glGetSemaphoreParameterui64vEXT; +#define glGetSemaphoreParameterui64vEXT glad_glGetSemaphoreParameterui64vEXT +GLAD_API_CALL PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog; +#define glGetShaderInfoLog glad_glGetShaderInfoLog +GLAD_API_CALL PFNGLGETSHADERPRECISIONFORMATPROC glad_glGetShaderPrecisionFormat; +#define glGetShaderPrecisionFormat glad_glGetShaderPrecisionFormat +GLAD_API_CALL PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource; +#define glGetShaderSource glad_glGetShaderSource +GLAD_API_CALL PFNGLGETSHADERIVPROC glad_glGetShaderiv; +#define glGetShaderiv glad_glGetShaderiv +GLAD_API_CALL PFNGLGETSTRINGPROC glad_glGetString; +#define glGetString glad_glGetString +GLAD_API_CALL PFNGLGETTEXPARAMETERIIVEXTPROC glad_glGetTexParameterIivEXT; +#define glGetTexParameterIivEXT glad_glGetTexParameterIivEXT +GLAD_API_CALL PFNGLGETTEXPARAMETERIIVOESPROC glad_glGetTexParameterIivOES; +#define glGetTexParameterIivOES glad_glGetTexParameterIivOES +GLAD_API_CALL PFNGLGETTEXPARAMETERIUIVEXTPROC glad_glGetTexParameterIuivEXT; +#define glGetTexParameterIuivEXT glad_glGetTexParameterIuivEXT +GLAD_API_CALL PFNGLGETTEXPARAMETERIUIVOESPROC glad_glGetTexParameterIuivOES; +#define glGetTexParameterIuivOES glad_glGetTexParameterIuivOES +GLAD_API_CALL PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv; +#define glGetTexParameterfv glad_glGetTexParameterfv +GLAD_API_CALL PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv; +#define glGetTexParameteriv glad_glGetTexParameteriv +GLAD_API_CALL PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation; +#define glGetUniformLocation glad_glGetUniformLocation +GLAD_API_CALL PFNGLGETUNIFORMFVPROC glad_glGetUniformfv; +#define glGetUniformfv glad_glGetUniformfv +GLAD_API_CALL PFNGLGETUNIFORMIVPROC glad_glGetUniformiv; +#define glGetUniformiv glad_glGetUniformiv +GLAD_API_CALL PFNGLGETUNSIGNEDBYTEI_VEXTPROC glad_glGetUnsignedBytei_vEXT; +#define glGetUnsignedBytei_vEXT glad_glGetUnsignedBytei_vEXT +GLAD_API_CALL PFNGLGETUNSIGNEDBYTEVEXTPROC glad_glGetUnsignedBytevEXT; +#define glGetUnsignedBytevEXT glad_glGetUnsignedBytevEXT +GLAD_API_CALL PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv; +#define glGetVertexAttribPointerv glad_glGetVertexAttribPointerv +GLAD_API_CALL PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv; +#define glGetVertexAttribfv glad_glGetVertexAttribfv +GLAD_API_CALL PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv; +#define glGetVertexAttribiv glad_glGetVertexAttribiv +GLAD_API_CALL PFNGLGETNUNIFORMFVEXTPROC glad_glGetnUniformfvEXT; +#define glGetnUniformfvEXT glad_glGetnUniformfvEXT +GLAD_API_CALL PFNGLGETNUNIFORMFVKHRPROC glad_glGetnUniformfvKHR; +#define glGetnUniformfvKHR glad_glGetnUniformfvKHR +GLAD_API_CALL PFNGLGETNUNIFORMIVEXTPROC glad_glGetnUniformivEXT; +#define glGetnUniformivEXT glad_glGetnUniformivEXT +GLAD_API_CALL PFNGLGETNUNIFORMIVKHRPROC glad_glGetnUniformivKHR; +#define glGetnUniformivKHR glad_glGetnUniformivKHR +GLAD_API_CALL PFNGLGETNUNIFORMUIVKHRPROC glad_glGetnUniformuivKHR; +#define glGetnUniformuivKHR glad_glGetnUniformuivKHR +GLAD_API_CALL PFNGLHINTPROC glad_glHint; +#define glHint glad_glHint +GLAD_API_CALL PFNGLIMPORTMEMORYFDEXTPROC glad_glImportMemoryFdEXT; +#define glImportMemoryFdEXT glad_glImportMemoryFdEXT +GLAD_API_CALL PFNGLIMPORTMEMORYWIN32HANDLEEXTPROC glad_glImportMemoryWin32HandleEXT; +#define glImportMemoryWin32HandleEXT glad_glImportMemoryWin32HandleEXT +GLAD_API_CALL PFNGLIMPORTMEMORYWIN32NAMEEXTPROC glad_glImportMemoryWin32NameEXT; +#define glImportMemoryWin32NameEXT glad_glImportMemoryWin32NameEXT +GLAD_API_CALL PFNGLIMPORTSEMAPHOREFDEXTPROC glad_glImportSemaphoreFdEXT; +#define glImportSemaphoreFdEXT glad_glImportSemaphoreFdEXT +GLAD_API_CALL PFNGLIMPORTSEMAPHOREWIN32HANDLEEXTPROC glad_glImportSemaphoreWin32HandleEXT; +#define glImportSemaphoreWin32HandleEXT glad_glImportSemaphoreWin32HandleEXT +GLAD_API_CALL PFNGLIMPORTSEMAPHOREWIN32NAMEEXTPROC glad_glImportSemaphoreWin32NameEXT; +#define glImportSemaphoreWin32NameEXT glad_glImportSemaphoreWin32NameEXT +GLAD_API_CALL PFNGLINSERTEVENTMARKEREXTPROC glad_glInsertEventMarkerEXT; +#define glInsertEventMarkerEXT glad_glInsertEventMarkerEXT +GLAD_API_CALL PFNGLISBUFFERPROC glad_glIsBuffer; +#define glIsBuffer glad_glIsBuffer +GLAD_API_CALL PFNGLISENABLEDPROC glad_glIsEnabled; +#define glIsEnabled glad_glIsEnabled +GLAD_API_CALL PFNGLISENABLEDIEXTPROC glad_glIsEnablediEXT; +#define glIsEnablediEXT glad_glIsEnablediEXT +GLAD_API_CALL PFNGLISENABLEDIOESPROC glad_glIsEnablediOES; +#define glIsEnablediOES glad_glIsEnablediOES +GLAD_API_CALL PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer; +#define glIsFramebuffer glad_glIsFramebuffer +GLAD_API_CALL PFNGLISMEMORYOBJECTEXTPROC glad_glIsMemoryObjectEXT; +#define glIsMemoryObjectEXT glad_glIsMemoryObjectEXT +GLAD_API_CALL PFNGLISPROGRAMPROC glad_glIsProgram; +#define glIsProgram glad_glIsProgram +GLAD_API_CALL PFNGLISPROGRAMPIPELINEEXTPROC glad_glIsProgramPipelineEXT; +#define glIsProgramPipelineEXT glad_glIsProgramPipelineEXT +GLAD_API_CALL PFNGLISQUERYEXTPROC glad_glIsQueryEXT; +#define glIsQueryEXT glad_glIsQueryEXT +GLAD_API_CALL PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer; +#define glIsRenderbuffer glad_glIsRenderbuffer +GLAD_API_CALL PFNGLISSEMAPHOREEXTPROC glad_glIsSemaphoreEXT; +#define glIsSemaphoreEXT glad_glIsSemaphoreEXT +GLAD_API_CALL PFNGLISSHADERPROC glad_glIsShader; +#define glIsShader glad_glIsShader +GLAD_API_CALL PFNGLISTEXTUREPROC glad_glIsTexture; +#define glIsTexture glad_glIsTexture +GLAD_API_CALL PFNGLISVERTEXARRAYOESPROC glad_glIsVertexArrayOES; +#define glIsVertexArrayOES glad_glIsVertexArrayOES +GLAD_API_CALL PFNGLLABELOBJECTEXTPROC glad_glLabelObjectEXT; +#define glLabelObjectEXT glad_glLabelObjectEXT +GLAD_API_CALL PFNGLLINEWIDTHPROC glad_glLineWidth; +#define glLineWidth glad_glLineWidth +GLAD_API_CALL PFNGLLINKPROGRAMPROC glad_glLinkProgram; +#define glLinkProgram glad_glLinkProgram +GLAD_API_CALL PFNGLMAPBUFFEROESPROC glad_glMapBufferOES; +#define glMapBufferOES glad_glMapBufferOES +GLAD_API_CALL PFNGLMAPBUFFERRANGEEXTPROC glad_glMapBufferRangeEXT; +#define glMapBufferRangeEXT glad_glMapBufferRangeEXT +GLAD_API_CALL PFNGLMAXSHADERCOMPILERTHREADSKHRPROC glad_glMaxShaderCompilerThreadsKHR; +#define glMaxShaderCompilerThreadsKHR glad_glMaxShaderCompilerThreadsKHR +GLAD_API_CALL PFNGLMEMORYOBJECTPARAMETERIVEXTPROC glad_glMemoryObjectParameterivEXT; +#define glMemoryObjectParameterivEXT glad_glMemoryObjectParameterivEXT +GLAD_API_CALL PFNGLMINSAMPLESHADINGOESPROC glad_glMinSampleShadingOES; +#define glMinSampleShadingOES glad_glMinSampleShadingOES +GLAD_API_CALL PFNGLMULTIDRAWARRAYSEXTPROC glad_glMultiDrawArraysEXT; +#define glMultiDrawArraysEXT glad_glMultiDrawArraysEXT +GLAD_API_CALL PFNGLMULTIDRAWARRAYSINDIRECTEXTPROC glad_glMultiDrawArraysIndirectEXT; +#define glMultiDrawArraysIndirectEXT glad_glMultiDrawArraysIndirectEXT +GLAD_API_CALL PFNGLMULTIDRAWELEMENTSBASEVERTEXEXTPROC glad_glMultiDrawElementsBaseVertexEXT; +#define glMultiDrawElementsBaseVertexEXT glad_glMultiDrawElementsBaseVertexEXT +GLAD_API_CALL PFNGLMULTIDRAWELEMENTSEXTPROC glad_glMultiDrawElementsEXT; +#define glMultiDrawElementsEXT glad_glMultiDrawElementsEXT +GLAD_API_CALL PFNGLMULTIDRAWELEMENTSINDIRECTEXTPROC glad_glMultiDrawElementsIndirectEXT; +#define glMultiDrawElementsIndirectEXT glad_glMultiDrawElementsIndirectEXT +GLAD_API_CALL PFNGLNAMEDBUFFERSTORAGEEXTERNALEXTPROC glad_glNamedBufferStorageExternalEXT; +#define glNamedBufferStorageExternalEXT glad_glNamedBufferStorageExternalEXT +GLAD_API_CALL PFNGLNAMEDBUFFERSTORAGEMEMEXTPROC glad_glNamedBufferStorageMemEXT; +#define glNamedBufferStorageMemEXT glad_glNamedBufferStorageMemEXT +GLAD_API_CALL PFNGLOBJECTLABELKHRPROC glad_glObjectLabelKHR; +#define glObjectLabelKHR glad_glObjectLabelKHR +GLAD_API_CALL PFNGLOBJECTPTRLABELKHRPROC glad_glObjectPtrLabelKHR; +#define glObjectPtrLabelKHR glad_glObjectPtrLabelKHR +GLAD_API_CALL PFNGLPATCHPARAMETERIEXTPROC glad_glPatchParameteriEXT; +#define glPatchParameteriEXT glad_glPatchParameteriEXT +GLAD_API_CALL PFNGLPATCHPARAMETERIOESPROC glad_glPatchParameteriOES; +#define glPatchParameteriOES glad_glPatchParameteriOES +GLAD_API_CALL PFNGLPIXELSTOREIPROC glad_glPixelStorei; +#define glPixelStorei glad_glPixelStorei +GLAD_API_CALL PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset; +#define glPolygonOffset glad_glPolygonOffset +GLAD_API_CALL PFNGLPOLYGONOFFSETCLAMPEXTPROC glad_glPolygonOffsetClampEXT; +#define glPolygonOffsetClampEXT glad_glPolygonOffsetClampEXT +GLAD_API_CALL PFNGLPOPDEBUGGROUPKHRPROC glad_glPopDebugGroupKHR; +#define glPopDebugGroupKHR glad_glPopDebugGroupKHR +GLAD_API_CALL PFNGLPOPGROUPMARKEREXTPROC glad_glPopGroupMarkerEXT; +#define glPopGroupMarkerEXT glad_glPopGroupMarkerEXT +GLAD_API_CALL PFNGLPRIMITIVEBOUNDINGBOXEXTPROC glad_glPrimitiveBoundingBoxEXT; +#define glPrimitiveBoundingBoxEXT glad_glPrimitiveBoundingBoxEXT +GLAD_API_CALL PFNGLPRIMITIVEBOUNDINGBOXOESPROC glad_glPrimitiveBoundingBoxOES; +#define glPrimitiveBoundingBoxOES glad_glPrimitiveBoundingBoxOES +GLAD_API_CALL PFNGLPROGRAMBINARYOESPROC glad_glProgramBinaryOES; +#define glProgramBinaryOES glad_glProgramBinaryOES +GLAD_API_CALL PFNGLPROGRAMPARAMETERIEXTPROC glad_glProgramParameteriEXT; +#define glProgramParameteriEXT glad_glProgramParameteriEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORM1FEXTPROC glad_glProgramUniform1fEXT; +#define glProgramUniform1fEXT glad_glProgramUniform1fEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORM1FVEXTPROC glad_glProgramUniform1fvEXT; +#define glProgramUniform1fvEXT glad_glProgramUniform1fvEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORM1IEXTPROC glad_glProgramUniform1iEXT; +#define glProgramUniform1iEXT glad_glProgramUniform1iEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORM1IVEXTPROC glad_glProgramUniform1ivEXT; +#define glProgramUniform1ivEXT glad_glProgramUniform1ivEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORM1UIEXTPROC glad_glProgramUniform1uiEXT; +#define glProgramUniform1uiEXT glad_glProgramUniform1uiEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORM1UIVEXTPROC glad_glProgramUniform1uivEXT; +#define glProgramUniform1uivEXT glad_glProgramUniform1uivEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORM2FEXTPROC glad_glProgramUniform2fEXT; +#define glProgramUniform2fEXT glad_glProgramUniform2fEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORM2FVEXTPROC glad_glProgramUniform2fvEXT; +#define glProgramUniform2fvEXT glad_glProgramUniform2fvEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORM2IEXTPROC glad_glProgramUniform2iEXT; +#define glProgramUniform2iEXT glad_glProgramUniform2iEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORM2IVEXTPROC glad_glProgramUniform2ivEXT; +#define glProgramUniform2ivEXT glad_glProgramUniform2ivEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORM2UIEXTPROC glad_glProgramUniform2uiEXT; +#define glProgramUniform2uiEXT glad_glProgramUniform2uiEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORM2UIVEXTPROC glad_glProgramUniform2uivEXT; +#define glProgramUniform2uivEXT glad_glProgramUniform2uivEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORM3FEXTPROC glad_glProgramUniform3fEXT; +#define glProgramUniform3fEXT glad_glProgramUniform3fEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORM3FVEXTPROC glad_glProgramUniform3fvEXT; +#define glProgramUniform3fvEXT glad_glProgramUniform3fvEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORM3IEXTPROC glad_glProgramUniform3iEXT; +#define glProgramUniform3iEXT glad_glProgramUniform3iEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORM3IVEXTPROC glad_glProgramUniform3ivEXT; +#define glProgramUniform3ivEXT glad_glProgramUniform3ivEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORM3UIEXTPROC glad_glProgramUniform3uiEXT; +#define glProgramUniform3uiEXT glad_glProgramUniform3uiEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORM3UIVEXTPROC glad_glProgramUniform3uivEXT; +#define glProgramUniform3uivEXT glad_glProgramUniform3uivEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORM4FEXTPROC glad_glProgramUniform4fEXT; +#define glProgramUniform4fEXT glad_glProgramUniform4fEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORM4FVEXTPROC glad_glProgramUniform4fvEXT; +#define glProgramUniform4fvEXT glad_glProgramUniform4fvEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORM4IEXTPROC glad_glProgramUniform4iEXT; +#define glProgramUniform4iEXT glad_glProgramUniform4iEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORM4IVEXTPROC glad_glProgramUniform4ivEXT; +#define glProgramUniform4ivEXT glad_glProgramUniform4ivEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORM4UIEXTPROC glad_glProgramUniform4uiEXT; +#define glProgramUniform4uiEXT glad_glProgramUniform4uiEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORM4UIVEXTPROC glad_glProgramUniform4uivEXT; +#define glProgramUniform4uivEXT glad_glProgramUniform4uivEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX2FVEXTPROC glad_glProgramUniformMatrix2fvEXT; +#define glProgramUniformMatrix2fvEXT glad_glProgramUniformMatrix2fvEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC glad_glProgramUniformMatrix2x3fvEXT; +#define glProgramUniformMatrix2x3fvEXT glad_glProgramUniformMatrix2x3fvEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC glad_glProgramUniformMatrix2x4fvEXT; +#define glProgramUniformMatrix2x4fvEXT glad_glProgramUniformMatrix2x4fvEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX3FVEXTPROC glad_glProgramUniformMatrix3fvEXT; +#define glProgramUniformMatrix3fvEXT glad_glProgramUniformMatrix3fvEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC glad_glProgramUniformMatrix3x2fvEXT; +#define glProgramUniformMatrix3x2fvEXT glad_glProgramUniformMatrix3x2fvEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC glad_glProgramUniformMatrix3x4fvEXT; +#define glProgramUniformMatrix3x4fvEXT glad_glProgramUniformMatrix3x4fvEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX4FVEXTPROC glad_glProgramUniformMatrix4fvEXT; +#define glProgramUniformMatrix4fvEXT glad_glProgramUniformMatrix4fvEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC glad_glProgramUniformMatrix4x2fvEXT; +#define glProgramUniformMatrix4x2fvEXT glad_glProgramUniformMatrix4x2fvEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC glad_glProgramUniformMatrix4x3fvEXT; +#define glProgramUniformMatrix4x3fvEXT glad_glProgramUniformMatrix4x3fvEXT +GLAD_API_CALL PFNGLPUSHDEBUGGROUPKHRPROC glad_glPushDebugGroupKHR; +#define glPushDebugGroupKHR glad_glPushDebugGroupKHR +GLAD_API_CALL PFNGLPUSHGROUPMARKEREXTPROC glad_glPushGroupMarkerEXT; +#define glPushGroupMarkerEXT glad_glPushGroupMarkerEXT +GLAD_API_CALL PFNGLQUERYCOUNTEREXTPROC glad_glQueryCounterEXT; +#define glQueryCounterEXT glad_glQueryCounterEXT +GLAD_API_CALL PFNGLRASTERSAMPLESEXTPROC glad_glRasterSamplesEXT; +#define glRasterSamplesEXT glad_glRasterSamplesEXT +GLAD_API_CALL PFNGLREADBUFFERINDEXEDEXTPROC glad_glReadBufferIndexedEXT; +#define glReadBufferIndexedEXT glad_glReadBufferIndexedEXT +GLAD_API_CALL PFNGLREADPIXELSPROC glad_glReadPixels; +#define glReadPixels glad_glReadPixels +GLAD_API_CALL PFNGLREADNPIXELSEXTPROC glad_glReadnPixelsEXT; +#define glReadnPixelsEXT glad_glReadnPixelsEXT +GLAD_API_CALL PFNGLREADNPIXELSKHRPROC glad_glReadnPixelsKHR; +#define glReadnPixelsKHR glad_glReadnPixelsKHR +GLAD_API_CALL PFNGLRELEASEKEYEDMUTEXWIN32EXTPROC glad_glReleaseKeyedMutexWin32EXT; +#define glReleaseKeyedMutexWin32EXT glad_glReleaseKeyedMutexWin32EXT +GLAD_API_CALL PFNGLRELEASESHADERCOMPILERPROC glad_glReleaseShaderCompiler; +#define glReleaseShaderCompiler glad_glReleaseShaderCompiler +GLAD_API_CALL PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage; +#define glRenderbufferStorage glad_glRenderbufferStorage +GLAD_API_CALL PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glad_glRenderbufferStorageMultisampleEXT; +#define glRenderbufferStorageMultisampleEXT glad_glRenderbufferStorageMultisampleEXT +GLAD_API_CALL PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage; +#define glSampleCoverage glad_glSampleCoverage +GLAD_API_CALL PFNGLSAMPLERPARAMETERIIVEXTPROC glad_glSamplerParameterIivEXT; +#define glSamplerParameterIivEXT glad_glSamplerParameterIivEXT +GLAD_API_CALL PFNGLSAMPLERPARAMETERIIVOESPROC glad_glSamplerParameterIivOES; +#define glSamplerParameterIivOES glad_glSamplerParameterIivOES +GLAD_API_CALL PFNGLSAMPLERPARAMETERIUIVEXTPROC glad_glSamplerParameterIuivEXT; +#define glSamplerParameterIuivEXT glad_glSamplerParameterIuivEXT +GLAD_API_CALL PFNGLSAMPLERPARAMETERIUIVOESPROC glad_glSamplerParameterIuivOES; +#define glSamplerParameterIuivOES glad_glSamplerParameterIuivOES +GLAD_API_CALL PFNGLSCISSORPROC glad_glScissor; +#define glScissor glad_glScissor +GLAD_API_CALL PFNGLSCISSORARRAYVOESPROC glad_glScissorArrayvOES; +#define glScissorArrayvOES glad_glScissorArrayvOES +GLAD_API_CALL PFNGLSCISSORINDEXEDOESPROC glad_glScissorIndexedOES; +#define glScissorIndexedOES glad_glScissorIndexedOES +GLAD_API_CALL PFNGLSCISSORINDEXEDVOESPROC glad_glScissorIndexedvOES; +#define glScissorIndexedvOES glad_glScissorIndexedvOES +GLAD_API_CALL PFNGLSEMAPHOREPARAMETERUI64VEXTPROC glad_glSemaphoreParameterui64vEXT; +#define glSemaphoreParameterui64vEXT glad_glSemaphoreParameterui64vEXT +GLAD_API_CALL PFNGLSHADERBINARYPROC glad_glShaderBinary; +#define glShaderBinary glad_glShaderBinary +GLAD_API_CALL PFNGLSHADERSOURCEPROC glad_glShaderSource; +#define glShaderSource glad_glShaderSource +GLAD_API_CALL PFNGLSHADINGRATECOMBINEROPSEXTPROC glad_glShadingRateCombinerOpsEXT; +#define glShadingRateCombinerOpsEXT glad_glShadingRateCombinerOpsEXT +GLAD_API_CALL PFNGLSHADINGRATEEXTPROC glad_glShadingRateEXT; +#define glShadingRateEXT glad_glShadingRateEXT +GLAD_API_CALL PFNGLSIGNALSEMAPHOREEXTPROC glad_glSignalSemaphoreEXT; +#define glSignalSemaphoreEXT glad_glSignalSemaphoreEXT +GLAD_API_CALL PFNGLSTENCILFUNCPROC glad_glStencilFunc; +#define glStencilFunc glad_glStencilFunc +GLAD_API_CALL PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate; +#define glStencilFuncSeparate glad_glStencilFuncSeparate +GLAD_API_CALL PFNGLSTENCILMASKPROC glad_glStencilMask; +#define glStencilMask glad_glStencilMask +GLAD_API_CALL PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate; +#define glStencilMaskSeparate glad_glStencilMaskSeparate +GLAD_API_CALL PFNGLSTENCILOPPROC glad_glStencilOp; +#define glStencilOp glad_glStencilOp +GLAD_API_CALL PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate; +#define glStencilOpSeparate glad_glStencilOpSeparate +GLAD_API_CALL PFNGLTEXBUFFEREXTPROC glad_glTexBufferEXT; +#define glTexBufferEXT glad_glTexBufferEXT +GLAD_API_CALL PFNGLTEXBUFFEROESPROC glad_glTexBufferOES; +#define glTexBufferOES glad_glTexBufferOES +GLAD_API_CALL PFNGLTEXBUFFERRANGEEXTPROC glad_glTexBufferRangeEXT; +#define glTexBufferRangeEXT glad_glTexBufferRangeEXT +GLAD_API_CALL PFNGLTEXBUFFERRANGEOESPROC glad_glTexBufferRangeOES; +#define glTexBufferRangeOES glad_glTexBufferRangeOES +GLAD_API_CALL PFNGLTEXIMAGE2DPROC glad_glTexImage2D; +#define glTexImage2D glad_glTexImage2D +GLAD_API_CALL PFNGLTEXIMAGE3DOESPROC glad_glTexImage3DOES; +#define glTexImage3DOES glad_glTexImage3DOES +GLAD_API_CALL PFNGLTEXPAGECOMMITMENTEXTPROC glad_glTexPageCommitmentEXT; +#define glTexPageCommitmentEXT glad_glTexPageCommitmentEXT +GLAD_API_CALL PFNGLTEXPARAMETERIIVEXTPROC glad_glTexParameterIivEXT; +#define glTexParameterIivEXT glad_glTexParameterIivEXT +GLAD_API_CALL PFNGLTEXPARAMETERIIVOESPROC glad_glTexParameterIivOES; +#define glTexParameterIivOES glad_glTexParameterIivOES +GLAD_API_CALL PFNGLTEXPARAMETERIUIVEXTPROC glad_glTexParameterIuivEXT; +#define glTexParameterIuivEXT glad_glTexParameterIuivEXT +GLAD_API_CALL PFNGLTEXPARAMETERIUIVOESPROC glad_glTexParameterIuivOES; +#define glTexParameterIuivOES glad_glTexParameterIuivOES +GLAD_API_CALL PFNGLTEXPARAMETERFPROC glad_glTexParameterf; +#define glTexParameterf glad_glTexParameterf +GLAD_API_CALL PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv; +#define glTexParameterfv glad_glTexParameterfv +GLAD_API_CALL PFNGLTEXPARAMETERIPROC glad_glTexParameteri; +#define glTexParameteri glad_glTexParameteri +GLAD_API_CALL PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv; +#define glTexParameteriv glad_glTexParameteriv +GLAD_API_CALL PFNGLTEXSTORAGE1DEXTPROC glad_glTexStorage1DEXT; +#define glTexStorage1DEXT glad_glTexStorage1DEXT +GLAD_API_CALL PFNGLTEXSTORAGE2DEXTPROC glad_glTexStorage2DEXT; +#define glTexStorage2DEXT glad_glTexStorage2DEXT +GLAD_API_CALL PFNGLTEXSTORAGE3DEXTPROC glad_glTexStorage3DEXT; +#define glTexStorage3DEXT glad_glTexStorage3DEXT +GLAD_API_CALL PFNGLTEXSTORAGE3DMULTISAMPLEOESPROC glad_glTexStorage3DMultisampleOES; +#define glTexStorage3DMultisampleOES glad_glTexStorage3DMultisampleOES +GLAD_API_CALL PFNGLTEXSTORAGEATTRIBS2DEXTPROC glad_glTexStorageAttribs2DEXT; +#define glTexStorageAttribs2DEXT glad_glTexStorageAttribs2DEXT +GLAD_API_CALL PFNGLTEXSTORAGEATTRIBS3DEXTPROC glad_glTexStorageAttribs3DEXT; +#define glTexStorageAttribs3DEXT glad_glTexStorageAttribs3DEXT +GLAD_API_CALL PFNGLTEXSTORAGEMEM2DEXTPROC glad_glTexStorageMem2DEXT; +#define glTexStorageMem2DEXT glad_glTexStorageMem2DEXT +GLAD_API_CALL PFNGLTEXSTORAGEMEM2DMULTISAMPLEEXTPROC glad_glTexStorageMem2DMultisampleEXT; +#define glTexStorageMem2DMultisampleEXT glad_glTexStorageMem2DMultisampleEXT +GLAD_API_CALL PFNGLTEXSTORAGEMEM3DEXTPROC glad_glTexStorageMem3DEXT; +#define glTexStorageMem3DEXT glad_glTexStorageMem3DEXT +GLAD_API_CALL PFNGLTEXSTORAGEMEM3DMULTISAMPLEEXTPROC glad_glTexStorageMem3DMultisampleEXT; +#define glTexStorageMem3DMultisampleEXT glad_glTexStorageMem3DMultisampleEXT +GLAD_API_CALL PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D; +#define glTexSubImage2D glad_glTexSubImage2D +GLAD_API_CALL PFNGLTEXSUBIMAGE3DOESPROC glad_glTexSubImage3DOES; +#define glTexSubImage3DOES glad_glTexSubImage3DOES +GLAD_API_CALL PFNGLTEXTURESTORAGE1DEXTPROC glad_glTextureStorage1DEXT; +#define glTextureStorage1DEXT glad_glTextureStorage1DEXT +GLAD_API_CALL PFNGLTEXTURESTORAGE2DEXTPROC glad_glTextureStorage2DEXT; +#define glTextureStorage2DEXT glad_glTextureStorage2DEXT +GLAD_API_CALL PFNGLTEXTURESTORAGE3DEXTPROC glad_glTextureStorage3DEXT; +#define glTextureStorage3DEXT glad_glTextureStorage3DEXT +GLAD_API_CALL PFNGLTEXTURESTORAGEMEM2DEXTPROC glad_glTextureStorageMem2DEXT; +#define glTextureStorageMem2DEXT glad_glTextureStorageMem2DEXT +GLAD_API_CALL PFNGLTEXTURESTORAGEMEM2DMULTISAMPLEEXTPROC glad_glTextureStorageMem2DMultisampleEXT; +#define glTextureStorageMem2DMultisampleEXT glad_glTextureStorageMem2DMultisampleEXT +GLAD_API_CALL PFNGLTEXTURESTORAGEMEM3DEXTPROC glad_glTextureStorageMem3DEXT; +#define glTextureStorageMem3DEXT glad_glTextureStorageMem3DEXT +GLAD_API_CALL PFNGLTEXTURESTORAGEMEM3DMULTISAMPLEEXTPROC glad_glTextureStorageMem3DMultisampleEXT; +#define glTextureStorageMem3DMultisampleEXT glad_glTextureStorageMem3DMultisampleEXT +GLAD_API_CALL PFNGLTEXTUREVIEWEXTPROC glad_glTextureViewEXT; +#define glTextureViewEXT glad_glTextureViewEXT +GLAD_API_CALL PFNGLTEXTUREVIEWOESPROC glad_glTextureViewOES; +#define glTextureViewOES glad_glTextureViewOES +GLAD_API_CALL PFNGLUNIFORM1FPROC glad_glUniform1f; +#define glUniform1f glad_glUniform1f +GLAD_API_CALL PFNGLUNIFORM1FVPROC glad_glUniform1fv; +#define glUniform1fv glad_glUniform1fv +GLAD_API_CALL PFNGLUNIFORM1IPROC glad_glUniform1i; +#define glUniform1i glad_glUniform1i +GLAD_API_CALL PFNGLUNIFORM1IVPROC glad_glUniform1iv; +#define glUniform1iv glad_glUniform1iv +GLAD_API_CALL PFNGLUNIFORM2FPROC glad_glUniform2f; +#define glUniform2f glad_glUniform2f +GLAD_API_CALL PFNGLUNIFORM2FVPROC glad_glUniform2fv; +#define glUniform2fv glad_glUniform2fv +GLAD_API_CALL PFNGLUNIFORM2IPROC glad_glUniform2i; +#define glUniform2i glad_glUniform2i +GLAD_API_CALL PFNGLUNIFORM2IVPROC glad_glUniform2iv; +#define glUniform2iv glad_glUniform2iv +GLAD_API_CALL PFNGLUNIFORM3FPROC glad_glUniform3f; +#define glUniform3f glad_glUniform3f +GLAD_API_CALL PFNGLUNIFORM3FVPROC glad_glUniform3fv; +#define glUniform3fv glad_glUniform3fv +GLAD_API_CALL PFNGLUNIFORM3IPROC glad_glUniform3i; +#define glUniform3i glad_glUniform3i +GLAD_API_CALL PFNGLUNIFORM3IVPROC glad_glUniform3iv; +#define glUniform3iv glad_glUniform3iv +GLAD_API_CALL PFNGLUNIFORM4FPROC glad_glUniform4f; +#define glUniform4f glad_glUniform4f +GLAD_API_CALL PFNGLUNIFORM4FVPROC glad_glUniform4fv; +#define glUniform4fv glad_glUniform4fv +GLAD_API_CALL PFNGLUNIFORM4IPROC glad_glUniform4i; +#define glUniform4i glad_glUniform4i +GLAD_API_CALL PFNGLUNIFORM4IVPROC glad_glUniform4iv; +#define glUniform4iv glad_glUniform4iv +GLAD_API_CALL PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv; +#define glUniformMatrix2fv glad_glUniformMatrix2fv +GLAD_API_CALL PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv; +#define glUniformMatrix3fv glad_glUniformMatrix3fv +GLAD_API_CALL PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv; +#define glUniformMatrix4fv glad_glUniformMatrix4fv +GLAD_API_CALL PFNGLUNMAPBUFFEROESPROC glad_glUnmapBufferOES; +#define glUnmapBufferOES glad_glUnmapBufferOES +GLAD_API_CALL PFNGLUSEPROGRAMPROC glad_glUseProgram; +#define glUseProgram glad_glUseProgram +GLAD_API_CALL PFNGLUSEPROGRAMSTAGESEXTPROC glad_glUseProgramStagesEXT; +#define glUseProgramStagesEXT glad_glUseProgramStagesEXT +GLAD_API_CALL PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram; +#define glValidateProgram glad_glValidateProgram +GLAD_API_CALL PFNGLVALIDATEPROGRAMPIPELINEEXTPROC glad_glValidateProgramPipelineEXT; +#define glValidateProgramPipelineEXT glad_glValidateProgramPipelineEXT +GLAD_API_CALL PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f; +#define glVertexAttrib1f glad_glVertexAttrib1f +GLAD_API_CALL PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv; +#define glVertexAttrib1fv glad_glVertexAttrib1fv +GLAD_API_CALL PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f; +#define glVertexAttrib2f glad_glVertexAttrib2f +GLAD_API_CALL PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv; +#define glVertexAttrib2fv glad_glVertexAttrib2fv +GLAD_API_CALL PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f; +#define glVertexAttrib3f glad_glVertexAttrib3f +GLAD_API_CALL PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv; +#define glVertexAttrib3fv glad_glVertexAttrib3fv +GLAD_API_CALL PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f; +#define glVertexAttrib4f glad_glVertexAttrib4f +GLAD_API_CALL PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv; +#define glVertexAttrib4fv glad_glVertexAttrib4fv +GLAD_API_CALL PFNGLVERTEXATTRIBDIVISOREXTPROC glad_glVertexAttribDivisorEXT; +#define glVertexAttribDivisorEXT glad_glVertexAttribDivisorEXT +GLAD_API_CALL PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer; +#define glVertexAttribPointer glad_glVertexAttribPointer +GLAD_API_CALL PFNGLVIEWPORTPROC glad_glViewport; +#define glViewport glad_glViewport +GLAD_API_CALL PFNGLVIEWPORTARRAYVOESPROC glad_glViewportArrayvOES; +#define glViewportArrayvOES glad_glViewportArrayvOES +GLAD_API_CALL PFNGLVIEWPORTINDEXEDFOESPROC glad_glViewportIndexedfOES; +#define glViewportIndexedfOES glad_glViewportIndexedfOES +GLAD_API_CALL PFNGLVIEWPORTINDEXEDFVOESPROC glad_glViewportIndexedfvOES; +#define glViewportIndexedfvOES glad_glViewportIndexedfvOES +GLAD_API_CALL PFNGLWAITSEMAPHOREEXTPROC glad_glWaitSemaphoreEXT; +#define glWaitSemaphoreEXT glad_glWaitSemaphoreEXT +GLAD_API_CALL PFNGLWINDOWRECTANGLESEXTPROC glad_glWindowRectanglesEXT; +#define glWindowRectanglesEXT glad_glWindowRectanglesEXT + + + + + +GLAD_API_CALL int gladLoadGLES2UserPtr( GLADuserptrloadfunc load, void *userptr); +GLAD_API_CALL int gladLoadGLES2( GLADloadfunc load); + + + +#ifdef __cplusplus +} +#endif +#endif + +/* Source */ +#ifdef GLAD_GLES2_IMPLEMENTATION +/** + * SPDX-License-Identifier: (WTFPL OR CC0-1.0) AND Apache-2.0 + */ +#include +#include +#include + +#ifndef GLAD_IMPL_UTIL_C_ +#define GLAD_IMPL_UTIL_C_ + +#ifdef _MSC_VER +#define GLAD_IMPL_UTIL_SSCANF sscanf_s +#else +#define GLAD_IMPL_UTIL_SSCANF sscanf +#endif + +#endif /* GLAD_IMPL_UTIL_C_ */ + +#ifdef __cplusplus +extern "C" { +#endif + + + +int GLAD_GL_ES_VERSION_2_0 = 0; +int GLAD_GL_EXT_EGL_image_array = 0; +int GLAD_GL_EXT_EGL_image_storage = 0; +int GLAD_GL_EXT_EGL_image_storage_compression = 0; +int GLAD_GL_EXT_YUV_target = 0; +int GLAD_GL_EXT_base_instance = 0; +int GLAD_GL_EXT_blend_func_extended = 0; +int GLAD_GL_EXT_blend_minmax = 0; +int GLAD_GL_EXT_buffer_storage = 0; +int GLAD_GL_EXT_clear_texture = 0; +int GLAD_GL_EXT_clip_control = 0; +int GLAD_GL_EXT_clip_cull_distance = 0; +int GLAD_GL_EXT_color_buffer_float = 0; +int GLAD_GL_EXT_color_buffer_half_float = 0; +int GLAD_GL_EXT_conservative_depth = 0; +int GLAD_GL_EXT_copy_image = 0; +int GLAD_GL_EXT_debug_label = 0; +int GLAD_GL_EXT_debug_marker = 0; +int GLAD_GL_EXT_depth_clamp = 0; +int GLAD_GL_EXT_discard_framebuffer = 0; +int GLAD_GL_EXT_disjoint_timer_query = 0; +int GLAD_GL_EXT_draw_buffers = 0; +int GLAD_GL_EXT_draw_buffers_indexed = 0; +int GLAD_GL_EXT_draw_elements_base_vertex = 0; +int GLAD_GL_EXT_draw_instanced = 0; +int GLAD_GL_EXT_draw_transform_feedback = 0; +int GLAD_GL_EXT_external_buffer = 0; +int GLAD_GL_EXT_float_blend = 0; +int GLAD_GL_EXT_fragment_shading_rate = 0; +int GLAD_GL_EXT_geometry_point_size = 0; +int GLAD_GL_EXT_geometry_shader = 0; +int GLAD_GL_EXT_gpu_shader5 = 0; +int GLAD_GL_EXT_instanced_arrays = 0; +int GLAD_GL_EXT_map_buffer_range = 0; +int GLAD_GL_EXT_memory_object = 0; +int GLAD_GL_EXT_memory_object_fd = 0; +int GLAD_GL_EXT_memory_object_win32 = 0; +int GLAD_GL_EXT_multi_draw_arrays = 0; +int GLAD_GL_EXT_multi_draw_indirect = 0; +int GLAD_GL_EXT_multisampled_compatibility = 0; +int GLAD_GL_EXT_multisampled_render_to_texture = 0; +int GLAD_GL_EXT_multisampled_render_to_texture2 = 0; +int GLAD_GL_EXT_multiview_draw_buffers = 0; +int GLAD_GL_EXT_multiview_tessellation_geometry_shader = 0; +int GLAD_GL_EXT_multiview_texture_multisample = 0; +int GLAD_GL_EXT_multiview_timer_query = 0; +int GLAD_GL_EXT_occlusion_query_boolean = 0; +int GLAD_GL_EXT_polygon_offset_clamp = 0; +int GLAD_GL_EXT_post_depth_coverage = 0; +int GLAD_GL_EXT_primitive_bounding_box = 0; +int GLAD_GL_EXT_protected_textures = 0; +int GLAD_GL_EXT_pvrtc_sRGB = 0; +int GLAD_GL_EXT_raster_multisample = 0; +int GLAD_GL_EXT_read_format_bgra = 0; +int GLAD_GL_EXT_render_snorm = 0; +int GLAD_GL_EXT_robustness = 0; +int GLAD_GL_EXT_sRGB = 0; +int GLAD_GL_EXT_sRGB_write_control = 0; +int GLAD_GL_EXT_semaphore = 0; +int GLAD_GL_EXT_semaphore_fd = 0; +int GLAD_GL_EXT_semaphore_win32 = 0; +int GLAD_GL_EXT_separate_depth_stencil = 0; +int GLAD_GL_EXT_separate_shader_objects = 0; +int GLAD_GL_EXT_shader_framebuffer_fetch = 0; +int GLAD_GL_EXT_shader_framebuffer_fetch_non_coherent = 0; +int GLAD_GL_EXT_shader_group_vote = 0; +int GLAD_GL_EXT_shader_implicit_conversions = 0; +int GLAD_GL_EXT_shader_integer_mix = 0; +int GLAD_GL_EXT_shader_io_blocks = 0; +int GLAD_GL_EXT_shader_non_constant_global_initializers = 0; +int GLAD_GL_EXT_shader_pixel_local_storage = 0; +int GLAD_GL_EXT_shader_pixel_local_storage2 = 0; +int GLAD_GL_EXT_shader_samples_identical = 0; +int GLAD_GL_EXT_shader_texture_lod = 0; +int GLAD_GL_EXT_shadow_samplers = 0; +int GLAD_GL_EXT_sparse_texture = 0; +int GLAD_GL_EXT_sparse_texture2 = 0; +int GLAD_GL_EXT_tessellation_point_size = 0; +int GLAD_GL_EXT_tessellation_shader = 0; +int GLAD_GL_EXT_texture_border_clamp = 0; +int GLAD_GL_EXT_texture_buffer = 0; +int GLAD_GL_EXT_texture_compression_astc_decode_mode = 0; +int GLAD_GL_EXT_texture_compression_bptc = 0; +int GLAD_GL_EXT_texture_compression_dxt1 = 0; +int GLAD_GL_EXT_texture_compression_rgtc = 0; +int GLAD_GL_EXT_texture_compression_s3tc = 0; +int GLAD_GL_EXT_texture_compression_s3tc_srgb = 0; +int GLAD_GL_EXT_texture_cube_map_array = 0; +int GLAD_GL_EXT_texture_filter_anisotropic = 0; +int GLAD_GL_EXT_texture_filter_minmax = 0; +int GLAD_GL_EXT_texture_format_BGRA8888 = 0; +int GLAD_GL_EXT_texture_format_sRGB_override = 0; +int GLAD_GL_EXT_texture_mirror_clamp_to_edge = 0; +int GLAD_GL_EXT_texture_norm16 = 0; +int GLAD_GL_EXT_texture_query_lod = 0; +int GLAD_GL_EXT_texture_rg = 0; +int GLAD_GL_EXT_texture_sRGB_R8 = 0; +int GLAD_GL_EXT_texture_sRGB_RG8 = 0; +int GLAD_GL_EXT_texture_sRGB_decode = 0; +int GLAD_GL_EXT_texture_shadow_lod = 0; +int GLAD_GL_EXT_texture_storage = 0; +int GLAD_GL_EXT_texture_storage_compression = 0; +int GLAD_GL_EXT_texture_type_2_10_10_10_REV = 0; +int GLAD_GL_EXT_texture_view = 0; +int GLAD_GL_EXT_unpack_subimage = 0; +int GLAD_GL_EXT_win32_keyed_mutex = 0; +int GLAD_GL_EXT_window_rectangles = 0; +int GLAD_GL_KHR_blend_equation_advanced = 0; +int GLAD_GL_KHR_blend_equation_advanced_coherent = 0; +int GLAD_GL_KHR_context_flush_control = 0; +int GLAD_GL_KHR_debug = 0; +int GLAD_GL_KHR_no_error = 0; +int GLAD_GL_KHR_parallel_shader_compile = 0; +int GLAD_GL_KHR_robust_buffer_access_behavior = 0; +int GLAD_GL_KHR_robustness = 0; +int GLAD_GL_KHR_shader_subgroup = 0; +int GLAD_GL_KHR_texture_compression_astc_hdr = 0; +int GLAD_GL_KHR_texture_compression_astc_ldr = 0; +int GLAD_GL_KHR_texture_compression_astc_sliced_3d = 0; +int GLAD_GL_OES_EGL_image = 0; +int GLAD_GL_OES_EGL_image_external = 0; +int GLAD_GL_OES_EGL_image_external_essl3 = 0; +int GLAD_GL_OES_compressed_ETC1_RGB8_sub_texture = 0; +int GLAD_GL_OES_compressed_ETC1_RGB8_texture = 0; +int GLAD_GL_OES_compressed_paletted_texture = 0; +int GLAD_GL_OES_copy_image = 0; +int GLAD_GL_OES_depth24 = 0; +int GLAD_GL_OES_depth32 = 0; +int GLAD_GL_OES_depth_texture = 0; +int GLAD_GL_OES_draw_buffers_indexed = 0; +int GLAD_GL_OES_draw_elements_base_vertex = 0; +int GLAD_GL_OES_element_index_uint = 0; +int GLAD_GL_OES_fbo_render_mipmap = 0; +int GLAD_GL_OES_fragment_precision_high = 0; +int GLAD_GL_OES_geometry_point_size = 0; +int GLAD_GL_OES_geometry_shader = 0; +int GLAD_GL_OES_get_program_binary = 0; +int GLAD_GL_OES_gpu_shader5 = 0; +int GLAD_GL_OES_mapbuffer = 0; +int GLAD_GL_OES_packed_depth_stencil = 0; +int GLAD_GL_OES_primitive_bounding_box = 0; +int GLAD_GL_OES_required_internalformat = 0; +int GLAD_GL_OES_rgb8_rgba8 = 0; +int GLAD_GL_OES_sample_shading = 0; +int GLAD_GL_OES_sample_variables = 0; +int GLAD_GL_OES_shader_image_atomic = 0; +int GLAD_GL_OES_shader_io_blocks = 0; +int GLAD_GL_OES_shader_multisample_interpolation = 0; +int GLAD_GL_OES_standard_derivatives = 0; +int GLAD_GL_OES_stencil1 = 0; +int GLAD_GL_OES_stencil4 = 0; +int GLAD_GL_OES_surfaceless_context = 0; +int GLAD_GL_OES_tessellation_point_size = 0; +int GLAD_GL_OES_tessellation_shader = 0; +int GLAD_GL_OES_texture_3D = 0; +int GLAD_GL_OES_texture_border_clamp = 0; +int GLAD_GL_OES_texture_buffer = 0; +int GLAD_GL_OES_texture_compression_astc = 0; +int GLAD_GL_OES_texture_cube_map_array = 0; +int GLAD_GL_OES_texture_float = 0; +int GLAD_GL_OES_texture_float_linear = 0; +int GLAD_GL_OES_texture_half_float = 0; +int GLAD_GL_OES_texture_half_float_linear = 0; +int GLAD_GL_OES_texture_npot = 0; +int GLAD_GL_OES_texture_stencil8 = 0; +int GLAD_GL_OES_texture_storage_multisample_2d_array = 0; +int GLAD_GL_OES_texture_view = 0; +int GLAD_GL_OES_vertex_array_object = 0; +int GLAD_GL_OES_vertex_half_float = 0; +int GLAD_GL_OES_vertex_type_10_10_10_2 = 0; +int GLAD_GL_OES_viewport_array = 0; + + + +PFNGLACQUIREKEYEDMUTEXWIN32EXTPROC glad_glAcquireKeyedMutexWin32EXT = NULL; +PFNGLACTIVESHADERPROGRAMEXTPROC glad_glActiveShaderProgramEXT = NULL; +PFNGLACTIVETEXTUREPROC glad_glActiveTexture = NULL; +PFNGLATTACHSHADERPROC glad_glAttachShader = NULL; +PFNGLBEGINQUERYEXTPROC glad_glBeginQueryEXT = NULL; +PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation = NULL; +PFNGLBINDBUFFERPROC glad_glBindBuffer = NULL; +PFNGLBINDFRAGDATALOCATIONEXTPROC glad_glBindFragDataLocationEXT = NULL; +PFNGLBINDFRAGDATALOCATIONINDEXEDEXTPROC glad_glBindFragDataLocationIndexedEXT = NULL; +PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer = NULL; +PFNGLBINDPROGRAMPIPELINEEXTPROC glad_glBindProgramPipelineEXT = NULL; +PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer = NULL; +PFNGLBINDTEXTUREPROC glad_glBindTexture = NULL; +PFNGLBINDVERTEXARRAYOESPROC glad_glBindVertexArrayOES = NULL; +PFNGLBLENDBARRIERKHRPROC glad_glBlendBarrierKHR = NULL; +PFNGLBLENDCOLORPROC glad_glBlendColor = NULL; +PFNGLBLENDEQUATIONPROC glad_glBlendEquation = NULL; +PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate = NULL; +PFNGLBLENDEQUATIONSEPARATEIEXTPROC glad_glBlendEquationSeparateiEXT = NULL; +PFNGLBLENDEQUATIONSEPARATEIOESPROC glad_glBlendEquationSeparateiOES = NULL; +PFNGLBLENDEQUATIONIEXTPROC glad_glBlendEquationiEXT = NULL; +PFNGLBLENDEQUATIONIOESPROC glad_glBlendEquationiOES = NULL; +PFNGLBLENDFUNCPROC glad_glBlendFunc = NULL; +PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate = NULL; +PFNGLBLENDFUNCSEPARATEIEXTPROC glad_glBlendFuncSeparateiEXT = NULL; +PFNGLBLENDFUNCSEPARATEIOESPROC glad_glBlendFuncSeparateiOES = NULL; +PFNGLBLENDFUNCIEXTPROC glad_glBlendFunciEXT = NULL; +PFNGLBLENDFUNCIOESPROC glad_glBlendFunciOES = NULL; +PFNGLBUFFERDATAPROC glad_glBufferData = NULL; +PFNGLBUFFERSTORAGEEXTPROC glad_glBufferStorageEXT = NULL; +PFNGLBUFFERSTORAGEEXTERNALEXTPROC glad_glBufferStorageExternalEXT = NULL; +PFNGLBUFFERSTORAGEMEMEXTPROC glad_glBufferStorageMemEXT = NULL; +PFNGLBUFFERSUBDATAPROC glad_glBufferSubData = NULL; +PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus = NULL; +PFNGLCLEARPROC glad_glClear = NULL; +PFNGLCLEARCOLORPROC glad_glClearColor = NULL; +PFNGLCLEARDEPTHFPROC glad_glClearDepthf = NULL; +PFNGLCLEARPIXELLOCALSTORAGEUIEXTPROC glad_glClearPixelLocalStorageuiEXT = NULL; +PFNGLCLEARSTENCILPROC glad_glClearStencil = NULL; +PFNGLCLEARTEXIMAGEEXTPROC glad_glClearTexImageEXT = NULL; +PFNGLCLEARTEXSUBIMAGEEXTPROC glad_glClearTexSubImageEXT = NULL; +PFNGLCLIPCONTROLEXTPROC glad_glClipControlEXT = NULL; +PFNGLCOLORMASKPROC glad_glColorMask = NULL; +PFNGLCOLORMASKIEXTPROC glad_glColorMaskiEXT = NULL; +PFNGLCOLORMASKIOESPROC glad_glColorMaskiOES = NULL; +PFNGLCOMPILESHADERPROC glad_glCompileShader = NULL; +PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D = NULL; +PFNGLCOMPRESSEDTEXIMAGE3DOESPROC glad_glCompressedTexImage3DOES = NULL; +PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D = NULL; +PFNGLCOMPRESSEDTEXSUBIMAGE3DOESPROC glad_glCompressedTexSubImage3DOES = NULL; +PFNGLCOPYIMAGESUBDATAEXTPROC glad_glCopyImageSubDataEXT = NULL; +PFNGLCOPYIMAGESUBDATAOESPROC glad_glCopyImageSubDataOES = NULL; +PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D = NULL; +PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D = NULL; +PFNGLCOPYTEXSUBIMAGE3DOESPROC glad_glCopyTexSubImage3DOES = NULL; +PFNGLCREATEMEMORYOBJECTSEXTPROC glad_glCreateMemoryObjectsEXT = NULL; +PFNGLCREATEPROGRAMPROC glad_glCreateProgram = NULL; +PFNGLCREATESHADERPROC glad_glCreateShader = NULL; +PFNGLCREATESHADERPROGRAMVEXTPROC glad_glCreateShaderProgramvEXT = NULL; +PFNGLCULLFACEPROC glad_glCullFace = NULL; +PFNGLDEBUGMESSAGECALLBACKKHRPROC glad_glDebugMessageCallbackKHR = NULL; +PFNGLDEBUGMESSAGECONTROLKHRPROC glad_glDebugMessageControlKHR = NULL; +PFNGLDEBUGMESSAGEINSERTKHRPROC glad_glDebugMessageInsertKHR = NULL; +PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers = NULL; +PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers = NULL; +PFNGLDELETEMEMORYOBJECTSEXTPROC glad_glDeleteMemoryObjectsEXT = NULL; +PFNGLDELETEPROGRAMPROC glad_glDeleteProgram = NULL; +PFNGLDELETEPROGRAMPIPELINESEXTPROC glad_glDeleteProgramPipelinesEXT = NULL; +PFNGLDELETEQUERIESEXTPROC glad_glDeleteQueriesEXT = NULL; +PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers = NULL; +PFNGLDELETESEMAPHORESEXTPROC glad_glDeleteSemaphoresEXT = NULL; +PFNGLDELETESHADERPROC glad_glDeleteShader = NULL; +PFNGLDELETETEXTURESPROC glad_glDeleteTextures = NULL; +PFNGLDELETEVERTEXARRAYSOESPROC glad_glDeleteVertexArraysOES = NULL; +PFNGLDEPTHFUNCPROC glad_glDepthFunc = NULL; +PFNGLDEPTHMASKPROC glad_glDepthMask = NULL; +PFNGLDEPTHRANGEARRAYFVOESPROC glad_glDepthRangeArrayfvOES = NULL; +PFNGLDEPTHRANGEINDEXEDFOESPROC glad_glDepthRangeIndexedfOES = NULL; +PFNGLDEPTHRANGEFPROC glad_glDepthRangef = NULL; +PFNGLDETACHSHADERPROC glad_glDetachShader = NULL; +PFNGLDISABLEPROC glad_glDisable = NULL; +PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray = NULL; +PFNGLDISABLEIEXTPROC glad_glDisableiEXT = NULL; +PFNGLDISABLEIOESPROC glad_glDisableiOES = NULL; +PFNGLDISCARDFRAMEBUFFEREXTPROC glad_glDiscardFramebufferEXT = NULL; +PFNGLDRAWARRAYSPROC glad_glDrawArrays = NULL; +PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEEXTPROC glad_glDrawArraysInstancedBaseInstanceEXT = NULL; +PFNGLDRAWARRAYSINSTANCEDEXTPROC glad_glDrawArraysInstancedEXT = NULL; +PFNGLDRAWBUFFERSEXTPROC glad_glDrawBuffersEXT = NULL; +PFNGLDRAWBUFFERSINDEXEDEXTPROC glad_glDrawBuffersIndexedEXT = NULL; +PFNGLDRAWELEMENTSPROC glad_glDrawElements = NULL; +PFNGLDRAWELEMENTSBASEVERTEXEXTPROC glad_glDrawElementsBaseVertexEXT = NULL; +PFNGLDRAWELEMENTSBASEVERTEXOESPROC glad_glDrawElementsBaseVertexOES = NULL; +PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEEXTPROC glad_glDrawElementsInstancedBaseInstanceEXT = NULL; +PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEEXTPROC glad_glDrawElementsInstancedBaseVertexBaseInstanceEXT = NULL; +PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXEXTPROC glad_glDrawElementsInstancedBaseVertexEXT = NULL; +PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXOESPROC glad_glDrawElementsInstancedBaseVertexOES = NULL; +PFNGLDRAWELEMENTSINSTANCEDEXTPROC glad_glDrawElementsInstancedEXT = NULL; +PFNGLDRAWRANGEELEMENTSBASEVERTEXEXTPROC glad_glDrawRangeElementsBaseVertexEXT = NULL; +PFNGLDRAWRANGEELEMENTSBASEVERTEXOESPROC glad_glDrawRangeElementsBaseVertexOES = NULL; +PFNGLDRAWTRANSFORMFEEDBACKEXTPROC glad_glDrawTransformFeedbackEXT = NULL; +PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDEXTPROC glad_glDrawTransformFeedbackInstancedEXT = NULL; +PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glad_glEGLImageTargetRenderbufferStorageOES = NULL; +PFNGLEGLIMAGETARGETTEXSTORAGEEXTPROC glad_glEGLImageTargetTexStorageEXT = NULL; +PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glad_glEGLImageTargetTexture2DOES = NULL; +PFNGLEGLIMAGETARGETTEXTURESTORAGEEXTPROC glad_glEGLImageTargetTextureStorageEXT = NULL; +PFNGLENABLEPROC glad_glEnable = NULL; +PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray = NULL; +PFNGLENABLEIEXTPROC glad_glEnableiEXT = NULL; +PFNGLENABLEIOESPROC glad_glEnableiOES = NULL; +PFNGLENDQUERYEXTPROC glad_glEndQueryEXT = NULL; +PFNGLFINISHPROC glad_glFinish = NULL; +PFNGLFLUSHPROC glad_glFlush = NULL; +PFNGLFLUSHMAPPEDBUFFERRANGEEXTPROC glad_glFlushMappedBufferRangeEXT = NULL; +PFNGLFRAMEBUFFERFETCHBARRIEREXTPROC glad_glFramebufferFetchBarrierEXT = NULL; +PFNGLFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC glad_glFramebufferPixelLocalStorageSizeEXT = NULL; +PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer = NULL; +PFNGLFRAMEBUFFERSHADINGRATEEXTPROC glad_glFramebufferShadingRateEXT = NULL; +PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D = NULL; +PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC glad_glFramebufferTexture2DMultisampleEXT = NULL; +PFNGLFRAMEBUFFERTEXTURE3DOESPROC glad_glFramebufferTexture3DOES = NULL; +PFNGLFRAMEBUFFERTEXTUREEXTPROC glad_glFramebufferTextureEXT = NULL; +PFNGLFRAMEBUFFERTEXTUREOESPROC glad_glFramebufferTextureOES = NULL; +PFNGLFRONTFACEPROC glad_glFrontFace = NULL; +PFNGLGENBUFFERSPROC glad_glGenBuffers = NULL; +PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers = NULL; +PFNGLGENPROGRAMPIPELINESEXTPROC glad_glGenProgramPipelinesEXT = NULL; +PFNGLGENQUERIESEXTPROC glad_glGenQueriesEXT = NULL; +PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers = NULL; +PFNGLGENSEMAPHORESEXTPROC glad_glGenSemaphoresEXT = NULL; +PFNGLGENTEXTURESPROC glad_glGenTextures = NULL; +PFNGLGENVERTEXARRAYSOESPROC glad_glGenVertexArraysOES = NULL; +PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap = NULL; +PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib = NULL; +PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform = NULL; +PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders = NULL; +PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation = NULL; +PFNGLGETBOOLEANVPROC glad_glGetBooleanv = NULL; +PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv = NULL; +PFNGLGETBUFFERPOINTERVOESPROC glad_glGetBufferPointervOES = NULL; +PFNGLGETDEBUGMESSAGELOGKHRPROC glad_glGetDebugMessageLogKHR = NULL; +PFNGLGETERRORPROC glad_glGetError = NULL; +PFNGLGETFLOATI_VOESPROC glad_glGetFloati_vOES = NULL; +PFNGLGETFLOATVPROC glad_glGetFloatv = NULL; +PFNGLGETFRAGDATAINDEXEXTPROC glad_glGetFragDataIndexEXT = NULL; +PFNGLGETFRAGMENTSHADINGRATESEXTPROC glad_glGetFragmentShadingRatesEXT = NULL; +PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv = NULL; +PFNGLGETFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC glad_glGetFramebufferPixelLocalStorageSizeEXT = NULL; +PFNGLGETGRAPHICSRESETSTATUSEXTPROC glad_glGetGraphicsResetStatusEXT = NULL; +PFNGLGETGRAPHICSRESETSTATUSKHRPROC glad_glGetGraphicsResetStatusKHR = NULL; +PFNGLGETINTEGER64VEXTPROC glad_glGetInteger64vEXT = NULL; +PFNGLGETINTEGERI_VEXTPROC glad_glGetIntegeri_vEXT = NULL; +PFNGLGETINTEGERVPROC glad_glGetIntegerv = NULL; +PFNGLGETMEMORYOBJECTPARAMETERIVEXTPROC glad_glGetMemoryObjectParameterivEXT = NULL; +PFNGLGETOBJECTLABELEXTPROC glad_glGetObjectLabelEXT = NULL; +PFNGLGETOBJECTLABELKHRPROC glad_glGetObjectLabelKHR = NULL; +PFNGLGETOBJECTPTRLABELKHRPROC glad_glGetObjectPtrLabelKHR = NULL; +PFNGLGETPOINTERVKHRPROC glad_glGetPointervKHR = NULL; +PFNGLGETPROGRAMBINARYOESPROC glad_glGetProgramBinaryOES = NULL; +PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog = NULL; +PFNGLGETPROGRAMPIPELINEINFOLOGEXTPROC glad_glGetProgramPipelineInfoLogEXT = NULL; +PFNGLGETPROGRAMPIPELINEIVEXTPROC glad_glGetProgramPipelineivEXT = NULL; +PFNGLGETPROGRAMRESOURCELOCATIONINDEXEXTPROC glad_glGetProgramResourceLocationIndexEXT = NULL; +PFNGLGETPROGRAMIVPROC glad_glGetProgramiv = NULL; +PFNGLGETQUERYOBJECTI64VEXTPROC glad_glGetQueryObjecti64vEXT = NULL; +PFNGLGETQUERYOBJECTIVEXTPROC glad_glGetQueryObjectivEXT = NULL; +PFNGLGETQUERYOBJECTUI64VEXTPROC glad_glGetQueryObjectui64vEXT = NULL; +PFNGLGETQUERYOBJECTUIVEXTPROC glad_glGetQueryObjectuivEXT = NULL; +PFNGLGETQUERYIVEXTPROC glad_glGetQueryivEXT = NULL; +PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv = NULL; +PFNGLGETSAMPLERPARAMETERIIVEXTPROC glad_glGetSamplerParameterIivEXT = NULL; +PFNGLGETSAMPLERPARAMETERIIVOESPROC glad_glGetSamplerParameterIivOES = NULL; +PFNGLGETSAMPLERPARAMETERIUIVEXTPROC glad_glGetSamplerParameterIuivEXT = NULL; +PFNGLGETSAMPLERPARAMETERIUIVOESPROC glad_glGetSamplerParameterIuivOES = NULL; +PFNGLGETSEMAPHOREPARAMETERUI64VEXTPROC glad_glGetSemaphoreParameterui64vEXT = NULL; +PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog = NULL; +PFNGLGETSHADERPRECISIONFORMATPROC glad_glGetShaderPrecisionFormat = NULL; +PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource = NULL; +PFNGLGETSHADERIVPROC glad_glGetShaderiv = NULL; +PFNGLGETSTRINGPROC glad_glGetString = NULL; +PFNGLGETTEXPARAMETERIIVEXTPROC glad_glGetTexParameterIivEXT = NULL; +PFNGLGETTEXPARAMETERIIVOESPROC glad_glGetTexParameterIivOES = NULL; +PFNGLGETTEXPARAMETERIUIVEXTPROC glad_glGetTexParameterIuivEXT = NULL; +PFNGLGETTEXPARAMETERIUIVOESPROC glad_glGetTexParameterIuivOES = NULL; +PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv = NULL; +PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv = NULL; +PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation = NULL; +PFNGLGETUNIFORMFVPROC glad_glGetUniformfv = NULL; +PFNGLGETUNIFORMIVPROC glad_glGetUniformiv = NULL; +PFNGLGETUNSIGNEDBYTEI_VEXTPROC glad_glGetUnsignedBytei_vEXT = NULL; +PFNGLGETUNSIGNEDBYTEVEXTPROC glad_glGetUnsignedBytevEXT = NULL; +PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv = NULL; +PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv = NULL; +PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv = NULL; +PFNGLGETNUNIFORMFVEXTPROC glad_glGetnUniformfvEXT = NULL; +PFNGLGETNUNIFORMFVKHRPROC glad_glGetnUniformfvKHR = NULL; +PFNGLGETNUNIFORMIVEXTPROC glad_glGetnUniformivEXT = NULL; +PFNGLGETNUNIFORMIVKHRPROC glad_glGetnUniformivKHR = NULL; +PFNGLGETNUNIFORMUIVKHRPROC glad_glGetnUniformuivKHR = NULL; +PFNGLHINTPROC glad_glHint = NULL; +PFNGLIMPORTMEMORYFDEXTPROC glad_glImportMemoryFdEXT = NULL; +PFNGLIMPORTMEMORYWIN32HANDLEEXTPROC glad_glImportMemoryWin32HandleEXT = NULL; +PFNGLIMPORTMEMORYWIN32NAMEEXTPROC glad_glImportMemoryWin32NameEXT = NULL; +PFNGLIMPORTSEMAPHOREFDEXTPROC glad_glImportSemaphoreFdEXT = NULL; +PFNGLIMPORTSEMAPHOREWIN32HANDLEEXTPROC glad_glImportSemaphoreWin32HandleEXT = NULL; +PFNGLIMPORTSEMAPHOREWIN32NAMEEXTPROC glad_glImportSemaphoreWin32NameEXT = NULL; +PFNGLINSERTEVENTMARKEREXTPROC glad_glInsertEventMarkerEXT = NULL; +PFNGLISBUFFERPROC glad_glIsBuffer = NULL; +PFNGLISENABLEDPROC glad_glIsEnabled = NULL; +PFNGLISENABLEDIEXTPROC glad_glIsEnablediEXT = NULL; +PFNGLISENABLEDIOESPROC glad_glIsEnablediOES = NULL; +PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer = NULL; +PFNGLISMEMORYOBJECTEXTPROC glad_glIsMemoryObjectEXT = NULL; +PFNGLISPROGRAMPROC glad_glIsProgram = NULL; +PFNGLISPROGRAMPIPELINEEXTPROC glad_glIsProgramPipelineEXT = NULL; +PFNGLISQUERYEXTPROC glad_glIsQueryEXT = NULL; +PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer = NULL; +PFNGLISSEMAPHOREEXTPROC glad_glIsSemaphoreEXT = NULL; +PFNGLISSHADERPROC glad_glIsShader = NULL; +PFNGLISTEXTUREPROC glad_glIsTexture = NULL; +PFNGLISVERTEXARRAYOESPROC glad_glIsVertexArrayOES = NULL; +PFNGLLABELOBJECTEXTPROC glad_glLabelObjectEXT = NULL; +PFNGLLINEWIDTHPROC glad_glLineWidth = NULL; +PFNGLLINKPROGRAMPROC glad_glLinkProgram = NULL; +PFNGLMAPBUFFEROESPROC glad_glMapBufferOES = NULL; +PFNGLMAPBUFFERRANGEEXTPROC glad_glMapBufferRangeEXT = NULL; +PFNGLMAXSHADERCOMPILERTHREADSKHRPROC glad_glMaxShaderCompilerThreadsKHR = NULL; +PFNGLMEMORYOBJECTPARAMETERIVEXTPROC glad_glMemoryObjectParameterivEXT = NULL; +PFNGLMINSAMPLESHADINGOESPROC glad_glMinSampleShadingOES = NULL; +PFNGLMULTIDRAWARRAYSEXTPROC glad_glMultiDrawArraysEXT = NULL; +PFNGLMULTIDRAWARRAYSINDIRECTEXTPROC glad_glMultiDrawArraysIndirectEXT = NULL; +PFNGLMULTIDRAWELEMENTSBASEVERTEXEXTPROC glad_glMultiDrawElementsBaseVertexEXT = NULL; +PFNGLMULTIDRAWELEMENTSEXTPROC glad_glMultiDrawElementsEXT = NULL; +PFNGLMULTIDRAWELEMENTSINDIRECTEXTPROC glad_glMultiDrawElementsIndirectEXT = NULL; +PFNGLNAMEDBUFFERSTORAGEEXTERNALEXTPROC glad_glNamedBufferStorageExternalEXT = NULL; +PFNGLNAMEDBUFFERSTORAGEMEMEXTPROC glad_glNamedBufferStorageMemEXT = NULL; +PFNGLOBJECTLABELKHRPROC glad_glObjectLabelKHR = NULL; +PFNGLOBJECTPTRLABELKHRPROC glad_glObjectPtrLabelKHR = NULL; +PFNGLPATCHPARAMETERIEXTPROC glad_glPatchParameteriEXT = NULL; +PFNGLPATCHPARAMETERIOESPROC glad_glPatchParameteriOES = NULL; +PFNGLPIXELSTOREIPROC glad_glPixelStorei = NULL; +PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset = NULL; +PFNGLPOLYGONOFFSETCLAMPEXTPROC glad_glPolygonOffsetClampEXT = NULL; +PFNGLPOPDEBUGGROUPKHRPROC glad_glPopDebugGroupKHR = NULL; +PFNGLPOPGROUPMARKEREXTPROC glad_glPopGroupMarkerEXT = NULL; +PFNGLPRIMITIVEBOUNDINGBOXEXTPROC glad_glPrimitiveBoundingBoxEXT = NULL; +PFNGLPRIMITIVEBOUNDINGBOXOESPROC glad_glPrimitiveBoundingBoxOES = NULL; +PFNGLPROGRAMBINARYOESPROC glad_glProgramBinaryOES = NULL; +PFNGLPROGRAMPARAMETERIEXTPROC glad_glProgramParameteriEXT = NULL; +PFNGLPROGRAMUNIFORM1FEXTPROC glad_glProgramUniform1fEXT = NULL; +PFNGLPROGRAMUNIFORM1FVEXTPROC glad_glProgramUniform1fvEXT = NULL; +PFNGLPROGRAMUNIFORM1IEXTPROC glad_glProgramUniform1iEXT = NULL; +PFNGLPROGRAMUNIFORM1IVEXTPROC glad_glProgramUniform1ivEXT = NULL; +PFNGLPROGRAMUNIFORM1UIEXTPROC glad_glProgramUniform1uiEXT = NULL; +PFNGLPROGRAMUNIFORM1UIVEXTPROC glad_glProgramUniform1uivEXT = NULL; +PFNGLPROGRAMUNIFORM2FEXTPROC glad_glProgramUniform2fEXT = NULL; +PFNGLPROGRAMUNIFORM2FVEXTPROC glad_glProgramUniform2fvEXT = NULL; +PFNGLPROGRAMUNIFORM2IEXTPROC glad_glProgramUniform2iEXT = NULL; +PFNGLPROGRAMUNIFORM2IVEXTPROC glad_glProgramUniform2ivEXT = NULL; +PFNGLPROGRAMUNIFORM2UIEXTPROC glad_glProgramUniform2uiEXT = NULL; +PFNGLPROGRAMUNIFORM2UIVEXTPROC glad_glProgramUniform2uivEXT = NULL; +PFNGLPROGRAMUNIFORM3FEXTPROC glad_glProgramUniform3fEXT = NULL; +PFNGLPROGRAMUNIFORM3FVEXTPROC glad_glProgramUniform3fvEXT = NULL; +PFNGLPROGRAMUNIFORM3IEXTPROC glad_glProgramUniform3iEXT = NULL; +PFNGLPROGRAMUNIFORM3IVEXTPROC glad_glProgramUniform3ivEXT = NULL; +PFNGLPROGRAMUNIFORM3UIEXTPROC glad_glProgramUniform3uiEXT = NULL; +PFNGLPROGRAMUNIFORM3UIVEXTPROC glad_glProgramUniform3uivEXT = NULL; +PFNGLPROGRAMUNIFORM4FEXTPROC glad_glProgramUniform4fEXT = NULL; +PFNGLPROGRAMUNIFORM4FVEXTPROC glad_glProgramUniform4fvEXT = NULL; +PFNGLPROGRAMUNIFORM4IEXTPROC glad_glProgramUniform4iEXT = NULL; +PFNGLPROGRAMUNIFORM4IVEXTPROC glad_glProgramUniform4ivEXT = NULL; +PFNGLPROGRAMUNIFORM4UIEXTPROC glad_glProgramUniform4uiEXT = NULL; +PFNGLPROGRAMUNIFORM4UIVEXTPROC glad_glProgramUniform4uivEXT = NULL; +PFNGLPROGRAMUNIFORMMATRIX2FVEXTPROC glad_glProgramUniformMatrix2fvEXT = NULL; +PFNGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC glad_glProgramUniformMatrix2x3fvEXT = NULL; +PFNGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC glad_glProgramUniformMatrix2x4fvEXT = NULL; +PFNGLPROGRAMUNIFORMMATRIX3FVEXTPROC glad_glProgramUniformMatrix3fvEXT = NULL; +PFNGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC glad_glProgramUniformMatrix3x2fvEXT = NULL; +PFNGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC glad_glProgramUniformMatrix3x4fvEXT = NULL; +PFNGLPROGRAMUNIFORMMATRIX4FVEXTPROC glad_glProgramUniformMatrix4fvEXT = NULL; +PFNGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC glad_glProgramUniformMatrix4x2fvEXT = NULL; +PFNGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC glad_glProgramUniformMatrix4x3fvEXT = NULL; +PFNGLPUSHDEBUGGROUPKHRPROC glad_glPushDebugGroupKHR = NULL; +PFNGLPUSHGROUPMARKEREXTPROC glad_glPushGroupMarkerEXT = NULL; +PFNGLQUERYCOUNTEREXTPROC glad_glQueryCounterEXT = NULL; +PFNGLRASTERSAMPLESEXTPROC glad_glRasterSamplesEXT = NULL; +PFNGLREADBUFFERINDEXEDEXTPROC glad_glReadBufferIndexedEXT = NULL; +PFNGLREADPIXELSPROC glad_glReadPixels = NULL; +PFNGLREADNPIXELSEXTPROC glad_glReadnPixelsEXT = NULL; +PFNGLREADNPIXELSKHRPROC glad_glReadnPixelsKHR = NULL; +PFNGLRELEASEKEYEDMUTEXWIN32EXTPROC glad_glReleaseKeyedMutexWin32EXT = NULL; +PFNGLRELEASESHADERCOMPILERPROC glad_glReleaseShaderCompiler = NULL; +PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage = NULL; +PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glad_glRenderbufferStorageMultisampleEXT = NULL; +PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage = NULL; +PFNGLSAMPLERPARAMETERIIVEXTPROC glad_glSamplerParameterIivEXT = NULL; +PFNGLSAMPLERPARAMETERIIVOESPROC glad_glSamplerParameterIivOES = NULL; +PFNGLSAMPLERPARAMETERIUIVEXTPROC glad_glSamplerParameterIuivEXT = NULL; +PFNGLSAMPLERPARAMETERIUIVOESPROC glad_glSamplerParameterIuivOES = NULL; +PFNGLSCISSORPROC glad_glScissor = NULL; +PFNGLSCISSORARRAYVOESPROC glad_glScissorArrayvOES = NULL; +PFNGLSCISSORINDEXEDOESPROC glad_glScissorIndexedOES = NULL; +PFNGLSCISSORINDEXEDVOESPROC glad_glScissorIndexedvOES = NULL; +PFNGLSEMAPHOREPARAMETERUI64VEXTPROC glad_glSemaphoreParameterui64vEXT = NULL; +PFNGLSHADERBINARYPROC glad_glShaderBinary = NULL; +PFNGLSHADERSOURCEPROC glad_glShaderSource = NULL; +PFNGLSHADINGRATECOMBINEROPSEXTPROC glad_glShadingRateCombinerOpsEXT = NULL; +PFNGLSHADINGRATEEXTPROC glad_glShadingRateEXT = NULL; +PFNGLSIGNALSEMAPHOREEXTPROC glad_glSignalSemaphoreEXT = NULL; +PFNGLSTENCILFUNCPROC glad_glStencilFunc = NULL; +PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate = NULL; +PFNGLSTENCILMASKPROC glad_glStencilMask = NULL; +PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate = NULL; +PFNGLSTENCILOPPROC glad_glStencilOp = NULL; +PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate = NULL; +PFNGLTEXBUFFEREXTPROC glad_glTexBufferEXT = NULL; +PFNGLTEXBUFFEROESPROC glad_glTexBufferOES = NULL; +PFNGLTEXBUFFERRANGEEXTPROC glad_glTexBufferRangeEXT = NULL; +PFNGLTEXBUFFERRANGEOESPROC glad_glTexBufferRangeOES = NULL; +PFNGLTEXIMAGE2DPROC glad_glTexImage2D = NULL; +PFNGLTEXIMAGE3DOESPROC glad_glTexImage3DOES = NULL; +PFNGLTEXPAGECOMMITMENTEXTPROC glad_glTexPageCommitmentEXT = NULL; +PFNGLTEXPARAMETERIIVEXTPROC glad_glTexParameterIivEXT = NULL; +PFNGLTEXPARAMETERIIVOESPROC glad_glTexParameterIivOES = NULL; +PFNGLTEXPARAMETERIUIVEXTPROC glad_glTexParameterIuivEXT = NULL; +PFNGLTEXPARAMETERIUIVOESPROC glad_glTexParameterIuivOES = NULL; +PFNGLTEXPARAMETERFPROC glad_glTexParameterf = NULL; +PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv = NULL; +PFNGLTEXPARAMETERIPROC glad_glTexParameteri = NULL; +PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv = NULL; +PFNGLTEXSTORAGE1DEXTPROC glad_glTexStorage1DEXT = NULL; +PFNGLTEXSTORAGE2DEXTPROC glad_glTexStorage2DEXT = NULL; +PFNGLTEXSTORAGE3DEXTPROC glad_glTexStorage3DEXT = NULL; +PFNGLTEXSTORAGE3DMULTISAMPLEOESPROC glad_glTexStorage3DMultisampleOES = NULL; +PFNGLTEXSTORAGEATTRIBS2DEXTPROC glad_glTexStorageAttribs2DEXT = NULL; +PFNGLTEXSTORAGEATTRIBS3DEXTPROC glad_glTexStorageAttribs3DEXT = NULL; +PFNGLTEXSTORAGEMEM2DEXTPROC glad_glTexStorageMem2DEXT = NULL; +PFNGLTEXSTORAGEMEM2DMULTISAMPLEEXTPROC glad_glTexStorageMem2DMultisampleEXT = NULL; +PFNGLTEXSTORAGEMEM3DEXTPROC glad_glTexStorageMem3DEXT = NULL; +PFNGLTEXSTORAGEMEM3DMULTISAMPLEEXTPROC glad_glTexStorageMem3DMultisampleEXT = NULL; +PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D = NULL; +PFNGLTEXSUBIMAGE3DOESPROC glad_glTexSubImage3DOES = NULL; +PFNGLTEXTURESTORAGE1DEXTPROC glad_glTextureStorage1DEXT = NULL; +PFNGLTEXTURESTORAGE2DEXTPROC glad_glTextureStorage2DEXT = NULL; +PFNGLTEXTURESTORAGE3DEXTPROC glad_glTextureStorage3DEXT = NULL; +PFNGLTEXTURESTORAGEMEM2DEXTPROC glad_glTextureStorageMem2DEXT = NULL; +PFNGLTEXTURESTORAGEMEM2DMULTISAMPLEEXTPROC glad_glTextureStorageMem2DMultisampleEXT = NULL; +PFNGLTEXTURESTORAGEMEM3DEXTPROC glad_glTextureStorageMem3DEXT = NULL; +PFNGLTEXTURESTORAGEMEM3DMULTISAMPLEEXTPROC glad_glTextureStorageMem3DMultisampleEXT = NULL; +PFNGLTEXTUREVIEWEXTPROC glad_glTextureViewEXT = NULL; +PFNGLTEXTUREVIEWOESPROC glad_glTextureViewOES = NULL; +PFNGLUNIFORM1FPROC glad_glUniform1f = NULL; +PFNGLUNIFORM1FVPROC glad_glUniform1fv = NULL; +PFNGLUNIFORM1IPROC glad_glUniform1i = NULL; +PFNGLUNIFORM1IVPROC glad_glUniform1iv = NULL; +PFNGLUNIFORM2FPROC glad_glUniform2f = NULL; +PFNGLUNIFORM2FVPROC glad_glUniform2fv = NULL; +PFNGLUNIFORM2IPROC glad_glUniform2i = NULL; +PFNGLUNIFORM2IVPROC glad_glUniform2iv = NULL; +PFNGLUNIFORM3FPROC glad_glUniform3f = NULL; +PFNGLUNIFORM3FVPROC glad_glUniform3fv = NULL; +PFNGLUNIFORM3IPROC glad_glUniform3i = NULL; +PFNGLUNIFORM3IVPROC glad_glUniform3iv = NULL; +PFNGLUNIFORM4FPROC glad_glUniform4f = NULL; +PFNGLUNIFORM4FVPROC glad_glUniform4fv = NULL; +PFNGLUNIFORM4IPROC glad_glUniform4i = NULL; +PFNGLUNIFORM4IVPROC glad_glUniform4iv = NULL; +PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv = NULL; +PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv = NULL; +PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv = NULL; +PFNGLUNMAPBUFFEROESPROC glad_glUnmapBufferOES = NULL; +PFNGLUSEPROGRAMPROC glad_glUseProgram = NULL; +PFNGLUSEPROGRAMSTAGESEXTPROC glad_glUseProgramStagesEXT = NULL; +PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram = NULL; +PFNGLVALIDATEPROGRAMPIPELINEEXTPROC glad_glValidateProgramPipelineEXT = NULL; +PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f = NULL; +PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv = NULL; +PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f = NULL; +PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv = NULL; +PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f = NULL; +PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv = NULL; +PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f = NULL; +PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv = NULL; +PFNGLVERTEXATTRIBDIVISOREXTPROC glad_glVertexAttribDivisorEXT = NULL; +PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer = NULL; +PFNGLVIEWPORTPROC glad_glViewport = NULL; +PFNGLVIEWPORTARRAYVOESPROC glad_glViewportArrayvOES = NULL; +PFNGLVIEWPORTINDEXEDFOESPROC glad_glViewportIndexedfOES = NULL; +PFNGLVIEWPORTINDEXEDFVOESPROC glad_glViewportIndexedfvOES = NULL; +PFNGLWAITSEMAPHOREEXTPROC glad_glWaitSemaphoreEXT = NULL; +PFNGLWINDOWRECTANGLESEXTPROC glad_glWindowRectanglesEXT = NULL; + + +static void glad_gl_load_GL_ES_VERSION_2_0( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_ES_VERSION_2_0) return; + glad_glActiveTexture = (PFNGLACTIVETEXTUREPROC) load(userptr, "glActiveTexture"); + glad_glAttachShader = (PFNGLATTACHSHADERPROC) load(userptr, "glAttachShader"); + glad_glBindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC) load(userptr, "glBindAttribLocation"); + glad_glBindBuffer = (PFNGLBINDBUFFERPROC) load(userptr, "glBindBuffer"); + glad_glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC) load(userptr, "glBindFramebuffer"); + glad_glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC) load(userptr, "glBindRenderbuffer"); + glad_glBindTexture = (PFNGLBINDTEXTUREPROC) load(userptr, "glBindTexture"); + glad_glBlendColor = (PFNGLBLENDCOLORPROC) load(userptr, "glBlendColor"); + glad_glBlendEquation = (PFNGLBLENDEQUATIONPROC) load(userptr, "glBlendEquation"); + glad_glBlendEquationSeparate = (PFNGLBLENDEQUATIONSEPARATEPROC) load(userptr, "glBlendEquationSeparate"); + glad_glBlendFunc = (PFNGLBLENDFUNCPROC) load(userptr, "glBlendFunc"); + glad_glBlendFuncSeparate = (PFNGLBLENDFUNCSEPARATEPROC) load(userptr, "glBlendFuncSeparate"); + glad_glBufferData = (PFNGLBUFFERDATAPROC) load(userptr, "glBufferData"); + glad_glBufferSubData = (PFNGLBUFFERSUBDATAPROC) load(userptr, "glBufferSubData"); + glad_glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC) load(userptr, "glCheckFramebufferStatus"); + glad_glClear = (PFNGLCLEARPROC) load(userptr, "glClear"); + glad_glClearColor = (PFNGLCLEARCOLORPROC) load(userptr, "glClearColor"); + glad_glClearDepthf = (PFNGLCLEARDEPTHFPROC) load(userptr, "glClearDepthf"); + glad_glClearStencil = (PFNGLCLEARSTENCILPROC) load(userptr, "glClearStencil"); + glad_glColorMask = (PFNGLCOLORMASKPROC) load(userptr, "glColorMask"); + glad_glCompileShader = (PFNGLCOMPILESHADERPROC) load(userptr, "glCompileShader"); + glad_glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC) load(userptr, "glCompressedTexImage2D"); + glad_glCompressedTexSubImage2D = (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) load(userptr, "glCompressedTexSubImage2D"); + glad_glCopyTexImage2D = (PFNGLCOPYTEXIMAGE2DPROC) load(userptr, "glCopyTexImage2D"); + glad_glCopyTexSubImage2D = (PFNGLCOPYTEXSUBIMAGE2DPROC) load(userptr, "glCopyTexSubImage2D"); + glad_glCreateProgram = (PFNGLCREATEPROGRAMPROC) load(userptr, "glCreateProgram"); + glad_glCreateShader = (PFNGLCREATESHADERPROC) load(userptr, "glCreateShader"); + glad_glCullFace = (PFNGLCULLFACEPROC) load(userptr, "glCullFace"); + glad_glDeleteBuffers = (PFNGLDELETEBUFFERSPROC) load(userptr, "glDeleteBuffers"); + glad_glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC) load(userptr, "glDeleteFramebuffers"); + glad_glDeleteProgram = (PFNGLDELETEPROGRAMPROC) load(userptr, "glDeleteProgram"); + glad_glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC) load(userptr, "glDeleteRenderbuffers"); + glad_glDeleteShader = (PFNGLDELETESHADERPROC) load(userptr, "glDeleteShader"); + glad_glDeleteTextures = (PFNGLDELETETEXTURESPROC) load(userptr, "glDeleteTextures"); + glad_glDepthFunc = (PFNGLDEPTHFUNCPROC) load(userptr, "glDepthFunc"); + glad_glDepthMask = (PFNGLDEPTHMASKPROC) load(userptr, "glDepthMask"); + glad_glDepthRangef = (PFNGLDEPTHRANGEFPROC) load(userptr, "glDepthRangef"); + glad_glDetachShader = (PFNGLDETACHSHADERPROC) load(userptr, "glDetachShader"); + glad_glDisable = (PFNGLDISABLEPROC) load(userptr, "glDisable"); + glad_glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC) load(userptr, "glDisableVertexAttribArray"); + glad_glDrawArrays = (PFNGLDRAWARRAYSPROC) load(userptr, "glDrawArrays"); + glad_glDrawElements = (PFNGLDRAWELEMENTSPROC) load(userptr, "glDrawElements"); + glad_glEnable = (PFNGLENABLEPROC) load(userptr, "glEnable"); + glad_glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC) load(userptr, "glEnableVertexAttribArray"); + glad_glFinish = (PFNGLFINISHPROC) load(userptr, "glFinish"); + glad_glFlush = (PFNGLFLUSHPROC) load(userptr, "glFlush"); + glad_glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC) load(userptr, "glFramebufferRenderbuffer"); + glad_glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC) load(userptr, "glFramebufferTexture2D"); + glad_glFrontFace = (PFNGLFRONTFACEPROC) load(userptr, "glFrontFace"); + glad_glGenBuffers = (PFNGLGENBUFFERSPROC) load(userptr, "glGenBuffers"); + glad_glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC) load(userptr, "glGenFramebuffers"); + glad_glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC) load(userptr, "glGenRenderbuffers"); + glad_glGenTextures = (PFNGLGENTEXTURESPROC) load(userptr, "glGenTextures"); + glad_glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC) load(userptr, "glGenerateMipmap"); + glad_glGetActiveAttrib = (PFNGLGETACTIVEATTRIBPROC) load(userptr, "glGetActiveAttrib"); + glad_glGetActiveUniform = (PFNGLGETACTIVEUNIFORMPROC) load(userptr, "glGetActiveUniform"); + glad_glGetAttachedShaders = (PFNGLGETATTACHEDSHADERSPROC) load(userptr, "glGetAttachedShaders"); + glad_glGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC) load(userptr, "glGetAttribLocation"); + glad_glGetBooleanv = (PFNGLGETBOOLEANVPROC) load(userptr, "glGetBooleanv"); + glad_glGetBufferParameteriv = (PFNGLGETBUFFERPARAMETERIVPROC) load(userptr, "glGetBufferParameteriv"); + glad_glGetError = (PFNGLGETERRORPROC) load(userptr, "glGetError"); + glad_glGetFloatv = (PFNGLGETFLOATVPROC) load(userptr, "glGetFloatv"); + glad_glGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC) load(userptr, "glGetFramebufferAttachmentParameteriv"); + glad_glGetIntegerv = (PFNGLGETINTEGERVPROC) load(userptr, "glGetIntegerv"); + glad_glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC) load(userptr, "glGetProgramInfoLog"); + glad_glGetProgramiv = (PFNGLGETPROGRAMIVPROC) load(userptr, "glGetProgramiv"); + glad_glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC) load(userptr, "glGetRenderbufferParameteriv"); + glad_glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC) load(userptr, "glGetShaderInfoLog"); + glad_glGetShaderPrecisionFormat = (PFNGLGETSHADERPRECISIONFORMATPROC) load(userptr, "glGetShaderPrecisionFormat"); + glad_glGetShaderSource = (PFNGLGETSHADERSOURCEPROC) load(userptr, "glGetShaderSource"); + glad_glGetShaderiv = (PFNGLGETSHADERIVPROC) load(userptr, "glGetShaderiv"); + glad_glGetString = (PFNGLGETSTRINGPROC) load(userptr, "glGetString"); + glad_glGetTexParameterfv = (PFNGLGETTEXPARAMETERFVPROC) load(userptr, "glGetTexParameterfv"); + glad_glGetTexParameteriv = (PFNGLGETTEXPARAMETERIVPROC) load(userptr, "glGetTexParameteriv"); + glad_glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC) load(userptr, "glGetUniformLocation"); + glad_glGetUniformfv = (PFNGLGETUNIFORMFVPROC) load(userptr, "glGetUniformfv"); + glad_glGetUniformiv = (PFNGLGETUNIFORMIVPROC) load(userptr, "glGetUniformiv"); + glad_glGetVertexAttribPointerv = (PFNGLGETVERTEXATTRIBPOINTERVPROC) load(userptr, "glGetVertexAttribPointerv"); + glad_glGetVertexAttribfv = (PFNGLGETVERTEXATTRIBFVPROC) load(userptr, "glGetVertexAttribfv"); + glad_glGetVertexAttribiv = (PFNGLGETVERTEXATTRIBIVPROC) load(userptr, "glGetVertexAttribiv"); + glad_glHint = (PFNGLHINTPROC) load(userptr, "glHint"); + glad_glIsBuffer = (PFNGLISBUFFERPROC) load(userptr, "glIsBuffer"); + glad_glIsEnabled = (PFNGLISENABLEDPROC) load(userptr, "glIsEnabled"); + glad_glIsFramebuffer = (PFNGLISFRAMEBUFFERPROC) load(userptr, "glIsFramebuffer"); + glad_glIsProgram = (PFNGLISPROGRAMPROC) load(userptr, "glIsProgram"); + glad_glIsRenderbuffer = (PFNGLISRENDERBUFFERPROC) load(userptr, "glIsRenderbuffer"); + glad_glIsShader = (PFNGLISSHADERPROC) load(userptr, "glIsShader"); + glad_glIsTexture = (PFNGLISTEXTUREPROC) load(userptr, "glIsTexture"); + glad_glLineWidth = (PFNGLLINEWIDTHPROC) load(userptr, "glLineWidth"); + glad_glLinkProgram = (PFNGLLINKPROGRAMPROC) load(userptr, "glLinkProgram"); + glad_glPixelStorei = (PFNGLPIXELSTOREIPROC) load(userptr, "glPixelStorei"); + glad_glPolygonOffset = (PFNGLPOLYGONOFFSETPROC) load(userptr, "glPolygonOffset"); + glad_glReadPixels = (PFNGLREADPIXELSPROC) load(userptr, "glReadPixels"); + glad_glReleaseShaderCompiler = (PFNGLRELEASESHADERCOMPILERPROC) load(userptr, "glReleaseShaderCompiler"); + glad_glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC) load(userptr, "glRenderbufferStorage"); + glad_glSampleCoverage = (PFNGLSAMPLECOVERAGEPROC) load(userptr, "glSampleCoverage"); + glad_glScissor = (PFNGLSCISSORPROC) load(userptr, "glScissor"); + glad_glShaderBinary = (PFNGLSHADERBINARYPROC) load(userptr, "glShaderBinary"); + glad_glShaderSource = (PFNGLSHADERSOURCEPROC) load(userptr, "glShaderSource"); + glad_glStencilFunc = (PFNGLSTENCILFUNCPROC) load(userptr, "glStencilFunc"); + glad_glStencilFuncSeparate = (PFNGLSTENCILFUNCSEPARATEPROC) load(userptr, "glStencilFuncSeparate"); + glad_glStencilMask = (PFNGLSTENCILMASKPROC) load(userptr, "glStencilMask"); + glad_glStencilMaskSeparate = (PFNGLSTENCILMASKSEPARATEPROC) load(userptr, "glStencilMaskSeparate"); + glad_glStencilOp = (PFNGLSTENCILOPPROC) load(userptr, "glStencilOp"); + glad_glStencilOpSeparate = (PFNGLSTENCILOPSEPARATEPROC) load(userptr, "glStencilOpSeparate"); + glad_glTexImage2D = (PFNGLTEXIMAGE2DPROC) load(userptr, "glTexImage2D"); + glad_glTexParameterf = (PFNGLTEXPARAMETERFPROC) load(userptr, "glTexParameterf"); + glad_glTexParameterfv = (PFNGLTEXPARAMETERFVPROC) load(userptr, "glTexParameterfv"); + glad_glTexParameteri = (PFNGLTEXPARAMETERIPROC) load(userptr, "glTexParameteri"); + glad_glTexParameteriv = (PFNGLTEXPARAMETERIVPROC) load(userptr, "glTexParameteriv"); + glad_glTexSubImage2D = (PFNGLTEXSUBIMAGE2DPROC) load(userptr, "glTexSubImage2D"); + glad_glUniform1f = (PFNGLUNIFORM1FPROC) load(userptr, "glUniform1f"); + glad_glUniform1fv = (PFNGLUNIFORM1FVPROC) load(userptr, "glUniform1fv"); + glad_glUniform1i = (PFNGLUNIFORM1IPROC) load(userptr, "glUniform1i"); + glad_glUniform1iv = (PFNGLUNIFORM1IVPROC) load(userptr, "glUniform1iv"); + glad_glUniform2f = (PFNGLUNIFORM2FPROC) load(userptr, "glUniform2f"); + glad_glUniform2fv = (PFNGLUNIFORM2FVPROC) load(userptr, "glUniform2fv"); + glad_glUniform2i = (PFNGLUNIFORM2IPROC) load(userptr, "glUniform2i"); + glad_glUniform2iv = (PFNGLUNIFORM2IVPROC) load(userptr, "glUniform2iv"); + glad_glUniform3f = (PFNGLUNIFORM3FPROC) load(userptr, "glUniform3f"); + glad_glUniform3fv = (PFNGLUNIFORM3FVPROC) load(userptr, "glUniform3fv"); + glad_glUniform3i = (PFNGLUNIFORM3IPROC) load(userptr, "glUniform3i"); + glad_glUniform3iv = (PFNGLUNIFORM3IVPROC) load(userptr, "glUniform3iv"); + glad_glUniform4f = (PFNGLUNIFORM4FPROC) load(userptr, "glUniform4f"); + glad_glUniform4fv = (PFNGLUNIFORM4FVPROC) load(userptr, "glUniform4fv"); + glad_glUniform4i = (PFNGLUNIFORM4IPROC) load(userptr, "glUniform4i"); + glad_glUniform4iv = (PFNGLUNIFORM4IVPROC) load(userptr, "glUniform4iv"); + glad_glUniformMatrix2fv = (PFNGLUNIFORMMATRIX2FVPROC) load(userptr, "glUniformMatrix2fv"); + glad_glUniformMatrix3fv = (PFNGLUNIFORMMATRIX3FVPROC) load(userptr, "glUniformMatrix3fv"); + glad_glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC) load(userptr, "glUniformMatrix4fv"); + glad_glUseProgram = (PFNGLUSEPROGRAMPROC) load(userptr, "glUseProgram"); + glad_glValidateProgram = (PFNGLVALIDATEPROGRAMPROC) load(userptr, "glValidateProgram"); + glad_glVertexAttrib1f = (PFNGLVERTEXATTRIB1FPROC) load(userptr, "glVertexAttrib1f"); + glad_glVertexAttrib1fv = (PFNGLVERTEXATTRIB1FVPROC) load(userptr, "glVertexAttrib1fv"); + glad_glVertexAttrib2f = (PFNGLVERTEXATTRIB2FPROC) load(userptr, "glVertexAttrib2f"); + glad_glVertexAttrib2fv = (PFNGLVERTEXATTRIB2FVPROC) load(userptr, "glVertexAttrib2fv"); + glad_glVertexAttrib3f = (PFNGLVERTEXATTRIB3FPROC) load(userptr, "glVertexAttrib3f"); + glad_glVertexAttrib3fv = (PFNGLVERTEXATTRIB3FVPROC) load(userptr, "glVertexAttrib3fv"); + glad_glVertexAttrib4f = (PFNGLVERTEXATTRIB4FPROC) load(userptr, "glVertexAttrib4f"); + glad_glVertexAttrib4fv = (PFNGLVERTEXATTRIB4FVPROC) load(userptr, "glVertexAttrib4fv"); + glad_glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC) load(userptr, "glVertexAttribPointer"); + glad_glViewport = (PFNGLVIEWPORTPROC) load(userptr, "glViewport"); +} +static void glad_gl_load_GL_EXT_EGL_image_storage( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_EGL_image_storage) return; + glad_glEGLImageTargetTexStorageEXT = (PFNGLEGLIMAGETARGETTEXSTORAGEEXTPROC) load(userptr, "glEGLImageTargetTexStorageEXT"); + glad_glEGLImageTargetTextureStorageEXT = (PFNGLEGLIMAGETARGETTEXTURESTORAGEEXTPROC) load(userptr, "glEGLImageTargetTextureStorageEXT"); +} +static void glad_gl_load_GL_EXT_base_instance( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_base_instance) return; + glad_glDrawArraysInstancedBaseInstanceEXT = (PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEEXTPROC) load(userptr, "glDrawArraysInstancedBaseInstanceEXT"); + glad_glDrawElementsInstancedBaseInstanceEXT = (PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEEXTPROC) load(userptr, "glDrawElementsInstancedBaseInstanceEXT"); + glad_glDrawElementsInstancedBaseVertexBaseInstanceEXT = (PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEEXTPROC) load(userptr, "glDrawElementsInstancedBaseVertexBaseInstanceEXT"); +} +static void glad_gl_load_GL_EXT_blend_func_extended( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_blend_func_extended) return; + glad_glBindFragDataLocationEXT = (PFNGLBINDFRAGDATALOCATIONEXTPROC) load(userptr, "glBindFragDataLocationEXT"); + glad_glBindFragDataLocationIndexedEXT = (PFNGLBINDFRAGDATALOCATIONINDEXEDEXTPROC) load(userptr, "glBindFragDataLocationIndexedEXT"); + glad_glGetFragDataIndexEXT = (PFNGLGETFRAGDATAINDEXEXTPROC) load(userptr, "glGetFragDataIndexEXT"); + glad_glGetProgramResourceLocationIndexEXT = (PFNGLGETPROGRAMRESOURCELOCATIONINDEXEXTPROC) load(userptr, "glGetProgramResourceLocationIndexEXT"); +} +static void glad_gl_load_GL_EXT_buffer_storage( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_buffer_storage) return; + glad_glBufferStorageEXT = (PFNGLBUFFERSTORAGEEXTPROC) load(userptr, "glBufferStorageEXT"); +} +static void glad_gl_load_GL_EXT_clear_texture( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_clear_texture) return; + glad_glClearTexImageEXT = (PFNGLCLEARTEXIMAGEEXTPROC) load(userptr, "glClearTexImageEXT"); + glad_glClearTexSubImageEXT = (PFNGLCLEARTEXSUBIMAGEEXTPROC) load(userptr, "glClearTexSubImageEXT"); +} +static void glad_gl_load_GL_EXT_clip_control( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_clip_control) return; + glad_glClipControlEXT = (PFNGLCLIPCONTROLEXTPROC) load(userptr, "glClipControlEXT"); +} +static void glad_gl_load_GL_EXT_copy_image( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_copy_image) return; + glad_glCopyImageSubDataEXT = (PFNGLCOPYIMAGESUBDATAEXTPROC) load(userptr, "glCopyImageSubDataEXT"); +} +static void glad_gl_load_GL_EXT_debug_label( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_debug_label) return; + glad_glGetObjectLabelEXT = (PFNGLGETOBJECTLABELEXTPROC) load(userptr, "glGetObjectLabelEXT"); + glad_glLabelObjectEXT = (PFNGLLABELOBJECTEXTPROC) load(userptr, "glLabelObjectEXT"); +} +static void glad_gl_load_GL_EXT_debug_marker( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_debug_marker) return; + glad_glInsertEventMarkerEXT = (PFNGLINSERTEVENTMARKEREXTPROC) load(userptr, "glInsertEventMarkerEXT"); + glad_glPopGroupMarkerEXT = (PFNGLPOPGROUPMARKEREXTPROC) load(userptr, "glPopGroupMarkerEXT"); + glad_glPushGroupMarkerEXT = (PFNGLPUSHGROUPMARKEREXTPROC) load(userptr, "glPushGroupMarkerEXT"); +} +static void glad_gl_load_GL_EXT_discard_framebuffer( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_discard_framebuffer) return; + glad_glDiscardFramebufferEXT = (PFNGLDISCARDFRAMEBUFFEREXTPROC) load(userptr, "glDiscardFramebufferEXT"); +} +static void glad_gl_load_GL_EXT_disjoint_timer_query( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_disjoint_timer_query) return; + glad_glBeginQueryEXT = (PFNGLBEGINQUERYEXTPROC) load(userptr, "glBeginQueryEXT"); + glad_glDeleteQueriesEXT = (PFNGLDELETEQUERIESEXTPROC) load(userptr, "glDeleteQueriesEXT"); + glad_glEndQueryEXT = (PFNGLENDQUERYEXTPROC) load(userptr, "glEndQueryEXT"); + glad_glGenQueriesEXT = (PFNGLGENQUERIESEXTPROC) load(userptr, "glGenQueriesEXT"); + glad_glGetInteger64vEXT = (PFNGLGETINTEGER64VEXTPROC) load(userptr, "glGetInteger64vEXT"); + glad_glGetQueryObjecti64vEXT = (PFNGLGETQUERYOBJECTI64VEXTPROC) load(userptr, "glGetQueryObjecti64vEXT"); + glad_glGetQueryObjectivEXT = (PFNGLGETQUERYOBJECTIVEXTPROC) load(userptr, "glGetQueryObjectivEXT"); + glad_glGetQueryObjectui64vEXT = (PFNGLGETQUERYOBJECTUI64VEXTPROC) load(userptr, "glGetQueryObjectui64vEXT"); + glad_glGetQueryObjectuivEXT = (PFNGLGETQUERYOBJECTUIVEXTPROC) load(userptr, "glGetQueryObjectuivEXT"); + glad_glGetQueryivEXT = (PFNGLGETQUERYIVEXTPROC) load(userptr, "glGetQueryivEXT"); + glad_glIsQueryEXT = (PFNGLISQUERYEXTPROC) load(userptr, "glIsQueryEXT"); + glad_glQueryCounterEXT = (PFNGLQUERYCOUNTEREXTPROC) load(userptr, "glQueryCounterEXT"); +} +static void glad_gl_load_GL_EXT_draw_buffers( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_draw_buffers) return; + glad_glDrawBuffersEXT = (PFNGLDRAWBUFFERSEXTPROC) load(userptr, "glDrawBuffersEXT"); +} +static void glad_gl_load_GL_EXT_draw_buffers_indexed( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_draw_buffers_indexed) return; + glad_glBlendEquationSeparateiEXT = (PFNGLBLENDEQUATIONSEPARATEIEXTPROC) load(userptr, "glBlendEquationSeparateiEXT"); + glad_glBlendEquationiEXT = (PFNGLBLENDEQUATIONIEXTPROC) load(userptr, "glBlendEquationiEXT"); + glad_glBlendFuncSeparateiEXT = (PFNGLBLENDFUNCSEPARATEIEXTPROC) load(userptr, "glBlendFuncSeparateiEXT"); + glad_glBlendFunciEXT = (PFNGLBLENDFUNCIEXTPROC) load(userptr, "glBlendFunciEXT"); + glad_glColorMaskiEXT = (PFNGLCOLORMASKIEXTPROC) load(userptr, "glColorMaskiEXT"); + glad_glDisableiEXT = (PFNGLDISABLEIEXTPROC) load(userptr, "glDisableiEXT"); + glad_glEnableiEXT = (PFNGLENABLEIEXTPROC) load(userptr, "glEnableiEXT"); + glad_glIsEnablediEXT = (PFNGLISENABLEDIEXTPROC) load(userptr, "glIsEnablediEXT"); +} +static void glad_gl_load_GL_EXT_draw_elements_base_vertex( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_draw_elements_base_vertex) return; + glad_glDrawElementsBaseVertexEXT = (PFNGLDRAWELEMENTSBASEVERTEXEXTPROC) load(userptr, "glDrawElementsBaseVertexEXT"); + glad_glDrawElementsInstancedBaseVertexEXT = (PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXEXTPROC) load(userptr, "glDrawElementsInstancedBaseVertexEXT"); + glad_glDrawRangeElementsBaseVertexEXT = (PFNGLDRAWRANGEELEMENTSBASEVERTEXEXTPROC) load(userptr, "glDrawRangeElementsBaseVertexEXT"); + glad_glMultiDrawElementsBaseVertexEXT = (PFNGLMULTIDRAWELEMENTSBASEVERTEXEXTPROC) load(userptr, "glMultiDrawElementsBaseVertexEXT"); +} +static void glad_gl_load_GL_EXT_draw_instanced( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_draw_instanced) return; + glad_glDrawArraysInstancedEXT = (PFNGLDRAWARRAYSINSTANCEDEXTPROC) load(userptr, "glDrawArraysInstancedEXT"); + glad_glDrawElementsInstancedEXT = (PFNGLDRAWELEMENTSINSTANCEDEXTPROC) load(userptr, "glDrawElementsInstancedEXT"); +} +static void glad_gl_load_GL_EXT_draw_transform_feedback( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_draw_transform_feedback) return; + glad_glDrawTransformFeedbackEXT = (PFNGLDRAWTRANSFORMFEEDBACKEXTPROC) load(userptr, "glDrawTransformFeedbackEXT"); + glad_glDrawTransformFeedbackInstancedEXT = (PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDEXTPROC) load(userptr, "glDrawTransformFeedbackInstancedEXT"); +} +static void glad_gl_load_GL_EXT_external_buffer( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_external_buffer) return; + glad_glBufferStorageExternalEXT = (PFNGLBUFFERSTORAGEEXTERNALEXTPROC) load(userptr, "glBufferStorageExternalEXT"); + glad_glNamedBufferStorageExternalEXT = (PFNGLNAMEDBUFFERSTORAGEEXTERNALEXTPROC) load(userptr, "glNamedBufferStorageExternalEXT"); +} +static void glad_gl_load_GL_EXT_fragment_shading_rate( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_fragment_shading_rate) return; + glad_glFramebufferShadingRateEXT = (PFNGLFRAMEBUFFERSHADINGRATEEXTPROC) load(userptr, "glFramebufferShadingRateEXT"); + glad_glGetFragmentShadingRatesEXT = (PFNGLGETFRAGMENTSHADINGRATESEXTPROC) load(userptr, "glGetFragmentShadingRatesEXT"); + glad_glShadingRateCombinerOpsEXT = (PFNGLSHADINGRATECOMBINEROPSEXTPROC) load(userptr, "glShadingRateCombinerOpsEXT"); + glad_glShadingRateEXT = (PFNGLSHADINGRATEEXTPROC) load(userptr, "glShadingRateEXT"); +} +static void glad_gl_load_GL_EXT_geometry_shader( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_geometry_shader) return; + glad_glFramebufferTextureEXT = (PFNGLFRAMEBUFFERTEXTUREEXTPROC) load(userptr, "glFramebufferTextureEXT"); +} +static void glad_gl_load_GL_EXT_instanced_arrays( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_instanced_arrays) return; + glad_glDrawArraysInstancedEXT = (PFNGLDRAWARRAYSINSTANCEDEXTPROC) load(userptr, "glDrawArraysInstancedEXT"); + glad_glDrawElementsInstancedEXT = (PFNGLDRAWELEMENTSINSTANCEDEXTPROC) load(userptr, "glDrawElementsInstancedEXT"); + glad_glVertexAttribDivisorEXT = (PFNGLVERTEXATTRIBDIVISOREXTPROC) load(userptr, "glVertexAttribDivisorEXT"); +} +static void glad_gl_load_GL_EXT_map_buffer_range( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_map_buffer_range) return; + glad_glFlushMappedBufferRangeEXT = (PFNGLFLUSHMAPPEDBUFFERRANGEEXTPROC) load(userptr, "glFlushMappedBufferRangeEXT"); + glad_glMapBufferRangeEXT = (PFNGLMAPBUFFERRANGEEXTPROC) load(userptr, "glMapBufferRangeEXT"); +} +static void glad_gl_load_GL_EXT_memory_object( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_memory_object) return; + glad_glBufferStorageMemEXT = (PFNGLBUFFERSTORAGEMEMEXTPROC) load(userptr, "glBufferStorageMemEXT"); + glad_glCreateMemoryObjectsEXT = (PFNGLCREATEMEMORYOBJECTSEXTPROC) load(userptr, "glCreateMemoryObjectsEXT"); + glad_glDeleteMemoryObjectsEXT = (PFNGLDELETEMEMORYOBJECTSEXTPROC) load(userptr, "glDeleteMemoryObjectsEXT"); + glad_glGetMemoryObjectParameterivEXT = (PFNGLGETMEMORYOBJECTPARAMETERIVEXTPROC) load(userptr, "glGetMemoryObjectParameterivEXT"); + glad_glGetUnsignedBytei_vEXT = (PFNGLGETUNSIGNEDBYTEI_VEXTPROC) load(userptr, "glGetUnsignedBytei_vEXT"); + glad_glGetUnsignedBytevEXT = (PFNGLGETUNSIGNEDBYTEVEXTPROC) load(userptr, "glGetUnsignedBytevEXT"); + glad_glIsMemoryObjectEXT = (PFNGLISMEMORYOBJECTEXTPROC) load(userptr, "glIsMemoryObjectEXT"); + glad_glMemoryObjectParameterivEXT = (PFNGLMEMORYOBJECTPARAMETERIVEXTPROC) load(userptr, "glMemoryObjectParameterivEXT"); + glad_glNamedBufferStorageMemEXT = (PFNGLNAMEDBUFFERSTORAGEMEMEXTPROC) load(userptr, "glNamedBufferStorageMemEXT"); + glad_glTexStorageMem2DEXT = (PFNGLTEXSTORAGEMEM2DEXTPROC) load(userptr, "glTexStorageMem2DEXT"); + glad_glTexStorageMem2DMultisampleEXT = (PFNGLTEXSTORAGEMEM2DMULTISAMPLEEXTPROC) load(userptr, "glTexStorageMem2DMultisampleEXT"); + glad_glTexStorageMem3DEXT = (PFNGLTEXSTORAGEMEM3DEXTPROC) load(userptr, "glTexStorageMem3DEXT"); + glad_glTexStorageMem3DMultisampleEXT = (PFNGLTEXSTORAGEMEM3DMULTISAMPLEEXTPROC) load(userptr, "glTexStorageMem3DMultisampleEXT"); + glad_glTextureStorageMem2DEXT = (PFNGLTEXTURESTORAGEMEM2DEXTPROC) load(userptr, "glTextureStorageMem2DEXT"); + glad_glTextureStorageMem2DMultisampleEXT = (PFNGLTEXTURESTORAGEMEM2DMULTISAMPLEEXTPROC) load(userptr, "glTextureStorageMem2DMultisampleEXT"); + glad_glTextureStorageMem3DEXT = (PFNGLTEXTURESTORAGEMEM3DEXTPROC) load(userptr, "glTextureStorageMem3DEXT"); + glad_glTextureStorageMem3DMultisampleEXT = (PFNGLTEXTURESTORAGEMEM3DMULTISAMPLEEXTPROC) load(userptr, "glTextureStorageMem3DMultisampleEXT"); +} +static void glad_gl_load_GL_EXT_memory_object_fd( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_memory_object_fd) return; + glad_glImportMemoryFdEXT = (PFNGLIMPORTMEMORYFDEXTPROC) load(userptr, "glImportMemoryFdEXT"); +} +static void glad_gl_load_GL_EXT_memory_object_win32( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_memory_object_win32) return; + glad_glImportMemoryWin32HandleEXT = (PFNGLIMPORTMEMORYWIN32HANDLEEXTPROC) load(userptr, "glImportMemoryWin32HandleEXT"); + glad_glImportMemoryWin32NameEXT = (PFNGLIMPORTMEMORYWIN32NAMEEXTPROC) load(userptr, "glImportMemoryWin32NameEXT"); +} +static void glad_gl_load_GL_EXT_multi_draw_arrays( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_multi_draw_arrays) return; + glad_glMultiDrawArraysEXT = (PFNGLMULTIDRAWARRAYSEXTPROC) load(userptr, "glMultiDrawArraysEXT"); + glad_glMultiDrawElementsEXT = (PFNGLMULTIDRAWELEMENTSEXTPROC) load(userptr, "glMultiDrawElementsEXT"); +} +static void glad_gl_load_GL_EXT_multi_draw_indirect( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_multi_draw_indirect) return; + glad_glMultiDrawArraysIndirectEXT = (PFNGLMULTIDRAWARRAYSINDIRECTEXTPROC) load(userptr, "glMultiDrawArraysIndirectEXT"); + glad_glMultiDrawElementsIndirectEXT = (PFNGLMULTIDRAWELEMENTSINDIRECTEXTPROC) load(userptr, "glMultiDrawElementsIndirectEXT"); +} +static void glad_gl_load_GL_EXT_multisampled_render_to_texture( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_multisampled_render_to_texture) return; + glad_glFramebufferTexture2DMultisampleEXT = (PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC) load(userptr, "glFramebufferTexture2DMultisampleEXT"); + glad_glRenderbufferStorageMultisampleEXT = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) load(userptr, "glRenderbufferStorageMultisampleEXT"); +} +static void glad_gl_load_GL_EXT_multiview_draw_buffers( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_multiview_draw_buffers) return; + glad_glDrawBuffersIndexedEXT = (PFNGLDRAWBUFFERSINDEXEDEXTPROC) load(userptr, "glDrawBuffersIndexedEXT"); + glad_glGetIntegeri_vEXT = (PFNGLGETINTEGERI_VEXTPROC) load(userptr, "glGetIntegeri_vEXT"); + glad_glReadBufferIndexedEXT = (PFNGLREADBUFFERINDEXEDEXTPROC) load(userptr, "glReadBufferIndexedEXT"); +} +static void glad_gl_load_GL_EXT_occlusion_query_boolean( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_occlusion_query_boolean) return; + glad_glBeginQueryEXT = (PFNGLBEGINQUERYEXTPROC) load(userptr, "glBeginQueryEXT"); + glad_glDeleteQueriesEXT = (PFNGLDELETEQUERIESEXTPROC) load(userptr, "glDeleteQueriesEXT"); + glad_glEndQueryEXT = (PFNGLENDQUERYEXTPROC) load(userptr, "glEndQueryEXT"); + glad_glGenQueriesEXT = (PFNGLGENQUERIESEXTPROC) load(userptr, "glGenQueriesEXT"); + glad_glGetQueryObjectuivEXT = (PFNGLGETQUERYOBJECTUIVEXTPROC) load(userptr, "glGetQueryObjectuivEXT"); + glad_glGetQueryivEXT = (PFNGLGETQUERYIVEXTPROC) load(userptr, "glGetQueryivEXT"); + glad_glIsQueryEXT = (PFNGLISQUERYEXTPROC) load(userptr, "glIsQueryEXT"); +} +static void glad_gl_load_GL_EXT_polygon_offset_clamp( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_polygon_offset_clamp) return; + glad_glPolygonOffsetClampEXT = (PFNGLPOLYGONOFFSETCLAMPEXTPROC) load(userptr, "glPolygonOffsetClampEXT"); +} +static void glad_gl_load_GL_EXT_primitive_bounding_box( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_primitive_bounding_box) return; + glad_glPrimitiveBoundingBoxEXT = (PFNGLPRIMITIVEBOUNDINGBOXEXTPROC) load(userptr, "glPrimitiveBoundingBoxEXT"); +} +static void glad_gl_load_GL_EXT_raster_multisample( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_raster_multisample) return; + glad_glRasterSamplesEXT = (PFNGLRASTERSAMPLESEXTPROC) load(userptr, "glRasterSamplesEXT"); +} +static void glad_gl_load_GL_EXT_robustness( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_robustness) return; + glad_glGetGraphicsResetStatusEXT = (PFNGLGETGRAPHICSRESETSTATUSEXTPROC) load(userptr, "glGetGraphicsResetStatusEXT"); + glad_glGetnUniformfvEXT = (PFNGLGETNUNIFORMFVEXTPROC) load(userptr, "glGetnUniformfvEXT"); + glad_glGetnUniformivEXT = (PFNGLGETNUNIFORMIVEXTPROC) load(userptr, "glGetnUniformivEXT"); + glad_glReadnPixelsEXT = (PFNGLREADNPIXELSEXTPROC) load(userptr, "glReadnPixelsEXT"); +} +static void glad_gl_load_GL_EXT_semaphore( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_semaphore) return; + glad_glDeleteSemaphoresEXT = (PFNGLDELETESEMAPHORESEXTPROC) load(userptr, "glDeleteSemaphoresEXT"); + glad_glGenSemaphoresEXT = (PFNGLGENSEMAPHORESEXTPROC) load(userptr, "glGenSemaphoresEXT"); + glad_glGetSemaphoreParameterui64vEXT = (PFNGLGETSEMAPHOREPARAMETERUI64VEXTPROC) load(userptr, "glGetSemaphoreParameterui64vEXT"); + glad_glGetUnsignedBytei_vEXT = (PFNGLGETUNSIGNEDBYTEI_VEXTPROC) load(userptr, "glGetUnsignedBytei_vEXT"); + glad_glGetUnsignedBytevEXT = (PFNGLGETUNSIGNEDBYTEVEXTPROC) load(userptr, "glGetUnsignedBytevEXT"); + glad_glIsSemaphoreEXT = (PFNGLISSEMAPHOREEXTPROC) load(userptr, "glIsSemaphoreEXT"); + glad_glSemaphoreParameterui64vEXT = (PFNGLSEMAPHOREPARAMETERUI64VEXTPROC) load(userptr, "glSemaphoreParameterui64vEXT"); + glad_glSignalSemaphoreEXT = (PFNGLSIGNALSEMAPHOREEXTPROC) load(userptr, "glSignalSemaphoreEXT"); + glad_glWaitSemaphoreEXT = (PFNGLWAITSEMAPHOREEXTPROC) load(userptr, "glWaitSemaphoreEXT"); +} +static void glad_gl_load_GL_EXT_semaphore_fd( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_semaphore_fd) return; + glad_glImportSemaphoreFdEXT = (PFNGLIMPORTSEMAPHOREFDEXTPROC) load(userptr, "glImportSemaphoreFdEXT"); +} +static void glad_gl_load_GL_EXT_semaphore_win32( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_semaphore_win32) return; + glad_glImportSemaphoreWin32HandleEXT = (PFNGLIMPORTSEMAPHOREWIN32HANDLEEXTPROC) load(userptr, "glImportSemaphoreWin32HandleEXT"); + glad_glImportSemaphoreWin32NameEXT = (PFNGLIMPORTSEMAPHOREWIN32NAMEEXTPROC) load(userptr, "glImportSemaphoreWin32NameEXT"); +} +static void glad_gl_load_GL_EXT_separate_shader_objects( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_separate_shader_objects) return; + glad_glActiveShaderProgramEXT = (PFNGLACTIVESHADERPROGRAMEXTPROC) load(userptr, "glActiveShaderProgramEXT"); + glad_glBindProgramPipelineEXT = (PFNGLBINDPROGRAMPIPELINEEXTPROC) load(userptr, "glBindProgramPipelineEXT"); + glad_glCreateShaderProgramvEXT = (PFNGLCREATESHADERPROGRAMVEXTPROC) load(userptr, "glCreateShaderProgramvEXT"); + glad_glDeleteProgramPipelinesEXT = (PFNGLDELETEPROGRAMPIPELINESEXTPROC) load(userptr, "glDeleteProgramPipelinesEXT"); + glad_glGenProgramPipelinesEXT = (PFNGLGENPROGRAMPIPELINESEXTPROC) load(userptr, "glGenProgramPipelinesEXT"); + glad_glGetProgramPipelineInfoLogEXT = (PFNGLGETPROGRAMPIPELINEINFOLOGEXTPROC) load(userptr, "glGetProgramPipelineInfoLogEXT"); + glad_glGetProgramPipelineivEXT = (PFNGLGETPROGRAMPIPELINEIVEXTPROC) load(userptr, "glGetProgramPipelineivEXT"); + glad_glIsProgramPipelineEXT = (PFNGLISPROGRAMPIPELINEEXTPROC) load(userptr, "glIsProgramPipelineEXT"); + glad_glProgramParameteriEXT = (PFNGLPROGRAMPARAMETERIEXTPROC) load(userptr, "glProgramParameteriEXT"); + glad_glProgramUniform1fEXT = (PFNGLPROGRAMUNIFORM1FEXTPROC) load(userptr, "glProgramUniform1fEXT"); + glad_glProgramUniform1fvEXT = (PFNGLPROGRAMUNIFORM1FVEXTPROC) load(userptr, "glProgramUniform1fvEXT"); + glad_glProgramUniform1iEXT = (PFNGLPROGRAMUNIFORM1IEXTPROC) load(userptr, "glProgramUniform1iEXT"); + glad_glProgramUniform1ivEXT = (PFNGLPROGRAMUNIFORM1IVEXTPROC) load(userptr, "glProgramUniform1ivEXT"); + glad_glProgramUniform1uiEXT = (PFNGLPROGRAMUNIFORM1UIEXTPROC) load(userptr, "glProgramUniform1uiEXT"); + glad_glProgramUniform1uivEXT = (PFNGLPROGRAMUNIFORM1UIVEXTPROC) load(userptr, "glProgramUniform1uivEXT"); + glad_glProgramUniform2fEXT = (PFNGLPROGRAMUNIFORM2FEXTPROC) load(userptr, "glProgramUniform2fEXT"); + glad_glProgramUniform2fvEXT = (PFNGLPROGRAMUNIFORM2FVEXTPROC) load(userptr, "glProgramUniform2fvEXT"); + glad_glProgramUniform2iEXT = (PFNGLPROGRAMUNIFORM2IEXTPROC) load(userptr, "glProgramUniform2iEXT"); + glad_glProgramUniform2ivEXT = (PFNGLPROGRAMUNIFORM2IVEXTPROC) load(userptr, "glProgramUniform2ivEXT"); + glad_glProgramUniform2uiEXT = (PFNGLPROGRAMUNIFORM2UIEXTPROC) load(userptr, "glProgramUniform2uiEXT"); + glad_glProgramUniform2uivEXT = (PFNGLPROGRAMUNIFORM2UIVEXTPROC) load(userptr, "glProgramUniform2uivEXT"); + glad_glProgramUniform3fEXT = (PFNGLPROGRAMUNIFORM3FEXTPROC) load(userptr, "glProgramUniform3fEXT"); + glad_glProgramUniform3fvEXT = (PFNGLPROGRAMUNIFORM3FVEXTPROC) load(userptr, "glProgramUniform3fvEXT"); + glad_glProgramUniform3iEXT = (PFNGLPROGRAMUNIFORM3IEXTPROC) load(userptr, "glProgramUniform3iEXT"); + glad_glProgramUniform3ivEXT = (PFNGLPROGRAMUNIFORM3IVEXTPROC) load(userptr, "glProgramUniform3ivEXT"); + glad_glProgramUniform3uiEXT = (PFNGLPROGRAMUNIFORM3UIEXTPROC) load(userptr, "glProgramUniform3uiEXT"); + glad_glProgramUniform3uivEXT = (PFNGLPROGRAMUNIFORM3UIVEXTPROC) load(userptr, "glProgramUniform3uivEXT"); + glad_glProgramUniform4fEXT = (PFNGLPROGRAMUNIFORM4FEXTPROC) load(userptr, "glProgramUniform4fEXT"); + glad_glProgramUniform4fvEXT = (PFNGLPROGRAMUNIFORM4FVEXTPROC) load(userptr, "glProgramUniform4fvEXT"); + glad_glProgramUniform4iEXT = (PFNGLPROGRAMUNIFORM4IEXTPROC) load(userptr, "glProgramUniform4iEXT"); + glad_glProgramUniform4ivEXT = (PFNGLPROGRAMUNIFORM4IVEXTPROC) load(userptr, "glProgramUniform4ivEXT"); + glad_glProgramUniform4uiEXT = (PFNGLPROGRAMUNIFORM4UIEXTPROC) load(userptr, "glProgramUniform4uiEXT"); + glad_glProgramUniform4uivEXT = (PFNGLPROGRAMUNIFORM4UIVEXTPROC) load(userptr, "glProgramUniform4uivEXT"); + glad_glProgramUniformMatrix2fvEXT = (PFNGLPROGRAMUNIFORMMATRIX2FVEXTPROC) load(userptr, "glProgramUniformMatrix2fvEXT"); + glad_glProgramUniformMatrix2x3fvEXT = (PFNGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC) load(userptr, "glProgramUniformMatrix2x3fvEXT"); + glad_glProgramUniformMatrix2x4fvEXT = (PFNGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC) load(userptr, "glProgramUniformMatrix2x4fvEXT"); + glad_glProgramUniformMatrix3fvEXT = (PFNGLPROGRAMUNIFORMMATRIX3FVEXTPROC) load(userptr, "glProgramUniformMatrix3fvEXT"); + glad_glProgramUniformMatrix3x2fvEXT = (PFNGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC) load(userptr, "glProgramUniformMatrix3x2fvEXT"); + glad_glProgramUniformMatrix3x4fvEXT = (PFNGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC) load(userptr, "glProgramUniformMatrix3x4fvEXT"); + glad_glProgramUniformMatrix4fvEXT = (PFNGLPROGRAMUNIFORMMATRIX4FVEXTPROC) load(userptr, "glProgramUniformMatrix4fvEXT"); + glad_glProgramUniformMatrix4x2fvEXT = (PFNGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC) load(userptr, "glProgramUniformMatrix4x2fvEXT"); + glad_glProgramUniformMatrix4x3fvEXT = (PFNGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC) load(userptr, "glProgramUniformMatrix4x3fvEXT"); + glad_glUseProgramStagesEXT = (PFNGLUSEPROGRAMSTAGESEXTPROC) load(userptr, "glUseProgramStagesEXT"); + glad_glValidateProgramPipelineEXT = (PFNGLVALIDATEPROGRAMPIPELINEEXTPROC) load(userptr, "glValidateProgramPipelineEXT"); +} +static void glad_gl_load_GL_EXT_shader_framebuffer_fetch_non_coherent( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_shader_framebuffer_fetch_non_coherent) return; + glad_glFramebufferFetchBarrierEXT = (PFNGLFRAMEBUFFERFETCHBARRIEREXTPROC) load(userptr, "glFramebufferFetchBarrierEXT"); +} +static void glad_gl_load_GL_EXT_shader_pixel_local_storage2( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_shader_pixel_local_storage2) return; + glad_glClearPixelLocalStorageuiEXT = (PFNGLCLEARPIXELLOCALSTORAGEUIEXTPROC) load(userptr, "glClearPixelLocalStorageuiEXT"); + glad_glFramebufferPixelLocalStorageSizeEXT = (PFNGLFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC) load(userptr, "glFramebufferPixelLocalStorageSizeEXT"); + glad_glGetFramebufferPixelLocalStorageSizeEXT = (PFNGLGETFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC) load(userptr, "glGetFramebufferPixelLocalStorageSizeEXT"); +} +static void glad_gl_load_GL_EXT_sparse_texture( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_sparse_texture) return; + glad_glTexPageCommitmentEXT = (PFNGLTEXPAGECOMMITMENTEXTPROC) load(userptr, "glTexPageCommitmentEXT"); +} +static void glad_gl_load_GL_EXT_tessellation_shader( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_tessellation_shader) return; + glad_glPatchParameteriEXT = (PFNGLPATCHPARAMETERIEXTPROC) load(userptr, "glPatchParameteriEXT"); +} +static void glad_gl_load_GL_EXT_texture_border_clamp( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_texture_border_clamp) return; + glad_glGetSamplerParameterIivEXT = (PFNGLGETSAMPLERPARAMETERIIVEXTPROC) load(userptr, "glGetSamplerParameterIivEXT"); + glad_glGetSamplerParameterIuivEXT = (PFNGLGETSAMPLERPARAMETERIUIVEXTPROC) load(userptr, "glGetSamplerParameterIuivEXT"); + glad_glGetTexParameterIivEXT = (PFNGLGETTEXPARAMETERIIVEXTPROC) load(userptr, "glGetTexParameterIivEXT"); + glad_glGetTexParameterIuivEXT = (PFNGLGETTEXPARAMETERIUIVEXTPROC) load(userptr, "glGetTexParameterIuivEXT"); + glad_glSamplerParameterIivEXT = (PFNGLSAMPLERPARAMETERIIVEXTPROC) load(userptr, "glSamplerParameterIivEXT"); + glad_glSamplerParameterIuivEXT = (PFNGLSAMPLERPARAMETERIUIVEXTPROC) load(userptr, "glSamplerParameterIuivEXT"); + glad_glTexParameterIivEXT = (PFNGLTEXPARAMETERIIVEXTPROC) load(userptr, "glTexParameterIivEXT"); + glad_glTexParameterIuivEXT = (PFNGLTEXPARAMETERIUIVEXTPROC) load(userptr, "glTexParameterIuivEXT"); +} +static void glad_gl_load_GL_EXT_texture_buffer( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_texture_buffer) return; + glad_glTexBufferEXT = (PFNGLTEXBUFFEREXTPROC) load(userptr, "glTexBufferEXT"); + glad_glTexBufferRangeEXT = (PFNGLTEXBUFFERRANGEEXTPROC) load(userptr, "glTexBufferRangeEXT"); +} +static void glad_gl_load_GL_EXT_texture_storage( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_texture_storage) return; + glad_glTexStorage1DEXT = (PFNGLTEXSTORAGE1DEXTPROC) load(userptr, "glTexStorage1DEXT"); + glad_glTexStorage2DEXT = (PFNGLTEXSTORAGE2DEXTPROC) load(userptr, "glTexStorage2DEXT"); + glad_glTexStorage3DEXT = (PFNGLTEXSTORAGE3DEXTPROC) load(userptr, "glTexStorage3DEXT"); + glad_glTextureStorage1DEXT = (PFNGLTEXTURESTORAGE1DEXTPROC) load(userptr, "glTextureStorage1DEXT"); + glad_glTextureStorage2DEXT = (PFNGLTEXTURESTORAGE2DEXTPROC) load(userptr, "glTextureStorage2DEXT"); + glad_glTextureStorage3DEXT = (PFNGLTEXTURESTORAGE3DEXTPROC) load(userptr, "glTextureStorage3DEXT"); +} +static void glad_gl_load_GL_EXT_texture_storage_compression( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_texture_storage_compression) return; + glad_glTexStorageAttribs2DEXT = (PFNGLTEXSTORAGEATTRIBS2DEXTPROC) load(userptr, "glTexStorageAttribs2DEXT"); + glad_glTexStorageAttribs3DEXT = (PFNGLTEXSTORAGEATTRIBS3DEXTPROC) load(userptr, "glTexStorageAttribs3DEXT"); +} +static void glad_gl_load_GL_EXT_texture_view( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_texture_view) return; + glad_glTextureViewEXT = (PFNGLTEXTUREVIEWEXTPROC) load(userptr, "glTextureViewEXT"); +} +static void glad_gl_load_GL_EXT_win32_keyed_mutex( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_win32_keyed_mutex) return; + glad_glAcquireKeyedMutexWin32EXT = (PFNGLACQUIREKEYEDMUTEXWIN32EXTPROC) load(userptr, "glAcquireKeyedMutexWin32EXT"); + glad_glReleaseKeyedMutexWin32EXT = (PFNGLRELEASEKEYEDMUTEXWIN32EXTPROC) load(userptr, "glReleaseKeyedMutexWin32EXT"); +} +static void glad_gl_load_GL_EXT_window_rectangles( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_window_rectangles) return; + glad_glWindowRectanglesEXT = (PFNGLWINDOWRECTANGLESEXTPROC) load(userptr, "glWindowRectanglesEXT"); +} +static void glad_gl_load_GL_KHR_blend_equation_advanced( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_KHR_blend_equation_advanced) return; + glad_glBlendBarrierKHR = (PFNGLBLENDBARRIERKHRPROC) load(userptr, "glBlendBarrierKHR"); +} +static void glad_gl_load_GL_KHR_debug( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_KHR_debug) return; + glad_glDebugMessageCallbackKHR = (PFNGLDEBUGMESSAGECALLBACKKHRPROC) load(userptr, "glDebugMessageCallbackKHR"); + glad_glDebugMessageControlKHR = (PFNGLDEBUGMESSAGECONTROLKHRPROC) load(userptr, "glDebugMessageControlKHR"); + glad_glDebugMessageInsertKHR = (PFNGLDEBUGMESSAGEINSERTKHRPROC) load(userptr, "glDebugMessageInsertKHR"); + glad_glGetDebugMessageLogKHR = (PFNGLGETDEBUGMESSAGELOGKHRPROC) load(userptr, "glGetDebugMessageLogKHR"); + glad_glGetObjectLabelKHR = (PFNGLGETOBJECTLABELKHRPROC) load(userptr, "glGetObjectLabelKHR"); + glad_glGetObjectPtrLabelKHR = (PFNGLGETOBJECTPTRLABELKHRPROC) load(userptr, "glGetObjectPtrLabelKHR"); + glad_glGetPointervKHR = (PFNGLGETPOINTERVKHRPROC) load(userptr, "glGetPointervKHR"); + glad_glObjectLabelKHR = (PFNGLOBJECTLABELKHRPROC) load(userptr, "glObjectLabelKHR"); + glad_glObjectPtrLabelKHR = (PFNGLOBJECTPTRLABELKHRPROC) load(userptr, "glObjectPtrLabelKHR"); + glad_glPopDebugGroupKHR = (PFNGLPOPDEBUGGROUPKHRPROC) load(userptr, "glPopDebugGroupKHR"); + glad_glPushDebugGroupKHR = (PFNGLPUSHDEBUGGROUPKHRPROC) load(userptr, "glPushDebugGroupKHR"); +} +static void glad_gl_load_GL_KHR_parallel_shader_compile( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_KHR_parallel_shader_compile) return; + glad_glMaxShaderCompilerThreadsKHR = (PFNGLMAXSHADERCOMPILERTHREADSKHRPROC) load(userptr, "glMaxShaderCompilerThreadsKHR"); +} +static void glad_gl_load_GL_KHR_robustness( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_KHR_robustness) return; + glad_glGetGraphicsResetStatusKHR = (PFNGLGETGRAPHICSRESETSTATUSKHRPROC) load(userptr, "glGetGraphicsResetStatusKHR"); + glad_glGetnUniformfvKHR = (PFNGLGETNUNIFORMFVKHRPROC) load(userptr, "glGetnUniformfvKHR"); + glad_glGetnUniformivKHR = (PFNGLGETNUNIFORMIVKHRPROC) load(userptr, "glGetnUniformivKHR"); + glad_glGetnUniformuivKHR = (PFNGLGETNUNIFORMUIVKHRPROC) load(userptr, "glGetnUniformuivKHR"); + glad_glReadnPixelsKHR = (PFNGLREADNPIXELSKHRPROC) load(userptr, "glReadnPixelsKHR"); +} +static void glad_gl_load_GL_OES_EGL_image( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_OES_EGL_image) return; + glad_glEGLImageTargetRenderbufferStorageOES = (PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) load(userptr, "glEGLImageTargetRenderbufferStorageOES"); + glad_glEGLImageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) load(userptr, "glEGLImageTargetTexture2DOES"); +} +static void glad_gl_load_GL_OES_copy_image( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_OES_copy_image) return; + glad_glCopyImageSubDataOES = (PFNGLCOPYIMAGESUBDATAOESPROC) load(userptr, "glCopyImageSubDataOES"); +} +static void glad_gl_load_GL_OES_draw_buffers_indexed( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_OES_draw_buffers_indexed) return; + glad_glBlendEquationSeparateiOES = (PFNGLBLENDEQUATIONSEPARATEIOESPROC) load(userptr, "glBlendEquationSeparateiOES"); + glad_glBlendEquationiOES = (PFNGLBLENDEQUATIONIOESPROC) load(userptr, "glBlendEquationiOES"); + glad_glBlendFuncSeparateiOES = (PFNGLBLENDFUNCSEPARATEIOESPROC) load(userptr, "glBlendFuncSeparateiOES"); + glad_glBlendFunciOES = (PFNGLBLENDFUNCIOESPROC) load(userptr, "glBlendFunciOES"); + glad_glColorMaskiOES = (PFNGLCOLORMASKIOESPROC) load(userptr, "glColorMaskiOES"); + glad_glDisableiOES = (PFNGLDISABLEIOESPROC) load(userptr, "glDisableiOES"); + glad_glEnableiOES = (PFNGLENABLEIOESPROC) load(userptr, "glEnableiOES"); + glad_glIsEnablediOES = (PFNGLISENABLEDIOESPROC) load(userptr, "glIsEnablediOES"); +} +static void glad_gl_load_GL_OES_draw_elements_base_vertex( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_OES_draw_elements_base_vertex) return; + glad_glDrawElementsBaseVertexOES = (PFNGLDRAWELEMENTSBASEVERTEXOESPROC) load(userptr, "glDrawElementsBaseVertexOES"); + glad_glDrawElementsInstancedBaseVertexOES = (PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXOESPROC) load(userptr, "glDrawElementsInstancedBaseVertexOES"); + glad_glDrawRangeElementsBaseVertexOES = (PFNGLDRAWRANGEELEMENTSBASEVERTEXOESPROC) load(userptr, "glDrawRangeElementsBaseVertexOES"); + glad_glMultiDrawElementsBaseVertexEXT = (PFNGLMULTIDRAWELEMENTSBASEVERTEXEXTPROC) load(userptr, "glMultiDrawElementsBaseVertexEXT"); +} +static void glad_gl_load_GL_OES_geometry_shader( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_OES_geometry_shader) return; + glad_glFramebufferTextureOES = (PFNGLFRAMEBUFFERTEXTUREOESPROC) load(userptr, "glFramebufferTextureOES"); +} +static void glad_gl_load_GL_OES_get_program_binary( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_OES_get_program_binary) return; + glad_glGetProgramBinaryOES = (PFNGLGETPROGRAMBINARYOESPROC) load(userptr, "glGetProgramBinaryOES"); + glad_glProgramBinaryOES = (PFNGLPROGRAMBINARYOESPROC) load(userptr, "glProgramBinaryOES"); +} +static void glad_gl_load_GL_OES_mapbuffer( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_OES_mapbuffer) return; + glad_glGetBufferPointervOES = (PFNGLGETBUFFERPOINTERVOESPROC) load(userptr, "glGetBufferPointervOES"); + glad_glMapBufferOES = (PFNGLMAPBUFFEROESPROC) load(userptr, "glMapBufferOES"); + glad_glUnmapBufferOES = (PFNGLUNMAPBUFFEROESPROC) load(userptr, "glUnmapBufferOES"); +} +static void glad_gl_load_GL_OES_primitive_bounding_box( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_OES_primitive_bounding_box) return; + glad_glPrimitiveBoundingBoxOES = (PFNGLPRIMITIVEBOUNDINGBOXOESPROC) load(userptr, "glPrimitiveBoundingBoxOES"); +} +static void glad_gl_load_GL_OES_sample_shading( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_OES_sample_shading) return; + glad_glMinSampleShadingOES = (PFNGLMINSAMPLESHADINGOESPROC) load(userptr, "glMinSampleShadingOES"); +} +static void glad_gl_load_GL_OES_tessellation_shader( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_OES_tessellation_shader) return; + glad_glPatchParameteriOES = (PFNGLPATCHPARAMETERIOESPROC) load(userptr, "glPatchParameteriOES"); +} +static void glad_gl_load_GL_OES_texture_3D( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_OES_texture_3D) return; + glad_glCompressedTexImage3DOES = (PFNGLCOMPRESSEDTEXIMAGE3DOESPROC) load(userptr, "glCompressedTexImage3DOES"); + glad_glCompressedTexSubImage3DOES = (PFNGLCOMPRESSEDTEXSUBIMAGE3DOESPROC) load(userptr, "glCompressedTexSubImage3DOES"); + glad_glCopyTexSubImage3DOES = (PFNGLCOPYTEXSUBIMAGE3DOESPROC) load(userptr, "glCopyTexSubImage3DOES"); + glad_glFramebufferTexture3DOES = (PFNGLFRAMEBUFFERTEXTURE3DOESPROC) load(userptr, "glFramebufferTexture3DOES"); + glad_glTexImage3DOES = (PFNGLTEXIMAGE3DOESPROC) load(userptr, "glTexImage3DOES"); + glad_glTexSubImage3DOES = (PFNGLTEXSUBIMAGE3DOESPROC) load(userptr, "glTexSubImage3DOES"); +} +static void glad_gl_load_GL_OES_texture_border_clamp( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_OES_texture_border_clamp) return; + glad_glGetSamplerParameterIivOES = (PFNGLGETSAMPLERPARAMETERIIVOESPROC) load(userptr, "glGetSamplerParameterIivOES"); + glad_glGetSamplerParameterIuivOES = (PFNGLGETSAMPLERPARAMETERIUIVOESPROC) load(userptr, "glGetSamplerParameterIuivOES"); + glad_glGetTexParameterIivOES = (PFNGLGETTEXPARAMETERIIVOESPROC) load(userptr, "glGetTexParameterIivOES"); + glad_glGetTexParameterIuivOES = (PFNGLGETTEXPARAMETERIUIVOESPROC) load(userptr, "glGetTexParameterIuivOES"); + glad_glSamplerParameterIivOES = (PFNGLSAMPLERPARAMETERIIVOESPROC) load(userptr, "glSamplerParameterIivOES"); + glad_glSamplerParameterIuivOES = (PFNGLSAMPLERPARAMETERIUIVOESPROC) load(userptr, "glSamplerParameterIuivOES"); + glad_glTexParameterIivOES = (PFNGLTEXPARAMETERIIVOESPROC) load(userptr, "glTexParameterIivOES"); + glad_glTexParameterIuivOES = (PFNGLTEXPARAMETERIUIVOESPROC) load(userptr, "glTexParameterIuivOES"); +} +static void glad_gl_load_GL_OES_texture_buffer( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_OES_texture_buffer) return; + glad_glTexBufferOES = (PFNGLTEXBUFFEROESPROC) load(userptr, "glTexBufferOES"); + glad_glTexBufferRangeOES = (PFNGLTEXBUFFERRANGEOESPROC) load(userptr, "glTexBufferRangeOES"); +} +static void glad_gl_load_GL_OES_texture_storage_multisample_2d_array( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_OES_texture_storage_multisample_2d_array) return; + glad_glTexStorage3DMultisampleOES = (PFNGLTEXSTORAGE3DMULTISAMPLEOESPROC) load(userptr, "glTexStorage3DMultisampleOES"); +} +static void glad_gl_load_GL_OES_texture_view( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_OES_texture_view) return; + glad_glTextureViewOES = (PFNGLTEXTUREVIEWOESPROC) load(userptr, "glTextureViewOES"); +} +static void glad_gl_load_GL_OES_vertex_array_object( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_OES_vertex_array_object) return; + glad_glBindVertexArrayOES = (PFNGLBINDVERTEXARRAYOESPROC) load(userptr, "glBindVertexArrayOES"); + glad_glDeleteVertexArraysOES = (PFNGLDELETEVERTEXARRAYSOESPROC) load(userptr, "glDeleteVertexArraysOES"); + glad_glGenVertexArraysOES = (PFNGLGENVERTEXARRAYSOESPROC) load(userptr, "glGenVertexArraysOES"); + glad_glIsVertexArrayOES = (PFNGLISVERTEXARRAYOESPROC) load(userptr, "glIsVertexArrayOES"); +} +static void glad_gl_load_GL_OES_viewport_array( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_OES_viewport_array) return; + glad_glDepthRangeArrayfvOES = (PFNGLDEPTHRANGEARRAYFVOESPROC) load(userptr, "glDepthRangeArrayfvOES"); + glad_glDepthRangeIndexedfOES = (PFNGLDEPTHRANGEINDEXEDFOESPROC) load(userptr, "glDepthRangeIndexedfOES"); + glad_glDisableiOES = (PFNGLDISABLEIOESPROC) load(userptr, "glDisableiOES"); + glad_glEnableiOES = (PFNGLENABLEIOESPROC) load(userptr, "glEnableiOES"); + glad_glGetFloati_vOES = (PFNGLGETFLOATI_VOESPROC) load(userptr, "glGetFloati_vOES"); + glad_glIsEnablediOES = (PFNGLISENABLEDIOESPROC) load(userptr, "glIsEnablediOES"); + glad_glScissorArrayvOES = (PFNGLSCISSORARRAYVOESPROC) load(userptr, "glScissorArrayvOES"); + glad_glScissorIndexedOES = (PFNGLSCISSORINDEXEDOESPROC) load(userptr, "glScissorIndexedOES"); + glad_glScissorIndexedvOES = (PFNGLSCISSORINDEXEDVOESPROC) load(userptr, "glScissorIndexedvOES"); + glad_glViewportArrayvOES = (PFNGLVIEWPORTARRAYVOESPROC) load(userptr, "glViewportArrayvOES"); + glad_glViewportIndexedfOES = (PFNGLVIEWPORTINDEXEDFOESPROC) load(userptr, "glViewportIndexedfOES"); + glad_glViewportIndexedfvOES = (PFNGLVIEWPORTINDEXEDFVOESPROC) load(userptr, "glViewportIndexedfvOES"); +} + + + +#if defined(GL_ES_VERSION_3_0) || defined(GL_VERSION_3_0) +#define GLAD_GL_IS_SOME_NEW_VERSION 1 +#else +#define GLAD_GL_IS_SOME_NEW_VERSION 0 +#endif + +static int glad_gl_get_extensions( int version, const char **out_exts, unsigned int *out_num_exts_i, char ***out_exts_i) { +#if GLAD_GL_IS_SOME_NEW_VERSION + if(GLAD_VERSION_MAJOR(version) < 3) { +#else + GLAD_UNUSED(version); + GLAD_UNUSED(out_num_exts_i); + GLAD_UNUSED(out_exts_i); +#endif + if (glad_glGetString == NULL) { + return 0; + } + *out_exts = (const char *)glad_glGetString(GL_EXTENSIONS); +#if GLAD_GL_IS_SOME_NEW_VERSION + } else { + unsigned int index = 0; + unsigned int num_exts_i = 0; + char **exts_i = NULL; + if (glad_glGetStringi == NULL || glad_glGetIntegerv == NULL) { + return 0; + } + glad_glGetIntegerv(GL_NUM_EXTENSIONS, (int*) &num_exts_i); + if (num_exts_i > 0) { + exts_i = (char **) malloc(num_exts_i * (sizeof *exts_i)); + } + if (exts_i == NULL) { + return 0; + } + for(index = 0; index < num_exts_i; index++) { + const char *gl_str_tmp = (const char*) glad_glGetStringi(GL_EXTENSIONS, index); + size_t len = strlen(gl_str_tmp) + 1; + + char *local_str = (char*) malloc(len * sizeof(char)); + if(local_str != NULL) { + memcpy(local_str, gl_str_tmp, len * sizeof(char)); + } + + exts_i[index] = local_str; + } + + *out_num_exts_i = num_exts_i; + *out_exts_i = exts_i; + } +#endif + return 1; +} +static void glad_gl_free_extensions(char **exts_i, unsigned int num_exts_i) { + if (exts_i != NULL) { + unsigned int index; + for(index = 0; index < num_exts_i; index++) { + free((void *) (exts_i[index])); + } + free((void *)exts_i); + exts_i = NULL; + } +} +static int glad_gl_has_extension(int version, const char *exts, unsigned int num_exts_i, char **exts_i, const char *ext) { + if(GLAD_VERSION_MAJOR(version) < 3 || !GLAD_GL_IS_SOME_NEW_VERSION) { + const char *extensions; + const char *loc; + const char *terminator; + extensions = exts; + if(extensions == NULL || ext == NULL) { + return 0; + } + while(1) { + loc = strstr(extensions, ext); + if(loc == NULL) { + return 0; + } + terminator = loc + strlen(ext); + if((loc == extensions || *(loc - 1) == ' ') && + (*terminator == ' ' || *terminator == '\0')) { + return 1; + } + extensions = terminator; + } + } else { + unsigned int index; + for(index = 0; index < num_exts_i; index++) { + const char *e = exts_i[index]; + if(strcmp(e, ext) == 0) { + return 1; + } + } + } + return 0; +} + +static GLADapiproc glad_gl_get_proc_from_userptr(void *userptr, const char* name) { + return (GLAD_GNUC_EXTENSION (GLADapiproc (*)(const char *name)) userptr)(name); +} + +static int glad_gl_find_extensions_gles2( int version) { + const char *exts = NULL; + unsigned int num_exts_i = 0; + char **exts_i = NULL; + if (!glad_gl_get_extensions(version, &exts, &num_exts_i, &exts_i)) return 0; + + GLAD_GL_EXT_EGL_image_array = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_EGL_image_array"); + GLAD_GL_EXT_EGL_image_storage = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_EGL_image_storage"); + GLAD_GL_EXT_EGL_image_storage_compression = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_EGL_image_storage_compression"); + GLAD_GL_EXT_YUV_target = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_YUV_target"); + GLAD_GL_EXT_base_instance = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_base_instance"); + GLAD_GL_EXT_blend_func_extended = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_blend_func_extended"); + GLAD_GL_EXT_blend_minmax = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_blend_minmax"); + GLAD_GL_EXT_buffer_storage = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_buffer_storage"); + GLAD_GL_EXT_clear_texture = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_clear_texture"); + GLAD_GL_EXT_clip_control = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_clip_control"); + GLAD_GL_EXT_clip_cull_distance = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_clip_cull_distance"); + GLAD_GL_EXT_color_buffer_float = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_color_buffer_float"); + GLAD_GL_EXT_color_buffer_half_float = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_color_buffer_half_float"); + GLAD_GL_EXT_conservative_depth = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_conservative_depth"); + GLAD_GL_EXT_copy_image = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_copy_image"); + GLAD_GL_EXT_debug_label = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_debug_label"); + GLAD_GL_EXT_debug_marker = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_debug_marker"); + GLAD_GL_EXT_depth_clamp = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_depth_clamp"); + GLAD_GL_EXT_discard_framebuffer = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_discard_framebuffer"); + GLAD_GL_EXT_disjoint_timer_query = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_disjoint_timer_query"); + GLAD_GL_EXT_draw_buffers = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_draw_buffers"); + GLAD_GL_EXT_draw_buffers_indexed = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_draw_buffers_indexed"); + GLAD_GL_EXT_draw_elements_base_vertex = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_draw_elements_base_vertex"); + GLAD_GL_EXT_draw_instanced = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_draw_instanced"); + GLAD_GL_EXT_draw_transform_feedback = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_draw_transform_feedback"); + GLAD_GL_EXT_external_buffer = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_external_buffer"); + GLAD_GL_EXT_float_blend = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_float_blend"); + GLAD_GL_EXT_fragment_shading_rate = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_fragment_shading_rate"); + GLAD_GL_EXT_geometry_point_size = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_geometry_point_size"); + GLAD_GL_EXT_geometry_shader = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_geometry_shader"); + GLAD_GL_EXT_gpu_shader5 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_gpu_shader5"); + GLAD_GL_EXT_instanced_arrays = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_instanced_arrays"); + GLAD_GL_EXT_map_buffer_range = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_map_buffer_range"); + GLAD_GL_EXT_memory_object = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_memory_object"); + GLAD_GL_EXT_memory_object_fd = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_memory_object_fd"); + GLAD_GL_EXT_memory_object_win32 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_memory_object_win32"); + GLAD_GL_EXT_multi_draw_arrays = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_multi_draw_arrays"); + GLAD_GL_EXT_multi_draw_indirect = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_multi_draw_indirect"); + GLAD_GL_EXT_multisampled_compatibility = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_multisampled_compatibility"); + GLAD_GL_EXT_multisampled_render_to_texture = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_multisampled_render_to_texture"); + GLAD_GL_EXT_multisampled_render_to_texture2 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_multisampled_render_to_texture2"); + GLAD_GL_EXT_multiview_draw_buffers = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_multiview_draw_buffers"); + GLAD_GL_EXT_multiview_tessellation_geometry_shader = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_multiview_tessellation_geometry_shader"); + GLAD_GL_EXT_multiview_texture_multisample = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_multiview_texture_multisample"); + GLAD_GL_EXT_multiview_timer_query = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_multiview_timer_query"); + GLAD_GL_EXT_occlusion_query_boolean = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_occlusion_query_boolean"); + GLAD_GL_EXT_polygon_offset_clamp = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_polygon_offset_clamp"); + GLAD_GL_EXT_post_depth_coverage = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_post_depth_coverage"); + GLAD_GL_EXT_primitive_bounding_box = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_primitive_bounding_box"); + GLAD_GL_EXT_protected_textures = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_protected_textures"); + GLAD_GL_EXT_pvrtc_sRGB = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_pvrtc_sRGB"); + GLAD_GL_EXT_raster_multisample = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_raster_multisample"); + GLAD_GL_EXT_read_format_bgra = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_read_format_bgra"); + GLAD_GL_EXT_render_snorm = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_render_snorm"); + GLAD_GL_EXT_robustness = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_robustness"); + GLAD_GL_EXT_sRGB = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_sRGB"); + GLAD_GL_EXT_sRGB_write_control = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_sRGB_write_control"); + GLAD_GL_EXT_semaphore = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_semaphore"); + GLAD_GL_EXT_semaphore_fd = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_semaphore_fd"); + GLAD_GL_EXT_semaphore_win32 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_semaphore_win32"); + GLAD_GL_EXT_separate_depth_stencil = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_separate_depth_stencil"); + GLAD_GL_EXT_separate_shader_objects = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_separate_shader_objects"); + GLAD_GL_EXT_shader_framebuffer_fetch = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_shader_framebuffer_fetch"); + GLAD_GL_EXT_shader_framebuffer_fetch_non_coherent = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_shader_framebuffer_fetch_non_coherent"); + GLAD_GL_EXT_shader_group_vote = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_shader_group_vote"); + GLAD_GL_EXT_shader_implicit_conversions = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_shader_implicit_conversions"); + GLAD_GL_EXT_shader_integer_mix = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_shader_integer_mix"); + GLAD_GL_EXT_shader_io_blocks = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_shader_io_blocks"); + GLAD_GL_EXT_shader_non_constant_global_initializers = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_shader_non_constant_global_initializers"); + GLAD_GL_EXT_shader_pixel_local_storage = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_shader_pixel_local_storage"); + GLAD_GL_EXT_shader_pixel_local_storage2 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_shader_pixel_local_storage2"); + GLAD_GL_EXT_shader_samples_identical = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_shader_samples_identical"); + GLAD_GL_EXT_shader_texture_lod = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_shader_texture_lod"); + GLAD_GL_EXT_shadow_samplers = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_shadow_samplers"); + GLAD_GL_EXT_sparse_texture = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_sparse_texture"); + GLAD_GL_EXT_sparse_texture2 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_sparse_texture2"); + GLAD_GL_EXT_tessellation_point_size = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_tessellation_point_size"); + GLAD_GL_EXT_tessellation_shader = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_tessellation_shader"); + GLAD_GL_EXT_texture_border_clamp = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_border_clamp"); + GLAD_GL_EXT_texture_buffer = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_buffer"); + GLAD_GL_EXT_texture_compression_astc_decode_mode = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_compression_astc_decode_mode"); + GLAD_GL_EXT_texture_compression_bptc = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_compression_bptc"); + GLAD_GL_EXT_texture_compression_dxt1 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_compression_dxt1"); + GLAD_GL_EXT_texture_compression_rgtc = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_compression_rgtc"); + GLAD_GL_EXT_texture_compression_s3tc = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_compression_s3tc"); + GLAD_GL_EXT_texture_compression_s3tc_srgb = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_compression_s3tc_srgb"); + GLAD_GL_EXT_texture_cube_map_array = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_cube_map_array"); + GLAD_GL_EXT_texture_filter_anisotropic = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_filter_anisotropic"); + GLAD_GL_EXT_texture_filter_minmax = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_filter_minmax"); + GLAD_GL_EXT_texture_format_BGRA8888 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_format_BGRA8888"); + GLAD_GL_EXT_texture_format_sRGB_override = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_format_sRGB_override"); + GLAD_GL_EXT_texture_mirror_clamp_to_edge = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_mirror_clamp_to_edge"); + GLAD_GL_EXT_texture_norm16 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_norm16"); + GLAD_GL_EXT_texture_query_lod = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_query_lod"); + GLAD_GL_EXT_texture_rg = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_rg"); + GLAD_GL_EXT_texture_sRGB_R8 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_sRGB_R8"); + GLAD_GL_EXT_texture_sRGB_RG8 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_sRGB_RG8"); + GLAD_GL_EXT_texture_sRGB_decode = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_sRGB_decode"); + GLAD_GL_EXT_texture_shadow_lod = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_shadow_lod"); + GLAD_GL_EXT_texture_storage = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_storage"); + GLAD_GL_EXT_texture_storage_compression = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_storage_compression"); + GLAD_GL_EXT_texture_type_2_10_10_10_REV = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_type_2_10_10_10_REV"); + GLAD_GL_EXT_texture_view = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_view"); + GLAD_GL_EXT_unpack_subimage = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_unpack_subimage"); + GLAD_GL_EXT_win32_keyed_mutex = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_win32_keyed_mutex"); + GLAD_GL_EXT_window_rectangles = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_window_rectangles"); + GLAD_GL_KHR_blend_equation_advanced = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_KHR_blend_equation_advanced"); + GLAD_GL_KHR_blend_equation_advanced_coherent = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_KHR_blend_equation_advanced_coherent"); + GLAD_GL_KHR_context_flush_control = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_KHR_context_flush_control"); + GLAD_GL_KHR_debug = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_KHR_debug"); + GLAD_GL_KHR_no_error = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_KHR_no_error"); + GLAD_GL_KHR_parallel_shader_compile = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_KHR_parallel_shader_compile"); + GLAD_GL_KHR_robust_buffer_access_behavior = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_KHR_robust_buffer_access_behavior"); + GLAD_GL_KHR_robustness = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_KHR_robustness"); + GLAD_GL_KHR_shader_subgroup = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_KHR_shader_subgroup"); + GLAD_GL_KHR_texture_compression_astc_hdr = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_KHR_texture_compression_astc_hdr"); + GLAD_GL_KHR_texture_compression_astc_ldr = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_KHR_texture_compression_astc_ldr"); + GLAD_GL_KHR_texture_compression_astc_sliced_3d = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_KHR_texture_compression_astc_sliced_3d"); + GLAD_GL_OES_EGL_image = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_EGL_image"); + GLAD_GL_OES_EGL_image_external = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_EGL_image_external"); + GLAD_GL_OES_EGL_image_external_essl3 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_EGL_image_external_essl3"); + GLAD_GL_OES_compressed_ETC1_RGB8_sub_texture = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_compressed_ETC1_RGB8_sub_texture"); + GLAD_GL_OES_compressed_ETC1_RGB8_texture = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_compressed_ETC1_RGB8_texture"); + GLAD_GL_OES_compressed_paletted_texture = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_compressed_paletted_texture"); + GLAD_GL_OES_copy_image = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_copy_image"); + GLAD_GL_OES_depth24 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_depth24"); + GLAD_GL_OES_depth32 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_depth32"); + GLAD_GL_OES_depth_texture = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_depth_texture"); + GLAD_GL_OES_draw_buffers_indexed = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_draw_buffers_indexed"); + GLAD_GL_OES_draw_elements_base_vertex = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_draw_elements_base_vertex"); + GLAD_GL_OES_element_index_uint = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_element_index_uint"); + GLAD_GL_OES_fbo_render_mipmap = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_fbo_render_mipmap"); + GLAD_GL_OES_fragment_precision_high = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_fragment_precision_high"); + GLAD_GL_OES_geometry_point_size = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_geometry_point_size"); + GLAD_GL_OES_geometry_shader = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_geometry_shader"); + GLAD_GL_OES_get_program_binary = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_get_program_binary"); + GLAD_GL_OES_gpu_shader5 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_gpu_shader5"); + GLAD_GL_OES_mapbuffer = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_mapbuffer"); + GLAD_GL_OES_packed_depth_stencil = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_packed_depth_stencil"); + GLAD_GL_OES_primitive_bounding_box = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_primitive_bounding_box"); + GLAD_GL_OES_required_internalformat = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_required_internalformat"); + GLAD_GL_OES_rgb8_rgba8 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_rgb8_rgba8"); + GLAD_GL_OES_sample_shading = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_sample_shading"); + GLAD_GL_OES_sample_variables = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_sample_variables"); + GLAD_GL_OES_shader_image_atomic = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_shader_image_atomic"); + GLAD_GL_OES_shader_io_blocks = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_shader_io_blocks"); + GLAD_GL_OES_shader_multisample_interpolation = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_shader_multisample_interpolation"); + GLAD_GL_OES_standard_derivatives = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_standard_derivatives"); + GLAD_GL_OES_stencil1 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_stencil1"); + GLAD_GL_OES_stencil4 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_stencil4"); + GLAD_GL_OES_surfaceless_context = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_surfaceless_context"); + GLAD_GL_OES_tessellation_point_size = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_tessellation_point_size"); + GLAD_GL_OES_tessellation_shader = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_tessellation_shader"); + GLAD_GL_OES_texture_3D = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_texture_3D"); + GLAD_GL_OES_texture_border_clamp = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_texture_border_clamp"); + GLAD_GL_OES_texture_buffer = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_texture_buffer"); + GLAD_GL_OES_texture_compression_astc = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_texture_compression_astc"); + GLAD_GL_OES_texture_cube_map_array = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_texture_cube_map_array"); + GLAD_GL_OES_texture_float = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_texture_float"); + GLAD_GL_OES_texture_float_linear = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_texture_float_linear"); + GLAD_GL_OES_texture_half_float = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_texture_half_float"); + GLAD_GL_OES_texture_half_float_linear = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_texture_half_float_linear"); + GLAD_GL_OES_texture_npot = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_texture_npot"); + GLAD_GL_OES_texture_stencil8 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_texture_stencil8"); + GLAD_GL_OES_texture_storage_multisample_2d_array = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_texture_storage_multisample_2d_array"); + GLAD_GL_OES_texture_view = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_texture_view"); + GLAD_GL_OES_vertex_array_object = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_vertex_array_object"); + GLAD_GL_OES_vertex_half_float = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_vertex_half_float"); + GLAD_GL_OES_vertex_type_10_10_10_2 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_vertex_type_10_10_10_2"); + GLAD_GL_OES_viewport_array = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_viewport_array"); + + glad_gl_free_extensions(exts_i, num_exts_i); + + return 1; +} + +static int glad_gl_find_core_gles2(void) { + int i; + const char* version; + const char* prefixes[] = { + "OpenGL ES-CM ", + "OpenGL ES-CL ", + "OpenGL ES ", + "OpenGL SC ", + NULL + }; + int major = 0; + int minor = 0; + version = (const char*) glad_glGetString(GL_VERSION); + if (!version) return 0; + for (i = 0; prefixes[i]; i++) { + const size_t length = strlen(prefixes[i]); + if (strncmp(version, prefixes[i], length) == 0) { + version += length; + break; + } + } + + GLAD_IMPL_UTIL_SSCANF(version, "%d.%d", &major, &minor); + + GLAD_GL_ES_VERSION_2_0 = (major == 2 && minor >= 0) || major > 2; + + return GLAD_MAKE_VERSION(major, minor); +} + +int gladLoadGLES2UserPtr( GLADuserptrloadfunc load, void *userptr) { + int version; + + glad_glGetString = (PFNGLGETSTRINGPROC) load(userptr, "glGetString"); + if(glad_glGetString == NULL) return 0; + if(glad_glGetString(GL_VERSION) == NULL) return 0; + version = glad_gl_find_core_gles2(); + + glad_gl_load_GL_ES_VERSION_2_0(load, userptr); + + if (!glad_gl_find_extensions_gles2(version)) return 0; + glad_gl_load_GL_EXT_EGL_image_storage(load, userptr); + glad_gl_load_GL_EXT_base_instance(load, userptr); + glad_gl_load_GL_EXT_blend_func_extended(load, userptr); + glad_gl_load_GL_EXT_buffer_storage(load, userptr); + glad_gl_load_GL_EXT_clear_texture(load, userptr); + glad_gl_load_GL_EXT_clip_control(load, userptr); + glad_gl_load_GL_EXT_copy_image(load, userptr); + glad_gl_load_GL_EXT_debug_label(load, userptr); + glad_gl_load_GL_EXT_debug_marker(load, userptr); + glad_gl_load_GL_EXT_discard_framebuffer(load, userptr); + glad_gl_load_GL_EXT_disjoint_timer_query(load, userptr); + glad_gl_load_GL_EXT_draw_buffers(load, userptr); + glad_gl_load_GL_EXT_draw_buffers_indexed(load, userptr); + glad_gl_load_GL_EXT_draw_elements_base_vertex(load, userptr); + glad_gl_load_GL_EXT_draw_instanced(load, userptr); + glad_gl_load_GL_EXT_draw_transform_feedback(load, userptr); + glad_gl_load_GL_EXT_external_buffer(load, userptr); + glad_gl_load_GL_EXT_fragment_shading_rate(load, userptr); + glad_gl_load_GL_EXT_geometry_shader(load, userptr); + glad_gl_load_GL_EXT_instanced_arrays(load, userptr); + glad_gl_load_GL_EXT_map_buffer_range(load, userptr); + glad_gl_load_GL_EXT_memory_object(load, userptr); + glad_gl_load_GL_EXT_memory_object_fd(load, userptr); + glad_gl_load_GL_EXT_memory_object_win32(load, userptr); + glad_gl_load_GL_EXT_multi_draw_arrays(load, userptr); + glad_gl_load_GL_EXT_multi_draw_indirect(load, userptr); + glad_gl_load_GL_EXT_multisampled_render_to_texture(load, userptr); + glad_gl_load_GL_EXT_multiview_draw_buffers(load, userptr); + glad_gl_load_GL_EXT_occlusion_query_boolean(load, userptr); + glad_gl_load_GL_EXT_polygon_offset_clamp(load, userptr); + glad_gl_load_GL_EXT_primitive_bounding_box(load, userptr); + glad_gl_load_GL_EXT_raster_multisample(load, userptr); + glad_gl_load_GL_EXT_robustness(load, userptr); + glad_gl_load_GL_EXT_semaphore(load, userptr); + glad_gl_load_GL_EXT_semaphore_fd(load, userptr); + glad_gl_load_GL_EXT_semaphore_win32(load, userptr); + glad_gl_load_GL_EXT_separate_shader_objects(load, userptr); + glad_gl_load_GL_EXT_shader_framebuffer_fetch_non_coherent(load, userptr); + glad_gl_load_GL_EXT_shader_pixel_local_storage2(load, userptr); + glad_gl_load_GL_EXT_sparse_texture(load, userptr); + glad_gl_load_GL_EXT_tessellation_shader(load, userptr); + glad_gl_load_GL_EXT_texture_border_clamp(load, userptr); + glad_gl_load_GL_EXT_texture_buffer(load, userptr); + glad_gl_load_GL_EXT_texture_storage(load, userptr); + glad_gl_load_GL_EXT_texture_storage_compression(load, userptr); + glad_gl_load_GL_EXT_texture_view(load, userptr); + glad_gl_load_GL_EXT_win32_keyed_mutex(load, userptr); + glad_gl_load_GL_EXT_window_rectangles(load, userptr); + glad_gl_load_GL_KHR_blend_equation_advanced(load, userptr); + glad_gl_load_GL_KHR_debug(load, userptr); + glad_gl_load_GL_KHR_parallel_shader_compile(load, userptr); + glad_gl_load_GL_KHR_robustness(load, userptr); + glad_gl_load_GL_OES_EGL_image(load, userptr); + glad_gl_load_GL_OES_copy_image(load, userptr); + glad_gl_load_GL_OES_draw_buffers_indexed(load, userptr); + glad_gl_load_GL_OES_draw_elements_base_vertex(load, userptr); + glad_gl_load_GL_OES_geometry_shader(load, userptr); + glad_gl_load_GL_OES_get_program_binary(load, userptr); + glad_gl_load_GL_OES_mapbuffer(load, userptr); + glad_gl_load_GL_OES_primitive_bounding_box(load, userptr); + glad_gl_load_GL_OES_sample_shading(load, userptr); + glad_gl_load_GL_OES_tessellation_shader(load, userptr); + glad_gl_load_GL_OES_texture_3D(load, userptr); + glad_gl_load_GL_OES_texture_border_clamp(load, userptr); + glad_gl_load_GL_OES_texture_buffer(load, userptr); + glad_gl_load_GL_OES_texture_storage_multisample_2d_array(load, userptr); + glad_gl_load_GL_OES_texture_view(load, userptr); + glad_gl_load_GL_OES_vertex_array_object(load, userptr); + glad_gl_load_GL_OES_viewport_array(load, userptr); + + + + return version; +} + + +int gladLoadGLES2( GLADloadfunc load) { + return gladLoadGLES2UserPtr( glad_gl_get_proc_from_userptr, GLAD_GNUC_EXTENSION (void*) load); +} + + + + + + +#ifdef __cplusplus +} +#endif + +#endif /* GLAD_GLES2_IMPLEMENTATION */ + diff --git a/examples/others/raylib_opengl_interop.c b/examples/others/raylib_opengl_interop.c index bda301a7e33e..bcdbbbdd5b4e 100644 --- a/examples/others/raylib_opengl_interop.c +++ b/examples/others/raylib_opengl_interop.c @@ -26,21 +26,29 @@ #include "raylib.h" -#include "rlgl.h" // Required for: rlDrawRenderBatchActive(), rlGetMatrixModelview(), rlGetMatrixProjection() -#if defined(__APPLE__) - #include // OpenGL 3 library for OSX - #include // OpenGL 3 extensions library for OSX -#else - #include "glad.h" // Required for: OpenGL functionality -#endif -#include "raymath.h" // Required for: MatrixMultiply(), MatrixToFloat() - #if defined(PLATFORM_DESKTOP) - #define GLSL_VERSION 330 + #if defined(GRAPHICS_API_OPENGL_ES2) + #include "glad_gles2.h" // Required for: OpenGL functionality + #define glGenVertexArrays glGenVertexArraysOES + #define glBindVertexArray glBindVertexArrayOES + #define glDeleteVertexArrays glDeleteVertexArraysOES + #define GLSL_VERSION 100 + #else + #if defined(__APPLE__) + #include // OpenGL 3 library for OSX + #include // OpenGL 3 extensions library for OSX + #else + #include "glad.h" // Required for: OpenGL functionality + #endif + #define GLSL_VERSION 330 + #endif #else // PLATFORM_RPI, PLATFORM_ANDROID, PLATFORM_WEB #define GLSL_VERSION 100 #endif +#include "rlgl.h" // Required for: rlDrawRenderBatchActive(), rlGetMatrixModelview(), rlGetMatrixProjection() +#include "raymath.h" // Required for: MatrixMultiply(), MatrixToFloat() + #define MAX_PARTICLES 1000 // Particle type @@ -97,7 +105,9 @@ int main(void) glBindVertexArray(0); // Allows the vertex shader to set the point size of each particle individually + #ifndef GRAPHICS_API_OPENGL_ES2 glEnable(GL_PROGRAM_POINT_SIZE); + #endif SetTargetFPS(60); //-------------------------------------------------------------------------------------- diff --git a/src/external/glad_gles2.h b/src/external/glad_gles2.h new file mode 100644 index 000000000000..6c753d0a4d50 --- /dev/null +++ b/src/external/glad_gles2.h @@ -0,0 +1,4774 @@ +/** + * Loader generated by glad 2.0.2 on Wed Dec 28 13:28:51 2022 + * + * SPDX-License-Identifier: (WTFPL OR CC0-1.0) AND Apache-2.0 + * + * Generator: C/C++ + * Specification: gl + * Extensions: 170 + * + * APIs: + * - gles2=2.0 + * + * Options: + * - ALIAS = False + * - DEBUG = False + * - HEADER_ONLY = True + * - LOADER = False + * - MX = False + * - ON_DEMAND = False + * + * Commandline: + * --api='gles2=2.0' --extensions='GL_EXT_EGL_image_array,GL_EXT_EGL_image_storage,GL_EXT_EGL_image_storage_compression,GL_EXT_YUV_target,GL_EXT_base_instance,GL_EXT_blend_func_extended,GL_EXT_blend_minmax,GL_EXT_buffer_storage,GL_EXT_clear_texture,GL_EXT_clip_control,GL_EXT_clip_cull_distance,GL_EXT_color_buffer_float,GL_EXT_color_buffer_half_float,GL_EXT_conservative_depth,GL_EXT_copy_image,GL_EXT_debug_label,GL_EXT_debug_marker,GL_EXT_depth_clamp,GL_EXT_discard_framebuffer,GL_EXT_disjoint_timer_query,GL_EXT_draw_buffers,GL_EXT_draw_buffers_indexed,GL_EXT_draw_elements_base_vertex,GL_EXT_draw_instanced,GL_EXT_draw_transform_feedback,GL_EXT_external_buffer,GL_EXT_float_blend,GL_EXT_fragment_shading_rate,GL_EXT_geometry_point_size,GL_EXT_geometry_shader,GL_EXT_gpu_shader5,GL_EXT_instanced_arrays,GL_EXT_map_buffer_range,GL_EXT_memory_object,GL_EXT_memory_object_fd,GL_EXT_memory_object_win32,GL_EXT_multi_draw_arrays,GL_EXT_multi_draw_indirect,GL_EXT_multisampled_compatibility,GL_EXT_multisampled_render_to_texture,GL_EXT_multisampled_render_to_texture2,GL_EXT_multiview_draw_buffers,GL_EXT_multiview_tessellation_geometry_shader,GL_EXT_multiview_texture_multisample,GL_EXT_multiview_timer_query,GL_EXT_occlusion_query_boolean,GL_EXT_polygon_offset_clamp,GL_EXT_post_depth_coverage,GL_EXT_primitive_bounding_box,GL_EXT_protected_textures,GL_EXT_pvrtc_sRGB,GL_EXT_raster_multisample,GL_EXT_read_format_bgra,GL_EXT_render_snorm,GL_EXT_robustness,GL_EXT_sRGB,GL_EXT_sRGB_write_control,GL_EXT_semaphore,GL_EXT_semaphore_fd,GL_EXT_semaphore_win32,GL_EXT_separate_depth_stencil,GL_EXT_separate_shader_objects,GL_EXT_shader_framebuffer_fetch,GL_EXT_shader_framebuffer_fetch_non_coherent,GL_EXT_shader_group_vote,GL_EXT_shader_implicit_conversions,GL_EXT_shader_integer_mix,GL_EXT_shader_io_blocks,GL_EXT_shader_non_constant_global_initializers,GL_EXT_shader_pixel_local_storage,GL_EXT_shader_pixel_local_storage2,GL_EXT_shader_samples_identical,GL_EXT_shader_texture_lod,GL_EXT_shadow_samplers,GL_EXT_sparse_texture,GL_EXT_sparse_texture2,GL_EXT_tessellation_point_size,GL_EXT_tessellation_shader,GL_EXT_texture_border_clamp,GL_EXT_texture_buffer,GL_EXT_texture_compression_astc_decode_mode,GL_EXT_texture_compression_bptc,GL_EXT_texture_compression_dxt1,GL_EXT_texture_compression_rgtc,GL_EXT_texture_compression_s3tc,GL_EXT_texture_compression_s3tc_srgb,GL_EXT_texture_cube_map_array,GL_EXT_texture_filter_anisotropic,GL_EXT_texture_filter_minmax,GL_EXT_texture_format_BGRA8888,GL_EXT_texture_format_sRGB_override,GL_EXT_texture_mirror_clamp_to_edge,GL_EXT_texture_norm16,GL_EXT_texture_query_lod,GL_EXT_texture_rg,GL_EXT_texture_sRGB_R8,GL_EXT_texture_sRGB_RG8,GL_EXT_texture_sRGB_decode,GL_EXT_texture_shadow_lod,GL_EXT_texture_storage,GL_EXT_texture_storage_compression,GL_EXT_texture_type_2_10_10_10_REV,GL_EXT_texture_view,GL_EXT_unpack_subimage,GL_EXT_win32_keyed_mutex,GL_EXT_window_rectangles,GL_KHR_blend_equation_advanced,GL_KHR_blend_equation_advanced_coherent,GL_KHR_context_flush_control,GL_KHR_debug,GL_KHR_no_error,GL_KHR_parallel_shader_compile,GL_KHR_robust_buffer_access_behavior,GL_KHR_robustness,GL_KHR_shader_subgroup,GL_KHR_texture_compression_astc_hdr,GL_KHR_texture_compression_astc_ldr,GL_KHR_texture_compression_astc_sliced_3d,GL_OES_EGL_image,GL_OES_EGL_image_external,GL_OES_EGL_image_external_essl3,GL_OES_compressed_ETC1_RGB8_sub_texture,GL_OES_compressed_ETC1_RGB8_texture,GL_OES_compressed_paletted_texture,GL_OES_copy_image,GL_OES_depth24,GL_OES_depth32,GL_OES_depth_texture,GL_OES_draw_buffers_indexed,GL_OES_draw_elements_base_vertex,GL_OES_element_index_uint,GL_OES_fbo_render_mipmap,GL_OES_fragment_precision_high,GL_OES_geometry_point_size,GL_OES_geometry_shader,GL_OES_get_program_binary,GL_OES_gpu_shader5,GL_OES_mapbuffer,GL_OES_packed_depth_stencil,GL_OES_primitive_bounding_box,GL_OES_required_internalformat,GL_OES_rgb8_rgba8,GL_OES_sample_shading,GL_OES_sample_variables,GL_OES_shader_image_atomic,GL_OES_shader_io_blocks,GL_OES_shader_multisample_interpolation,GL_OES_standard_derivatives,GL_OES_stencil1,GL_OES_stencil4,GL_OES_surfaceless_context,GL_OES_tessellation_point_size,GL_OES_tessellation_shader,GL_OES_texture_3D,GL_OES_texture_border_clamp,GL_OES_texture_buffer,GL_OES_texture_compression_astc,GL_OES_texture_cube_map_array,GL_OES_texture_float,GL_OES_texture_float_linear,GL_OES_texture_half_float,GL_OES_texture_half_float_linear,GL_OES_texture_npot,GL_OES_texture_stencil8,GL_OES_texture_storage_multisample_2d_array,GL_OES_texture_view,GL_OES_vertex_array_object,GL_OES_vertex_half_float,GL_OES_vertex_type_10_10_10_2,GL_OES_viewport_array' c --header-only + * + * Online: + * http://glad.sh/#api=gles2%3D2.0&generator=c&options=HEADER_ONLY + * + */ + +#ifndef GLAD_GLES2_H_ +#define GLAD_GLES2_H_ + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wreserved-id-macro" +#endif +#ifdef __gl2_h_ + #error OpenGL ES 2 header already included (API: gles2), remove previous include! +#endif +#define __gl2_h_ 1 +#ifdef __gles2_gl2_h_ + #error OpenGL ES 2 header already included (API: gles2), remove previous include! +#endif +#define __gles2_gl2_h_ 1 +#ifdef __gl3_h_ + #error OpenGL ES 3 header already included (API: gles2), remove previous include! +#endif +#define __gl3_h_ 1 +#ifdef __gles2_gl3_h_ + #error OpenGL ES 3 header already included (API: gles2), remove previous include! +#endif +#define __gles2_gl3_h_ 1 +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#define GLAD_GLES2 +#define GLAD_OPTION_GLES2_HEADER_ONLY + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef GLAD_PLATFORM_H_ +#define GLAD_PLATFORM_H_ + +#ifndef GLAD_PLATFORM_WIN32 + #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(__MINGW32__) + #define GLAD_PLATFORM_WIN32 1 + #else + #define GLAD_PLATFORM_WIN32 0 + #endif +#endif + +#ifndef GLAD_PLATFORM_APPLE + #ifdef __APPLE__ + #define GLAD_PLATFORM_APPLE 1 + #else + #define GLAD_PLATFORM_APPLE 0 + #endif +#endif + +#ifndef GLAD_PLATFORM_EMSCRIPTEN + #ifdef __EMSCRIPTEN__ + #define GLAD_PLATFORM_EMSCRIPTEN 1 + #else + #define GLAD_PLATFORM_EMSCRIPTEN 0 + #endif +#endif + +#ifndef GLAD_PLATFORM_UWP + #if defined(_MSC_VER) && !defined(GLAD_INTERNAL_HAVE_WINAPIFAMILY) + #ifdef __has_include + #if __has_include() + #define GLAD_INTERNAL_HAVE_WINAPIFAMILY 1 + #endif + #elif _MSC_VER >= 1700 && !_USING_V110_SDK71_ + #define GLAD_INTERNAL_HAVE_WINAPIFAMILY 1 + #endif + #endif + + #ifdef GLAD_INTERNAL_HAVE_WINAPIFAMILY + #include + #if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) + #define GLAD_PLATFORM_UWP 1 + #endif + #endif + + #ifndef GLAD_PLATFORM_UWP + #define GLAD_PLATFORM_UWP 0 + #endif +#endif + +#ifdef __GNUC__ + #define GLAD_GNUC_EXTENSION __extension__ +#else + #define GLAD_GNUC_EXTENSION +#endif + +#define GLAD_UNUSED(x) (void)(x) + +#ifndef GLAD_API_CALL + #if defined(GLAD_API_CALL_EXPORT) + #if GLAD_PLATFORM_WIN32 || defined(__CYGWIN__) + #if defined(GLAD_API_CALL_EXPORT_BUILD) + #if defined(__GNUC__) + #define GLAD_API_CALL __attribute__ ((dllexport)) extern + #else + #define GLAD_API_CALL __declspec(dllexport) extern + #endif + #else + #if defined(__GNUC__) + #define GLAD_API_CALL __attribute__ ((dllimport)) extern + #else + #define GLAD_API_CALL __declspec(dllimport) extern + #endif + #endif + #elif defined(__GNUC__) && defined(GLAD_API_CALL_EXPORT_BUILD) + #define GLAD_API_CALL __attribute__ ((visibility ("default"))) extern + #else + #define GLAD_API_CALL extern + #endif + #else + #define GLAD_API_CALL extern + #endif +#endif + +#ifdef APIENTRY + #define GLAD_API_PTR APIENTRY +#elif GLAD_PLATFORM_WIN32 + #define GLAD_API_PTR __stdcall +#else + #define GLAD_API_PTR +#endif + +#ifndef GLAPI +#define GLAPI GLAD_API_CALL +#endif + +#ifndef GLAPIENTRY +#define GLAPIENTRY GLAD_API_PTR +#endif + +#define GLAD_MAKE_VERSION(major, minor) (major * 10000 + minor) +#define GLAD_VERSION_MAJOR(version) (version / 10000) +#define GLAD_VERSION_MINOR(version) (version % 10000) + +#define GLAD_GENERATOR_VERSION "2.0.2" + +typedef void (*GLADapiproc)(void); + +typedef GLADapiproc (*GLADloadfunc)(const char *name); +typedef GLADapiproc (*GLADuserptrloadfunc)(void *userptr, const char *name); + +typedef void (*GLADprecallback)(const char *name, GLADapiproc apiproc, int len_args, ...); +typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apiproc, int len_args, ...); + +#endif /* GLAD_PLATFORM_H_ */ + +#define GL_ACTIVE_ATTRIBUTES 0x8B89 +#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A +#define GL_ACTIVE_PROGRAM_EXT 0x8259 +#define GL_ACTIVE_TEXTURE 0x84E0 +#define GL_ACTIVE_UNIFORMS 0x8B86 +#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 +#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E +#define GL_ALIASED_POINT_SIZE_RANGE 0x846D +#define GL_ALL_SHADER_BITS_EXT 0xFFFFFFFF +#define GL_ALPHA 0x1906 +#define GL_ALPHA16F_EXT 0x881C +#define GL_ALPHA32F_EXT 0x8816 +#define GL_ALPHA8_EXT 0x803C +#define GL_ALPHA8_OES 0x803C +#define GL_ALPHA_BITS 0x0D55 +#define GL_ALWAYS 0x0207 +#define GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT 0x8D6A +#define GL_ANY_SAMPLES_PASSED_EXT 0x8C2F +#define GL_ARRAY_BUFFER 0x8892 +#define GL_ARRAY_BUFFER_BINDING 0x8894 +#define GL_ATTACHED_SHADERS 0x8B85 +#define GL_BACK 0x0405 +#define GL_BGRA8_EXT 0x93A1 +#define GL_BGRA_EXT 0x80E1 +#define GL_BLEND 0x0BE2 +#define GL_BLEND_ADVANCED_COHERENT_KHR 0x9285 +#define GL_BLEND_COLOR 0x8005 +#define GL_BLEND_DST_ALPHA 0x80CA +#define GL_BLEND_DST_RGB 0x80C8 +#define GL_BLEND_EQUATION 0x8009 +#define GL_BLEND_EQUATION_ALPHA 0x883D +#define GL_BLEND_EQUATION_RGB 0x8009 +#define GL_BLEND_SRC_ALPHA 0x80CB +#define GL_BLEND_SRC_RGB 0x80C9 +#define GL_BLUE_BITS 0x0D54 +#define GL_BOOL 0x8B56 +#define GL_BOOL_VEC2 0x8B57 +#define GL_BOOL_VEC3 0x8B58 +#define GL_BOOL_VEC4 0x8B59 +#define GL_BUFFER_ACCESS_OES 0x88BB +#define GL_BUFFER_IMMUTABLE_STORAGE_EXT 0x821F +#define GL_BUFFER_KHR 0x82E0 +#define GL_BUFFER_MAPPED_OES 0x88BC +#define GL_BUFFER_MAP_POINTER_OES 0x88BD +#define GL_BUFFER_OBJECT_EXT 0x9151 +#define GL_BUFFER_SIZE 0x8764 +#define GL_BUFFER_STORAGE_FLAGS_EXT 0x8220 +#define GL_BUFFER_USAGE 0x8765 +#define GL_BYTE 0x1400 +#define GL_CCW 0x0901 +#define GL_CLAMP_TO_BORDER_EXT 0x812D +#define GL_CLAMP_TO_BORDER_OES 0x812D +#define GL_CLAMP_TO_EDGE 0x812F +#define GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT_EXT 0x00004000 +#define GL_CLIENT_STORAGE_BIT_EXT 0x0200 +#define GL_CLIP_DEPTH_MODE 0x935D +#define GL_CLIP_DEPTH_MODE_EXT 0x935D +#define GL_CLIP_DISTANCE0_EXT 0x3000 +#define GL_CLIP_DISTANCE1_EXT 0x3001 +#define GL_CLIP_DISTANCE2_EXT 0x3002 +#define GL_CLIP_DISTANCE3_EXT 0x3003 +#define GL_CLIP_DISTANCE4_EXT 0x3004 +#define GL_CLIP_DISTANCE5_EXT 0x3005 +#define GL_CLIP_DISTANCE6 0x3006 +#define GL_CLIP_DISTANCE6_EXT 0x3006 +#define GL_CLIP_DISTANCE7 0x3007 +#define GL_CLIP_DISTANCE7_EXT 0x3007 +#define GL_CLIP_ORIGIN 0x935C +#define GL_CLIP_ORIGIN_EXT 0x935C +#define GL_CLIP_PLANE0 0x3000 +#define GL_CLIP_PLANE1 0x3001 +#define GL_CLIP_PLANE2 0x3002 +#define GL_CLIP_PLANE3 0x3003 +#define GL_CLIP_PLANE4 0x3004 +#define GL_CLIP_PLANE5 0x3005 +#define GL_COLORBURN_KHR 0x929A +#define GL_COLORDODGE_KHR 0x9299 +#define GL_COLOR_ATTACHMENT0 0x8CE0 +#define GL_COLOR_ATTACHMENT0_EXT 0x8CE0 +#define GL_COLOR_ATTACHMENT10_EXT 0x8CEA +#define GL_COLOR_ATTACHMENT11_EXT 0x8CEB +#define GL_COLOR_ATTACHMENT12_EXT 0x8CEC +#define GL_COLOR_ATTACHMENT13_EXT 0x8CED +#define GL_COLOR_ATTACHMENT14_EXT 0x8CEE +#define GL_COLOR_ATTACHMENT15_EXT 0x8CEF +#define GL_COLOR_ATTACHMENT1_EXT 0x8CE1 +#define GL_COLOR_ATTACHMENT2_EXT 0x8CE2 +#define GL_COLOR_ATTACHMENT3_EXT 0x8CE3 +#define GL_COLOR_ATTACHMENT4_EXT 0x8CE4 +#define GL_COLOR_ATTACHMENT5_EXT 0x8CE5 +#define GL_COLOR_ATTACHMENT6_EXT 0x8CE6 +#define GL_COLOR_ATTACHMENT7_EXT 0x8CE7 +#define GL_COLOR_ATTACHMENT8_EXT 0x8CE8 +#define GL_COLOR_ATTACHMENT9_EXT 0x8CE9 +#define GL_COLOR_ATTACHMENT_EXT 0x90F0 +#define GL_COLOR_BUFFER_BIT 0x00004000 +#define GL_COLOR_CLEAR_VALUE 0x0C22 +#define GL_COLOR_EXT 0x1800 +#define GL_COLOR_WRITEMASK 0x0C23 +#define GL_COMPARE_REF_TO_TEXTURE_EXT 0x884E +#define GL_COMPILE_STATUS 0x8B81 +#define GL_COMPLETION_STATUS_KHR 0x91B1 +#define GL_COMPRESSED_RED_GREEN_RGTC2_EXT 0x8DBD +#define GL_COMPRESSED_RED_RGTC1_EXT 0x8DBB +#define GL_COMPRESSED_RGBA_ASTC_10x10_KHR 0x93BB +#define GL_COMPRESSED_RGBA_ASTC_10x5_KHR 0x93B8 +#define GL_COMPRESSED_RGBA_ASTC_10x6_KHR 0x93B9 +#define GL_COMPRESSED_RGBA_ASTC_10x8_KHR 0x93BA +#define GL_COMPRESSED_RGBA_ASTC_12x10_KHR 0x93BC +#define GL_COMPRESSED_RGBA_ASTC_12x12_KHR 0x93BD +#define GL_COMPRESSED_RGBA_ASTC_3x3x3_OES 0x93C0 +#define GL_COMPRESSED_RGBA_ASTC_4x3x3_OES 0x93C1 +#define GL_COMPRESSED_RGBA_ASTC_4x4_KHR 0x93B0 +#define GL_COMPRESSED_RGBA_ASTC_4x4x3_OES 0x93C2 +#define GL_COMPRESSED_RGBA_ASTC_4x4x4_OES 0x93C3 +#define GL_COMPRESSED_RGBA_ASTC_5x4_KHR 0x93B1 +#define GL_COMPRESSED_RGBA_ASTC_5x4x4_OES 0x93C4 +#define GL_COMPRESSED_RGBA_ASTC_5x5_KHR 0x93B2 +#define GL_COMPRESSED_RGBA_ASTC_5x5x4_OES 0x93C5 +#define GL_COMPRESSED_RGBA_ASTC_5x5x5_OES 0x93C6 +#define GL_COMPRESSED_RGBA_ASTC_6x5_KHR 0x93B3 +#define GL_COMPRESSED_RGBA_ASTC_6x5x5_OES 0x93C7 +#define GL_COMPRESSED_RGBA_ASTC_6x6_KHR 0x93B4 +#define GL_COMPRESSED_RGBA_ASTC_6x6x5_OES 0x93C8 +#define GL_COMPRESSED_RGBA_ASTC_6x6x6_OES 0x93C9 +#define GL_COMPRESSED_RGBA_ASTC_8x5_KHR 0x93B5 +#define GL_COMPRESSED_RGBA_ASTC_8x6_KHR 0x93B6 +#define GL_COMPRESSED_RGBA_ASTC_8x8_KHR 0x93B7 +#define GL_COMPRESSED_RGBA_BPTC_UNORM_EXT 0x8E8C +#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 +#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2 +#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3 +#define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT 0x8E8E +#define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT 0x8E8F +#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0 +#define GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT 0x8DBE +#define GL_COMPRESSED_SIGNED_RED_RGTC1_EXT 0x8DBC +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR 0x93DB +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR 0x93D8 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR 0x93D9 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR 0x93DA +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR 0x93DC +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR 0x93DD +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_3x3x3_OES 0x93E0 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x3x3_OES 0x93E1 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR 0x93D0 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4x3_OES 0x93E2 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4x4_OES 0x93E3 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR 0x93D1 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4x4_OES 0x93E4 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR 0x93D2 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5x4_OES 0x93E5 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5x5_OES 0x93E6 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR 0x93D3 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5x5_OES 0x93E7 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR 0x93D4 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6x5_OES 0x93E8 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6x6_OES 0x93E9 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR 0x93D5 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR 0x93D6 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR 0x93D7 +#define GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT 0x8E8D +#define GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1_EXT 0x8A56 +#define GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV2_IMG 0x93F0 +#define GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1_EXT 0x8A57 +#define GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV2_IMG 0x93F1 +#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT 0x8C4D +#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT 0x8C4E +#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT 0x8C4F +#define GL_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT 0x8A54 +#define GL_COMPRESSED_SRGB_PVRTC_4BPPV1_EXT 0x8A55 +#define GL_COMPRESSED_SRGB_S3TC_DXT1_EXT 0x8C4C +#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 +#define GL_CONSTANT_ALPHA 0x8003 +#define GL_CONSTANT_COLOR 0x8001 +#define GL_CONTEXT_FLAG_DEBUG_BIT_KHR 0x00000002 +#define GL_CONTEXT_FLAG_NO_ERROR_BIT 0x00000008 +#define GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR 0x00000008 +#define GL_CONTEXT_FLAG_PROTECTED_CONTENT_BIT_EXT 0x00000010 +#define GL_CONTEXT_LOST_KHR 0x0507 +#define GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR 0x82FC +#define GL_CONTEXT_RELEASE_BEHAVIOR_KHR 0x82FB +#define GL_CONTEXT_ROBUST_ACCESS_EXT 0x90F3 +#define GL_CONTEXT_ROBUST_ACCESS_KHR 0x90F3 +#define GL_CULL_FACE 0x0B44 +#define GL_CULL_FACE_MODE 0x0B45 +#define GL_CURRENT_PROGRAM 0x8B8D +#define GL_CURRENT_QUERY_EXT 0x8865 +#define GL_CURRENT_VERTEX_ATTRIB 0x8626 +#define GL_CW 0x0900 +#define GL_D3D12_FENCE_VALUE_EXT 0x9595 +#define GL_DARKEN_KHR 0x9297 +#define GL_DEBUG_CALLBACK_FUNCTION_KHR 0x8244 +#define GL_DEBUG_CALLBACK_USER_PARAM_KHR 0x8245 +#define GL_DEBUG_GROUP_STACK_DEPTH_KHR 0x826D +#define GL_DEBUG_LOGGED_MESSAGES_KHR 0x9145 +#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_KHR 0x8243 +#define GL_DEBUG_OUTPUT_KHR 0x92E0 +#define GL_DEBUG_OUTPUT_SYNCHRONOUS_KHR 0x8242 +#define GL_DEBUG_SEVERITY_HIGH_KHR 0x9146 +#define GL_DEBUG_SEVERITY_LOW_KHR 0x9148 +#define GL_DEBUG_SEVERITY_MEDIUM_KHR 0x9147 +#define GL_DEBUG_SEVERITY_NOTIFICATION_KHR 0x826B +#define GL_DEBUG_SOURCE_API_KHR 0x8246 +#define GL_DEBUG_SOURCE_APPLICATION_KHR 0x824A +#define GL_DEBUG_SOURCE_OTHER_KHR 0x824B +#define GL_DEBUG_SOURCE_SHADER_COMPILER_KHR 0x8248 +#define GL_DEBUG_SOURCE_THIRD_PARTY_KHR 0x8249 +#define GL_DEBUG_SOURCE_WINDOW_SYSTEM_KHR 0x8247 +#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_KHR 0x824D +#define GL_DEBUG_TYPE_ERROR_KHR 0x824C +#define GL_DEBUG_TYPE_MARKER_KHR 0x8268 +#define GL_DEBUG_TYPE_OTHER_KHR 0x8251 +#define GL_DEBUG_TYPE_PERFORMANCE_KHR 0x8250 +#define GL_DEBUG_TYPE_POP_GROUP_KHR 0x826A +#define GL_DEBUG_TYPE_PORTABILITY_KHR 0x824F +#define GL_DEBUG_TYPE_PUSH_GROUP_KHR 0x8269 +#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_KHR 0x824E +#define GL_DECODE_EXT 0x8A49 +#define GL_DECR 0x1E03 +#define GL_DECR_WRAP 0x8508 +#define GL_DEDICATED_MEMORY_OBJECT_EXT 0x9581 +#define GL_DELETE_STATUS 0x8B80 +#define GL_DEPTH24_STENCIL8_OES 0x88F0 +#define GL_DEPTH_ATTACHMENT 0x8D00 +#define GL_DEPTH_BITS 0x0D56 +#define GL_DEPTH_BUFFER_BIT 0x00000100 +#define GL_DEPTH_CLAMP_EXT 0x864F +#define GL_DEPTH_CLEAR_VALUE 0x0B73 +#define GL_DEPTH_COMPONENT 0x1902 +#define GL_DEPTH_COMPONENT16 0x81A5 +#define GL_DEPTH_COMPONENT16_OES 0x81A5 +#define GL_DEPTH_COMPONENT24_OES 0x81A6 +#define GL_DEPTH_COMPONENT32_OES 0x81A7 +#define GL_DEPTH_EXT 0x1801 +#define GL_DEPTH_FUNC 0x0B74 +#define GL_DEPTH_RANGE 0x0B70 +#define GL_DEPTH_STENCIL_OES 0x84F9 +#define GL_DEPTH_TEST 0x0B71 +#define GL_DEPTH_WRITEMASK 0x0B72 +#define GL_DEVICE_LUID_EXT 0x9599 +#define GL_DEVICE_NODE_MASK_EXT 0x959A +#define GL_DEVICE_UUID_EXT 0x9597 +#define GL_DIFFERENCE_KHR 0x929E +#define GL_DITHER 0x0BD0 +#define GL_DONT_CARE 0x1100 +#define GL_DRAW_BUFFER0_EXT 0x8825 +#define GL_DRAW_BUFFER10_EXT 0x882F +#define GL_DRAW_BUFFER11_EXT 0x8830 +#define GL_DRAW_BUFFER12_EXT 0x8831 +#define GL_DRAW_BUFFER13_EXT 0x8832 +#define GL_DRAW_BUFFER14_EXT 0x8833 +#define GL_DRAW_BUFFER15_EXT 0x8834 +#define GL_DRAW_BUFFER1_EXT 0x8826 +#define GL_DRAW_BUFFER2_EXT 0x8827 +#define GL_DRAW_BUFFER3_EXT 0x8828 +#define GL_DRAW_BUFFER4_EXT 0x8829 +#define GL_DRAW_BUFFER5_EXT 0x882A +#define GL_DRAW_BUFFER6_EXT 0x882B +#define GL_DRAW_BUFFER7_EXT 0x882C +#define GL_DRAW_BUFFER8_EXT 0x882D +#define GL_DRAW_BUFFER9_EXT 0x882E +#define GL_DRAW_BUFFER_EXT 0x0C01 +#define GL_DRIVER_UUID_EXT 0x9598 +#define GL_DST_ALPHA 0x0304 +#define GL_DST_COLOR 0x0306 +#define GL_DYNAMIC_DRAW 0x88E8 +#define GL_DYNAMIC_STORAGE_BIT_EXT 0x0100 +#define GL_EFFECTIVE_RASTER_SAMPLES_EXT 0x932C +#define GL_ELEMENT_ARRAY_BUFFER 0x8893 +#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 +#define GL_EQUAL 0x0202 +#define GL_ETC1_RGB8_OES 0x8D64 +#define GL_EXCLUSION_KHR 0x92A0 +#define GL_EXCLUSIVE_EXT 0x8F11 +#define GL_EXTENSIONS 0x1F03 +#define GL_FALSE 0 +#define GL_FASTEST 0x1101 +#define GL_FIRST_VERTEX_CONVENTION_EXT 0x8E4D +#define GL_FIRST_VERTEX_CONVENTION_OES 0x8E4D +#define GL_FIXED 0x140C +#define GL_FLOAT 0x1406 +#define GL_FLOAT_MAT2 0x8B5A +#define GL_FLOAT_MAT3 0x8B5B +#define GL_FLOAT_MAT4 0x8B5C +#define GL_FLOAT_VEC2 0x8B50 +#define GL_FLOAT_VEC3 0x8B51 +#define GL_FLOAT_VEC4 0x8B52 +#define GL_FRACTIONAL_EVEN_EXT 0x8E7C +#define GL_FRACTIONAL_EVEN_OES 0x8E7C +#define GL_FRACTIONAL_ODD_EXT 0x8E7B +#define GL_FRACTIONAL_ODD_OES 0x8E7B +#define GL_FRAGMENT_INTERPOLATION_OFFSET_BITS_OES 0x8E5D +#define GL_FRAGMENT_SHADER 0x8B30 +#define GL_FRAGMENT_SHADER_BIT_EXT 0x00000002 +#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES 0x8B8B +#define GL_FRAGMENT_SHADER_DISCARDS_SAMPLES_EXT 0x8A52 +#define GL_FRAGMENT_SHADING_RATE_ATTACHMENT_WITH_DEFAULT_FRAMEBUFFER_SUPPORTED_EXT 0x96DF +#define GL_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_EXT 0x96D2 +#define GL_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_EXT 0x96D5 +#define GL_FRAGMENT_SHADING_RATE_COMBINER_OP_MIN_EXT 0x96D4 +#define GL_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL_EXT 0x96D6 +#define GL_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_EXT 0x96D3 +#define GL_FRAGMENT_SHADING_RATE_NON_TRIVIAL_COMBINERS_SUPPORTED_EXT 0x8F6F +#define GL_FRAGMENT_SHADING_RATE_WITH_SAMPLE_MASK_SUPPORTED_EXT 0x96DE +#define GL_FRAGMENT_SHADING_RATE_WITH_SHADER_DEPTH_STENCIL_WRITES_SUPPORTED_EXT 0x96DD +#define GL_FRAMEBUFFER 0x8D40 +#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT 0x8210 +#define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT 0x8211 +#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED_EXT 0x8DA7 +#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED_OES 0x8DA7 +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1 +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_OES 0x8CD4 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SAMPLES_EXT 0x8D6C +#define GL_FRAMEBUFFER_BINDING 0x8CA6 +#define GL_FRAMEBUFFER_COMPLETE 0x8CD5 +#define GL_FRAMEBUFFER_DEFAULT_LAYERS_EXT 0x9312 +#define GL_FRAMEBUFFER_DEFAULT_LAYERS_OES 0x9312 +#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 +#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS 0x8CD9 +#define GL_FRAMEBUFFER_INCOMPLETE_INSUFFICIENT_SHADER_COMBINED_LOCAL_STORAGE_EXT 0x9652 +#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT 0x8DA8 +#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_OES 0x8DA8 +#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 +#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT 0x8D56 +#define GL_FRAMEBUFFER_SRGB_EXT 0x8DB9 +#define GL_FRAMEBUFFER_UNDEFINED_OES 0x8219 +#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD +#define GL_FRONT 0x0404 +#define GL_FRONT_AND_BACK 0x0408 +#define GL_FRONT_FACE 0x0B46 +#define GL_FUNC_ADD 0x8006 +#define GL_FUNC_REVERSE_SUBTRACT 0x800B +#define GL_FUNC_SUBTRACT 0x800A +#define GL_GENERATE_MIPMAP_HINT 0x8192 +#define GL_GEOMETRY_LINKED_INPUT_TYPE_EXT 0x8917 +#define GL_GEOMETRY_LINKED_INPUT_TYPE_OES 0x8917 +#define GL_GEOMETRY_LINKED_OUTPUT_TYPE_EXT 0x8918 +#define GL_GEOMETRY_LINKED_OUTPUT_TYPE_OES 0x8918 +#define GL_GEOMETRY_LINKED_VERTICES_OUT_EXT 0x8916 +#define GL_GEOMETRY_LINKED_VERTICES_OUT_OES 0x8916 +#define GL_GEOMETRY_SHADER_BIT_EXT 0x00000004 +#define GL_GEOMETRY_SHADER_BIT_OES 0x00000004 +#define GL_GEOMETRY_SHADER_EXT 0x8DD9 +#define GL_GEOMETRY_SHADER_INVOCATIONS_EXT 0x887F +#define GL_GEOMETRY_SHADER_INVOCATIONS_OES 0x887F +#define GL_GEOMETRY_SHADER_OES 0x8DD9 +#define GL_GEQUAL 0x0206 +#define GL_GPU_DISJOINT_EXT 0x8FBB +#define GL_GREATER 0x0204 +#define GL_GREEN_BITS 0x0D53 +#define GL_GUILTY_CONTEXT_RESET_EXT 0x8253 +#define GL_GUILTY_CONTEXT_RESET_KHR 0x8253 +#define GL_HALF_FLOAT_OES 0x8D61 +#define GL_HANDLE_TYPE_D3D11_IMAGE_EXT 0x958B +#define GL_HANDLE_TYPE_D3D11_IMAGE_KMT_EXT 0x958C +#define GL_HANDLE_TYPE_D3D12_FENCE_EXT 0x9594 +#define GL_HANDLE_TYPE_D3D12_RESOURCE_EXT 0x958A +#define GL_HANDLE_TYPE_D3D12_TILEPOOL_EXT 0x9589 +#define GL_HANDLE_TYPE_OPAQUE_FD_EXT 0x9586 +#define GL_HANDLE_TYPE_OPAQUE_WIN32_EXT 0x9587 +#define GL_HANDLE_TYPE_OPAQUE_WIN32_KMT_EXT 0x9588 +#define GL_HARDLIGHT_KHR 0x929B +#define GL_HIGH_FLOAT 0x8DF2 +#define GL_HIGH_INT 0x8DF5 +#define GL_HSL_COLOR_KHR 0x92AF +#define GL_HSL_HUE_KHR 0x92AD +#define GL_HSL_LUMINOSITY_KHR 0x92B0 +#define GL_HSL_SATURATION_KHR 0x92AE +#define GL_IMAGE_BUFFER_EXT 0x9051 +#define GL_IMAGE_BUFFER_OES 0x9051 +#define GL_IMAGE_CUBE_MAP_ARRAY_EXT 0x9054 +#define GL_IMAGE_CUBE_MAP_ARRAY_OES 0x9054 +#define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B +#define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A +#define GL_INCLUSIVE_EXT 0x8F10 +#define GL_INCR 0x1E02 +#define GL_INCR_WRAP 0x8507 +#define GL_INFO_LOG_LENGTH 0x8B84 +#define GL_INNOCENT_CONTEXT_RESET_EXT 0x8254 +#define GL_INNOCENT_CONTEXT_RESET_KHR 0x8254 +#define GL_INT 0x1404 +#define GL_INT_10_10_10_2_OES 0x8DF7 +#define GL_INT_IMAGE_BUFFER_EXT 0x905C +#define GL_INT_IMAGE_BUFFER_OES 0x905C +#define GL_INT_IMAGE_CUBE_MAP_ARRAY_EXT 0x905F +#define GL_INT_IMAGE_CUBE_MAP_ARRAY_OES 0x905F +#define GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY_OES 0x910C +#define GL_INT_SAMPLER_BUFFER_EXT 0x8DD0 +#define GL_INT_SAMPLER_BUFFER_OES 0x8DD0 +#define GL_INT_SAMPLER_CUBE_MAP_ARRAY_EXT 0x900E +#define GL_INT_SAMPLER_CUBE_MAP_ARRAY_OES 0x900E +#define GL_INT_VEC2 0x8B53 +#define GL_INT_VEC3 0x8B54 +#define GL_INT_VEC4 0x8B55 +#define GL_INVALID_ENUM 0x0500 +#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 +#define GL_INVALID_OPERATION 0x0502 +#define GL_INVALID_VALUE 0x0501 +#define GL_INVERT 0x150A +#define GL_ISOLINES_EXT 0x8E7A +#define GL_ISOLINES_OES 0x8E7A +#define GL_IS_PER_PATCH_EXT 0x92E7 +#define GL_IS_PER_PATCH_OES 0x92E7 +#define GL_KEEP 0x1E00 +#define GL_LAST_VERTEX_CONVENTION_EXT 0x8E4E +#define GL_LAST_VERTEX_CONVENTION_OES 0x8E4E +#define GL_LAYER_PROVOKING_VERTEX_EXT 0x825E +#define GL_LAYER_PROVOKING_VERTEX_OES 0x825E +#define GL_LAYOUT_COLOR_ATTACHMENT_EXT 0x958E +#define GL_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_EXT 0x9531 +#define GL_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_EXT 0x9530 +#define GL_LAYOUT_DEPTH_STENCIL_ATTACHMENT_EXT 0x958F +#define GL_LAYOUT_DEPTH_STENCIL_READ_ONLY_EXT 0x9590 +#define GL_LAYOUT_GENERAL_EXT 0x958D +#define GL_LAYOUT_SHADER_READ_ONLY_EXT 0x9591 +#define GL_LAYOUT_TRANSFER_DST_EXT 0x9593 +#define GL_LAYOUT_TRANSFER_SRC_EXT 0x9592 +#define GL_LEQUAL 0x0203 +#define GL_LESS 0x0201 +#define GL_LIGHTEN_KHR 0x9298 +#define GL_LINEAR 0x2601 +#define GL_LINEAR_MIPMAP_LINEAR 0x2703 +#define GL_LINEAR_MIPMAP_NEAREST 0x2701 +#define GL_LINEAR_TILING_EXT 0x9585 +#define GL_LINES 0x0001 +#define GL_LINES_ADJACENCY_EXT 0x000A +#define GL_LINES_ADJACENCY_OES 0x000A +#define GL_LINE_LOOP 0x0002 +#define GL_LINE_STRIP 0x0003 +#define GL_LINE_STRIP_ADJACENCY_EXT 0x000B +#define GL_LINE_STRIP_ADJACENCY_OES 0x000B +#define GL_LINE_WIDTH 0x0B21 +#define GL_LINK_STATUS 0x8B82 +#define GL_LOCATION_INDEX_EXT 0x930F +#define GL_LOSE_CONTEXT_ON_RESET_EXT 0x8252 +#define GL_LOSE_CONTEXT_ON_RESET_KHR 0x8252 +#define GL_LOWER_LEFT 0x8CA1 +#define GL_LOWER_LEFT_EXT 0x8CA1 +#define GL_LOW_FLOAT 0x8DF0 +#define GL_LOW_INT 0x8DF3 +#define GL_LUID_SIZE_EXT 8 +#define GL_LUMINANCE 0x1909 +#define GL_LUMINANCE16F_EXT 0x881E +#define GL_LUMINANCE32F_EXT 0x8818 +#define GL_LUMINANCE4_ALPHA4_OES 0x8043 +#define GL_LUMINANCE8_ALPHA8_EXT 0x8045 +#define GL_LUMINANCE8_ALPHA8_OES 0x8045 +#define GL_LUMINANCE8_EXT 0x8040 +#define GL_LUMINANCE8_OES 0x8040 +#define GL_LUMINANCE_ALPHA 0x190A +#define GL_LUMINANCE_ALPHA16F_EXT 0x881F +#define GL_LUMINANCE_ALPHA32F_EXT 0x8819 +#define GL_MAP_COHERENT_BIT_EXT 0x0080 +#define GL_MAP_FLUSH_EXPLICIT_BIT_EXT 0x0010 +#define GL_MAP_INVALIDATE_BUFFER_BIT_EXT 0x0008 +#define GL_MAP_INVALIDATE_RANGE_BIT_EXT 0x0004 +#define GL_MAP_PERSISTENT_BIT_EXT 0x0040 +#define GL_MAP_READ_BIT 0x0001 +#define GL_MAP_READ_BIT_EXT 0x0001 +#define GL_MAP_UNSYNCHRONIZED_BIT_EXT 0x0020 +#define GL_MAP_WRITE_BIT 0x0002 +#define GL_MAP_WRITE_BIT_EXT 0x0002 +#define GL_MAX 0x8008 +#define GL_MAX_3D_TEXTURE_SIZE_OES 0x8073 +#define GL_MAX_CLIP_DISTANCES_EXT 0x0D32 +#define GL_MAX_CLIP_PLANES 0x0D32 +#define GL_MAX_COLOR_ATTACHMENTS_EXT 0x8CDF +#define GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES 0x82FA +#define GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES_EXT 0x82FA +#define GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS_EXT 0x8A32 +#define GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS_OES 0x8A32 +#define GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS_EXT 0x8E1E +#define GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS_OES 0x8E1E +#define GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS_EXT 0x8E1F +#define GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS_OES 0x8E1F +#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D +#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C +#define GL_MAX_CULL_DISTANCES 0x82F9 +#define GL_MAX_CULL_DISTANCES_EXT 0x82F9 +#define GL_MAX_DEBUG_GROUP_STACK_DEPTH_KHR 0x826C +#define GL_MAX_DEBUG_LOGGED_MESSAGES_KHR 0x9144 +#define GL_MAX_DEBUG_MESSAGE_LENGTH_KHR 0x9143 +#define GL_MAX_DRAW_BUFFERS_EXT 0x8824 +#define GL_MAX_DUAL_SOURCE_DRAW_BUFFERS_EXT 0x88FC +#define GL_MAX_EXT 0x8008 +#define GL_MAX_FRAGMENT_INTERPOLATION_OFFSET_OES 0x8E5C +#define GL_MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_LAYERS_EXT 0x96DC +#define GL_MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_ASPECT_RATIO_EXT 0x96DB +#define GL_MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_HEIGHT_EXT 0x96DA +#define GL_MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_WIDTH_EXT 0x96D8 +#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD +#define GL_MAX_FRAMEBUFFER_LAYERS_EXT 0x9317 +#define GL_MAX_FRAMEBUFFER_LAYERS_OES 0x9317 +#define GL_MAX_GEOMETRY_ATOMIC_COUNTERS_EXT 0x92D5 +#define GL_MAX_GEOMETRY_ATOMIC_COUNTERS_OES 0x92D5 +#define GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS_EXT 0x92CF +#define GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS_OES 0x92CF +#define GL_MAX_GEOMETRY_IMAGE_UNIFORMS_EXT 0x90CD +#define GL_MAX_GEOMETRY_IMAGE_UNIFORMS_OES 0x90CD +#define GL_MAX_GEOMETRY_INPUT_COMPONENTS_EXT 0x9123 +#define GL_MAX_GEOMETRY_INPUT_COMPONENTS_OES 0x9123 +#define GL_MAX_GEOMETRY_OUTPUT_COMPONENTS_EXT 0x9124 +#define GL_MAX_GEOMETRY_OUTPUT_COMPONENTS_OES 0x9124 +#define GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT 0x8DE0 +#define GL_MAX_GEOMETRY_OUTPUT_VERTICES_OES 0x8DE0 +#define GL_MAX_GEOMETRY_SHADER_INVOCATIONS_EXT 0x8E5A +#define GL_MAX_GEOMETRY_SHADER_INVOCATIONS_OES 0x8E5A +#define GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS_EXT 0x90D7 +#define GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS_OES 0x90D7 +#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT 0x8C29 +#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_OES 0x8C29 +#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_EXT 0x8DE1 +#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_OES 0x8DE1 +#define GL_MAX_GEOMETRY_UNIFORM_BLOCKS_EXT 0x8A2C +#define GL_MAX_GEOMETRY_UNIFORM_BLOCKS_OES 0x8A2C +#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_EXT 0x8DDF +#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_OES 0x8DDF +#define GL_MAX_LABEL_LENGTH_KHR 0x82E8 +#define GL_MAX_MULTIVIEW_BUFFERS_EXT 0x90F2 +#define GL_MAX_PATCH_VERTICES_EXT 0x8E7D +#define GL_MAX_PATCH_VERTICES_OES 0x8E7D +#define GL_MAX_RASTER_SAMPLES_EXT 0x9329 +#define GL_MAX_RENDERBUFFER_SIZE 0x84E8 +#define GL_MAX_SAMPLES_EXT 0x8D57 +#define GL_MAX_SHADER_COMBINED_LOCAL_STORAGE_FAST_SIZE_EXT 0x9650 +#define GL_MAX_SHADER_COMBINED_LOCAL_STORAGE_SIZE_EXT 0x9651 +#define GL_MAX_SHADER_COMPILER_THREADS_KHR 0x91B0 +#define GL_MAX_SHADER_PIXEL_LOCAL_STORAGE_FAST_SIZE_EXT 0x8F63 +#define GL_MAX_SHADER_PIXEL_LOCAL_STORAGE_SIZE_EXT 0x8F67 +#define GL_MAX_SPARSE_3D_TEXTURE_SIZE_EXT 0x9199 +#define GL_MAX_SPARSE_ARRAY_TEXTURE_LAYERS_EXT 0x919A +#define GL_MAX_SPARSE_TEXTURE_SIZE_EXT 0x9198 +#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS_EXT 0x92D3 +#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS_OES 0x92D3 +#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS_EXT 0x92CD +#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS_OES 0x92CD +#define GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS_EXT 0x90CB +#define GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS_OES 0x90CB +#define GL_MAX_TESS_CONTROL_INPUT_COMPONENTS_EXT 0x886C +#define GL_MAX_TESS_CONTROL_INPUT_COMPONENTS_OES 0x886C +#define GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS_EXT 0x8E83 +#define GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS_OES 0x8E83 +#define GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS_EXT 0x90D8 +#define GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS_OES 0x90D8 +#define GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS_EXT 0x8E81 +#define GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS_OES 0x8E81 +#define GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS_EXT 0x8E85 +#define GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS_OES 0x8E85 +#define GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS_EXT 0x8E89 +#define GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS_OES 0x8E89 +#define GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS_EXT 0x8E7F +#define GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS_OES 0x8E7F +#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS_EXT 0x92D4 +#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS_OES 0x92D4 +#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS_EXT 0x92CE +#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS_OES 0x92CE +#define GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS_EXT 0x90CC +#define GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS_OES 0x90CC +#define GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS_EXT 0x886D +#define GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS_OES 0x886D +#define GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS_EXT 0x8E86 +#define GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS_OES 0x8E86 +#define GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS_EXT 0x90D9 +#define GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS_OES 0x90D9 +#define GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS_EXT 0x8E82 +#define GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS_OES 0x8E82 +#define GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS_EXT 0x8E8A +#define GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS_OES 0x8E8A +#define GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS_EXT 0x8E80 +#define GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS_OES 0x8E80 +#define GL_MAX_TESS_GEN_LEVEL_EXT 0x8E7E +#define GL_MAX_TESS_GEN_LEVEL_OES 0x8E7E +#define GL_MAX_TESS_PATCH_COMPONENTS_EXT 0x8E84 +#define GL_MAX_TESS_PATCH_COMPONENTS_OES 0x8E84 +#define GL_MAX_TEXTURE_BUFFER_SIZE_EXT 0x8C2B +#define GL_MAX_TEXTURE_BUFFER_SIZE_OES 0x8C2B +#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 +#define GL_MAX_TEXTURE_MAX_ANISOTROPY 0x84FF +#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF +#define GL_MAX_TEXTURE_SIZE 0x0D33 +#define GL_MAX_VARYING_VECTORS 0x8DFC +#define GL_MAX_VERTEX_ATTRIBS 0x8869 +#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C +#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB +#define GL_MAX_VIEWPORTS_OES 0x825B +#define GL_MAX_VIEWPORT_DIMS 0x0D3A +#define GL_MAX_WINDOW_RECTANGLES_EXT 0x8F14 +#define GL_MEDIUM_FLOAT 0x8DF1 +#define GL_MEDIUM_INT 0x8DF4 +#define GL_MIN 0x8007 +#define GL_MIN_EXT 0x8007 +#define GL_MIN_FRAGMENT_INTERPOLATION_OFFSET_OES 0x8E5B +#define GL_MIN_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_HEIGHT_EXT 0x96D9 +#define GL_MIN_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_WIDTH_EXT 0x96D7 +#define GL_MIN_SAMPLE_SHADING_VALUE_OES 0x8C37 +#define GL_MIRRORED_REPEAT 0x8370 +#define GL_MIRROR_CLAMP_TO_EDGE_EXT 0x8743 +#define GL_MULTIPLY_KHR 0x9294 +#define GL_MULTISAMPLE_EXT 0x809D +#define GL_MULTISAMPLE_RASTERIZATION_ALLOWED_EXT 0x932B +#define GL_MULTIVIEW_EXT 0x90F1 +#define GL_NEAREST 0x2600 +#define GL_NEAREST_MIPMAP_LINEAR 0x2702 +#define GL_NEAREST_MIPMAP_NEAREST 0x2700 +#define GL_NEGATIVE_ONE_TO_ONE 0x935E +#define GL_NEGATIVE_ONE_TO_ONE_EXT 0x935E +#define GL_NEVER 0x0200 +#define GL_NICEST 0x1102 +#define GL_NONE 0 +#define GL_NOTEQUAL 0x0205 +#define GL_NO_ERROR 0 +#define GL_NO_RESET_NOTIFICATION_EXT 0x8261 +#define GL_NO_RESET_NOTIFICATION_KHR 0x8261 +#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 +#define GL_NUM_DEVICE_UUIDS_EXT 0x9596 +#define GL_NUM_PROGRAM_BINARY_FORMATS_OES 0x87FE +#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9 +#define GL_NUM_SPARSE_LEVELS_EXT 0x91AA +#define GL_NUM_SURFACE_COMPRESSION_FIXED_RATES_EXT 0x8F6E +#define GL_NUM_TILING_TYPES_EXT 0x9582 +#define GL_NUM_VIRTUAL_PAGE_SIZES_EXT 0x91A8 +#define GL_NUM_WINDOW_RECTANGLES_EXT 0x8F15 +#define GL_ONE 1 +#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 +#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 +#define GL_ONE_MINUS_DST_ALPHA 0x0305 +#define GL_ONE_MINUS_DST_COLOR 0x0307 +#define GL_ONE_MINUS_SRC1_ALPHA_EXT 0x88FB +#define GL_ONE_MINUS_SRC1_COLOR_EXT 0x88FA +#define GL_ONE_MINUS_SRC_ALPHA 0x0303 +#define GL_ONE_MINUS_SRC_COLOR 0x0301 +#define GL_OPTIMAL_TILING_EXT 0x9584 +#define GL_OUT_OF_MEMORY 0x0505 +#define GL_OVERLAY_KHR 0x9296 +#define GL_PACK_ALIGNMENT 0x0D05 +#define GL_PALETTE4_R5_G6_B5_OES 0x8B92 +#define GL_PALETTE4_RGB5_A1_OES 0x8B94 +#define GL_PALETTE4_RGB8_OES 0x8B90 +#define GL_PALETTE4_RGBA4_OES 0x8B93 +#define GL_PALETTE4_RGBA8_OES 0x8B91 +#define GL_PALETTE8_R5_G6_B5_OES 0x8B97 +#define GL_PALETTE8_RGB5_A1_OES 0x8B99 +#define GL_PALETTE8_RGB8_OES 0x8B95 +#define GL_PALETTE8_RGBA4_OES 0x8B98 +#define GL_PALETTE8_RGBA8_OES 0x8B96 +#define GL_PATCHES_EXT 0x000E +#define GL_PATCHES_OES 0x000E +#define GL_PATCH_VERTICES_EXT 0x8E72 +#define GL_PATCH_VERTICES_OES 0x8E72 +#define GL_POINTS 0x0000 +#define GL_POLYGON_OFFSET_CLAMP 0x8E1B +#define GL_POLYGON_OFFSET_CLAMP_EXT 0x8E1B +#define GL_POLYGON_OFFSET_FACTOR 0x8038 +#define GL_POLYGON_OFFSET_FILL 0x8037 +#define GL_POLYGON_OFFSET_UNITS 0x2A00 +#define GL_PRIMITIVES_GENERATED_EXT 0x8C87 +#define GL_PRIMITIVES_GENERATED_OES 0x8C87 +#define GL_PRIMITIVE_BOUNDING_BOX_EXT 0x92BE +#define GL_PRIMITIVE_BOUNDING_BOX_OES 0x92BE +#define GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED 0x8221 +#define GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED_OES 0x8221 +#define GL_PROGRAM_BINARY_FORMATS_OES 0x87FF +#define GL_PROGRAM_BINARY_LENGTH_OES 0x8741 +#define GL_PROGRAM_KHR 0x82E2 +#define GL_PROGRAM_OBJECT_EXT 0x8B40 +#define GL_PROGRAM_PIPELINE_BINDING_EXT 0x825A +#define GL_PROGRAM_PIPELINE_KHR 0x82E4 +#define GL_PROGRAM_PIPELINE_OBJECT_EXT 0x8A4F +#define GL_PROGRAM_SEPARABLE_EXT 0x8258 +#define GL_PROTECTED_MEMORY_OBJECT_EXT 0x959B +#define GL_QUADS_EXT 0x0007 +#define GL_QUADS_OES 0x0007 +#define GL_QUERY_COUNTER_BITS_EXT 0x8864 +#define GL_QUERY_KHR 0x82E3 +#define GL_QUERY_OBJECT_EXT 0x9153 +#define GL_QUERY_RESULT_AVAILABLE_EXT 0x8867 +#define GL_QUERY_RESULT_EXT 0x8866 +#define GL_R16F_EXT 0x822D +#define GL_R16_EXT 0x822A +#define GL_R16_SNORM_EXT 0x8F98 +#define GL_R32F_EXT 0x822E +#define GL_R8_EXT 0x8229 +#define GL_R8_SNORM 0x8F94 +#define GL_RASTER_FIXED_SAMPLE_LOCATIONS_EXT 0x932A +#define GL_RASTER_MULTISAMPLE_EXT 0x9327 +#define GL_RASTER_SAMPLES_EXT 0x9328 +#define GL_READ_BUFFER_EXT 0x0C02 +#define GL_RED_BITS 0x0D52 +#define GL_RED_EXT 0x1903 +#define GL_REFERENCED_BY_GEOMETRY_SHADER_EXT 0x9309 +#define GL_REFERENCED_BY_GEOMETRY_SHADER_OES 0x9309 +#define GL_REFERENCED_BY_TESS_CONTROL_SHADER_EXT 0x9307 +#define GL_REFERENCED_BY_TESS_CONTROL_SHADER_OES 0x9307 +#define GL_REFERENCED_BY_TESS_EVALUATION_SHADER_EXT 0x9308 +#define GL_REFERENCED_BY_TESS_EVALUATION_SHADER_OES 0x9308 +#define GL_RENDERBUFFER 0x8D41 +#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53 +#define GL_RENDERBUFFER_BINDING 0x8CA7 +#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52 +#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54 +#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51 +#define GL_RENDERBUFFER_HEIGHT 0x8D43 +#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44 +#define GL_RENDERBUFFER_RED_SIZE 0x8D50 +#define GL_RENDERBUFFER_SAMPLES_EXT 0x8CAB +#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55 +#define GL_RENDERBUFFER_WIDTH 0x8D42 +#define GL_RENDERER 0x1F01 +#define GL_REPEAT 0x2901 +#define GL_REPLACE 0x1E01 +#define GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES 0x8D68 +#define GL_RESET_NOTIFICATION_STRATEGY_EXT 0x8256 +#define GL_RESET_NOTIFICATION_STRATEGY_KHR 0x8256 +#define GL_RG16F_EXT 0x822F +#define GL_RG16_EXT 0x822C +#define GL_RG16_SNORM_EXT 0x8F99 +#define GL_RG32F_EXT 0x8230 +#define GL_RG8_EXT 0x822B +#define GL_RG8_SNORM 0x8F95 +#define GL_RGB 0x1907 +#define GL_RGB10_A2_EXT 0x8059 +#define GL_RGB10_EXT 0x8052 +#define GL_RGB16F_EXT 0x881B +#define GL_RGB16_EXT 0x8054 +#define GL_RGB16_SNORM_EXT 0x8F9A +#define GL_RGB32F_EXT 0x8815 +#define GL_RGB565 0x8D62 +#define GL_RGB565_OES 0x8D62 +#define GL_RGB5_A1 0x8057 +#define GL_RGB5_A1_OES 0x8057 +#define GL_RGB8_OES 0x8051 +#define GL_RGBA 0x1908 +#define GL_RGBA16F_EXT 0x881A +#define GL_RGBA16_EXT 0x805B +#define GL_RGBA16_SNORM_EXT 0x8F9B +#define GL_RGBA32F_EXT 0x8814 +#define GL_RGBA4 0x8056 +#define GL_RGBA4_OES 0x8056 +#define GL_RGBA8_OES 0x8058 +#define GL_RGBA8_SNORM 0x8F97 +#define GL_RG_EXT 0x8227 +#define GL_SAMPLER 0x82E6 +#define GL_SAMPLER_2D 0x8B5E +#define GL_SAMPLER_2D_MULTISAMPLE_ARRAY_OES 0x910B +#define GL_SAMPLER_2D_SHADOW_EXT 0x8B62 +#define GL_SAMPLER_3D_OES 0x8B5F +#define GL_SAMPLER_BUFFER_EXT 0x8DC2 +#define GL_SAMPLER_BUFFER_OES 0x8DC2 +#define GL_SAMPLER_CUBE 0x8B60 +#define GL_SAMPLER_CUBE_MAP_ARRAY_EXT 0x900C +#define GL_SAMPLER_CUBE_MAP_ARRAY_OES 0x900C +#define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW_EXT 0x900D +#define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW_OES 0x900D +#define GL_SAMPLER_EXTERNAL_2D_Y2Y_EXT 0x8BE7 +#define GL_SAMPLER_EXTERNAL_OES 0x8D66 +#define GL_SAMPLER_KHR 0x82E6 +#define GL_SAMPLES 0x80A9 +#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E +#define GL_SAMPLE_ALPHA_TO_ONE_EXT 0x809F +#define GL_SAMPLE_BUFFERS 0x80A8 +#define GL_SAMPLE_COVERAGE 0x80A0 +#define GL_SAMPLE_COVERAGE_INVERT 0x80AB +#define GL_SAMPLE_COVERAGE_VALUE 0x80AA +#define GL_SAMPLE_SHADING_OES 0x8C36 +#define GL_SCISSOR_BOX 0x0C10 +#define GL_SCISSOR_TEST 0x0C11 +#define GL_SCREEN_KHR 0x9295 +#define GL_SHADER_BINARY_FORMATS 0x8DF8 +#define GL_SHADER_COMPILER 0x8DFA +#define GL_SHADER_KHR 0x82E1 +#define GL_SHADER_OBJECT_EXT 0x8B48 +#define GL_SHADER_PIXEL_LOCAL_STORAGE_EXT 0x8F64 +#define GL_SHADER_SOURCE_LENGTH 0x8B88 +#define GL_SHADER_TYPE 0x8B4F +#define GL_SHADING_LANGUAGE_VERSION 0x8B8C +#define GL_SHADING_RATE_1X1_PIXELS_EXT 0x96A6 +#define GL_SHADING_RATE_1X1_PIXELS_QCOM 0x96A6 +#define GL_SHADING_RATE_1X2_PIXELS_EXT 0x96A7 +#define GL_SHADING_RATE_1X2_PIXELS_QCOM 0x96A7 +#define GL_SHADING_RATE_1X4_PIXELS_EXT 0x96AA +#define GL_SHADING_RATE_1X4_PIXELS_QCOM 0x96AA +#define GL_SHADING_RATE_2X1_PIXELS_EXT 0x96A8 +#define GL_SHADING_RATE_2X1_PIXELS_QCOM 0x96A8 +#define GL_SHADING_RATE_2X2_PIXELS_EXT 0x96A9 +#define GL_SHADING_RATE_2X2_PIXELS_QCOM 0x96A9 +#define GL_SHADING_RATE_2X4_PIXELS_EXT 0x96AD +#define GL_SHADING_RATE_2X4_PIXELS_QCOM 0x96AD +#define GL_SHADING_RATE_4X1_PIXELS_EXT 0x96AB +#define GL_SHADING_RATE_4X1_PIXELS_QCOM 0x96AB +#define GL_SHADING_RATE_4X2_PIXELS_EXT 0x96AC +#define GL_SHADING_RATE_4X2_PIXELS_QCOM 0x96AC +#define GL_SHADING_RATE_4X4_PIXELS_EXT 0x96AE +#define GL_SHADING_RATE_4X4_PIXELS_QCOM 0x96AE +#define GL_SHADING_RATE_ATTACHMENT_EXT 0x96D1 +#define GL_SHADING_RATE_EXT 0x96D0 +#define GL_SHORT 0x1402 +#define GL_SKIP_DECODE_EXT 0x8A4A +#define GL_SOFTLIGHT_KHR 0x929C +#define GL_SPARSE_TEXTURE_FULL_ARRAY_CUBE_MIPMAPS_EXT 0x91A9 +#define GL_SR8_EXT 0x8FBD +#define GL_SRC1_ALPHA_EXT 0x8589 +#define GL_SRC1_COLOR_EXT 0x88F9 +#define GL_SRC_ALPHA 0x0302 +#define GL_SRC_ALPHA_SATURATE 0x0308 +#define GL_SRC_ALPHA_SATURATE_EXT 0x0308 +#define GL_SRC_COLOR 0x0300 +#define GL_SRG8_EXT 0x8FBE +#define GL_SRGB8_ALPHA8_EXT 0x8C43 +#define GL_SRGB_ALPHA_EXT 0x8C42 +#define GL_SRGB_EXT 0x8C40 +#define GL_STACK_OVERFLOW_KHR 0x0503 +#define GL_STACK_UNDERFLOW_KHR 0x0504 +#define GL_STATIC_DRAW 0x88E4 +#define GL_STENCIL_ATTACHMENT 0x8D20 +#define GL_STENCIL_BACK_FAIL 0x8801 +#define GL_STENCIL_BACK_FUNC 0x8800 +#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 +#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 +#define GL_STENCIL_BACK_REF 0x8CA3 +#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 +#define GL_STENCIL_BACK_WRITEMASK 0x8CA5 +#define GL_STENCIL_BITS 0x0D57 +#define GL_STENCIL_BUFFER_BIT 0x00000400 +#define GL_STENCIL_CLEAR_VALUE 0x0B91 +#define GL_STENCIL_EXT 0x1802 +#define GL_STENCIL_FAIL 0x0B94 +#define GL_STENCIL_FUNC 0x0B92 +#define GL_STENCIL_INDEX1_OES 0x8D46 +#define GL_STENCIL_INDEX4_OES 0x8D47 +#define GL_STENCIL_INDEX8 0x8D48 +#define GL_STENCIL_INDEX8_OES 0x8D48 +#define GL_STENCIL_INDEX_OES 0x1901 +#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95 +#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96 +#define GL_STENCIL_REF 0x0B97 +#define GL_STENCIL_TEST 0x0B90 +#define GL_STENCIL_VALUE_MASK 0x0B93 +#define GL_STENCIL_WRITEMASK 0x0B98 +#define GL_STREAM_DRAW 0x88E0 +#define GL_SUBGROUP_FEATURE_ARITHMETIC_BIT_KHR 0x00000004 +#define GL_SUBGROUP_FEATURE_BALLOT_BIT_KHR 0x00000008 +#define GL_SUBGROUP_FEATURE_BASIC_BIT_KHR 0x00000001 +#define GL_SUBGROUP_FEATURE_CLUSTERED_BIT_KHR 0x00000040 +#define GL_SUBGROUP_FEATURE_QUAD_BIT_KHR 0x00000080 +#define GL_SUBGROUP_FEATURE_SHUFFLE_BIT_KHR 0x00000010 +#define GL_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT_KHR 0x00000020 +#define GL_SUBGROUP_FEATURE_VOTE_BIT_KHR 0x00000002 +#define GL_SUBGROUP_QUAD_ALL_STAGES_KHR 0x9535 +#define GL_SUBGROUP_SIZE_KHR 0x9532 +#define GL_SUBGROUP_SUPPORTED_FEATURES_KHR 0x9534 +#define GL_SUBGROUP_SUPPORTED_STAGES_KHR 0x9533 +#define GL_SUBPIXEL_BITS 0x0D50 +#define GL_SURFACE_COMPRESSION_EXT 0x96C0 +#define GL_SURFACE_COMPRESSION_FIXED_RATE_10BPC_EXT 0x96CD +#define GL_SURFACE_COMPRESSION_FIXED_RATE_11BPC_EXT 0x96CE +#define GL_SURFACE_COMPRESSION_FIXED_RATE_12BPC_EXT 0x96CF +#define GL_SURFACE_COMPRESSION_FIXED_RATE_1BPC_EXT 0x96C4 +#define GL_SURFACE_COMPRESSION_FIXED_RATE_2BPC_EXT 0x96C5 +#define GL_SURFACE_COMPRESSION_FIXED_RATE_3BPC_EXT 0x96C6 +#define GL_SURFACE_COMPRESSION_FIXED_RATE_4BPC_EXT 0x96C7 +#define GL_SURFACE_COMPRESSION_FIXED_RATE_5BPC_EXT 0x96C8 +#define GL_SURFACE_COMPRESSION_FIXED_RATE_6BPC_EXT 0x96C9 +#define GL_SURFACE_COMPRESSION_FIXED_RATE_7BPC_EXT 0x96CA +#define GL_SURFACE_COMPRESSION_FIXED_RATE_8BPC_EXT 0x96CB +#define GL_SURFACE_COMPRESSION_FIXED_RATE_9BPC_EXT 0x96CC +#define GL_SURFACE_COMPRESSION_FIXED_RATE_DEFAULT_EXT 0x96C2 +#define GL_SURFACE_COMPRESSION_FIXED_RATE_NONE_EXT 0x96C1 +#define GL_TESS_CONTROL_OUTPUT_VERTICES_EXT 0x8E75 +#define GL_TESS_CONTROL_OUTPUT_VERTICES_OES 0x8E75 +#define GL_TESS_CONTROL_SHADER_BIT_EXT 0x00000008 +#define GL_TESS_CONTROL_SHADER_BIT_OES 0x00000008 +#define GL_TESS_CONTROL_SHADER_EXT 0x8E88 +#define GL_TESS_CONTROL_SHADER_OES 0x8E88 +#define GL_TESS_EVALUATION_SHADER_BIT_EXT 0x00000010 +#define GL_TESS_EVALUATION_SHADER_BIT_OES 0x00000010 +#define GL_TESS_EVALUATION_SHADER_EXT 0x8E87 +#define GL_TESS_EVALUATION_SHADER_OES 0x8E87 +#define GL_TESS_GEN_MODE_EXT 0x8E76 +#define GL_TESS_GEN_MODE_OES 0x8E76 +#define GL_TESS_GEN_POINT_MODE_EXT 0x8E79 +#define GL_TESS_GEN_POINT_MODE_OES 0x8E79 +#define GL_TESS_GEN_SPACING_EXT 0x8E77 +#define GL_TESS_GEN_SPACING_OES 0x8E77 +#define GL_TESS_GEN_VERTEX_ORDER_EXT 0x8E78 +#define GL_TESS_GEN_VERTEX_ORDER_OES 0x8E78 +#define GL_TEXTURE 0x1702 +#define GL_TEXTURE0 0x84C0 +#define GL_TEXTURE1 0x84C1 +#define GL_TEXTURE10 0x84CA +#define GL_TEXTURE11 0x84CB +#define GL_TEXTURE12 0x84CC +#define GL_TEXTURE13 0x84CD +#define GL_TEXTURE14 0x84CE +#define GL_TEXTURE15 0x84CF +#define GL_TEXTURE16 0x84D0 +#define GL_TEXTURE17 0x84D1 +#define GL_TEXTURE18 0x84D2 +#define GL_TEXTURE19 0x84D3 +#define GL_TEXTURE2 0x84C2 +#define GL_TEXTURE20 0x84D4 +#define GL_TEXTURE21 0x84D5 +#define GL_TEXTURE22 0x84D6 +#define GL_TEXTURE23 0x84D7 +#define GL_TEXTURE24 0x84D8 +#define GL_TEXTURE25 0x84D9 +#define GL_TEXTURE26 0x84DA +#define GL_TEXTURE27 0x84DB +#define GL_TEXTURE28 0x84DC +#define GL_TEXTURE29 0x84DD +#define GL_TEXTURE3 0x84C3 +#define GL_TEXTURE30 0x84DE +#define GL_TEXTURE31 0x84DF +#define GL_TEXTURE4 0x84C4 +#define GL_TEXTURE5 0x84C5 +#define GL_TEXTURE6 0x84C6 +#define GL_TEXTURE7 0x84C7 +#define GL_TEXTURE8 0x84C8 +#define GL_TEXTURE9 0x84C9 +#define GL_TEXTURE_2D 0x0DE1 +#define GL_TEXTURE_2D_ARRAY 0x8C1A +#define GL_TEXTURE_2D_MULTISAMPLE_ARRAY_OES 0x9102 +#define GL_TEXTURE_3D 0x806F +#define GL_TEXTURE_3D_OES 0x806F +#define GL_TEXTURE_ASTC_DECODE_PRECISION_EXT 0x8F69 +#define GL_TEXTURE_BINDING_2D 0x8069 +#define GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY_OES 0x9105 +#define GL_TEXTURE_BINDING_3D_OES 0x806A +#define GL_TEXTURE_BINDING_BUFFER_EXT 0x8C2C +#define GL_TEXTURE_BINDING_BUFFER_OES 0x8C2C +#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514 +#define GL_TEXTURE_BINDING_CUBE_MAP_ARRAY_EXT 0x900A +#define GL_TEXTURE_BINDING_CUBE_MAP_ARRAY_OES 0x900A +#define GL_TEXTURE_BINDING_EXTERNAL_OES 0x8D67 +#define GL_TEXTURE_BORDER_COLOR_EXT 0x1004 +#define GL_TEXTURE_BORDER_COLOR_OES 0x1004 +#define GL_TEXTURE_BUFFER_BINDING_EXT 0x8C2A +#define GL_TEXTURE_BUFFER_BINDING_OES 0x8C2A +#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING_EXT 0x8C2D +#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING_OES 0x8C2D +#define GL_TEXTURE_BUFFER_EXT 0x8C2A +#define GL_TEXTURE_BUFFER_OES 0x8C2A +#define GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT_EXT 0x919F +#define GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT_OES 0x919F +#define GL_TEXTURE_BUFFER_OFFSET_EXT 0x919D +#define GL_TEXTURE_BUFFER_OFFSET_OES 0x919D +#define GL_TEXTURE_BUFFER_SIZE_EXT 0x919E +#define GL_TEXTURE_BUFFER_SIZE_OES 0x919E +#define GL_TEXTURE_COMPARE_FUNC_EXT 0x884D +#define GL_TEXTURE_COMPARE_MODE_EXT 0x884C +#define GL_TEXTURE_CUBE_MAP 0x8513 +#define GL_TEXTURE_CUBE_MAP_ARRAY_EXT 0x9009 +#define GL_TEXTURE_CUBE_MAP_ARRAY_OES 0x9009 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A +#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 +#define GL_TEXTURE_EXTERNAL_OES 0x8D65 +#define GL_TEXTURE_FORMAT_SRGB_OVERRIDE_EXT 0x8FBF +#define GL_TEXTURE_IMMUTABLE_FORMAT_EXT 0x912F +#define GL_TEXTURE_IMMUTABLE_LEVELS 0x82DF +#define GL_TEXTURE_MAG_FILTER 0x2800 +#define GL_TEXTURE_MAX_ANISOTROPY 0x84FE +#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE +#define GL_TEXTURE_MIN_FILTER 0x2801 +#define GL_TEXTURE_PROTECTED_EXT 0x8BFA +#define GL_TEXTURE_REDUCTION_MODE_ARB 0x9366 +#define GL_TEXTURE_REDUCTION_MODE_EXT 0x9366 +#define GL_TEXTURE_SPARSE_EXT 0x91A6 +#define GL_TEXTURE_SRGB_DECODE_EXT 0x8A48 +#define GL_TEXTURE_TILING_EXT 0x9580 +#define GL_TEXTURE_VIEW_MIN_LAYER_EXT 0x82DD +#define GL_TEXTURE_VIEW_MIN_LAYER_OES 0x82DD +#define GL_TEXTURE_VIEW_MIN_LEVEL_EXT 0x82DB +#define GL_TEXTURE_VIEW_MIN_LEVEL_OES 0x82DB +#define GL_TEXTURE_VIEW_NUM_LAYERS_EXT 0x82DE +#define GL_TEXTURE_VIEW_NUM_LAYERS_OES 0x82DE +#define GL_TEXTURE_VIEW_NUM_LEVELS_EXT 0x82DC +#define GL_TEXTURE_VIEW_NUM_LEVELS_OES 0x82DC +#define GL_TEXTURE_WRAP_R_OES 0x8072 +#define GL_TEXTURE_WRAP_S 0x2802 +#define GL_TEXTURE_WRAP_T 0x2803 +#define GL_TILING_TYPES_EXT 0x9583 +#define GL_TIMESTAMP_EXT 0x8E28 +#define GL_TIME_ELAPSED_EXT 0x88BF +#define GL_TRANSFORM_FEEDBACK 0x8E22 +#define GL_TRIANGLES 0x0004 +#define GL_TRIANGLES_ADJACENCY_EXT 0x000C +#define GL_TRIANGLES_ADJACENCY_OES 0x000C +#define GL_TRIANGLE_FAN 0x0006 +#define GL_TRIANGLE_STRIP 0x0005 +#define GL_TRIANGLE_STRIP_ADJACENCY_EXT 0x000D +#define GL_TRIANGLE_STRIP_ADJACENCY_OES 0x000D +#define GL_TRUE 1 +#define GL_UNDEFINED_VERTEX_EXT 0x8260 +#define GL_UNDEFINED_VERTEX_OES 0x8260 +#define GL_UNKNOWN_CONTEXT_RESET_EXT 0x8255 +#define GL_UNKNOWN_CONTEXT_RESET_KHR 0x8255 +#define GL_UNPACK_ALIGNMENT 0x0CF5 +#define GL_UNPACK_ROW_LENGTH_EXT 0x0CF2 +#define GL_UNPACK_SKIP_PIXELS_EXT 0x0CF4 +#define GL_UNPACK_SKIP_ROWS_EXT 0x0CF3 +#define GL_UNSIGNED_BYTE 0x1401 +#define GL_UNSIGNED_INT 0x1405 +#define GL_UNSIGNED_INT_10_10_10_2_OES 0x8DF6 +#define GL_UNSIGNED_INT_24_8_OES 0x84FA +#define GL_UNSIGNED_INT_2_10_10_10_REV_EXT 0x8368 +#define GL_UNSIGNED_INT_IMAGE_BUFFER_EXT 0x9067 +#define GL_UNSIGNED_INT_IMAGE_BUFFER_OES 0x9067 +#define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY_EXT 0x906A +#define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY_OES 0x906A +#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY_OES 0x910D +#define GL_UNSIGNED_INT_SAMPLER_BUFFER_EXT 0x8DD8 +#define GL_UNSIGNED_INT_SAMPLER_BUFFER_OES 0x8DD8 +#define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY_EXT 0x900F +#define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY_OES 0x900F +#define GL_UNSIGNED_NORMALIZED_EXT 0x8C17 +#define GL_UNSIGNED_SHORT 0x1403 +#define GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT 0x8366 +#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 +#define GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT 0x8365 +#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 +#define GL_UNSIGNED_SHORT_5_6_5 0x8363 +#define GL_UPPER_LEFT 0x8CA2 +#define GL_UPPER_LEFT_EXT 0x8CA2 +#define GL_UUID_SIZE_EXT 16 +#define GL_VALIDATE_STATUS 0x8B83 +#define GL_VENDOR 0x1F00 +#define GL_VERSION 0x1F02 +#define GL_VERTEX_ARRAY_BINDING_OES 0x85B5 +#define GL_VERTEX_ARRAY_KHR 0x8074 +#define GL_VERTEX_ARRAY_OBJECT_EXT 0x9154 +#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F +#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR_EXT 0x88FE +#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 +#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A +#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 +#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 +#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 +#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 +#define GL_VERTEX_SHADER 0x8B31 +#define GL_VERTEX_SHADER_BIT_EXT 0x00000001 +#define GL_VIEWPORT 0x0BA2 +#define GL_VIEWPORT_BOUNDS_RANGE_OES 0x825D +#define GL_VIEWPORT_INDEX_PROVOKING_VERTEX_OES 0x825F +#define GL_VIEWPORT_SUBPIXEL_BITS_OES 0x825C +#define GL_VIRTUAL_PAGE_SIZE_INDEX_EXT 0x91A7 +#define GL_VIRTUAL_PAGE_SIZE_X_EXT 0x9195 +#define GL_VIRTUAL_PAGE_SIZE_Y_EXT 0x9196 +#define GL_VIRTUAL_PAGE_SIZE_Z_EXT 0x9197 +#define GL_WEIGHTED_AVERAGE_ARB 0x9367 +#define GL_WEIGHTED_AVERAGE_EXT 0x9367 +#define GL_WINDOW_RECTANGLE_EXT 0x8F12 +#define GL_WINDOW_RECTANGLE_MODE_EXT 0x8F13 +#define GL_WRITE_ONLY_OES 0x88B9 +#define GL_ZERO 0 +#define GL_ZERO_TO_ONE 0x935F +#define GL_ZERO_TO_ONE_EXT 0x935F + + +#ifndef __khrplatform_h_ +#define __khrplatform_h_ + +/* +** Copyright (c) 2008-2018 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are 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 Materials. +** +** THE MATERIALS ARE 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 +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +/* Khronos platform-specific types and definitions. + * + * The master copy of khrplatform.h is maintained in the Khronos EGL + * Registry repository at https://github.com/KhronosGroup/EGL-Registry + * The last semantic modification to khrplatform.h was at commit ID: + * 67a3e0864c2d75ea5287b9f3d2eb74a745936692 + * + * Adopters may modify this file to suit their platform. Adopters are + * encouraged to submit platform specific modifications to the Khronos + * group so that they can be included in future versions of this file. + * Please submit changes by filing pull requests or issues on + * the EGL Registry repository linked above. + * + * + * See the Implementer's Guidelines for information about where this file + * should be located on your system and for more details of its use: + * http://www.khronos.org/registry/implementers_guide.pdf + * + * This file should be included as + * #include + * by Khronos client API header files that use its types and defines. + * + * The types in khrplatform.h should only be used to define API-specific types. + * + * Types defined in khrplatform.h: + * khronos_int8_t signed 8 bit + * khronos_uint8_t unsigned 8 bit + * khronos_int16_t signed 16 bit + * khronos_uint16_t unsigned 16 bit + * khronos_int32_t signed 32 bit + * khronos_uint32_t unsigned 32 bit + * khronos_int64_t signed 64 bit + * khronos_uint64_t unsigned 64 bit + * khronos_intptr_t signed same number of bits as a pointer + * khronos_uintptr_t unsigned same number of bits as a pointer + * khronos_ssize_t signed size + * khronos_usize_t unsigned size + * khronos_float_t signed 32 bit floating point + * khronos_time_ns_t unsigned 64 bit time in nanoseconds + * khronos_utime_nanoseconds_t unsigned time interval or absolute time in + * nanoseconds + * khronos_stime_nanoseconds_t signed time interval in nanoseconds + * khronos_boolean_enum_t enumerated boolean type. This should + * only be used as a base type when a client API's boolean type is + * an enum. Client APIs which use an integer or other type for + * booleans cannot use this as the base type for their boolean. + * + * Tokens defined in khrplatform.h: + * + * KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values. + * + * KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0. + * KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0. + * + * Calling convention macros defined in this file: + * KHRONOS_APICALL + * KHRONOS_GLAD_API_PTR + * KHRONOS_APIATTRIBUTES + * + * These may be used in function prototypes as: + * + * KHRONOS_APICALL void KHRONOS_GLAD_API_PTR funcname( + * int arg1, + * int arg2) KHRONOS_APIATTRIBUTES; + */ + +#if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC) +# define KHRONOS_STATIC 1 +#endif + +/*------------------------------------------------------------------------- + * Definition of KHRONOS_APICALL + *------------------------------------------------------------------------- + * This precedes the return type of the function in the function prototype. + */ +#if defined(KHRONOS_STATIC) + /* If the preprocessor constant KHRONOS_STATIC is defined, make the + * header compatible with static linking. */ +# define KHRONOS_APICALL +#elif defined(_WIN32) +# define KHRONOS_APICALL __declspec(dllimport) +#elif defined (__SYMBIAN32__) +# define KHRONOS_APICALL IMPORT_C +#elif defined(__ANDROID__) +# define KHRONOS_APICALL __attribute__((visibility("default"))) +#else +# define KHRONOS_APICALL +#endif + +/*------------------------------------------------------------------------- + * Definition of KHRONOS_GLAD_API_PTR + *------------------------------------------------------------------------- + * This follows the return type of the function and precedes the function + * name in the function prototype. + */ +#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__) + /* Win32 but not WinCE */ +# define KHRONOS_GLAD_API_PTR __stdcall +#else +# define KHRONOS_GLAD_API_PTR +#endif + +/*------------------------------------------------------------------------- + * Definition of KHRONOS_APIATTRIBUTES + *------------------------------------------------------------------------- + * This follows the closing parenthesis of the function prototype arguments. + */ +#if defined (__ARMCC_2__) +#define KHRONOS_APIATTRIBUTES __softfp +#else +#define KHRONOS_APIATTRIBUTES +#endif + +/*------------------------------------------------------------------------- + * basic type definitions + *-----------------------------------------------------------------------*/ +#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__) + + +/* + * Using + */ +#include +typedef int32_t khronos_int32_t; +typedef uint32_t khronos_uint32_t; +typedef int64_t khronos_int64_t; +typedef uint64_t khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 +/* + * To support platform where unsigned long cannot be used interchangeably with + * inptr_t (e.g. CHERI-extended ISAs), we can use the stdint.h intptr_t. + * Ideally, we could just use (u)intptr_t everywhere, but this could result in + * ABI breakage if khronos_uintptr_t is changed from unsigned long to + * unsigned long long or similar (this results in different C++ name mangling). + * To avoid changes for existing platforms, we restrict usage of intptr_t to + * platforms where the size of a pointer is larger than the size of long. + */ +#if defined(__SIZEOF_LONG__) && defined(__SIZEOF_POINTER__) +#if __SIZEOF_POINTER__ > __SIZEOF_LONG__ +#define KHRONOS_USE_INTPTR_T +#endif +#endif + +#elif defined(__VMS ) || defined(__sgi) + +/* + * Using + */ +#include +typedef int32_t khronos_int32_t; +typedef uint32_t khronos_uint32_t; +typedef int64_t khronos_int64_t; +typedef uint64_t khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif defined(_WIN32) && !defined(__SCITECH_SNAP__) + +/* + * Win32 + */ +typedef __int32 khronos_int32_t; +typedef unsigned __int32 khronos_uint32_t; +typedef __int64 khronos_int64_t; +typedef unsigned __int64 khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif defined(__sun__) || defined(__digital__) + +/* + * Sun or Digital + */ +typedef int khronos_int32_t; +typedef unsigned int khronos_uint32_t; +#if defined(__arch64__) || defined(_LP64) +typedef long int khronos_int64_t; +typedef unsigned long int khronos_uint64_t; +#else +typedef long long int khronos_int64_t; +typedef unsigned long long int khronos_uint64_t; +#endif /* __arch64__ */ +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif 0 + +/* + * Hypothetical platform with no float or int64 support + */ +typedef int khronos_int32_t; +typedef unsigned int khronos_uint32_t; +#define KHRONOS_SUPPORT_INT64 0 +#define KHRONOS_SUPPORT_FLOAT 0 + +#else + +/* + * Generic fallback + */ +#include +typedef int32_t khronos_int32_t; +typedef uint32_t khronos_uint32_t; +typedef int64_t khronos_int64_t; +typedef uint64_t khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#endif + + +/* + * Types that are (so far) the same on all platforms + */ +typedef signed char khronos_int8_t; +typedef unsigned char khronos_uint8_t; +typedef signed short int khronos_int16_t; +typedef unsigned short int khronos_uint16_t; + +/* + * Types that differ between LLP64 and LP64 architectures - in LLP64, + * pointers are 64 bits, but 'long' is still 32 bits. Win64 appears + * to be the only LLP64 architecture in current use. + */ +#ifdef KHRONOS_USE_INTPTR_T +typedef intptr_t khronos_intptr_t; +typedef uintptr_t khronos_uintptr_t; +#elif defined(_WIN64) +typedef signed long long int khronos_intptr_t; +typedef unsigned long long int khronos_uintptr_t; +#else +typedef signed long int khronos_intptr_t; +typedef unsigned long int khronos_uintptr_t; +#endif + +#if defined(_WIN64) +typedef signed long long int khronos_ssize_t; +typedef unsigned long long int khronos_usize_t; +#else +typedef signed long int khronos_ssize_t; +typedef unsigned long int khronos_usize_t; +#endif + +#if KHRONOS_SUPPORT_FLOAT +/* + * Float type + */ +typedef float khronos_float_t; +#endif + +#if KHRONOS_SUPPORT_INT64 +/* Time types + * + * These types can be used to represent a time interval in nanoseconds or + * an absolute Unadjusted System Time. Unadjusted System Time is the number + * of nanoseconds since some arbitrary system event (e.g. since the last + * time the system booted). The Unadjusted System Time is an unsigned + * 64 bit value that wraps back to 0 every 584 years. Time intervals + * may be either signed or unsigned. + */ +typedef khronos_uint64_t khronos_utime_nanoseconds_t; +typedef khronos_int64_t khronos_stime_nanoseconds_t; +#endif + +/* + * Dummy value used to pad enum types to 32 bits. + */ +#ifndef KHRONOS_MAX_ENUM +#define KHRONOS_MAX_ENUM 0x7FFFFFFF +#endif + +/* + * Enumerated boolean type + * + * Values other than zero should be considered to be true. Therefore + * comparisons should not be made against KHRONOS_TRUE. + */ +typedef enum { + KHRONOS_FALSE = 0, + KHRONOS_TRUE = 1, + KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM +} khronos_boolean_enum_t; + +#endif /* __khrplatform_h_ */ +typedef unsigned int GLenum; +typedef unsigned char GLboolean; +typedef unsigned int GLbitfield; +typedef void GLvoid; +typedef khronos_int8_t GLbyte; +typedef khronos_uint8_t GLubyte; +typedef khronos_int16_t GLshort; +typedef khronos_uint16_t GLushort; +typedef int GLint; +typedef unsigned int GLuint; +typedef khronos_int32_t GLclampx; +typedef int GLsizei; +typedef khronos_float_t GLfloat; +typedef khronos_float_t GLclampf; +typedef double GLdouble; +typedef double GLclampd; +typedef void *GLeglClientBufferEXT; +typedef void *GLeglImageOES; +typedef char GLchar; +typedef char GLcharARB; +#ifdef __APPLE__ +typedef void *GLhandleARB; +#else +typedef unsigned int GLhandleARB; +#endif +typedef khronos_uint16_t GLhalf; +typedef khronos_uint16_t GLhalfARB; +typedef khronos_int32_t GLfixed; +#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060) +typedef khronos_intptr_t GLintptr; +#else +typedef khronos_intptr_t GLintptr; +#endif +#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060) +typedef khronos_intptr_t GLintptrARB; +#else +typedef khronos_intptr_t GLintptrARB; +#endif +#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060) +typedef khronos_ssize_t GLsizeiptr; +#else +typedef khronos_ssize_t GLsizeiptr; +#endif +#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060) +typedef khronos_ssize_t GLsizeiptrARB; +#else +typedef khronos_ssize_t GLsizeiptrARB; +#endif +typedef khronos_int64_t GLint64; +typedef khronos_int64_t GLint64EXT; +typedef khronos_uint64_t GLuint64; +typedef khronos_uint64_t GLuint64EXT; +typedef struct __GLsync *GLsync; +struct _cl_context; +struct _cl_event; +typedef void (GLAD_API_PTR *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); +typedef void (GLAD_API_PTR *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); +typedef void (GLAD_API_PTR *GLDEBUGPROCKHR)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); +typedef void (GLAD_API_PTR *GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenum severity,GLsizei length,const GLchar *message,void *userParam); +typedef unsigned short GLhalfNV; +typedef GLintptr GLvdpauSurfaceNV; +typedef void (GLAD_API_PTR *GLVULKANPROCNV)(void); + + +#define GL_ES_VERSION_2_0 1 +GLAD_API_CALL int GLAD_GL_ES_VERSION_2_0; +#define GL_EXT_EGL_image_array 1 +GLAD_API_CALL int GLAD_GL_EXT_EGL_image_array; +#define GL_EXT_EGL_image_storage 1 +GLAD_API_CALL int GLAD_GL_EXT_EGL_image_storage; +#define GL_EXT_EGL_image_storage_compression 1 +GLAD_API_CALL int GLAD_GL_EXT_EGL_image_storage_compression; +#define GL_EXT_YUV_target 1 +GLAD_API_CALL int GLAD_GL_EXT_YUV_target; +#define GL_EXT_base_instance 1 +GLAD_API_CALL int GLAD_GL_EXT_base_instance; +#define GL_EXT_blend_func_extended 1 +GLAD_API_CALL int GLAD_GL_EXT_blend_func_extended; +#define GL_EXT_blend_minmax 1 +GLAD_API_CALL int GLAD_GL_EXT_blend_minmax; +#define GL_EXT_buffer_storage 1 +GLAD_API_CALL int GLAD_GL_EXT_buffer_storage; +#define GL_EXT_clear_texture 1 +GLAD_API_CALL int GLAD_GL_EXT_clear_texture; +#define GL_EXT_clip_control 1 +GLAD_API_CALL int GLAD_GL_EXT_clip_control; +#define GL_EXT_clip_cull_distance 1 +GLAD_API_CALL int GLAD_GL_EXT_clip_cull_distance; +#define GL_EXT_color_buffer_float 1 +GLAD_API_CALL int GLAD_GL_EXT_color_buffer_float; +#define GL_EXT_color_buffer_half_float 1 +GLAD_API_CALL int GLAD_GL_EXT_color_buffer_half_float; +#define GL_EXT_conservative_depth 1 +GLAD_API_CALL int GLAD_GL_EXT_conservative_depth; +#define GL_EXT_copy_image 1 +GLAD_API_CALL int GLAD_GL_EXT_copy_image; +#define GL_EXT_debug_label 1 +GLAD_API_CALL int GLAD_GL_EXT_debug_label; +#define GL_EXT_debug_marker 1 +GLAD_API_CALL int GLAD_GL_EXT_debug_marker; +#define GL_EXT_depth_clamp 1 +GLAD_API_CALL int GLAD_GL_EXT_depth_clamp; +#define GL_EXT_discard_framebuffer 1 +GLAD_API_CALL int GLAD_GL_EXT_discard_framebuffer; +#define GL_EXT_disjoint_timer_query 1 +GLAD_API_CALL int GLAD_GL_EXT_disjoint_timer_query; +#define GL_EXT_draw_buffers 1 +GLAD_API_CALL int GLAD_GL_EXT_draw_buffers; +#define GL_EXT_draw_buffers_indexed 1 +GLAD_API_CALL int GLAD_GL_EXT_draw_buffers_indexed; +#define GL_EXT_draw_elements_base_vertex 1 +GLAD_API_CALL int GLAD_GL_EXT_draw_elements_base_vertex; +#define GL_EXT_draw_instanced 1 +GLAD_API_CALL int GLAD_GL_EXT_draw_instanced; +#define GL_EXT_draw_transform_feedback 1 +GLAD_API_CALL int GLAD_GL_EXT_draw_transform_feedback; +#define GL_EXT_external_buffer 1 +GLAD_API_CALL int GLAD_GL_EXT_external_buffer; +#define GL_EXT_float_blend 1 +GLAD_API_CALL int GLAD_GL_EXT_float_blend; +#define GL_EXT_fragment_shading_rate 1 +GLAD_API_CALL int GLAD_GL_EXT_fragment_shading_rate; +#define GL_EXT_geometry_point_size 1 +GLAD_API_CALL int GLAD_GL_EXT_geometry_point_size; +#define GL_EXT_geometry_shader 1 +GLAD_API_CALL int GLAD_GL_EXT_geometry_shader; +#define GL_EXT_gpu_shader5 1 +GLAD_API_CALL int GLAD_GL_EXT_gpu_shader5; +#define GL_EXT_instanced_arrays 1 +GLAD_API_CALL int GLAD_GL_EXT_instanced_arrays; +#define GL_EXT_map_buffer_range 1 +GLAD_API_CALL int GLAD_GL_EXT_map_buffer_range; +#define GL_EXT_memory_object 1 +GLAD_API_CALL int GLAD_GL_EXT_memory_object; +#define GL_EXT_memory_object_fd 1 +GLAD_API_CALL int GLAD_GL_EXT_memory_object_fd; +#define GL_EXT_memory_object_win32 1 +GLAD_API_CALL int GLAD_GL_EXT_memory_object_win32; +#define GL_EXT_multi_draw_arrays 1 +GLAD_API_CALL int GLAD_GL_EXT_multi_draw_arrays; +#define GL_EXT_multi_draw_indirect 1 +GLAD_API_CALL int GLAD_GL_EXT_multi_draw_indirect; +#define GL_EXT_multisampled_compatibility 1 +GLAD_API_CALL int GLAD_GL_EXT_multisampled_compatibility; +#define GL_EXT_multisampled_render_to_texture 1 +GLAD_API_CALL int GLAD_GL_EXT_multisampled_render_to_texture; +#define GL_EXT_multisampled_render_to_texture2 1 +GLAD_API_CALL int GLAD_GL_EXT_multisampled_render_to_texture2; +#define GL_EXT_multiview_draw_buffers 1 +GLAD_API_CALL int GLAD_GL_EXT_multiview_draw_buffers; +#define GL_EXT_multiview_tessellation_geometry_shader 1 +GLAD_API_CALL int GLAD_GL_EXT_multiview_tessellation_geometry_shader; +#define GL_EXT_multiview_texture_multisample 1 +GLAD_API_CALL int GLAD_GL_EXT_multiview_texture_multisample; +#define GL_EXT_multiview_timer_query 1 +GLAD_API_CALL int GLAD_GL_EXT_multiview_timer_query; +#define GL_EXT_occlusion_query_boolean 1 +GLAD_API_CALL int GLAD_GL_EXT_occlusion_query_boolean; +#define GL_EXT_polygon_offset_clamp 1 +GLAD_API_CALL int GLAD_GL_EXT_polygon_offset_clamp; +#define GL_EXT_post_depth_coverage 1 +GLAD_API_CALL int GLAD_GL_EXT_post_depth_coverage; +#define GL_EXT_primitive_bounding_box 1 +GLAD_API_CALL int GLAD_GL_EXT_primitive_bounding_box; +#define GL_EXT_protected_textures 1 +GLAD_API_CALL int GLAD_GL_EXT_protected_textures; +#define GL_EXT_pvrtc_sRGB 1 +GLAD_API_CALL int GLAD_GL_EXT_pvrtc_sRGB; +#define GL_EXT_raster_multisample 1 +GLAD_API_CALL int GLAD_GL_EXT_raster_multisample; +#define GL_EXT_read_format_bgra 1 +GLAD_API_CALL int GLAD_GL_EXT_read_format_bgra; +#define GL_EXT_render_snorm 1 +GLAD_API_CALL int GLAD_GL_EXT_render_snorm; +#define GL_EXT_robustness 1 +GLAD_API_CALL int GLAD_GL_EXT_robustness; +#define GL_EXT_sRGB 1 +GLAD_API_CALL int GLAD_GL_EXT_sRGB; +#define GL_EXT_sRGB_write_control 1 +GLAD_API_CALL int GLAD_GL_EXT_sRGB_write_control; +#define GL_EXT_semaphore 1 +GLAD_API_CALL int GLAD_GL_EXT_semaphore; +#define GL_EXT_semaphore_fd 1 +GLAD_API_CALL int GLAD_GL_EXT_semaphore_fd; +#define GL_EXT_semaphore_win32 1 +GLAD_API_CALL int GLAD_GL_EXT_semaphore_win32; +#define GL_EXT_separate_depth_stencil 1 +GLAD_API_CALL int GLAD_GL_EXT_separate_depth_stencil; +#define GL_EXT_separate_shader_objects 1 +GLAD_API_CALL int GLAD_GL_EXT_separate_shader_objects; +#define GL_EXT_shader_framebuffer_fetch 1 +GLAD_API_CALL int GLAD_GL_EXT_shader_framebuffer_fetch; +#define GL_EXT_shader_framebuffer_fetch_non_coherent 1 +GLAD_API_CALL int GLAD_GL_EXT_shader_framebuffer_fetch_non_coherent; +#define GL_EXT_shader_group_vote 1 +GLAD_API_CALL int GLAD_GL_EXT_shader_group_vote; +#define GL_EXT_shader_implicit_conversions 1 +GLAD_API_CALL int GLAD_GL_EXT_shader_implicit_conversions; +#define GL_EXT_shader_integer_mix 1 +GLAD_API_CALL int GLAD_GL_EXT_shader_integer_mix; +#define GL_EXT_shader_io_blocks 1 +GLAD_API_CALL int GLAD_GL_EXT_shader_io_blocks; +#define GL_EXT_shader_non_constant_global_initializers 1 +GLAD_API_CALL int GLAD_GL_EXT_shader_non_constant_global_initializers; +#define GL_EXT_shader_pixel_local_storage 1 +GLAD_API_CALL int GLAD_GL_EXT_shader_pixel_local_storage; +#define GL_EXT_shader_pixel_local_storage2 1 +GLAD_API_CALL int GLAD_GL_EXT_shader_pixel_local_storage2; +#define GL_EXT_shader_samples_identical 1 +GLAD_API_CALL int GLAD_GL_EXT_shader_samples_identical; +#define GL_EXT_shader_texture_lod 1 +GLAD_API_CALL int GLAD_GL_EXT_shader_texture_lod; +#define GL_EXT_shadow_samplers 1 +GLAD_API_CALL int GLAD_GL_EXT_shadow_samplers; +#define GL_EXT_sparse_texture 1 +GLAD_API_CALL int GLAD_GL_EXT_sparse_texture; +#define GL_EXT_sparse_texture2 1 +GLAD_API_CALL int GLAD_GL_EXT_sparse_texture2; +#define GL_EXT_tessellation_point_size 1 +GLAD_API_CALL int GLAD_GL_EXT_tessellation_point_size; +#define GL_EXT_tessellation_shader 1 +GLAD_API_CALL int GLAD_GL_EXT_tessellation_shader; +#define GL_EXT_texture_border_clamp 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_border_clamp; +#define GL_EXT_texture_buffer 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_buffer; +#define GL_EXT_texture_compression_astc_decode_mode 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_compression_astc_decode_mode; +#define GL_EXT_texture_compression_bptc 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_compression_bptc; +#define GL_EXT_texture_compression_dxt1 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_compression_dxt1; +#define GL_EXT_texture_compression_rgtc 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_compression_rgtc; +#define GL_EXT_texture_compression_s3tc 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_compression_s3tc; +#define GL_EXT_texture_compression_s3tc_srgb 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_compression_s3tc_srgb; +#define GL_EXT_texture_cube_map_array 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_cube_map_array; +#define GL_EXT_texture_filter_anisotropic 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_filter_anisotropic; +#define GL_EXT_texture_filter_minmax 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_filter_minmax; +#define GL_EXT_texture_format_BGRA8888 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_format_BGRA8888; +#define GL_EXT_texture_format_sRGB_override 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_format_sRGB_override; +#define GL_EXT_texture_mirror_clamp_to_edge 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_mirror_clamp_to_edge; +#define GL_EXT_texture_norm16 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_norm16; +#define GL_EXT_texture_query_lod 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_query_lod; +#define GL_EXT_texture_rg 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_rg; +#define GL_EXT_texture_sRGB_R8 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_sRGB_R8; +#define GL_EXT_texture_sRGB_RG8 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_sRGB_RG8; +#define GL_EXT_texture_sRGB_decode 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_sRGB_decode; +#define GL_EXT_texture_shadow_lod 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_shadow_lod; +#define GL_EXT_texture_storage 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_storage; +#define GL_EXT_texture_storage_compression 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_storage_compression; +#define GL_EXT_texture_type_2_10_10_10_REV 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_type_2_10_10_10_REV; +#define GL_EXT_texture_view 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_view; +#define GL_EXT_unpack_subimage 1 +GLAD_API_CALL int GLAD_GL_EXT_unpack_subimage; +#define GL_EXT_win32_keyed_mutex 1 +GLAD_API_CALL int GLAD_GL_EXT_win32_keyed_mutex; +#define GL_EXT_window_rectangles 1 +GLAD_API_CALL int GLAD_GL_EXT_window_rectangles; +#define GL_KHR_blend_equation_advanced 1 +GLAD_API_CALL int GLAD_GL_KHR_blend_equation_advanced; +#define GL_KHR_blend_equation_advanced_coherent 1 +GLAD_API_CALL int GLAD_GL_KHR_blend_equation_advanced_coherent; +#define GL_KHR_context_flush_control 1 +GLAD_API_CALL int GLAD_GL_KHR_context_flush_control; +#define GL_KHR_debug 1 +GLAD_API_CALL int GLAD_GL_KHR_debug; +#define GL_KHR_no_error 1 +GLAD_API_CALL int GLAD_GL_KHR_no_error; +#define GL_KHR_parallel_shader_compile 1 +GLAD_API_CALL int GLAD_GL_KHR_parallel_shader_compile; +#define GL_KHR_robust_buffer_access_behavior 1 +GLAD_API_CALL int GLAD_GL_KHR_robust_buffer_access_behavior; +#define GL_KHR_robustness 1 +GLAD_API_CALL int GLAD_GL_KHR_robustness; +#define GL_KHR_shader_subgroup 1 +GLAD_API_CALL int GLAD_GL_KHR_shader_subgroup; +#define GL_KHR_texture_compression_astc_hdr 1 +GLAD_API_CALL int GLAD_GL_KHR_texture_compression_astc_hdr; +#define GL_KHR_texture_compression_astc_ldr 1 +GLAD_API_CALL int GLAD_GL_KHR_texture_compression_astc_ldr; +#define GL_KHR_texture_compression_astc_sliced_3d 1 +GLAD_API_CALL int GLAD_GL_KHR_texture_compression_astc_sliced_3d; +#define GL_OES_EGL_image 1 +GLAD_API_CALL int GLAD_GL_OES_EGL_image; +#define GL_OES_EGL_image_external 1 +GLAD_API_CALL int GLAD_GL_OES_EGL_image_external; +#define GL_OES_EGL_image_external_essl3 1 +GLAD_API_CALL int GLAD_GL_OES_EGL_image_external_essl3; +#define GL_OES_compressed_ETC1_RGB8_sub_texture 1 +GLAD_API_CALL int GLAD_GL_OES_compressed_ETC1_RGB8_sub_texture; +#define GL_OES_compressed_ETC1_RGB8_texture 1 +GLAD_API_CALL int GLAD_GL_OES_compressed_ETC1_RGB8_texture; +#define GL_OES_compressed_paletted_texture 1 +GLAD_API_CALL int GLAD_GL_OES_compressed_paletted_texture; +#define GL_OES_copy_image 1 +GLAD_API_CALL int GLAD_GL_OES_copy_image; +#define GL_OES_depth24 1 +GLAD_API_CALL int GLAD_GL_OES_depth24; +#define GL_OES_depth32 1 +GLAD_API_CALL int GLAD_GL_OES_depth32; +#define GL_OES_depth_texture 1 +GLAD_API_CALL int GLAD_GL_OES_depth_texture; +#define GL_OES_draw_buffers_indexed 1 +GLAD_API_CALL int GLAD_GL_OES_draw_buffers_indexed; +#define GL_OES_draw_elements_base_vertex 1 +GLAD_API_CALL int GLAD_GL_OES_draw_elements_base_vertex; +#define GL_OES_element_index_uint 1 +GLAD_API_CALL int GLAD_GL_OES_element_index_uint; +#define GL_OES_fbo_render_mipmap 1 +GLAD_API_CALL int GLAD_GL_OES_fbo_render_mipmap; +#define GL_OES_fragment_precision_high 1 +GLAD_API_CALL int GLAD_GL_OES_fragment_precision_high; +#define GL_OES_geometry_point_size 1 +GLAD_API_CALL int GLAD_GL_OES_geometry_point_size; +#define GL_OES_geometry_shader 1 +GLAD_API_CALL int GLAD_GL_OES_geometry_shader; +#define GL_OES_get_program_binary 1 +GLAD_API_CALL int GLAD_GL_OES_get_program_binary; +#define GL_OES_gpu_shader5 1 +GLAD_API_CALL int GLAD_GL_OES_gpu_shader5; +#define GL_OES_mapbuffer 1 +GLAD_API_CALL int GLAD_GL_OES_mapbuffer; +#define GL_OES_packed_depth_stencil 1 +GLAD_API_CALL int GLAD_GL_OES_packed_depth_stencil; +#define GL_OES_primitive_bounding_box 1 +GLAD_API_CALL int GLAD_GL_OES_primitive_bounding_box; +#define GL_OES_required_internalformat 1 +GLAD_API_CALL int GLAD_GL_OES_required_internalformat; +#define GL_OES_rgb8_rgba8 1 +GLAD_API_CALL int GLAD_GL_OES_rgb8_rgba8; +#define GL_OES_sample_shading 1 +GLAD_API_CALL int GLAD_GL_OES_sample_shading; +#define GL_OES_sample_variables 1 +GLAD_API_CALL int GLAD_GL_OES_sample_variables; +#define GL_OES_shader_image_atomic 1 +GLAD_API_CALL int GLAD_GL_OES_shader_image_atomic; +#define GL_OES_shader_io_blocks 1 +GLAD_API_CALL int GLAD_GL_OES_shader_io_blocks; +#define GL_OES_shader_multisample_interpolation 1 +GLAD_API_CALL int GLAD_GL_OES_shader_multisample_interpolation; +#define GL_OES_standard_derivatives 1 +GLAD_API_CALL int GLAD_GL_OES_standard_derivatives; +#define GL_OES_stencil1 1 +GLAD_API_CALL int GLAD_GL_OES_stencil1; +#define GL_OES_stencil4 1 +GLAD_API_CALL int GLAD_GL_OES_stencil4; +#define GL_OES_surfaceless_context 1 +GLAD_API_CALL int GLAD_GL_OES_surfaceless_context; +#define GL_OES_tessellation_point_size 1 +GLAD_API_CALL int GLAD_GL_OES_tessellation_point_size; +#define GL_OES_tessellation_shader 1 +GLAD_API_CALL int GLAD_GL_OES_tessellation_shader; +#define GL_OES_texture_3D 1 +GLAD_API_CALL int GLAD_GL_OES_texture_3D; +#define GL_OES_texture_border_clamp 1 +GLAD_API_CALL int GLAD_GL_OES_texture_border_clamp; +#define GL_OES_texture_buffer 1 +GLAD_API_CALL int GLAD_GL_OES_texture_buffer; +#define GL_OES_texture_compression_astc 1 +GLAD_API_CALL int GLAD_GL_OES_texture_compression_astc; +#define GL_OES_texture_cube_map_array 1 +GLAD_API_CALL int GLAD_GL_OES_texture_cube_map_array; +#define GL_OES_texture_float 1 +GLAD_API_CALL int GLAD_GL_OES_texture_float; +#define GL_OES_texture_float_linear 1 +GLAD_API_CALL int GLAD_GL_OES_texture_float_linear; +#define GL_OES_texture_half_float 1 +GLAD_API_CALL int GLAD_GL_OES_texture_half_float; +#define GL_OES_texture_half_float_linear 1 +GLAD_API_CALL int GLAD_GL_OES_texture_half_float_linear; +#define GL_OES_texture_npot 1 +GLAD_API_CALL int GLAD_GL_OES_texture_npot; +#define GL_OES_texture_stencil8 1 +GLAD_API_CALL int GLAD_GL_OES_texture_stencil8; +#define GL_OES_texture_storage_multisample_2d_array 1 +GLAD_API_CALL int GLAD_GL_OES_texture_storage_multisample_2d_array; +#define GL_OES_texture_view 1 +GLAD_API_CALL int GLAD_GL_OES_texture_view; +#define GL_OES_vertex_array_object 1 +GLAD_API_CALL int GLAD_GL_OES_vertex_array_object; +#define GL_OES_vertex_half_float 1 +GLAD_API_CALL int GLAD_GL_OES_vertex_half_float; +#define GL_OES_vertex_type_10_10_10_2 1 +GLAD_API_CALL int GLAD_GL_OES_vertex_type_10_10_10_2; +#define GL_OES_viewport_array 1 +GLAD_API_CALL int GLAD_GL_OES_viewport_array; + + +typedef GLboolean (GLAD_API_PTR *PFNGLACQUIREKEYEDMUTEXWIN32EXTPROC)(GLuint memory, GLuint64 key, GLuint timeout); +typedef void (GLAD_API_PTR *PFNGLACTIVESHADERPROGRAMEXTPROC)(GLuint pipeline, GLuint program); +typedef void (GLAD_API_PTR *PFNGLACTIVETEXTUREPROC)(GLenum texture); +typedef void (GLAD_API_PTR *PFNGLATTACHSHADERPROC)(GLuint program, GLuint shader); +typedef void (GLAD_API_PTR *PFNGLBEGINQUERYEXTPROC)(GLenum target, GLuint id); +typedef void (GLAD_API_PTR *PFNGLBINDATTRIBLOCATIONPROC)(GLuint program, GLuint index, const GLchar * name); +typedef void (GLAD_API_PTR *PFNGLBINDBUFFERPROC)(GLenum target, GLuint buffer); +typedef void (GLAD_API_PTR *PFNGLBINDFRAGDATALOCATIONEXTPROC)(GLuint program, GLuint color, const GLchar * name); +typedef void (GLAD_API_PTR *PFNGLBINDFRAGDATALOCATIONINDEXEDEXTPROC)(GLuint program, GLuint colorNumber, GLuint index, const GLchar * name); +typedef void (GLAD_API_PTR *PFNGLBINDFRAMEBUFFERPROC)(GLenum target, GLuint framebuffer); +typedef void (GLAD_API_PTR *PFNGLBINDPROGRAMPIPELINEEXTPROC)(GLuint pipeline); +typedef void (GLAD_API_PTR *PFNGLBINDRENDERBUFFERPROC)(GLenum target, GLuint renderbuffer); +typedef void (GLAD_API_PTR *PFNGLBINDTEXTUREPROC)(GLenum target, GLuint texture); +typedef void (GLAD_API_PTR *PFNGLBINDVERTEXARRAYOESPROC)(GLuint array); +typedef void (GLAD_API_PTR *PFNGLBLENDBARRIERKHRPROC)(void); +typedef void (GLAD_API_PTR *PFNGLBLENDCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +typedef void (GLAD_API_PTR *PFNGLBLENDEQUATIONPROC)(GLenum mode); +typedef void (GLAD_API_PTR *PFNGLBLENDEQUATIONSEPARATEPROC)(GLenum modeRGB, GLenum modeAlpha); +typedef void (GLAD_API_PTR *PFNGLBLENDEQUATIONSEPARATEIEXTPROC)(GLuint buf, GLenum modeRGB, GLenum modeAlpha); +typedef void (GLAD_API_PTR *PFNGLBLENDEQUATIONSEPARATEIOESPROC)(GLuint buf, GLenum modeRGB, GLenum modeAlpha); +typedef void (GLAD_API_PTR *PFNGLBLENDEQUATIONIEXTPROC)(GLuint buf, GLenum mode); +typedef void (GLAD_API_PTR *PFNGLBLENDEQUATIONIOESPROC)(GLuint buf, GLenum mode); +typedef void (GLAD_API_PTR *PFNGLBLENDFUNCPROC)(GLenum sfactor, GLenum dfactor); +typedef void (GLAD_API_PTR *PFNGLBLENDFUNCSEPARATEPROC)(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); +typedef void (GLAD_API_PTR *PFNGLBLENDFUNCSEPARATEIEXTPROC)(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); +typedef void (GLAD_API_PTR *PFNGLBLENDFUNCSEPARATEIOESPROC)(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); +typedef void (GLAD_API_PTR *PFNGLBLENDFUNCIEXTPROC)(GLuint buf, GLenum src, GLenum dst); +typedef void (GLAD_API_PTR *PFNGLBLENDFUNCIOESPROC)(GLuint buf, GLenum src, GLenum dst); +typedef void (GLAD_API_PTR *PFNGLBUFFERDATAPROC)(GLenum target, GLsizeiptr size, const void * data, GLenum usage); +typedef void (GLAD_API_PTR *PFNGLBUFFERSTORAGEEXTPROC)(GLenum target, GLsizeiptr size, const void * data, GLbitfield flags); +typedef void (GLAD_API_PTR *PFNGLBUFFERSTORAGEEXTERNALEXTPROC)(GLenum target, GLintptr offset, GLsizeiptr size, GLeglClientBufferEXT clientBuffer, GLbitfield flags); +typedef void (GLAD_API_PTR *PFNGLBUFFERSTORAGEMEMEXTPROC)(GLenum target, GLsizeiptr size, GLuint memory, GLuint64 offset); +typedef void (GLAD_API_PTR *PFNGLBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, const void * data); +typedef GLenum (GLAD_API_PTR *PFNGLCHECKFRAMEBUFFERSTATUSPROC)(GLenum target); +typedef void (GLAD_API_PTR *PFNGLCLEARPROC)(GLbitfield mask); +typedef void (GLAD_API_PTR *PFNGLCLEARCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +typedef void (GLAD_API_PTR *PFNGLCLEARDEPTHFPROC)(GLfloat d); +typedef void (GLAD_API_PTR *PFNGLCLEARPIXELLOCALSTORAGEUIEXTPROC)(GLsizei offset, GLsizei n, const GLuint * values); +typedef void (GLAD_API_PTR *PFNGLCLEARSTENCILPROC)(GLint s); +typedef void (GLAD_API_PTR *PFNGLCLEARTEXIMAGEEXTPROC)(GLuint texture, GLint level, GLenum format, GLenum type, const void * data); +typedef void (GLAD_API_PTR *PFNGLCLEARTEXSUBIMAGEEXTPROC)(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void * data); +typedef void (GLAD_API_PTR *PFNGLCLIPCONTROLEXTPROC)(GLenum origin, GLenum depth); +typedef void (GLAD_API_PTR *PFNGLCOLORMASKPROC)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); +typedef void (GLAD_API_PTR *PFNGLCOLORMASKIEXTPROC)(GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); +typedef void (GLAD_API_PTR *PFNGLCOLORMASKIOESPROC)(GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); +typedef void (GLAD_API_PTR *PFNGLCOMPILESHADERPROC)(GLuint shader); +typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void * data); +typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXIMAGE3DOESPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void * data); +typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void * data); +typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXSUBIMAGE3DOESPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void * data); +typedef void (GLAD_API_PTR *PFNGLCOPYIMAGESUBDATAEXTPROC)(GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth); +typedef void (GLAD_API_PTR *PFNGLCOPYIMAGESUBDATAOESPROC)(GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth); +typedef void (GLAD_API_PTR *PFNGLCOPYTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +typedef void (GLAD_API_PTR *PFNGLCOPYTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (GLAD_API_PTR *PFNGLCOPYTEXSUBIMAGE3DOESPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (GLAD_API_PTR *PFNGLCREATEMEMORYOBJECTSEXTPROC)(GLsizei n, GLuint * memoryObjects); +typedef GLuint (GLAD_API_PTR *PFNGLCREATEPROGRAMPROC)(void); +typedef GLuint (GLAD_API_PTR *PFNGLCREATESHADERPROC)(GLenum type); +typedef GLuint (GLAD_API_PTR *PFNGLCREATESHADERPROGRAMVEXTPROC)(GLenum type, GLsizei count, const GLchar *const* strings); +typedef void (GLAD_API_PTR *PFNGLCULLFACEPROC)(GLenum mode); +typedef void (GLAD_API_PTR *PFNGLDEBUGMESSAGECALLBACKKHRPROC)(GLDEBUGPROCKHR callback, const void * userParam); +typedef void (GLAD_API_PTR *PFNGLDEBUGMESSAGECONTROLKHRPROC)(GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint * ids, GLboolean enabled); +typedef void (GLAD_API_PTR *PFNGLDEBUGMESSAGEINSERTKHRPROC)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar * buf); +typedef void (GLAD_API_PTR *PFNGLDELETEBUFFERSPROC)(GLsizei n, const GLuint * buffers); +typedef void (GLAD_API_PTR *PFNGLDELETEFRAMEBUFFERSPROC)(GLsizei n, const GLuint * framebuffers); +typedef void (GLAD_API_PTR *PFNGLDELETEMEMORYOBJECTSEXTPROC)(GLsizei n, const GLuint * memoryObjects); +typedef void (GLAD_API_PTR *PFNGLDELETEPROGRAMPROC)(GLuint program); +typedef void (GLAD_API_PTR *PFNGLDELETEPROGRAMPIPELINESEXTPROC)(GLsizei n, const GLuint * pipelines); +typedef void (GLAD_API_PTR *PFNGLDELETEQUERIESEXTPROC)(GLsizei n, const GLuint * ids); +typedef void (GLAD_API_PTR *PFNGLDELETERENDERBUFFERSPROC)(GLsizei n, const GLuint * renderbuffers); +typedef void (GLAD_API_PTR *PFNGLDELETESEMAPHORESEXTPROC)(GLsizei n, const GLuint * semaphores); +typedef void (GLAD_API_PTR *PFNGLDELETESHADERPROC)(GLuint shader); +typedef void (GLAD_API_PTR *PFNGLDELETETEXTURESPROC)(GLsizei n, const GLuint * textures); +typedef void (GLAD_API_PTR *PFNGLDELETEVERTEXARRAYSOESPROC)(GLsizei n, const GLuint * arrays); +typedef void (GLAD_API_PTR *PFNGLDEPTHFUNCPROC)(GLenum func); +typedef void (GLAD_API_PTR *PFNGLDEPTHMASKPROC)(GLboolean flag); +typedef void (GLAD_API_PTR *PFNGLDEPTHRANGEARRAYFVOESPROC)(GLuint first, GLsizei count, const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLDEPTHRANGEINDEXEDFOESPROC)(GLuint index, GLfloat n, GLfloat f); +typedef void (GLAD_API_PTR *PFNGLDEPTHRANGEFPROC)(GLfloat n, GLfloat f); +typedef void (GLAD_API_PTR *PFNGLDETACHSHADERPROC)(GLuint program, GLuint shader); +typedef void (GLAD_API_PTR *PFNGLDISABLEPROC)(GLenum cap); +typedef void (GLAD_API_PTR *PFNGLDISABLEVERTEXATTRIBARRAYPROC)(GLuint index); +typedef void (GLAD_API_PTR *PFNGLDISABLEIEXTPROC)(GLenum target, GLuint index); +typedef void (GLAD_API_PTR *PFNGLDISABLEIOESPROC)(GLenum target, GLuint index); +typedef void (GLAD_API_PTR *PFNGLDISCARDFRAMEBUFFEREXTPROC)(GLenum target, GLsizei numAttachments, const GLenum * attachments); +typedef void (GLAD_API_PTR *PFNGLDRAWARRAYSPROC)(GLenum mode, GLint first, GLsizei count); +typedef void (GLAD_API_PTR *PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEEXTPROC)(GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance); +typedef void (GLAD_API_PTR *PFNGLDRAWARRAYSINSTANCEDEXTPROC)(GLenum mode, GLint start, GLsizei count, GLsizei primcount); +typedef void (GLAD_API_PTR *PFNGLDRAWBUFFERSEXTPROC)(GLsizei n, const GLenum * bufs); +typedef void (GLAD_API_PTR *PFNGLDRAWBUFFERSINDEXEDEXTPROC)(GLint n, const GLenum * location, const GLint * indices); +typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices); +typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSBASEVERTEXEXTPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices, GLint basevertex); +typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSBASEVERTEXOESPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices, GLint basevertex); +typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEEXTPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices, GLsizei instancecount, GLuint baseinstance); +typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEEXTPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance); +typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXEXTPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices, GLsizei instancecount, GLint basevertex); +typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXOESPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices, GLsizei instancecount, GLint basevertex); +typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSINSTANCEDEXTPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices, GLsizei primcount); +typedef void (GLAD_API_PTR *PFNGLDRAWRANGEELEMENTSBASEVERTEXEXTPROC)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void * indices, GLint basevertex); +typedef void (GLAD_API_PTR *PFNGLDRAWRANGEELEMENTSBASEVERTEXOESPROC)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void * indices, GLint basevertex); +typedef void (GLAD_API_PTR *PFNGLDRAWTRANSFORMFEEDBACKEXTPROC)(GLenum mode, GLuint id); +typedef void (GLAD_API_PTR *PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDEXTPROC)(GLenum mode, GLuint id, GLsizei instancecount); +typedef void (GLAD_API_PTR *PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC)(GLenum target, GLeglImageOES image); +typedef void (GLAD_API_PTR *PFNGLEGLIMAGETARGETTEXSTORAGEEXTPROC)(GLenum target, GLeglImageOES image, const GLint * attrib_list); +typedef void (GLAD_API_PTR *PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)(GLenum target, GLeglImageOES image); +typedef void (GLAD_API_PTR *PFNGLEGLIMAGETARGETTEXTURESTORAGEEXTPROC)(GLuint texture, GLeglImageOES image, const GLint * attrib_list); +typedef void (GLAD_API_PTR *PFNGLENABLEPROC)(GLenum cap); +typedef void (GLAD_API_PTR *PFNGLENABLEVERTEXATTRIBARRAYPROC)(GLuint index); +typedef void (GLAD_API_PTR *PFNGLENABLEIEXTPROC)(GLenum target, GLuint index); +typedef void (GLAD_API_PTR *PFNGLENABLEIOESPROC)(GLenum target, GLuint index); +typedef void (GLAD_API_PTR *PFNGLENDQUERYEXTPROC)(GLenum target); +typedef void (GLAD_API_PTR *PFNGLFINISHPROC)(void); +typedef void (GLAD_API_PTR *PFNGLFLUSHPROC)(void); +typedef void (GLAD_API_PTR *PFNGLFLUSHMAPPEDBUFFERRANGEEXTPROC)(GLenum target, GLintptr offset, GLsizeiptr length); +typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERFETCHBARRIEREXTPROC)(void); +typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC)(GLuint target, GLsizei size); +typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERRENDERBUFFERPROC)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERSHADINGRATEEXTPROC)(GLenum target, GLenum attachment, GLuint texture, GLint baseLayer, GLsizei numLayers, GLsizei texelWidth, GLsizei texelHeight); +typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURE2DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples); +typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURE3DOESPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); +typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTUREEXTPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level); +typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTUREOESPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level); +typedef void (GLAD_API_PTR *PFNGLFRONTFACEPROC)(GLenum mode); +typedef void (GLAD_API_PTR *PFNGLGENBUFFERSPROC)(GLsizei n, GLuint * buffers); +typedef void (GLAD_API_PTR *PFNGLGENFRAMEBUFFERSPROC)(GLsizei n, GLuint * framebuffers); +typedef void (GLAD_API_PTR *PFNGLGENPROGRAMPIPELINESEXTPROC)(GLsizei n, GLuint * pipelines); +typedef void (GLAD_API_PTR *PFNGLGENQUERIESEXTPROC)(GLsizei n, GLuint * ids); +typedef void (GLAD_API_PTR *PFNGLGENRENDERBUFFERSPROC)(GLsizei n, GLuint * renderbuffers); +typedef void (GLAD_API_PTR *PFNGLGENSEMAPHORESEXTPROC)(GLsizei n, GLuint * semaphores); +typedef void (GLAD_API_PTR *PFNGLGENTEXTURESPROC)(GLsizei n, GLuint * textures); +typedef void (GLAD_API_PTR *PFNGLGENVERTEXARRAYSOESPROC)(GLsizei n, GLuint * arrays); +typedef void (GLAD_API_PTR *PFNGLGENERATEMIPMAPPROC)(GLenum target); +typedef void (GLAD_API_PTR *PFNGLGETACTIVEATTRIBPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei * length, GLint * size, GLenum * type, GLchar * name); +typedef void (GLAD_API_PTR *PFNGLGETACTIVEUNIFORMPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei * length, GLint * size, GLenum * type, GLchar * name); +typedef void (GLAD_API_PTR *PFNGLGETATTACHEDSHADERSPROC)(GLuint program, GLsizei maxCount, GLsizei * count, GLuint * shaders); +typedef GLint (GLAD_API_PTR *PFNGLGETATTRIBLOCATIONPROC)(GLuint program, const GLchar * name); +typedef void (GLAD_API_PTR *PFNGLGETBOOLEANVPROC)(GLenum pname, GLboolean * data); +typedef void (GLAD_API_PTR *PFNGLGETBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETBUFFERPOINTERVOESPROC)(GLenum target, GLenum pname, void ** params); +typedef GLuint (GLAD_API_PTR *PFNGLGETDEBUGMESSAGELOGKHRPROC)(GLuint count, GLsizei bufSize, GLenum * sources, GLenum * types, GLuint * ids, GLenum * severities, GLsizei * lengths, GLchar * messageLog); +typedef GLenum (GLAD_API_PTR *PFNGLGETERRORPROC)(void); +typedef void (GLAD_API_PTR *PFNGLGETFLOATI_VOESPROC)(GLenum target, GLuint index, GLfloat * data); +typedef void (GLAD_API_PTR *PFNGLGETFLOATVPROC)(GLenum pname, GLfloat * data); +typedef GLint (GLAD_API_PTR *PFNGLGETFRAGDATAINDEXEXTPROC)(GLuint program, const GLchar * name); +typedef void (GLAD_API_PTR *PFNGLGETFRAGMENTSHADINGRATESEXTPROC)(GLsizei samples, GLsizei maxCount, GLsizei * count, GLenum * shadingRates); +typedef void (GLAD_API_PTR *PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)(GLenum target, GLenum attachment, GLenum pname, GLint * params); +typedef GLsizei (GLAD_API_PTR *PFNGLGETFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC)(GLuint target); +typedef GLenum (GLAD_API_PTR *PFNGLGETGRAPHICSRESETSTATUSEXTPROC)(void); +typedef GLenum (GLAD_API_PTR *PFNGLGETGRAPHICSRESETSTATUSKHRPROC)(void); +typedef void (GLAD_API_PTR *PFNGLGETINTEGER64VEXTPROC)(GLenum pname, GLint64 * data); +typedef void (GLAD_API_PTR *PFNGLGETINTEGERI_VEXTPROC)(GLenum target, GLuint index, GLint * data); +typedef void (GLAD_API_PTR *PFNGLGETINTEGERVPROC)(GLenum pname, GLint * data); +typedef void (GLAD_API_PTR *PFNGLGETMEMORYOBJECTPARAMETERIVEXTPROC)(GLuint memoryObject, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETOBJECTLABELEXTPROC)(GLenum type, GLuint object, GLsizei bufSize, GLsizei * length, GLchar * label); +typedef void (GLAD_API_PTR *PFNGLGETOBJECTLABELKHRPROC)(GLenum identifier, GLuint name, GLsizei bufSize, GLsizei * length, GLchar * label); +typedef void (GLAD_API_PTR *PFNGLGETOBJECTPTRLABELKHRPROC)(const void * ptr, GLsizei bufSize, GLsizei * length, GLchar * label); +typedef void (GLAD_API_PTR *PFNGLGETPOINTERVKHRPROC)(GLenum pname, void ** params); +typedef void (GLAD_API_PTR *PFNGLGETPROGRAMBINARYOESPROC)(GLuint program, GLsizei bufSize, GLsizei * length, GLenum * binaryFormat, void * binary); +typedef void (GLAD_API_PTR *PFNGLGETPROGRAMINFOLOGPROC)(GLuint program, GLsizei bufSize, GLsizei * length, GLchar * infoLog); +typedef void (GLAD_API_PTR *PFNGLGETPROGRAMPIPELINEINFOLOGEXTPROC)(GLuint pipeline, GLsizei bufSize, GLsizei * length, GLchar * infoLog); +typedef void (GLAD_API_PTR *PFNGLGETPROGRAMPIPELINEIVEXTPROC)(GLuint pipeline, GLenum pname, GLint * params); +typedef GLint (GLAD_API_PTR *PFNGLGETPROGRAMRESOURCELOCATIONINDEXEXTPROC)(GLuint program, GLenum programInterface, const GLchar * name); +typedef void (GLAD_API_PTR *PFNGLGETPROGRAMIVPROC)(GLuint program, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETQUERYOBJECTI64VEXTPROC)(GLuint id, GLenum pname, GLint64 * params); +typedef void (GLAD_API_PTR *PFNGLGETQUERYOBJECTIVEXTPROC)(GLuint id, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETQUERYOBJECTUI64VEXTPROC)(GLuint id, GLenum pname, GLuint64 * params); +typedef void (GLAD_API_PTR *PFNGLGETQUERYOBJECTUIVEXTPROC)(GLuint id, GLenum pname, GLuint * params); +typedef void (GLAD_API_PTR *PFNGLGETQUERYIVEXTPROC)(GLenum target, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETRENDERBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETSAMPLERPARAMETERIIVEXTPROC)(GLuint sampler, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETSAMPLERPARAMETERIIVOESPROC)(GLuint sampler, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETSAMPLERPARAMETERIUIVEXTPROC)(GLuint sampler, GLenum pname, GLuint * params); +typedef void (GLAD_API_PTR *PFNGLGETSAMPLERPARAMETERIUIVOESPROC)(GLuint sampler, GLenum pname, GLuint * params); +typedef void (GLAD_API_PTR *PFNGLGETSEMAPHOREPARAMETERUI64VEXTPROC)(GLuint semaphore, GLenum pname, GLuint64 * params); +typedef void (GLAD_API_PTR *PFNGLGETSHADERINFOLOGPROC)(GLuint shader, GLsizei bufSize, GLsizei * length, GLchar * infoLog); +typedef void (GLAD_API_PTR *PFNGLGETSHADERPRECISIONFORMATPROC)(GLenum shadertype, GLenum precisiontype, GLint * range, GLint * precision); +typedef void (GLAD_API_PTR *PFNGLGETSHADERSOURCEPROC)(GLuint shader, GLsizei bufSize, GLsizei * length, GLchar * source); +typedef void (GLAD_API_PTR *PFNGLGETSHADERIVPROC)(GLuint shader, GLenum pname, GLint * params); +typedef const GLubyte * (GLAD_API_PTR *PFNGLGETSTRINGPROC)(GLenum name); +typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERIIVEXTPROC)(GLenum target, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERIIVOESPROC)(GLenum target, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERIUIVEXTPROC)(GLenum target, GLenum pname, GLuint * params); +typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERIUIVOESPROC)(GLenum target, GLenum pname, GLuint * params); +typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERFVPROC)(GLenum target, GLenum pname, GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERIVPROC)(GLenum target, GLenum pname, GLint * params); +typedef GLint (GLAD_API_PTR *PFNGLGETUNIFORMLOCATIONPROC)(GLuint program, const GLchar * name); +typedef void (GLAD_API_PTR *PFNGLGETUNIFORMFVPROC)(GLuint program, GLint location, GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLGETUNIFORMIVPROC)(GLuint program, GLint location, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETUNSIGNEDBYTEI_VEXTPROC)(GLenum target, GLuint index, GLubyte * data); +typedef void (GLAD_API_PTR *PFNGLGETUNSIGNEDBYTEVEXTPROC)(GLenum pname, GLubyte * data); +typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBPOINTERVPROC)(GLuint index, GLenum pname, void ** pointer); +typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBFVPROC)(GLuint index, GLenum pname, GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBIVPROC)(GLuint index, GLenum pname, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETNUNIFORMFVEXTPROC)(GLuint program, GLint location, GLsizei bufSize, GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLGETNUNIFORMFVKHRPROC)(GLuint program, GLint location, GLsizei bufSize, GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLGETNUNIFORMIVEXTPROC)(GLuint program, GLint location, GLsizei bufSize, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETNUNIFORMIVKHRPROC)(GLuint program, GLint location, GLsizei bufSize, GLint * params); +typedef void (GLAD_API_PTR *PFNGLGETNUNIFORMUIVKHRPROC)(GLuint program, GLint location, GLsizei bufSize, GLuint * params); +typedef void (GLAD_API_PTR *PFNGLHINTPROC)(GLenum target, GLenum mode); +typedef void (GLAD_API_PTR *PFNGLIMPORTMEMORYFDEXTPROC)(GLuint memory, GLuint64 size, GLenum handleType, GLint fd); +typedef void (GLAD_API_PTR *PFNGLIMPORTMEMORYWIN32HANDLEEXTPROC)(GLuint memory, GLuint64 size, GLenum handleType, void * handle); +typedef void (GLAD_API_PTR *PFNGLIMPORTMEMORYWIN32NAMEEXTPROC)(GLuint memory, GLuint64 size, GLenum handleType, const void * name); +typedef void (GLAD_API_PTR *PFNGLIMPORTSEMAPHOREFDEXTPROC)(GLuint semaphore, GLenum handleType, GLint fd); +typedef void (GLAD_API_PTR *PFNGLIMPORTSEMAPHOREWIN32HANDLEEXTPROC)(GLuint semaphore, GLenum handleType, void * handle); +typedef void (GLAD_API_PTR *PFNGLIMPORTSEMAPHOREWIN32NAMEEXTPROC)(GLuint semaphore, GLenum handleType, const void * name); +typedef void (GLAD_API_PTR *PFNGLINSERTEVENTMARKEREXTPROC)(GLsizei length, const GLchar * marker); +typedef GLboolean (GLAD_API_PTR *PFNGLISBUFFERPROC)(GLuint buffer); +typedef GLboolean (GLAD_API_PTR *PFNGLISENABLEDPROC)(GLenum cap); +typedef GLboolean (GLAD_API_PTR *PFNGLISENABLEDIEXTPROC)(GLenum target, GLuint index); +typedef GLboolean (GLAD_API_PTR *PFNGLISENABLEDIOESPROC)(GLenum target, GLuint index); +typedef GLboolean (GLAD_API_PTR *PFNGLISFRAMEBUFFERPROC)(GLuint framebuffer); +typedef GLboolean (GLAD_API_PTR *PFNGLISMEMORYOBJECTEXTPROC)(GLuint memoryObject); +typedef GLboolean (GLAD_API_PTR *PFNGLISPROGRAMPROC)(GLuint program); +typedef GLboolean (GLAD_API_PTR *PFNGLISPROGRAMPIPELINEEXTPROC)(GLuint pipeline); +typedef GLboolean (GLAD_API_PTR *PFNGLISQUERYEXTPROC)(GLuint id); +typedef GLboolean (GLAD_API_PTR *PFNGLISRENDERBUFFERPROC)(GLuint renderbuffer); +typedef GLboolean (GLAD_API_PTR *PFNGLISSEMAPHOREEXTPROC)(GLuint semaphore); +typedef GLboolean (GLAD_API_PTR *PFNGLISSHADERPROC)(GLuint shader); +typedef GLboolean (GLAD_API_PTR *PFNGLISTEXTUREPROC)(GLuint texture); +typedef GLboolean (GLAD_API_PTR *PFNGLISVERTEXARRAYOESPROC)(GLuint array); +typedef void (GLAD_API_PTR *PFNGLLABELOBJECTEXTPROC)(GLenum type, GLuint object, GLsizei length, const GLchar * label); +typedef void (GLAD_API_PTR *PFNGLLINEWIDTHPROC)(GLfloat width); +typedef void (GLAD_API_PTR *PFNGLLINKPROGRAMPROC)(GLuint program); +typedef void * (GLAD_API_PTR *PFNGLMAPBUFFEROESPROC)(GLenum target, GLenum access); +typedef void * (GLAD_API_PTR *PFNGLMAPBUFFERRANGEEXTPROC)(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); +typedef void (GLAD_API_PTR *PFNGLMAXSHADERCOMPILERTHREADSKHRPROC)(GLuint count); +typedef void (GLAD_API_PTR *PFNGLMEMORYOBJECTPARAMETERIVEXTPROC)(GLuint memoryObject, GLenum pname, const GLint * params); +typedef void (GLAD_API_PTR *PFNGLMINSAMPLESHADINGOESPROC)(GLfloat value); +typedef void (GLAD_API_PTR *PFNGLMULTIDRAWARRAYSEXTPROC)(GLenum mode, const GLint * first, const GLsizei * count, GLsizei primcount); +typedef void (GLAD_API_PTR *PFNGLMULTIDRAWARRAYSINDIRECTEXTPROC)(GLenum mode, const void * indirect, GLsizei drawcount, GLsizei stride); +typedef void (GLAD_API_PTR *PFNGLMULTIDRAWELEMENTSBASEVERTEXEXTPROC)(GLenum mode, const GLsizei * count, GLenum type, const void *const* indices, GLsizei drawcount, const GLint * basevertex); +typedef void (GLAD_API_PTR *PFNGLMULTIDRAWELEMENTSEXTPROC)(GLenum mode, const GLsizei * count, GLenum type, const void *const* indices, GLsizei primcount); +typedef void (GLAD_API_PTR *PFNGLMULTIDRAWELEMENTSINDIRECTEXTPROC)(GLenum mode, GLenum type, const void * indirect, GLsizei drawcount, GLsizei stride); +typedef void (GLAD_API_PTR *PFNGLNAMEDBUFFERSTORAGEEXTERNALEXTPROC)(GLuint buffer, GLintptr offset, GLsizeiptr size, GLeglClientBufferEXT clientBuffer, GLbitfield flags); +typedef void (GLAD_API_PTR *PFNGLNAMEDBUFFERSTORAGEMEMEXTPROC)(GLuint buffer, GLsizeiptr size, GLuint memory, GLuint64 offset); +typedef void (GLAD_API_PTR *PFNGLOBJECTLABELKHRPROC)(GLenum identifier, GLuint name, GLsizei length, const GLchar * label); +typedef void (GLAD_API_PTR *PFNGLOBJECTPTRLABELKHRPROC)(const void * ptr, GLsizei length, const GLchar * label); +typedef void (GLAD_API_PTR *PFNGLPATCHPARAMETERIEXTPROC)(GLenum pname, GLint value); +typedef void (GLAD_API_PTR *PFNGLPATCHPARAMETERIOESPROC)(GLenum pname, GLint value); +typedef void (GLAD_API_PTR *PFNGLPIXELSTOREIPROC)(GLenum pname, GLint param); +typedef void (GLAD_API_PTR *PFNGLPOLYGONOFFSETPROC)(GLfloat factor, GLfloat units); +typedef void (GLAD_API_PTR *PFNGLPOLYGONOFFSETCLAMPEXTPROC)(GLfloat factor, GLfloat units, GLfloat clamp); +typedef void (GLAD_API_PTR *PFNGLPOPDEBUGGROUPKHRPROC)(void); +typedef void (GLAD_API_PTR *PFNGLPOPGROUPMARKEREXTPROC)(void); +typedef void (GLAD_API_PTR *PFNGLPRIMITIVEBOUNDINGBOXEXTPROC)(GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW); +typedef void (GLAD_API_PTR *PFNGLPRIMITIVEBOUNDINGBOXOESPROC)(GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW); +typedef void (GLAD_API_PTR *PFNGLPROGRAMBINARYOESPROC)(GLuint program, GLenum binaryFormat, const void * binary, GLint length); +typedef void (GLAD_API_PTR *PFNGLPROGRAMPARAMETERIEXTPROC)(GLuint program, GLenum pname, GLint value); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1FEXTPROC)(GLuint program, GLint location, GLfloat v0); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1FVEXTPROC)(GLuint program, GLint location, GLsizei count, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1IEXTPROC)(GLuint program, GLint location, GLint v0); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1IVEXTPROC)(GLuint program, GLint location, GLsizei count, const GLint * value); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1UIEXTPROC)(GLuint program, GLint location, GLuint v0); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1UIVEXTPROC)(GLuint program, GLint location, GLsizei count, const GLuint * value); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2FEXTPROC)(GLuint program, GLint location, GLfloat v0, GLfloat v1); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2FVEXTPROC)(GLuint program, GLint location, GLsizei count, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2IEXTPROC)(GLuint program, GLint location, GLint v0, GLint v1); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2IVEXTPROC)(GLuint program, GLint location, GLsizei count, const GLint * value); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2UIEXTPROC)(GLuint program, GLint location, GLuint v0, GLuint v1); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2UIVEXTPROC)(GLuint program, GLint location, GLsizei count, const GLuint * value); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3FEXTPROC)(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3FVEXTPROC)(GLuint program, GLint location, GLsizei count, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3IEXTPROC)(GLuint program, GLint location, GLint v0, GLint v1, GLint v2); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3IVEXTPROC)(GLuint program, GLint location, GLsizei count, const GLint * value); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3UIEXTPROC)(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3UIVEXTPROC)(GLuint program, GLint location, GLsizei count, const GLuint * value); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4FEXTPROC)(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4FVEXTPROC)(GLuint program, GLint location, GLsizei count, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4IEXTPROC)(GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4IVEXTPROC)(GLuint program, GLint location, GLsizei count, const GLint * value); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4UIEXTPROC)(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4UIVEXTPROC)(GLuint program, GLint location, GLsizei count, const GLuint * value); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX2FVEXTPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX3FVEXTPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX4FVEXTPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLPUSHDEBUGGROUPKHRPROC)(GLenum source, GLuint id, GLsizei length, const GLchar * message); +typedef void (GLAD_API_PTR *PFNGLPUSHGROUPMARKEREXTPROC)(GLsizei length, const GLchar * marker); +typedef void (GLAD_API_PTR *PFNGLQUERYCOUNTEREXTPROC)(GLuint id, GLenum target); +typedef void (GLAD_API_PTR *PFNGLRASTERSAMPLESEXTPROC)(GLuint samples, GLboolean fixedsamplelocations); +typedef void (GLAD_API_PTR *PFNGLREADBUFFERINDEXEDEXTPROC)(GLenum src, GLint index); +typedef void (GLAD_API_PTR *PFNGLREADPIXELSPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void * pixels); +typedef void (GLAD_API_PTR *PFNGLREADNPIXELSEXTPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void * data); +typedef void (GLAD_API_PTR *PFNGLREADNPIXELSKHRPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void * data); +typedef GLboolean (GLAD_API_PTR *PFNGLRELEASEKEYEDMUTEXWIN32EXTPROC)(GLuint memory, GLuint64 key); +typedef void (GLAD_API_PTR *PFNGLRELEASESHADERCOMPILERPROC)(void); +typedef void (GLAD_API_PTR *PFNGLRENDERBUFFERSTORAGEPROC)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (GLAD_API_PTR *PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (GLAD_API_PTR *PFNGLSAMPLECOVERAGEPROC)(GLfloat value, GLboolean invert); +typedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERIIVEXTPROC)(GLuint sampler, GLenum pname, const GLint * param); +typedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERIIVOESPROC)(GLuint sampler, GLenum pname, const GLint * param); +typedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERIUIVEXTPROC)(GLuint sampler, GLenum pname, const GLuint * param); +typedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERIUIVOESPROC)(GLuint sampler, GLenum pname, const GLuint * param); +typedef void (GLAD_API_PTR *PFNGLSCISSORPROC)(GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (GLAD_API_PTR *PFNGLSCISSORARRAYVOESPROC)(GLuint first, GLsizei count, const GLint * v); +typedef void (GLAD_API_PTR *PFNGLSCISSORINDEXEDOESPROC)(GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height); +typedef void (GLAD_API_PTR *PFNGLSCISSORINDEXEDVOESPROC)(GLuint index, const GLint * v); +typedef void (GLAD_API_PTR *PFNGLSEMAPHOREPARAMETERUI64VEXTPROC)(GLuint semaphore, GLenum pname, const GLuint64 * params); +typedef void (GLAD_API_PTR *PFNGLSHADERBINARYPROC)(GLsizei count, const GLuint * shaders, GLenum binaryFormat, const void * binary, GLsizei length); +typedef void (GLAD_API_PTR *PFNGLSHADERSOURCEPROC)(GLuint shader, GLsizei count, const GLchar *const* string, const GLint * length); +typedef void (GLAD_API_PTR *PFNGLSHADINGRATECOMBINEROPSEXTPROC)(GLenum combinerOp0, GLenum combinerOp1); +typedef void (GLAD_API_PTR *PFNGLSHADINGRATEEXTPROC)(GLenum rate); +typedef void (GLAD_API_PTR *PFNGLSIGNALSEMAPHOREEXTPROC)(GLuint semaphore, GLuint numBufferBarriers, const GLuint * buffers, GLuint numTextureBarriers, const GLuint * textures, const GLenum * dstLayouts); +typedef void (GLAD_API_PTR *PFNGLSTENCILFUNCPROC)(GLenum func, GLint ref, GLuint mask); +typedef void (GLAD_API_PTR *PFNGLSTENCILFUNCSEPARATEPROC)(GLenum face, GLenum func, GLint ref, GLuint mask); +typedef void (GLAD_API_PTR *PFNGLSTENCILMASKPROC)(GLuint mask); +typedef void (GLAD_API_PTR *PFNGLSTENCILMASKSEPARATEPROC)(GLenum face, GLuint mask); +typedef void (GLAD_API_PTR *PFNGLSTENCILOPPROC)(GLenum fail, GLenum zfail, GLenum zpass); +typedef void (GLAD_API_PTR *PFNGLSTENCILOPSEPARATEPROC)(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); +typedef void (GLAD_API_PTR *PFNGLTEXBUFFEREXTPROC)(GLenum target, GLenum internalformat, GLuint buffer); +typedef void (GLAD_API_PTR *PFNGLTEXBUFFEROESPROC)(GLenum target, GLenum internalformat, GLuint buffer); +typedef void (GLAD_API_PTR *PFNGLTEXBUFFERRANGEEXTPROC)(GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); +typedef void (GLAD_API_PTR *PFNGLTEXBUFFERRANGEOESPROC)(GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); +typedef void (GLAD_API_PTR *PFNGLTEXIMAGE2DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void * pixels); +typedef void (GLAD_API_PTR *PFNGLTEXIMAGE3DOESPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void * pixels); +typedef void (GLAD_API_PTR *PFNGLTEXPAGECOMMITMENTEXTPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean commit); +typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIIVEXTPROC)(GLenum target, GLenum pname, const GLint * params); +typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIIVOESPROC)(GLenum target, GLenum pname, const GLint * params); +typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIUIVEXTPROC)(GLenum target, GLenum pname, const GLuint * params); +typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIUIVOESPROC)(GLenum target, GLenum pname, const GLuint * params); +typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERFPROC)(GLenum target, GLenum pname, GLfloat param); +typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERFVPROC)(GLenum target, GLenum pname, const GLfloat * params); +typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIPROC)(GLenum target, GLenum pname, GLint param); +typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIVPROC)(GLenum target, GLenum pname, const GLint * params); +typedef void (GLAD_API_PTR *PFNGLTEXSTORAGE1DEXTPROC)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); +typedef void (GLAD_API_PTR *PFNGLTEXSTORAGE2DEXTPROC)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (GLAD_API_PTR *PFNGLTEXSTORAGE3DEXTPROC)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); +typedef void (GLAD_API_PTR *PFNGLTEXSTORAGE3DMULTISAMPLEOESPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); +typedef void (GLAD_API_PTR *PFNGLTEXSTORAGEATTRIBS2DEXTPROC)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, const GLint * attrib_list); +typedef void (GLAD_API_PTR *PFNGLTEXSTORAGEATTRIBS3DEXTPROC)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, const GLint * attrib_list); +typedef void (GLAD_API_PTR *PFNGLTEXSTORAGEMEM2DEXTPROC)(GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLuint memory, GLuint64 offset); +typedef void (GLAD_API_PTR *PFNGLTEXSTORAGEMEM2DMULTISAMPLEEXTPROC)(GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset); +typedef void (GLAD_API_PTR *PFNGLTEXSTORAGEMEM3DEXTPROC)(GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLuint memory, GLuint64 offset); +typedef void (GLAD_API_PTR *PFNGLTEXSTORAGEMEM3DMULTISAMPLEEXTPROC)(GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset); +typedef void (GLAD_API_PTR *PFNGLTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void * pixels); +typedef void (GLAD_API_PTR *PFNGLTEXSUBIMAGE3DOESPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void * pixels); +typedef void (GLAD_API_PTR *PFNGLTEXTURESTORAGE1DEXTPROC)(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); +typedef void (GLAD_API_PTR *PFNGLTEXTURESTORAGE2DEXTPROC)(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (GLAD_API_PTR *PFNGLTEXTURESTORAGE3DEXTPROC)(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); +typedef void (GLAD_API_PTR *PFNGLTEXTURESTORAGEMEM2DEXTPROC)(GLuint texture, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLuint memory, GLuint64 offset); +typedef void (GLAD_API_PTR *PFNGLTEXTURESTORAGEMEM2DMULTISAMPLEEXTPROC)(GLuint texture, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset); +typedef void (GLAD_API_PTR *PFNGLTEXTURESTORAGEMEM3DEXTPROC)(GLuint texture, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLuint memory, GLuint64 offset); +typedef void (GLAD_API_PTR *PFNGLTEXTURESTORAGEMEM3DMULTISAMPLEEXTPROC)(GLuint texture, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset); +typedef void (GLAD_API_PTR *PFNGLTEXTUREVIEWEXTPROC)(GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers); +typedef void (GLAD_API_PTR *PFNGLTEXTUREVIEWOESPROC)(GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers); +typedef void (GLAD_API_PTR *PFNGLUNIFORM1FPROC)(GLint location, GLfloat v0); +typedef void (GLAD_API_PTR *PFNGLUNIFORM1FVPROC)(GLint location, GLsizei count, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORM1IPROC)(GLint location, GLint v0); +typedef void (GLAD_API_PTR *PFNGLUNIFORM1IVPROC)(GLint location, GLsizei count, const GLint * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORM2FPROC)(GLint location, GLfloat v0, GLfloat v1); +typedef void (GLAD_API_PTR *PFNGLUNIFORM2FVPROC)(GLint location, GLsizei count, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORM2IPROC)(GLint location, GLint v0, GLint v1); +typedef void (GLAD_API_PTR *PFNGLUNIFORM2IVPROC)(GLint location, GLsizei count, const GLint * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORM3FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +typedef void (GLAD_API_PTR *PFNGLUNIFORM3FVPROC)(GLint location, GLsizei count, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORM3IPROC)(GLint location, GLint v0, GLint v1, GLint v2); +typedef void (GLAD_API_PTR *PFNGLUNIFORM3IVPROC)(GLint location, GLsizei count, const GLint * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORM4FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +typedef void (GLAD_API_PTR *PFNGLUNIFORM4FVPROC)(GLint location, GLsizei count, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORM4IPROC)(GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +typedef void (GLAD_API_PTR *PFNGLUNIFORM4IVPROC)(GLint location, GLsizei count, const GLint * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); +typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); +typedef GLboolean (GLAD_API_PTR *PFNGLUNMAPBUFFEROESPROC)(GLenum target); +typedef void (GLAD_API_PTR *PFNGLUSEPROGRAMPROC)(GLuint program); +typedef void (GLAD_API_PTR *PFNGLUSEPROGRAMSTAGESEXTPROC)(GLuint pipeline, GLbitfield stages, GLuint program); +typedef void (GLAD_API_PTR *PFNGLVALIDATEPROGRAMPROC)(GLuint program); +typedef void (GLAD_API_PTR *PFNGLVALIDATEPROGRAMPIPELINEEXTPROC)(GLuint pipeline); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1FPROC)(GLuint index, GLfloat x); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1FVPROC)(GLuint index, const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2FPROC)(GLuint index, GLfloat x, GLfloat y); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2FVPROC)(GLuint index, const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3FVPROC)(GLuint index, const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4FVPROC)(GLuint index, const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBDIVISOREXTPROC)(GLuint index, GLuint divisor); +typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBPOINTERPROC)(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void * pointer); +typedef void (GLAD_API_PTR *PFNGLVIEWPORTPROC)(GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (GLAD_API_PTR *PFNGLVIEWPORTARRAYVOESPROC)(GLuint first, GLsizei count, const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLVIEWPORTINDEXEDFOESPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h); +typedef void (GLAD_API_PTR *PFNGLVIEWPORTINDEXEDFVOESPROC)(GLuint index, const GLfloat * v); +typedef void (GLAD_API_PTR *PFNGLWAITSEMAPHOREEXTPROC)(GLuint semaphore, GLuint numBufferBarriers, const GLuint * buffers, GLuint numTextureBarriers, const GLuint * textures, const GLenum * srcLayouts); +typedef void (GLAD_API_PTR *PFNGLWINDOWRECTANGLESEXTPROC)(GLenum mode, GLsizei count, const GLint * box); + +GLAD_API_CALL PFNGLACQUIREKEYEDMUTEXWIN32EXTPROC glad_glAcquireKeyedMutexWin32EXT; +#define glAcquireKeyedMutexWin32EXT glad_glAcquireKeyedMutexWin32EXT +GLAD_API_CALL PFNGLACTIVESHADERPROGRAMEXTPROC glad_glActiveShaderProgramEXT; +#define glActiveShaderProgramEXT glad_glActiveShaderProgramEXT +GLAD_API_CALL PFNGLACTIVETEXTUREPROC glad_glActiveTexture; +#define glActiveTexture glad_glActiveTexture +GLAD_API_CALL PFNGLATTACHSHADERPROC glad_glAttachShader; +#define glAttachShader glad_glAttachShader +GLAD_API_CALL PFNGLBEGINQUERYEXTPROC glad_glBeginQueryEXT; +#define glBeginQueryEXT glad_glBeginQueryEXT +GLAD_API_CALL PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation; +#define glBindAttribLocation glad_glBindAttribLocation +GLAD_API_CALL PFNGLBINDBUFFERPROC glad_glBindBuffer; +#define glBindBuffer glad_glBindBuffer +GLAD_API_CALL PFNGLBINDFRAGDATALOCATIONEXTPROC glad_glBindFragDataLocationEXT; +#define glBindFragDataLocationEXT glad_glBindFragDataLocationEXT +GLAD_API_CALL PFNGLBINDFRAGDATALOCATIONINDEXEDEXTPROC glad_glBindFragDataLocationIndexedEXT; +#define glBindFragDataLocationIndexedEXT glad_glBindFragDataLocationIndexedEXT +GLAD_API_CALL PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer; +#define glBindFramebuffer glad_glBindFramebuffer +GLAD_API_CALL PFNGLBINDPROGRAMPIPELINEEXTPROC glad_glBindProgramPipelineEXT; +#define glBindProgramPipelineEXT glad_glBindProgramPipelineEXT +GLAD_API_CALL PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer; +#define glBindRenderbuffer glad_glBindRenderbuffer +GLAD_API_CALL PFNGLBINDTEXTUREPROC glad_glBindTexture; +#define glBindTexture glad_glBindTexture +GLAD_API_CALL PFNGLBINDVERTEXARRAYOESPROC glad_glBindVertexArrayOES; +#define glBindVertexArrayOES glad_glBindVertexArrayOES +GLAD_API_CALL PFNGLBLENDBARRIERKHRPROC glad_glBlendBarrierKHR; +#define glBlendBarrierKHR glad_glBlendBarrierKHR +GLAD_API_CALL PFNGLBLENDCOLORPROC glad_glBlendColor; +#define glBlendColor glad_glBlendColor +GLAD_API_CALL PFNGLBLENDEQUATIONPROC glad_glBlendEquation; +#define glBlendEquation glad_glBlendEquation +GLAD_API_CALL PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate; +#define glBlendEquationSeparate glad_glBlendEquationSeparate +GLAD_API_CALL PFNGLBLENDEQUATIONSEPARATEIEXTPROC glad_glBlendEquationSeparateiEXT; +#define glBlendEquationSeparateiEXT glad_glBlendEquationSeparateiEXT +GLAD_API_CALL PFNGLBLENDEQUATIONSEPARATEIOESPROC glad_glBlendEquationSeparateiOES; +#define glBlendEquationSeparateiOES glad_glBlendEquationSeparateiOES +GLAD_API_CALL PFNGLBLENDEQUATIONIEXTPROC glad_glBlendEquationiEXT; +#define glBlendEquationiEXT glad_glBlendEquationiEXT +GLAD_API_CALL PFNGLBLENDEQUATIONIOESPROC glad_glBlendEquationiOES; +#define glBlendEquationiOES glad_glBlendEquationiOES +GLAD_API_CALL PFNGLBLENDFUNCPROC glad_glBlendFunc; +#define glBlendFunc glad_glBlendFunc +GLAD_API_CALL PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate; +#define glBlendFuncSeparate glad_glBlendFuncSeparate +GLAD_API_CALL PFNGLBLENDFUNCSEPARATEIEXTPROC glad_glBlendFuncSeparateiEXT; +#define glBlendFuncSeparateiEXT glad_glBlendFuncSeparateiEXT +GLAD_API_CALL PFNGLBLENDFUNCSEPARATEIOESPROC glad_glBlendFuncSeparateiOES; +#define glBlendFuncSeparateiOES glad_glBlendFuncSeparateiOES +GLAD_API_CALL PFNGLBLENDFUNCIEXTPROC glad_glBlendFunciEXT; +#define glBlendFunciEXT glad_glBlendFunciEXT +GLAD_API_CALL PFNGLBLENDFUNCIOESPROC glad_glBlendFunciOES; +#define glBlendFunciOES glad_glBlendFunciOES +GLAD_API_CALL PFNGLBUFFERDATAPROC glad_glBufferData; +#define glBufferData glad_glBufferData +GLAD_API_CALL PFNGLBUFFERSTORAGEEXTPROC glad_glBufferStorageEXT; +#define glBufferStorageEXT glad_glBufferStorageEXT +GLAD_API_CALL PFNGLBUFFERSTORAGEEXTERNALEXTPROC glad_glBufferStorageExternalEXT; +#define glBufferStorageExternalEXT glad_glBufferStorageExternalEXT +GLAD_API_CALL PFNGLBUFFERSTORAGEMEMEXTPROC glad_glBufferStorageMemEXT; +#define glBufferStorageMemEXT glad_glBufferStorageMemEXT +GLAD_API_CALL PFNGLBUFFERSUBDATAPROC glad_glBufferSubData; +#define glBufferSubData glad_glBufferSubData +GLAD_API_CALL PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus; +#define glCheckFramebufferStatus glad_glCheckFramebufferStatus +GLAD_API_CALL PFNGLCLEARPROC glad_glClear; +#define glClear glad_glClear +GLAD_API_CALL PFNGLCLEARCOLORPROC glad_glClearColor; +#define glClearColor glad_glClearColor +GLAD_API_CALL PFNGLCLEARDEPTHFPROC glad_glClearDepthf; +#define glClearDepthf glad_glClearDepthf +GLAD_API_CALL PFNGLCLEARPIXELLOCALSTORAGEUIEXTPROC glad_glClearPixelLocalStorageuiEXT; +#define glClearPixelLocalStorageuiEXT glad_glClearPixelLocalStorageuiEXT +GLAD_API_CALL PFNGLCLEARSTENCILPROC glad_glClearStencil; +#define glClearStencil glad_glClearStencil +GLAD_API_CALL PFNGLCLEARTEXIMAGEEXTPROC glad_glClearTexImageEXT; +#define glClearTexImageEXT glad_glClearTexImageEXT +GLAD_API_CALL PFNGLCLEARTEXSUBIMAGEEXTPROC glad_glClearTexSubImageEXT; +#define glClearTexSubImageEXT glad_glClearTexSubImageEXT +GLAD_API_CALL PFNGLCLIPCONTROLEXTPROC glad_glClipControlEXT; +#define glClipControlEXT glad_glClipControlEXT +GLAD_API_CALL PFNGLCOLORMASKPROC glad_glColorMask; +#define glColorMask glad_glColorMask +GLAD_API_CALL PFNGLCOLORMASKIEXTPROC glad_glColorMaskiEXT; +#define glColorMaskiEXT glad_glColorMaskiEXT +GLAD_API_CALL PFNGLCOLORMASKIOESPROC glad_glColorMaskiOES; +#define glColorMaskiOES glad_glColorMaskiOES +GLAD_API_CALL PFNGLCOMPILESHADERPROC glad_glCompileShader; +#define glCompileShader glad_glCompileShader +GLAD_API_CALL PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D; +#define glCompressedTexImage2D glad_glCompressedTexImage2D +GLAD_API_CALL PFNGLCOMPRESSEDTEXIMAGE3DOESPROC glad_glCompressedTexImage3DOES; +#define glCompressedTexImage3DOES glad_glCompressedTexImage3DOES +GLAD_API_CALL PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D; +#define glCompressedTexSubImage2D glad_glCompressedTexSubImage2D +GLAD_API_CALL PFNGLCOMPRESSEDTEXSUBIMAGE3DOESPROC glad_glCompressedTexSubImage3DOES; +#define glCompressedTexSubImage3DOES glad_glCompressedTexSubImage3DOES +GLAD_API_CALL PFNGLCOPYIMAGESUBDATAEXTPROC glad_glCopyImageSubDataEXT; +#define glCopyImageSubDataEXT glad_glCopyImageSubDataEXT +GLAD_API_CALL PFNGLCOPYIMAGESUBDATAOESPROC glad_glCopyImageSubDataOES; +#define glCopyImageSubDataOES glad_glCopyImageSubDataOES +GLAD_API_CALL PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D; +#define glCopyTexImage2D glad_glCopyTexImage2D +GLAD_API_CALL PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D; +#define glCopyTexSubImage2D glad_glCopyTexSubImage2D +GLAD_API_CALL PFNGLCOPYTEXSUBIMAGE3DOESPROC glad_glCopyTexSubImage3DOES; +#define glCopyTexSubImage3DOES glad_glCopyTexSubImage3DOES +GLAD_API_CALL PFNGLCREATEMEMORYOBJECTSEXTPROC glad_glCreateMemoryObjectsEXT; +#define glCreateMemoryObjectsEXT glad_glCreateMemoryObjectsEXT +GLAD_API_CALL PFNGLCREATEPROGRAMPROC glad_glCreateProgram; +#define glCreateProgram glad_glCreateProgram +GLAD_API_CALL PFNGLCREATESHADERPROC glad_glCreateShader; +#define glCreateShader glad_glCreateShader +GLAD_API_CALL PFNGLCREATESHADERPROGRAMVEXTPROC glad_glCreateShaderProgramvEXT; +#define glCreateShaderProgramvEXT glad_glCreateShaderProgramvEXT +GLAD_API_CALL PFNGLCULLFACEPROC glad_glCullFace; +#define glCullFace glad_glCullFace +GLAD_API_CALL PFNGLDEBUGMESSAGECALLBACKKHRPROC glad_glDebugMessageCallbackKHR; +#define glDebugMessageCallbackKHR glad_glDebugMessageCallbackKHR +GLAD_API_CALL PFNGLDEBUGMESSAGECONTROLKHRPROC glad_glDebugMessageControlKHR; +#define glDebugMessageControlKHR glad_glDebugMessageControlKHR +GLAD_API_CALL PFNGLDEBUGMESSAGEINSERTKHRPROC glad_glDebugMessageInsertKHR; +#define glDebugMessageInsertKHR glad_glDebugMessageInsertKHR +GLAD_API_CALL PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers; +#define glDeleteBuffers glad_glDeleteBuffers +GLAD_API_CALL PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers; +#define glDeleteFramebuffers glad_glDeleteFramebuffers +GLAD_API_CALL PFNGLDELETEMEMORYOBJECTSEXTPROC glad_glDeleteMemoryObjectsEXT; +#define glDeleteMemoryObjectsEXT glad_glDeleteMemoryObjectsEXT +GLAD_API_CALL PFNGLDELETEPROGRAMPROC glad_glDeleteProgram; +#define glDeleteProgram glad_glDeleteProgram +GLAD_API_CALL PFNGLDELETEPROGRAMPIPELINESEXTPROC glad_glDeleteProgramPipelinesEXT; +#define glDeleteProgramPipelinesEXT glad_glDeleteProgramPipelinesEXT +GLAD_API_CALL PFNGLDELETEQUERIESEXTPROC glad_glDeleteQueriesEXT; +#define glDeleteQueriesEXT glad_glDeleteQueriesEXT +GLAD_API_CALL PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers; +#define glDeleteRenderbuffers glad_glDeleteRenderbuffers +GLAD_API_CALL PFNGLDELETESEMAPHORESEXTPROC glad_glDeleteSemaphoresEXT; +#define glDeleteSemaphoresEXT glad_glDeleteSemaphoresEXT +GLAD_API_CALL PFNGLDELETESHADERPROC glad_glDeleteShader; +#define glDeleteShader glad_glDeleteShader +GLAD_API_CALL PFNGLDELETETEXTURESPROC glad_glDeleteTextures; +#define glDeleteTextures glad_glDeleteTextures +GLAD_API_CALL PFNGLDELETEVERTEXARRAYSOESPROC glad_glDeleteVertexArraysOES; +#define glDeleteVertexArraysOES glad_glDeleteVertexArraysOES +GLAD_API_CALL PFNGLDEPTHFUNCPROC glad_glDepthFunc; +#define glDepthFunc glad_glDepthFunc +GLAD_API_CALL PFNGLDEPTHMASKPROC glad_glDepthMask; +#define glDepthMask glad_glDepthMask +GLAD_API_CALL PFNGLDEPTHRANGEARRAYFVOESPROC glad_glDepthRangeArrayfvOES; +#define glDepthRangeArrayfvOES glad_glDepthRangeArrayfvOES +GLAD_API_CALL PFNGLDEPTHRANGEINDEXEDFOESPROC glad_glDepthRangeIndexedfOES; +#define glDepthRangeIndexedfOES glad_glDepthRangeIndexedfOES +GLAD_API_CALL PFNGLDEPTHRANGEFPROC glad_glDepthRangef; +#define glDepthRangef glad_glDepthRangef +GLAD_API_CALL PFNGLDETACHSHADERPROC glad_glDetachShader; +#define glDetachShader glad_glDetachShader +GLAD_API_CALL PFNGLDISABLEPROC glad_glDisable; +#define glDisable glad_glDisable +GLAD_API_CALL PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray; +#define glDisableVertexAttribArray glad_glDisableVertexAttribArray +GLAD_API_CALL PFNGLDISABLEIEXTPROC glad_glDisableiEXT; +#define glDisableiEXT glad_glDisableiEXT +GLAD_API_CALL PFNGLDISABLEIOESPROC glad_glDisableiOES; +#define glDisableiOES glad_glDisableiOES +GLAD_API_CALL PFNGLDISCARDFRAMEBUFFEREXTPROC glad_glDiscardFramebufferEXT; +#define glDiscardFramebufferEXT glad_glDiscardFramebufferEXT +GLAD_API_CALL PFNGLDRAWARRAYSPROC glad_glDrawArrays; +#define glDrawArrays glad_glDrawArrays +GLAD_API_CALL PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEEXTPROC glad_glDrawArraysInstancedBaseInstanceEXT; +#define glDrawArraysInstancedBaseInstanceEXT glad_glDrawArraysInstancedBaseInstanceEXT +GLAD_API_CALL PFNGLDRAWARRAYSINSTANCEDEXTPROC glad_glDrawArraysInstancedEXT; +#define glDrawArraysInstancedEXT glad_glDrawArraysInstancedEXT +GLAD_API_CALL PFNGLDRAWBUFFERSEXTPROC glad_glDrawBuffersEXT; +#define glDrawBuffersEXT glad_glDrawBuffersEXT +GLAD_API_CALL PFNGLDRAWBUFFERSINDEXEDEXTPROC glad_glDrawBuffersIndexedEXT; +#define glDrawBuffersIndexedEXT glad_glDrawBuffersIndexedEXT +GLAD_API_CALL PFNGLDRAWELEMENTSPROC glad_glDrawElements; +#define glDrawElements glad_glDrawElements +GLAD_API_CALL PFNGLDRAWELEMENTSBASEVERTEXEXTPROC glad_glDrawElementsBaseVertexEXT; +#define glDrawElementsBaseVertexEXT glad_glDrawElementsBaseVertexEXT +GLAD_API_CALL PFNGLDRAWELEMENTSBASEVERTEXOESPROC glad_glDrawElementsBaseVertexOES; +#define glDrawElementsBaseVertexOES glad_glDrawElementsBaseVertexOES +GLAD_API_CALL PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEEXTPROC glad_glDrawElementsInstancedBaseInstanceEXT; +#define glDrawElementsInstancedBaseInstanceEXT glad_glDrawElementsInstancedBaseInstanceEXT +GLAD_API_CALL PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEEXTPROC glad_glDrawElementsInstancedBaseVertexBaseInstanceEXT; +#define glDrawElementsInstancedBaseVertexBaseInstanceEXT glad_glDrawElementsInstancedBaseVertexBaseInstanceEXT +GLAD_API_CALL PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXEXTPROC glad_glDrawElementsInstancedBaseVertexEXT; +#define glDrawElementsInstancedBaseVertexEXT glad_glDrawElementsInstancedBaseVertexEXT +GLAD_API_CALL PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXOESPROC glad_glDrawElementsInstancedBaseVertexOES; +#define glDrawElementsInstancedBaseVertexOES glad_glDrawElementsInstancedBaseVertexOES +GLAD_API_CALL PFNGLDRAWELEMENTSINSTANCEDEXTPROC glad_glDrawElementsInstancedEXT; +#define glDrawElementsInstancedEXT glad_glDrawElementsInstancedEXT +GLAD_API_CALL PFNGLDRAWRANGEELEMENTSBASEVERTEXEXTPROC glad_glDrawRangeElementsBaseVertexEXT; +#define glDrawRangeElementsBaseVertexEXT glad_glDrawRangeElementsBaseVertexEXT +GLAD_API_CALL PFNGLDRAWRANGEELEMENTSBASEVERTEXOESPROC glad_glDrawRangeElementsBaseVertexOES; +#define glDrawRangeElementsBaseVertexOES glad_glDrawRangeElementsBaseVertexOES +GLAD_API_CALL PFNGLDRAWTRANSFORMFEEDBACKEXTPROC glad_glDrawTransformFeedbackEXT; +#define glDrawTransformFeedbackEXT glad_glDrawTransformFeedbackEXT +GLAD_API_CALL PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDEXTPROC glad_glDrawTransformFeedbackInstancedEXT; +#define glDrawTransformFeedbackInstancedEXT glad_glDrawTransformFeedbackInstancedEXT +GLAD_API_CALL PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glad_glEGLImageTargetRenderbufferStorageOES; +#define glEGLImageTargetRenderbufferStorageOES glad_glEGLImageTargetRenderbufferStorageOES +GLAD_API_CALL PFNGLEGLIMAGETARGETTEXSTORAGEEXTPROC glad_glEGLImageTargetTexStorageEXT; +#define glEGLImageTargetTexStorageEXT glad_glEGLImageTargetTexStorageEXT +GLAD_API_CALL PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glad_glEGLImageTargetTexture2DOES; +#define glEGLImageTargetTexture2DOES glad_glEGLImageTargetTexture2DOES +GLAD_API_CALL PFNGLEGLIMAGETARGETTEXTURESTORAGEEXTPROC glad_glEGLImageTargetTextureStorageEXT; +#define glEGLImageTargetTextureStorageEXT glad_glEGLImageTargetTextureStorageEXT +GLAD_API_CALL PFNGLENABLEPROC glad_glEnable; +#define glEnable glad_glEnable +GLAD_API_CALL PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray; +#define glEnableVertexAttribArray glad_glEnableVertexAttribArray +GLAD_API_CALL PFNGLENABLEIEXTPROC glad_glEnableiEXT; +#define glEnableiEXT glad_glEnableiEXT +GLAD_API_CALL PFNGLENABLEIOESPROC glad_glEnableiOES; +#define glEnableiOES glad_glEnableiOES +GLAD_API_CALL PFNGLENDQUERYEXTPROC glad_glEndQueryEXT; +#define glEndQueryEXT glad_glEndQueryEXT +GLAD_API_CALL PFNGLFINISHPROC glad_glFinish; +#define glFinish glad_glFinish +GLAD_API_CALL PFNGLFLUSHPROC glad_glFlush; +#define glFlush glad_glFlush +GLAD_API_CALL PFNGLFLUSHMAPPEDBUFFERRANGEEXTPROC glad_glFlushMappedBufferRangeEXT; +#define glFlushMappedBufferRangeEXT glad_glFlushMappedBufferRangeEXT +GLAD_API_CALL PFNGLFRAMEBUFFERFETCHBARRIEREXTPROC glad_glFramebufferFetchBarrierEXT; +#define glFramebufferFetchBarrierEXT glad_glFramebufferFetchBarrierEXT +GLAD_API_CALL PFNGLFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC glad_glFramebufferPixelLocalStorageSizeEXT; +#define glFramebufferPixelLocalStorageSizeEXT glad_glFramebufferPixelLocalStorageSizeEXT +GLAD_API_CALL PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer; +#define glFramebufferRenderbuffer glad_glFramebufferRenderbuffer +GLAD_API_CALL PFNGLFRAMEBUFFERSHADINGRATEEXTPROC glad_glFramebufferShadingRateEXT; +#define glFramebufferShadingRateEXT glad_glFramebufferShadingRateEXT +GLAD_API_CALL PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D; +#define glFramebufferTexture2D glad_glFramebufferTexture2D +GLAD_API_CALL PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC glad_glFramebufferTexture2DMultisampleEXT; +#define glFramebufferTexture2DMultisampleEXT glad_glFramebufferTexture2DMultisampleEXT +GLAD_API_CALL PFNGLFRAMEBUFFERTEXTURE3DOESPROC glad_glFramebufferTexture3DOES; +#define glFramebufferTexture3DOES glad_glFramebufferTexture3DOES +GLAD_API_CALL PFNGLFRAMEBUFFERTEXTUREEXTPROC glad_glFramebufferTextureEXT; +#define glFramebufferTextureEXT glad_glFramebufferTextureEXT +GLAD_API_CALL PFNGLFRAMEBUFFERTEXTUREOESPROC glad_glFramebufferTextureOES; +#define glFramebufferTextureOES glad_glFramebufferTextureOES +GLAD_API_CALL PFNGLFRONTFACEPROC glad_glFrontFace; +#define glFrontFace glad_glFrontFace +GLAD_API_CALL PFNGLGENBUFFERSPROC glad_glGenBuffers; +#define glGenBuffers glad_glGenBuffers +GLAD_API_CALL PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers; +#define glGenFramebuffers glad_glGenFramebuffers +GLAD_API_CALL PFNGLGENPROGRAMPIPELINESEXTPROC glad_glGenProgramPipelinesEXT; +#define glGenProgramPipelinesEXT glad_glGenProgramPipelinesEXT +GLAD_API_CALL PFNGLGENQUERIESEXTPROC glad_glGenQueriesEXT; +#define glGenQueriesEXT glad_glGenQueriesEXT +GLAD_API_CALL PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers; +#define glGenRenderbuffers glad_glGenRenderbuffers +GLAD_API_CALL PFNGLGENSEMAPHORESEXTPROC glad_glGenSemaphoresEXT; +#define glGenSemaphoresEXT glad_glGenSemaphoresEXT +GLAD_API_CALL PFNGLGENTEXTURESPROC glad_glGenTextures; +#define glGenTextures glad_glGenTextures +GLAD_API_CALL PFNGLGENVERTEXARRAYSOESPROC glad_glGenVertexArraysOES; +#define glGenVertexArraysOES glad_glGenVertexArraysOES +GLAD_API_CALL PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap; +#define glGenerateMipmap glad_glGenerateMipmap +GLAD_API_CALL PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib; +#define glGetActiveAttrib glad_glGetActiveAttrib +GLAD_API_CALL PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform; +#define glGetActiveUniform glad_glGetActiveUniform +GLAD_API_CALL PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders; +#define glGetAttachedShaders glad_glGetAttachedShaders +GLAD_API_CALL PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation; +#define glGetAttribLocation glad_glGetAttribLocation +GLAD_API_CALL PFNGLGETBOOLEANVPROC glad_glGetBooleanv; +#define glGetBooleanv glad_glGetBooleanv +GLAD_API_CALL PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv; +#define glGetBufferParameteriv glad_glGetBufferParameteriv +GLAD_API_CALL PFNGLGETBUFFERPOINTERVOESPROC glad_glGetBufferPointervOES; +#define glGetBufferPointervOES glad_glGetBufferPointervOES +GLAD_API_CALL PFNGLGETDEBUGMESSAGELOGKHRPROC glad_glGetDebugMessageLogKHR; +#define glGetDebugMessageLogKHR glad_glGetDebugMessageLogKHR +GLAD_API_CALL PFNGLGETERRORPROC glad_glGetError; +#define glGetError glad_glGetError +GLAD_API_CALL PFNGLGETFLOATI_VOESPROC glad_glGetFloati_vOES; +#define glGetFloati_vOES glad_glGetFloati_vOES +GLAD_API_CALL PFNGLGETFLOATVPROC glad_glGetFloatv; +#define glGetFloatv glad_glGetFloatv +GLAD_API_CALL PFNGLGETFRAGDATAINDEXEXTPROC glad_glGetFragDataIndexEXT; +#define glGetFragDataIndexEXT glad_glGetFragDataIndexEXT +GLAD_API_CALL PFNGLGETFRAGMENTSHADINGRATESEXTPROC glad_glGetFragmentShadingRatesEXT; +#define glGetFragmentShadingRatesEXT glad_glGetFragmentShadingRatesEXT +GLAD_API_CALL PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv; +#define glGetFramebufferAttachmentParameteriv glad_glGetFramebufferAttachmentParameteriv +GLAD_API_CALL PFNGLGETFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC glad_glGetFramebufferPixelLocalStorageSizeEXT; +#define glGetFramebufferPixelLocalStorageSizeEXT glad_glGetFramebufferPixelLocalStorageSizeEXT +GLAD_API_CALL PFNGLGETGRAPHICSRESETSTATUSEXTPROC glad_glGetGraphicsResetStatusEXT; +#define glGetGraphicsResetStatusEXT glad_glGetGraphicsResetStatusEXT +GLAD_API_CALL PFNGLGETGRAPHICSRESETSTATUSKHRPROC glad_glGetGraphicsResetStatusKHR; +#define glGetGraphicsResetStatusKHR glad_glGetGraphicsResetStatusKHR +GLAD_API_CALL PFNGLGETINTEGER64VEXTPROC glad_glGetInteger64vEXT; +#define glGetInteger64vEXT glad_glGetInteger64vEXT +GLAD_API_CALL PFNGLGETINTEGERI_VEXTPROC glad_glGetIntegeri_vEXT; +#define glGetIntegeri_vEXT glad_glGetIntegeri_vEXT +GLAD_API_CALL PFNGLGETINTEGERVPROC glad_glGetIntegerv; +#define glGetIntegerv glad_glGetIntegerv +GLAD_API_CALL PFNGLGETMEMORYOBJECTPARAMETERIVEXTPROC glad_glGetMemoryObjectParameterivEXT; +#define glGetMemoryObjectParameterivEXT glad_glGetMemoryObjectParameterivEXT +GLAD_API_CALL PFNGLGETOBJECTLABELEXTPROC glad_glGetObjectLabelEXT; +#define glGetObjectLabelEXT glad_glGetObjectLabelEXT +GLAD_API_CALL PFNGLGETOBJECTLABELKHRPROC glad_glGetObjectLabelKHR; +#define glGetObjectLabelKHR glad_glGetObjectLabelKHR +GLAD_API_CALL PFNGLGETOBJECTPTRLABELKHRPROC glad_glGetObjectPtrLabelKHR; +#define glGetObjectPtrLabelKHR glad_glGetObjectPtrLabelKHR +GLAD_API_CALL PFNGLGETPOINTERVKHRPROC glad_glGetPointervKHR; +#define glGetPointervKHR glad_glGetPointervKHR +GLAD_API_CALL PFNGLGETPROGRAMBINARYOESPROC glad_glGetProgramBinaryOES; +#define glGetProgramBinaryOES glad_glGetProgramBinaryOES +GLAD_API_CALL PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog; +#define glGetProgramInfoLog glad_glGetProgramInfoLog +GLAD_API_CALL PFNGLGETPROGRAMPIPELINEINFOLOGEXTPROC glad_glGetProgramPipelineInfoLogEXT; +#define glGetProgramPipelineInfoLogEXT glad_glGetProgramPipelineInfoLogEXT +GLAD_API_CALL PFNGLGETPROGRAMPIPELINEIVEXTPROC glad_glGetProgramPipelineivEXT; +#define glGetProgramPipelineivEXT glad_glGetProgramPipelineivEXT +GLAD_API_CALL PFNGLGETPROGRAMRESOURCELOCATIONINDEXEXTPROC glad_glGetProgramResourceLocationIndexEXT; +#define glGetProgramResourceLocationIndexEXT glad_glGetProgramResourceLocationIndexEXT +GLAD_API_CALL PFNGLGETPROGRAMIVPROC glad_glGetProgramiv; +#define glGetProgramiv glad_glGetProgramiv +GLAD_API_CALL PFNGLGETQUERYOBJECTI64VEXTPROC glad_glGetQueryObjecti64vEXT; +#define glGetQueryObjecti64vEXT glad_glGetQueryObjecti64vEXT +GLAD_API_CALL PFNGLGETQUERYOBJECTIVEXTPROC glad_glGetQueryObjectivEXT; +#define glGetQueryObjectivEXT glad_glGetQueryObjectivEXT +GLAD_API_CALL PFNGLGETQUERYOBJECTUI64VEXTPROC glad_glGetQueryObjectui64vEXT; +#define glGetQueryObjectui64vEXT glad_glGetQueryObjectui64vEXT +GLAD_API_CALL PFNGLGETQUERYOBJECTUIVEXTPROC glad_glGetQueryObjectuivEXT; +#define glGetQueryObjectuivEXT glad_glGetQueryObjectuivEXT +GLAD_API_CALL PFNGLGETQUERYIVEXTPROC glad_glGetQueryivEXT; +#define glGetQueryivEXT glad_glGetQueryivEXT +GLAD_API_CALL PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv; +#define glGetRenderbufferParameteriv glad_glGetRenderbufferParameteriv +GLAD_API_CALL PFNGLGETSAMPLERPARAMETERIIVEXTPROC glad_glGetSamplerParameterIivEXT; +#define glGetSamplerParameterIivEXT glad_glGetSamplerParameterIivEXT +GLAD_API_CALL PFNGLGETSAMPLERPARAMETERIIVOESPROC glad_glGetSamplerParameterIivOES; +#define glGetSamplerParameterIivOES glad_glGetSamplerParameterIivOES +GLAD_API_CALL PFNGLGETSAMPLERPARAMETERIUIVEXTPROC glad_glGetSamplerParameterIuivEXT; +#define glGetSamplerParameterIuivEXT glad_glGetSamplerParameterIuivEXT +GLAD_API_CALL PFNGLGETSAMPLERPARAMETERIUIVOESPROC glad_glGetSamplerParameterIuivOES; +#define glGetSamplerParameterIuivOES glad_glGetSamplerParameterIuivOES +GLAD_API_CALL PFNGLGETSEMAPHOREPARAMETERUI64VEXTPROC glad_glGetSemaphoreParameterui64vEXT; +#define glGetSemaphoreParameterui64vEXT glad_glGetSemaphoreParameterui64vEXT +GLAD_API_CALL PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog; +#define glGetShaderInfoLog glad_glGetShaderInfoLog +GLAD_API_CALL PFNGLGETSHADERPRECISIONFORMATPROC glad_glGetShaderPrecisionFormat; +#define glGetShaderPrecisionFormat glad_glGetShaderPrecisionFormat +GLAD_API_CALL PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource; +#define glGetShaderSource glad_glGetShaderSource +GLAD_API_CALL PFNGLGETSHADERIVPROC glad_glGetShaderiv; +#define glGetShaderiv glad_glGetShaderiv +GLAD_API_CALL PFNGLGETSTRINGPROC glad_glGetString; +#define glGetString glad_glGetString +GLAD_API_CALL PFNGLGETTEXPARAMETERIIVEXTPROC glad_glGetTexParameterIivEXT; +#define glGetTexParameterIivEXT glad_glGetTexParameterIivEXT +GLAD_API_CALL PFNGLGETTEXPARAMETERIIVOESPROC glad_glGetTexParameterIivOES; +#define glGetTexParameterIivOES glad_glGetTexParameterIivOES +GLAD_API_CALL PFNGLGETTEXPARAMETERIUIVEXTPROC glad_glGetTexParameterIuivEXT; +#define glGetTexParameterIuivEXT glad_glGetTexParameterIuivEXT +GLAD_API_CALL PFNGLGETTEXPARAMETERIUIVOESPROC glad_glGetTexParameterIuivOES; +#define glGetTexParameterIuivOES glad_glGetTexParameterIuivOES +GLAD_API_CALL PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv; +#define glGetTexParameterfv glad_glGetTexParameterfv +GLAD_API_CALL PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv; +#define glGetTexParameteriv glad_glGetTexParameteriv +GLAD_API_CALL PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation; +#define glGetUniformLocation glad_glGetUniformLocation +GLAD_API_CALL PFNGLGETUNIFORMFVPROC glad_glGetUniformfv; +#define glGetUniformfv glad_glGetUniformfv +GLAD_API_CALL PFNGLGETUNIFORMIVPROC glad_glGetUniformiv; +#define glGetUniformiv glad_glGetUniformiv +GLAD_API_CALL PFNGLGETUNSIGNEDBYTEI_VEXTPROC glad_glGetUnsignedBytei_vEXT; +#define glGetUnsignedBytei_vEXT glad_glGetUnsignedBytei_vEXT +GLAD_API_CALL PFNGLGETUNSIGNEDBYTEVEXTPROC glad_glGetUnsignedBytevEXT; +#define glGetUnsignedBytevEXT glad_glGetUnsignedBytevEXT +GLAD_API_CALL PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv; +#define glGetVertexAttribPointerv glad_glGetVertexAttribPointerv +GLAD_API_CALL PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv; +#define glGetVertexAttribfv glad_glGetVertexAttribfv +GLAD_API_CALL PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv; +#define glGetVertexAttribiv glad_glGetVertexAttribiv +GLAD_API_CALL PFNGLGETNUNIFORMFVEXTPROC glad_glGetnUniformfvEXT; +#define glGetnUniformfvEXT glad_glGetnUniformfvEXT +GLAD_API_CALL PFNGLGETNUNIFORMFVKHRPROC glad_glGetnUniformfvKHR; +#define glGetnUniformfvKHR glad_glGetnUniformfvKHR +GLAD_API_CALL PFNGLGETNUNIFORMIVEXTPROC glad_glGetnUniformivEXT; +#define glGetnUniformivEXT glad_glGetnUniformivEXT +GLAD_API_CALL PFNGLGETNUNIFORMIVKHRPROC glad_glGetnUniformivKHR; +#define glGetnUniformivKHR glad_glGetnUniformivKHR +GLAD_API_CALL PFNGLGETNUNIFORMUIVKHRPROC glad_glGetnUniformuivKHR; +#define glGetnUniformuivKHR glad_glGetnUniformuivKHR +GLAD_API_CALL PFNGLHINTPROC glad_glHint; +#define glHint glad_glHint +GLAD_API_CALL PFNGLIMPORTMEMORYFDEXTPROC glad_glImportMemoryFdEXT; +#define glImportMemoryFdEXT glad_glImportMemoryFdEXT +GLAD_API_CALL PFNGLIMPORTMEMORYWIN32HANDLEEXTPROC glad_glImportMemoryWin32HandleEXT; +#define glImportMemoryWin32HandleEXT glad_glImportMemoryWin32HandleEXT +GLAD_API_CALL PFNGLIMPORTMEMORYWIN32NAMEEXTPROC glad_glImportMemoryWin32NameEXT; +#define glImportMemoryWin32NameEXT glad_glImportMemoryWin32NameEXT +GLAD_API_CALL PFNGLIMPORTSEMAPHOREFDEXTPROC glad_glImportSemaphoreFdEXT; +#define glImportSemaphoreFdEXT glad_glImportSemaphoreFdEXT +GLAD_API_CALL PFNGLIMPORTSEMAPHOREWIN32HANDLEEXTPROC glad_glImportSemaphoreWin32HandleEXT; +#define glImportSemaphoreWin32HandleEXT glad_glImportSemaphoreWin32HandleEXT +GLAD_API_CALL PFNGLIMPORTSEMAPHOREWIN32NAMEEXTPROC glad_glImportSemaphoreWin32NameEXT; +#define glImportSemaphoreWin32NameEXT glad_glImportSemaphoreWin32NameEXT +GLAD_API_CALL PFNGLINSERTEVENTMARKEREXTPROC glad_glInsertEventMarkerEXT; +#define glInsertEventMarkerEXT glad_glInsertEventMarkerEXT +GLAD_API_CALL PFNGLISBUFFERPROC glad_glIsBuffer; +#define glIsBuffer glad_glIsBuffer +GLAD_API_CALL PFNGLISENABLEDPROC glad_glIsEnabled; +#define glIsEnabled glad_glIsEnabled +GLAD_API_CALL PFNGLISENABLEDIEXTPROC glad_glIsEnablediEXT; +#define glIsEnablediEXT glad_glIsEnablediEXT +GLAD_API_CALL PFNGLISENABLEDIOESPROC glad_glIsEnablediOES; +#define glIsEnablediOES glad_glIsEnablediOES +GLAD_API_CALL PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer; +#define glIsFramebuffer glad_glIsFramebuffer +GLAD_API_CALL PFNGLISMEMORYOBJECTEXTPROC glad_glIsMemoryObjectEXT; +#define glIsMemoryObjectEXT glad_glIsMemoryObjectEXT +GLAD_API_CALL PFNGLISPROGRAMPROC glad_glIsProgram; +#define glIsProgram glad_glIsProgram +GLAD_API_CALL PFNGLISPROGRAMPIPELINEEXTPROC glad_glIsProgramPipelineEXT; +#define glIsProgramPipelineEXT glad_glIsProgramPipelineEXT +GLAD_API_CALL PFNGLISQUERYEXTPROC glad_glIsQueryEXT; +#define glIsQueryEXT glad_glIsQueryEXT +GLAD_API_CALL PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer; +#define glIsRenderbuffer glad_glIsRenderbuffer +GLAD_API_CALL PFNGLISSEMAPHOREEXTPROC glad_glIsSemaphoreEXT; +#define glIsSemaphoreEXT glad_glIsSemaphoreEXT +GLAD_API_CALL PFNGLISSHADERPROC glad_glIsShader; +#define glIsShader glad_glIsShader +GLAD_API_CALL PFNGLISTEXTUREPROC glad_glIsTexture; +#define glIsTexture glad_glIsTexture +GLAD_API_CALL PFNGLISVERTEXARRAYOESPROC glad_glIsVertexArrayOES; +#define glIsVertexArrayOES glad_glIsVertexArrayOES +GLAD_API_CALL PFNGLLABELOBJECTEXTPROC glad_glLabelObjectEXT; +#define glLabelObjectEXT glad_glLabelObjectEXT +GLAD_API_CALL PFNGLLINEWIDTHPROC glad_glLineWidth; +#define glLineWidth glad_glLineWidth +GLAD_API_CALL PFNGLLINKPROGRAMPROC glad_glLinkProgram; +#define glLinkProgram glad_glLinkProgram +GLAD_API_CALL PFNGLMAPBUFFEROESPROC glad_glMapBufferOES; +#define glMapBufferOES glad_glMapBufferOES +GLAD_API_CALL PFNGLMAPBUFFERRANGEEXTPROC glad_glMapBufferRangeEXT; +#define glMapBufferRangeEXT glad_glMapBufferRangeEXT +GLAD_API_CALL PFNGLMAXSHADERCOMPILERTHREADSKHRPROC glad_glMaxShaderCompilerThreadsKHR; +#define glMaxShaderCompilerThreadsKHR glad_glMaxShaderCompilerThreadsKHR +GLAD_API_CALL PFNGLMEMORYOBJECTPARAMETERIVEXTPROC glad_glMemoryObjectParameterivEXT; +#define glMemoryObjectParameterivEXT glad_glMemoryObjectParameterivEXT +GLAD_API_CALL PFNGLMINSAMPLESHADINGOESPROC glad_glMinSampleShadingOES; +#define glMinSampleShadingOES glad_glMinSampleShadingOES +GLAD_API_CALL PFNGLMULTIDRAWARRAYSEXTPROC glad_glMultiDrawArraysEXT; +#define glMultiDrawArraysEXT glad_glMultiDrawArraysEXT +GLAD_API_CALL PFNGLMULTIDRAWARRAYSINDIRECTEXTPROC glad_glMultiDrawArraysIndirectEXT; +#define glMultiDrawArraysIndirectEXT glad_glMultiDrawArraysIndirectEXT +GLAD_API_CALL PFNGLMULTIDRAWELEMENTSBASEVERTEXEXTPROC glad_glMultiDrawElementsBaseVertexEXT; +#define glMultiDrawElementsBaseVertexEXT glad_glMultiDrawElementsBaseVertexEXT +GLAD_API_CALL PFNGLMULTIDRAWELEMENTSEXTPROC glad_glMultiDrawElementsEXT; +#define glMultiDrawElementsEXT glad_glMultiDrawElementsEXT +GLAD_API_CALL PFNGLMULTIDRAWELEMENTSINDIRECTEXTPROC glad_glMultiDrawElementsIndirectEXT; +#define glMultiDrawElementsIndirectEXT glad_glMultiDrawElementsIndirectEXT +GLAD_API_CALL PFNGLNAMEDBUFFERSTORAGEEXTERNALEXTPROC glad_glNamedBufferStorageExternalEXT; +#define glNamedBufferStorageExternalEXT glad_glNamedBufferStorageExternalEXT +GLAD_API_CALL PFNGLNAMEDBUFFERSTORAGEMEMEXTPROC glad_glNamedBufferStorageMemEXT; +#define glNamedBufferStorageMemEXT glad_glNamedBufferStorageMemEXT +GLAD_API_CALL PFNGLOBJECTLABELKHRPROC glad_glObjectLabelKHR; +#define glObjectLabelKHR glad_glObjectLabelKHR +GLAD_API_CALL PFNGLOBJECTPTRLABELKHRPROC glad_glObjectPtrLabelKHR; +#define glObjectPtrLabelKHR glad_glObjectPtrLabelKHR +GLAD_API_CALL PFNGLPATCHPARAMETERIEXTPROC glad_glPatchParameteriEXT; +#define glPatchParameteriEXT glad_glPatchParameteriEXT +GLAD_API_CALL PFNGLPATCHPARAMETERIOESPROC glad_glPatchParameteriOES; +#define glPatchParameteriOES glad_glPatchParameteriOES +GLAD_API_CALL PFNGLPIXELSTOREIPROC glad_glPixelStorei; +#define glPixelStorei glad_glPixelStorei +GLAD_API_CALL PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset; +#define glPolygonOffset glad_glPolygonOffset +GLAD_API_CALL PFNGLPOLYGONOFFSETCLAMPEXTPROC glad_glPolygonOffsetClampEXT; +#define glPolygonOffsetClampEXT glad_glPolygonOffsetClampEXT +GLAD_API_CALL PFNGLPOPDEBUGGROUPKHRPROC glad_glPopDebugGroupKHR; +#define glPopDebugGroupKHR glad_glPopDebugGroupKHR +GLAD_API_CALL PFNGLPOPGROUPMARKEREXTPROC glad_glPopGroupMarkerEXT; +#define glPopGroupMarkerEXT glad_glPopGroupMarkerEXT +GLAD_API_CALL PFNGLPRIMITIVEBOUNDINGBOXEXTPROC glad_glPrimitiveBoundingBoxEXT; +#define glPrimitiveBoundingBoxEXT glad_glPrimitiveBoundingBoxEXT +GLAD_API_CALL PFNGLPRIMITIVEBOUNDINGBOXOESPROC glad_glPrimitiveBoundingBoxOES; +#define glPrimitiveBoundingBoxOES glad_glPrimitiveBoundingBoxOES +GLAD_API_CALL PFNGLPROGRAMBINARYOESPROC glad_glProgramBinaryOES; +#define glProgramBinaryOES glad_glProgramBinaryOES +GLAD_API_CALL PFNGLPROGRAMPARAMETERIEXTPROC glad_glProgramParameteriEXT; +#define glProgramParameteriEXT glad_glProgramParameteriEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORM1FEXTPROC glad_glProgramUniform1fEXT; +#define glProgramUniform1fEXT glad_glProgramUniform1fEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORM1FVEXTPROC glad_glProgramUniform1fvEXT; +#define glProgramUniform1fvEXT glad_glProgramUniform1fvEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORM1IEXTPROC glad_glProgramUniform1iEXT; +#define glProgramUniform1iEXT glad_glProgramUniform1iEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORM1IVEXTPROC glad_glProgramUniform1ivEXT; +#define glProgramUniform1ivEXT glad_glProgramUniform1ivEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORM1UIEXTPROC glad_glProgramUniform1uiEXT; +#define glProgramUniform1uiEXT glad_glProgramUniform1uiEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORM1UIVEXTPROC glad_glProgramUniform1uivEXT; +#define glProgramUniform1uivEXT glad_glProgramUniform1uivEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORM2FEXTPROC glad_glProgramUniform2fEXT; +#define glProgramUniform2fEXT glad_glProgramUniform2fEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORM2FVEXTPROC glad_glProgramUniform2fvEXT; +#define glProgramUniform2fvEXT glad_glProgramUniform2fvEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORM2IEXTPROC glad_glProgramUniform2iEXT; +#define glProgramUniform2iEXT glad_glProgramUniform2iEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORM2IVEXTPROC glad_glProgramUniform2ivEXT; +#define glProgramUniform2ivEXT glad_glProgramUniform2ivEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORM2UIEXTPROC glad_glProgramUniform2uiEXT; +#define glProgramUniform2uiEXT glad_glProgramUniform2uiEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORM2UIVEXTPROC glad_glProgramUniform2uivEXT; +#define glProgramUniform2uivEXT glad_glProgramUniform2uivEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORM3FEXTPROC glad_glProgramUniform3fEXT; +#define glProgramUniform3fEXT glad_glProgramUniform3fEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORM3FVEXTPROC glad_glProgramUniform3fvEXT; +#define glProgramUniform3fvEXT glad_glProgramUniform3fvEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORM3IEXTPROC glad_glProgramUniform3iEXT; +#define glProgramUniform3iEXT glad_glProgramUniform3iEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORM3IVEXTPROC glad_glProgramUniform3ivEXT; +#define glProgramUniform3ivEXT glad_glProgramUniform3ivEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORM3UIEXTPROC glad_glProgramUniform3uiEXT; +#define glProgramUniform3uiEXT glad_glProgramUniform3uiEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORM3UIVEXTPROC glad_glProgramUniform3uivEXT; +#define glProgramUniform3uivEXT glad_glProgramUniform3uivEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORM4FEXTPROC glad_glProgramUniform4fEXT; +#define glProgramUniform4fEXT glad_glProgramUniform4fEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORM4FVEXTPROC glad_glProgramUniform4fvEXT; +#define glProgramUniform4fvEXT glad_glProgramUniform4fvEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORM4IEXTPROC glad_glProgramUniform4iEXT; +#define glProgramUniform4iEXT glad_glProgramUniform4iEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORM4IVEXTPROC glad_glProgramUniform4ivEXT; +#define glProgramUniform4ivEXT glad_glProgramUniform4ivEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORM4UIEXTPROC glad_glProgramUniform4uiEXT; +#define glProgramUniform4uiEXT glad_glProgramUniform4uiEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORM4UIVEXTPROC glad_glProgramUniform4uivEXT; +#define glProgramUniform4uivEXT glad_glProgramUniform4uivEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX2FVEXTPROC glad_glProgramUniformMatrix2fvEXT; +#define glProgramUniformMatrix2fvEXT glad_glProgramUniformMatrix2fvEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC glad_glProgramUniformMatrix2x3fvEXT; +#define glProgramUniformMatrix2x3fvEXT glad_glProgramUniformMatrix2x3fvEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC glad_glProgramUniformMatrix2x4fvEXT; +#define glProgramUniformMatrix2x4fvEXT glad_glProgramUniformMatrix2x4fvEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX3FVEXTPROC glad_glProgramUniformMatrix3fvEXT; +#define glProgramUniformMatrix3fvEXT glad_glProgramUniformMatrix3fvEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC glad_glProgramUniformMatrix3x2fvEXT; +#define glProgramUniformMatrix3x2fvEXT glad_glProgramUniformMatrix3x2fvEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC glad_glProgramUniformMatrix3x4fvEXT; +#define glProgramUniformMatrix3x4fvEXT glad_glProgramUniformMatrix3x4fvEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX4FVEXTPROC glad_glProgramUniformMatrix4fvEXT; +#define glProgramUniformMatrix4fvEXT glad_glProgramUniformMatrix4fvEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC glad_glProgramUniformMatrix4x2fvEXT; +#define glProgramUniformMatrix4x2fvEXT glad_glProgramUniformMatrix4x2fvEXT +GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC glad_glProgramUniformMatrix4x3fvEXT; +#define glProgramUniformMatrix4x3fvEXT glad_glProgramUniformMatrix4x3fvEXT +GLAD_API_CALL PFNGLPUSHDEBUGGROUPKHRPROC glad_glPushDebugGroupKHR; +#define glPushDebugGroupKHR glad_glPushDebugGroupKHR +GLAD_API_CALL PFNGLPUSHGROUPMARKEREXTPROC glad_glPushGroupMarkerEXT; +#define glPushGroupMarkerEXT glad_glPushGroupMarkerEXT +GLAD_API_CALL PFNGLQUERYCOUNTEREXTPROC glad_glQueryCounterEXT; +#define glQueryCounterEXT glad_glQueryCounterEXT +GLAD_API_CALL PFNGLRASTERSAMPLESEXTPROC glad_glRasterSamplesEXT; +#define glRasterSamplesEXT glad_glRasterSamplesEXT +GLAD_API_CALL PFNGLREADBUFFERINDEXEDEXTPROC glad_glReadBufferIndexedEXT; +#define glReadBufferIndexedEXT glad_glReadBufferIndexedEXT +GLAD_API_CALL PFNGLREADPIXELSPROC glad_glReadPixels; +#define glReadPixels glad_glReadPixels +GLAD_API_CALL PFNGLREADNPIXELSEXTPROC glad_glReadnPixelsEXT; +#define glReadnPixelsEXT glad_glReadnPixelsEXT +GLAD_API_CALL PFNGLREADNPIXELSKHRPROC glad_glReadnPixelsKHR; +#define glReadnPixelsKHR glad_glReadnPixelsKHR +GLAD_API_CALL PFNGLRELEASEKEYEDMUTEXWIN32EXTPROC glad_glReleaseKeyedMutexWin32EXT; +#define glReleaseKeyedMutexWin32EXT glad_glReleaseKeyedMutexWin32EXT +GLAD_API_CALL PFNGLRELEASESHADERCOMPILERPROC glad_glReleaseShaderCompiler; +#define glReleaseShaderCompiler glad_glReleaseShaderCompiler +GLAD_API_CALL PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage; +#define glRenderbufferStorage glad_glRenderbufferStorage +GLAD_API_CALL PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glad_glRenderbufferStorageMultisampleEXT; +#define glRenderbufferStorageMultisampleEXT glad_glRenderbufferStorageMultisampleEXT +GLAD_API_CALL PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage; +#define glSampleCoverage glad_glSampleCoverage +GLAD_API_CALL PFNGLSAMPLERPARAMETERIIVEXTPROC glad_glSamplerParameterIivEXT; +#define glSamplerParameterIivEXT glad_glSamplerParameterIivEXT +GLAD_API_CALL PFNGLSAMPLERPARAMETERIIVOESPROC glad_glSamplerParameterIivOES; +#define glSamplerParameterIivOES glad_glSamplerParameterIivOES +GLAD_API_CALL PFNGLSAMPLERPARAMETERIUIVEXTPROC glad_glSamplerParameterIuivEXT; +#define glSamplerParameterIuivEXT glad_glSamplerParameterIuivEXT +GLAD_API_CALL PFNGLSAMPLERPARAMETERIUIVOESPROC glad_glSamplerParameterIuivOES; +#define glSamplerParameterIuivOES glad_glSamplerParameterIuivOES +GLAD_API_CALL PFNGLSCISSORPROC glad_glScissor; +#define glScissor glad_glScissor +GLAD_API_CALL PFNGLSCISSORARRAYVOESPROC glad_glScissorArrayvOES; +#define glScissorArrayvOES glad_glScissorArrayvOES +GLAD_API_CALL PFNGLSCISSORINDEXEDOESPROC glad_glScissorIndexedOES; +#define glScissorIndexedOES glad_glScissorIndexedOES +GLAD_API_CALL PFNGLSCISSORINDEXEDVOESPROC glad_glScissorIndexedvOES; +#define glScissorIndexedvOES glad_glScissorIndexedvOES +GLAD_API_CALL PFNGLSEMAPHOREPARAMETERUI64VEXTPROC glad_glSemaphoreParameterui64vEXT; +#define glSemaphoreParameterui64vEXT glad_glSemaphoreParameterui64vEXT +GLAD_API_CALL PFNGLSHADERBINARYPROC glad_glShaderBinary; +#define glShaderBinary glad_glShaderBinary +GLAD_API_CALL PFNGLSHADERSOURCEPROC glad_glShaderSource; +#define glShaderSource glad_glShaderSource +GLAD_API_CALL PFNGLSHADINGRATECOMBINEROPSEXTPROC glad_glShadingRateCombinerOpsEXT; +#define glShadingRateCombinerOpsEXT glad_glShadingRateCombinerOpsEXT +GLAD_API_CALL PFNGLSHADINGRATEEXTPROC glad_glShadingRateEXT; +#define glShadingRateEXT glad_glShadingRateEXT +GLAD_API_CALL PFNGLSIGNALSEMAPHOREEXTPROC glad_glSignalSemaphoreEXT; +#define glSignalSemaphoreEXT glad_glSignalSemaphoreEXT +GLAD_API_CALL PFNGLSTENCILFUNCPROC glad_glStencilFunc; +#define glStencilFunc glad_glStencilFunc +GLAD_API_CALL PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate; +#define glStencilFuncSeparate glad_glStencilFuncSeparate +GLAD_API_CALL PFNGLSTENCILMASKPROC glad_glStencilMask; +#define glStencilMask glad_glStencilMask +GLAD_API_CALL PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate; +#define glStencilMaskSeparate glad_glStencilMaskSeparate +GLAD_API_CALL PFNGLSTENCILOPPROC glad_glStencilOp; +#define glStencilOp glad_glStencilOp +GLAD_API_CALL PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate; +#define glStencilOpSeparate glad_glStencilOpSeparate +GLAD_API_CALL PFNGLTEXBUFFEREXTPROC glad_glTexBufferEXT; +#define glTexBufferEXT glad_glTexBufferEXT +GLAD_API_CALL PFNGLTEXBUFFEROESPROC glad_glTexBufferOES; +#define glTexBufferOES glad_glTexBufferOES +GLAD_API_CALL PFNGLTEXBUFFERRANGEEXTPROC glad_glTexBufferRangeEXT; +#define glTexBufferRangeEXT glad_glTexBufferRangeEXT +GLAD_API_CALL PFNGLTEXBUFFERRANGEOESPROC glad_glTexBufferRangeOES; +#define glTexBufferRangeOES glad_glTexBufferRangeOES +GLAD_API_CALL PFNGLTEXIMAGE2DPROC glad_glTexImage2D; +#define glTexImage2D glad_glTexImage2D +GLAD_API_CALL PFNGLTEXIMAGE3DOESPROC glad_glTexImage3DOES; +#define glTexImage3DOES glad_glTexImage3DOES +GLAD_API_CALL PFNGLTEXPAGECOMMITMENTEXTPROC glad_glTexPageCommitmentEXT; +#define glTexPageCommitmentEXT glad_glTexPageCommitmentEXT +GLAD_API_CALL PFNGLTEXPARAMETERIIVEXTPROC glad_glTexParameterIivEXT; +#define glTexParameterIivEXT glad_glTexParameterIivEXT +GLAD_API_CALL PFNGLTEXPARAMETERIIVOESPROC glad_glTexParameterIivOES; +#define glTexParameterIivOES glad_glTexParameterIivOES +GLAD_API_CALL PFNGLTEXPARAMETERIUIVEXTPROC glad_glTexParameterIuivEXT; +#define glTexParameterIuivEXT glad_glTexParameterIuivEXT +GLAD_API_CALL PFNGLTEXPARAMETERIUIVOESPROC glad_glTexParameterIuivOES; +#define glTexParameterIuivOES glad_glTexParameterIuivOES +GLAD_API_CALL PFNGLTEXPARAMETERFPROC glad_glTexParameterf; +#define glTexParameterf glad_glTexParameterf +GLAD_API_CALL PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv; +#define glTexParameterfv glad_glTexParameterfv +GLAD_API_CALL PFNGLTEXPARAMETERIPROC glad_glTexParameteri; +#define glTexParameteri glad_glTexParameteri +GLAD_API_CALL PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv; +#define glTexParameteriv glad_glTexParameteriv +GLAD_API_CALL PFNGLTEXSTORAGE1DEXTPROC glad_glTexStorage1DEXT; +#define glTexStorage1DEXT glad_glTexStorage1DEXT +GLAD_API_CALL PFNGLTEXSTORAGE2DEXTPROC glad_glTexStorage2DEXT; +#define glTexStorage2DEXT glad_glTexStorage2DEXT +GLAD_API_CALL PFNGLTEXSTORAGE3DEXTPROC glad_glTexStorage3DEXT; +#define glTexStorage3DEXT glad_glTexStorage3DEXT +GLAD_API_CALL PFNGLTEXSTORAGE3DMULTISAMPLEOESPROC glad_glTexStorage3DMultisampleOES; +#define glTexStorage3DMultisampleOES glad_glTexStorage3DMultisampleOES +GLAD_API_CALL PFNGLTEXSTORAGEATTRIBS2DEXTPROC glad_glTexStorageAttribs2DEXT; +#define glTexStorageAttribs2DEXT glad_glTexStorageAttribs2DEXT +GLAD_API_CALL PFNGLTEXSTORAGEATTRIBS3DEXTPROC glad_glTexStorageAttribs3DEXT; +#define glTexStorageAttribs3DEXT glad_glTexStorageAttribs3DEXT +GLAD_API_CALL PFNGLTEXSTORAGEMEM2DEXTPROC glad_glTexStorageMem2DEXT; +#define glTexStorageMem2DEXT glad_glTexStorageMem2DEXT +GLAD_API_CALL PFNGLTEXSTORAGEMEM2DMULTISAMPLEEXTPROC glad_glTexStorageMem2DMultisampleEXT; +#define glTexStorageMem2DMultisampleEXT glad_glTexStorageMem2DMultisampleEXT +GLAD_API_CALL PFNGLTEXSTORAGEMEM3DEXTPROC glad_glTexStorageMem3DEXT; +#define glTexStorageMem3DEXT glad_glTexStorageMem3DEXT +GLAD_API_CALL PFNGLTEXSTORAGEMEM3DMULTISAMPLEEXTPROC glad_glTexStorageMem3DMultisampleEXT; +#define glTexStorageMem3DMultisampleEXT glad_glTexStorageMem3DMultisampleEXT +GLAD_API_CALL PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D; +#define glTexSubImage2D glad_glTexSubImage2D +GLAD_API_CALL PFNGLTEXSUBIMAGE3DOESPROC glad_glTexSubImage3DOES; +#define glTexSubImage3DOES glad_glTexSubImage3DOES +GLAD_API_CALL PFNGLTEXTURESTORAGE1DEXTPROC glad_glTextureStorage1DEXT; +#define glTextureStorage1DEXT glad_glTextureStorage1DEXT +GLAD_API_CALL PFNGLTEXTURESTORAGE2DEXTPROC glad_glTextureStorage2DEXT; +#define glTextureStorage2DEXT glad_glTextureStorage2DEXT +GLAD_API_CALL PFNGLTEXTURESTORAGE3DEXTPROC glad_glTextureStorage3DEXT; +#define glTextureStorage3DEXT glad_glTextureStorage3DEXT +GLAD_API_CALL PFNGLTEXTURESTORAGEMEM2DEXTPROC glad_glTextureStorageMem2DEXT; +#define glTextureStorageMem2DEXT glad_glTextureStorageMem2DEXT +GLAD_API_CALL PFNGLTEXTURESTORAGEMEM2DMULTISAMPLEEXTPROC glad_glTextureStorageMem2DMultisampleEXT; +#define glTextureStorageMem2DMultisampleEXT glad_glTextureStorageMem2DMultisampleEXT +GLAD_API_CALL PFNGLTEXTURESTORAGEMEM3DEXTPROC glad_glTextureStorageMem3DEXT; +#define glTextureStorageMem3DEXT glad_glTextureStorageMem3DEXT +GLAD_API_CALL PFNGLTEXTURESTORAGEMEM3DMULTISAMPLEEXTPROC glad_glTextureStorageMem3DMultisampleEXT; +#define glTextureStorageMem3DMultisampleEXT glad_glTextureStorageMem3DMultisampleEXT +GLAD_API_CALL PFNGLTEXTUREVIEWEXTPROC glad_glTextureViewEXT; +#define glTextureViewEXT glad_glTextureViewEXT +GLAD_API_CALL PFNGLTEXTUREVIEWOESPROC glad_glTextureViewOES; +#define glTextureViewOES glad_glTextureViewOES +GLAD_API_CALL PFNGLUNIFORM1FPROC glad_glUniform1f; +#define glUniform1f glad_glUniform1f +GLAD_API_CALL PFNGLUNIFORM1FVPROC glad_glUniform1fv; +#define glUniform1fv glad_glUniform1fv +GLAD_API_CALL PFNGLUNIFORM1IPROC glad_glUniform1i; +#define glUniform1i glad_glUniform1i +GLAD_API_CALL PFNGLUNIFORM1IVPROC glad_glUniform1iv; +#define glUniform1iv glad_glUniform1iv +GLAD_API_CALL PFNGLUNIFORM2FPROC glad_glUniform2f; +#define glUniform2f glad_glUniform2f +GLAD_API_CALL PFNGLUNIFORM2FVPROC glad_glUniform2fv; +#define glUniform2fv glad_glUniform2fv +GLAD_API_CALL PFNGLUNIFORM2IPROC glad_glUniform2i; +#define glUniform2i glad_glUniform2i +GLAD_API_CALL PFNGLUNIFORM2IVPROC glad_glUniform2iv; +#define glUniform2iv glad_glUniform2iv +GLAD_API_CALL PFNGLUNIFORM3FPROC glad_glUniform3f; +#define glUniform3f glad_glUniform3f +GLAD_API_CALL PFNGLUNIFORM3FVPROC glad_glUniform3fv; +#define glUniform3fv glad_glUniform3fv +GLAD_API_CALL PFNGLUNIFORM3IPROC glad_glUniform3i; +#define glUniform3i glad_glUniform3i +GLAD_API_CALL PFNGLUNIFORM3IVPROC glad_glUniform3iv; +#define glUniform3iv glad_glUniform3iv +GLAD_API_CALL PFNGLUNIFORM4FPROC glad_glUniform4f; +#define glUniform4f glad_glUniform4f +GLAD_API_CALL PFNGLUNIFORM4FVPROC glad_glUniform4fv; +#define glUniform4fv glad_glUniform4fv +GLAD_API_CALL PFNGLUNIFORM4IPROC glad_glUniform4i; +#define glUniform4i glad_glUniform4i +GLAD_API_CALL PFNGLUNIFORM4IVPROC glad_glUniform4iv; +#define glUniform4iv glad_glUniform4iv +GLAD_API_CALL PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv; +#define glUniformMatrix2fv glad_glUniformMatrix2fv +GLAD_API_CALL PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv; +#define glUniformMatrix3fv glad_glUniformMatrix3fv +GLAD_API_CALL PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv; +#define glUniformMatrix4fv glad_glUniformMatrix4fv +GLAD_API_CALL PFNGLUNMAPBUFFEROESPROC glad_glUnmapBufferOES; +#define glUnmapBufferOES glad_glUnmapBufferOES +GLAD_API_CALL PFNGLUSEPROGRAMPROC glad_glUseProgram; +#define glUseProgram glad_glUseProgram +GLAD_API_CALL PFNGLUSEPROGRAMSTAGESEXTPROC glad_glUseProgramStagesEXT; +#define glUseProgramStagesEXT glad_glUseProgramStagesEXT +GLAD_API_CALL PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram; +#define glValidateProgram glad_glValidateProgram +GLAD_API_CALL PFNGLVALIDATEPROGRAMPIPELINEEXTPROC glad_glValidateProgramPipelineEXT; +#define glValidateProgramPipelineEXT glad_glValidateProgramPipelineEXT +GLAD_API_CALL PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f; +#define glVertexAttrib1f glad_glVertexAttrib1f +GLAD_API_CALL PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv; +#define glVertexAttrib1fv glad_glVertexAttrib1fv +GLAD_API_CALL PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f; +#define glVertexAttrib2f glad_glVertexAttrib2f +GLAD_API_CALL PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv; +#define glVertexAttrib2fv glad_glVertexAttrib2fv +GLAD_API_CALL PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f; +#define glVertexAttrib3f glad_glVertexAttrib3f +GLAD_API_CALL PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv; +#define glVertexAttrib3fv glad_glVertexAttrib3fv +GLAD_API_CALL PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f; +#define glVertexAttrib4f glad_glVertexAttrib4f +GLAD_API_CALL PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv; +#define glVertexAttrib4fv glad_glVertexAttrib4fv +GLAD_API_CALL PFNGLVERTEXATTRIBDIVISOREXTPROC glad_glVertexAttribDivisorEXT; +#define glVertexAttribDivisorEXT glad_glVertexAttribDivisorEXT +GLAD_API_CALL PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer; +#define glVertexAttribPointer glad_glVertexAttribPointer +GLAD_API_CALL PFNGLVIEWPORTPROC glad_glViewport; +#define glViewport glad_glViewport +GLAD_API_CALL PFNGLVIEWPORTARRAYVOESPROC glad_glViewportArrayvOES; +#define glViewportArrayvOES glad_glViewportArrayvOES +GLAD_API_CALL PFNGLVIEWPORTINDEXEDFOESPROC glad_glViewportIndexedfOES; +#define glViewportIndexedfOES glad_glViewportIndexedfOES +GLAD_API_CALL PFNGLVIEWPORTINDEXEDFVOESPROC glad_glViewportIndexedfvOES; +#define glViewportIndexedfvOES glad_glViewportIndexedfvOES +GLAD_API_CALL PFNGLWAITSEMAPHOREEXTPROC glad_glWaitSemaphoreEXT; +#define glWaitSemaphoreEXT glad_glWaitSemaphoreEXT +GLAD_API_CALL PFNGLWINDOWRECTANGLESEXTPROC glad_glWindowRectanglesEXT; +#define glWindowRectanglesEXT glad_glWindowRectanglesEXT + + + + + +GLAD_API_CALL int gladLoadGLES2UserPtr( GLADuserptrloadfunc load, void *userptr); +GLAD_API_CALL int gladLoadGLES2( GLADloadfunc load); + + + +#ifdef __cplusplus +} +#endif +#endif + +/* Source */ +#ifdef GLAD_GLES2_IMPLEMENTATION +/** + * SPDX-License-Identifier: (WTFPL OR CC0-1.0) AND Apache-2.0 + */ +#include +#include +#include + +#ifndef GLAD_IMPL_UTIL_C_ +#define GLAD_IMPL_UTIL_C_ + +#ifdef _MSC_VER +#define GLAD_IMPL_UTIL_SSCANF sscanf_s +#else +#define GLAD_IMPL_UTIL_SSCANF sscanf +#endif + +#endif /* GLAD_IMPL_UTIL_C_ */ + +#ifdef __cplusplus +extern "C" { +#endif + + + +int GLAD_GL_ES_VERSION_2_0 = 0; +int GLAD_GL_EXT_EGL_image_array = 0; +int GLAD_GL_EXT_EGL_image_storage = 0; +int GLAD_GL_EXT_EGL_image_storage_compression = 0; +int GLAD_GL_EXT_YUV_target = 0; +int GLAD_GL_EXT_base_instance = 0; +int GLAD_GL_EXT_blend_func_extended = 0; +int GLAD_GL_EXT_blend_minmax = 0; +int GLAD_GL_EXT_buffer_storage = 0; +int GLAD_GL_EXT_clear_texture = 0; +int GLAD_GL_EXT_clip_control = 0; +int GLAD_GL_EXT_clip_cull_distance = 0; +int GLAD_GL_EXT_color_buffer_float = 0; +int GLAD_GL_EXT_color_buffer_half_float = 0; +int GLAD_GL_EXT_conservative_depth = 0; +int GLAD_GL_EXT_copy_image = 0; +int GLAD_GL_EXT_debug_label = 0; +int GLAD_GL_EXT_debug_marker = 0; +int GLAD_GL_EXT_depth_clamp = 0; +int GLAD_GL_EXT_discard_framebuffer = 0; +int GLAD_GL_EXT_disjoint_timer_query = 0; +int GLAD_GL_EXT_draw_buffers = 0; +int GLAD_GL_EXT_draw_buffers_indexed = 0; +int GLAD_GL_EXT_draw_elements_base_vertex = 0; +int GLAD_GL_EXT_draw_instanced = 0; +int GLAD_GL_EXT_draw_transform_feedback = 0; +int GLAD_GL_EXT_external_buffer = 0; +int GLAD_GL_EXT_float_blend = 0; +int GLAD_GL_EXT_fragment_shading_rate = 0; +int GLAD_GL_EXT_geometry_point_size = 0; +int GLAD_GL_EXT_geometry_shader = 0; +int GLAD_GL_EXT_gpu_shader5 = 0; +int GLAD_GL_EXT_instanced_arrays = 0; +int GLAD_GL_EXT_map_buffer_range = 0; +int GLAD_GL_EXT_memory_object = 0; +int GLAD_GL_EXT_memory_object_fd = 0; +int GLAD_GL_EXT_memory_object_win32 = 0; +int GLAD_GL_EXT_multi_draw_arrays = 0; +int GLAD_GL_EXT_multi_draw_indirect = 0; +int GLAD_GL_EXT_multisampled_compatibility = 0; +int GLAD_GL_EXT_multisampled_render_to_texture = 0; +int GLAD_GL_EXT_multisampled_render_to_texture2 = 0; +int GLAD_GL_EXT_multiview_draw_buffers = 0; +int GLAD_GL_EXT_multiview_tessellation_geometry_shader = 0; +int GLAD_GL_EXT_multiview_texture_multisample = 0; +int GLAD_GL_EXT_multiview_timer_query = 0; +int GLAD_GL_EXT_occlusion_query_boolean = 0; +int GLAD_GL_EXT_polygon_offset_clamp = 0; +int GLAD_GL_EXT_post_depth_coverage = 0; +int GLAD_GL_EXT_primitive_bounding_box = 0; +int GLAD_GL_EXT_protected_textures = 0; +int GLAD_GL_EXT_pvrtc_sRGB = 0; +int GLAD_GL_EXT_raster_multisample = 0; +int GLAD_GL_EXT_read_format_bgra = 0; +int GLAD_GL_EXT_render_snorm = 0; +int GLAD_GL_EXT_robustness = 0; +int GLAD_GL_EXT_sRGB = 0; +int GLAD_GL_EXT_sRGB_write_control = 0; +int GLAD_GL_EXT_semaphore = 0; +int GLAD_GL_EXT_semaphore_fd = 0; +int GLAD_GL_EXT_semaphore_win32 = 0; +int GLAD_GL_EXT_separate_depth_stencil = 0; +int GLAD_GL_EXT_separate_shader_objects = 0; +int GLAD_GL_EXT_shader_framebuffer_fetch = 0; +int GLAD_GL_EXT_shader_framebuffer_fetch_non_coherent = 0; +int GLAD_GL_EXT_shader_group_vote = 0; +int GLAD_GL_EXT_shader_implicit_conversions = 0; +int GLAD_GL_EXT_shader_integer_mix = 0; +int GLAD_GL_EXT_shader_io_blocks = 0; +int GLAD_GL_EXT_shader_non_constant_global_initializers = 0; +int GLAD_GL_EXT_shader_pixel_local_storage = 0; +int GLAD_GL_EXT_shader_pixel_local_storage2 = 0; +int GLAD_GL_EXT_shader_samples_identical = 0; +int GLAD_GL_EXT_shader_texture_lod = 0; +int GLAD_GL_EXT_shadow_samplers = 0; +int GLAD_GL_EXT_sparse_texture = 0; +int GLAD_GL_EXT_sparse_texture2 = 0; +int GLAD_GL_EXT_tessellation_point_size = 0; +int GLAD_GL_EXT_tessellation_shader = 0; +int GLAD_GL_EXT_texture_border_clamp = 0; +int GLAD_GL_EXT_texture_buffer = 0; +int GLAD_GL_EXT_texture_compression_astc_decode_mode = 0; +int GLAD_GL_EXT_texture_compression_bptc = 0; +int GLAD_GL_EXT_texture_compression_dxt1 = 0; +int GLAD_GL_EXT_texture_compression_rgtc = 0; +int GLAD_GL_EXT_texture_compression_s3tc = 0; +int GLAD_GL_EXT_texture_compression_s3tc_srgb = 0; +int GLAD_GL_EXT_texture_cube_map_array = 0; +int GLAD_GL_EXT_texture_filter_anisotropic = 0; +int GLAD_GL_EXT_texture_filter_minmax = 0; +int GLAD_GL_EXT_texture_format_BGRA8888 = 0; +int GLAD_GL_EXT_texture_format_sRGB_override = 0; +int GLAD_GL_EXT_texture_mirror_clamp_to_edge = 0; +int GLAD_GL_EXT_texture_norm16 = 0; +int GLAD_GL_EXT_texture_query_lod = 0; +int GLAD_GL_EXT_texture_rg = 0; +int GLAD_GL_EXT_texture_sRGB_R8 = 0; +int GLAD_GL_EXT_texture_sRGB_RG8 = 0; +int GLAD_GL_EXT_texture_sRGB_decode = 0; +int GLAD_GL_EXT_texture_shadow_lod = 0; +int GLAD_GL_EXT_texture_storage = 0; +int GLAD_GL_EXT_texture_storage_compression = 0; +int GLAD_GL_EXT_texture_type_2_10_10_10_REV = 0; +int GLAD_GL_EXT_texture_view = 0; +int GLAD_GL_EXT_unpack_subimage = 0; +int GLAD_GL_EXT_win32_keyed_mutex = 0; +int GLAD_GL_EXT_window_rectangles = 0; +int GLAD_GL_KHR_blend_equation_advanced = 0; +int GLAD_GL_KHR_blend_equation_advanced_coherent = 0; +int GLAD_GL_KHR_context_flush_control = 0; +int GLAD_GL_KHR_debug = 0; +int GLAD_GL_KHR_no_error = 0; +int GLAD_GL_KHR_parallel_shader_compile = 0; +int GLAD_GL_KHR_robust_buffer_access_behavior = 0; +int GLAD_GL_KHR_robustness = 0; +int GLAD_GL_KHR_shader_subgroup = 0; +int GLAD_GL_KHR_texture_compression_astc_hdr = 0; +int GLAD_GL_KHR_texture_compression_astc_ldr = 0; +int GLAD_GL_KHR_texture_compression_astc_sliced_3d = 0; +int GLAD_GL_OES_EGL_image = 0; +int GLAD_GL_OES_EGL_image_external = 0; +int GLAD_GL_OES_EGL_image_external_essl3 = 0; +int GLAD_GL_OES_compressed_ETC1_RGB8_sub_texture = 0; +int GLAD_GL_OES_compressed_ETC1_RGB8_texture = 0; +int GLAD_GL_OES_compressed_paletted_texture = 0; +int GLAD_GL_OES_copy_image = 0; +int GLAD_GL_OES_depth24 = 0; +int GLAD_GL_OES_depth32 = 0; +int GLAD_GL_OES_depth_texture = 0; +int GLAD_GL_OES_draw_buffers_indexed = 0; +int GLAD_GL_OES_draw_elements_base_vertex = 0; +int GLAD_GL_OES_element_index_uint = 0; +int GLAD_GL_OES_fbo_render_mipmap = 0; +int GLAD_GL_OES_fragment_precision_high = 0; +int GLAD_GL_OES_geometry_point_size = 0; +int GLAD_GL_OES_geometry_shader = 0; +int GLAD_GL_OES_get_program_binary = 0; +int GLAD_GL_OES_gpu_shader5 = 0; +int GLAD_GL_OES_mapbuffer = 0; +int GLAD_GL_OES_packed_depth_stencil = 0; +int GLAD_GL_OES_primitive_bounding_box = 0; +int GLAD_GL_OES_required_internalformat = 0; +int GLAD_GL_OES_rgb8_rgba8 = 0; +int GLAD_GL_OES_sample_shading = 0; +int GLAD_GL_OES_sample_variables = 0; +int GLAD_GL_OES_shader_image_atomic = 0; +int GLAD_GL_OES_shader_io_blocks = 0; +int GLAD_GL_OES_shader_multisample_interpolation = 0; +int GLAD_GL_OES_standard_derivatives = 0; +int GLAD_GL_OES_stencil1 = 0; +int GLAD_GL_OES_stencil4 = 0; +int GLAD_GL_OES_surfaceless_context = 0; +int GLAD_GL_OES_tessellation_point_size = 0; +int GLAD_GL_OES_tessellation_shader = 0; +int GLAD_GL_OES_texture_3D = 0; +int GLAD_GL_OES_texture_border_clamp = 0; +int GLAD_GL_OES_texture_buffer = 0; +int GLAD_GL_OES_texture_compression_astc = 0; +int GLAD_GL_OES_texture_cube_map_array = 0; +int GLAD_GL_OES_texture_float = 0; +int GLAD_GL_OES_texture_float_linear = 0; +int GLAD_GL_OES_texture_half_float = 0; +int GLAD_GL_OES_texture_half_float_linear = 0; +int GLAD_GL_OES_texture_npot = 0; +int GLAD_GL_OES_texture_stencil8 = 0; +int GLAD_GL_OES_texture_storage_multisample_2d_array = 0; +int GLAD_GL_OES_texture_view = 0; +int GLAD_GL_OES_vertex_array_object = 0; +int GLAD_GL_OES_vertex_half_float = 0; +int GLAD_GL_OES_vertex_type_10_10_10_2 = 0; +int GLAD_GL_OES_viewport_array = 0; + + + +PFNGLACQUIREKEYEDMUTEXWIN32EXTPROC glad_glAcquireKeyedMutexWin32EXT = NULL; +PFNGLACTIVESHADERPROGRAMEXTPROC glad_glActiveShaderProgramEXT = NULL; +PFNGLACTIVETEXTUREPROC glad_glActiveTexture = NULL; +PFNGLATTACHSHADERPROC glad_glAttachShader = NULL; +PFNGLBEGINQUERYEXTPROC glad_glBeginQueryEXT = NULL; +PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation = NULL; +PFNGLBINDBUFFERPROC glad_glBindBuffer = NULL; +PFNGLBINDFRAGDATALOCATIONEXTPROC glad_glBindFragDataLocationEXT = NULL; +PFNGLBINDFRAGDATALOCATIONINDEXEDEXTPROC glad_glBindFragDataLocationIndexedEXT = NULL; +PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer = NULL; +PFNGLBINDPROGRAMPIPELINEEXTPROC glad_glBindProgramPipelineEXT = NULL; +PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer = NULL; +PFNGLBINDTEXTUREPROC glad_glBindTexture = NULL; +PFNGLBINDVERTEXARRAYOESPROC glad_glBindVertexArrayOES = NULL; +PFNGLBLENDBARRIERKHRPROC glad_glBlendBarrierKHR = NULL; +PFNGLBLENDCOLORPROC glad_glBlendColor = NULL; +PFNGLBLENDEQUATIONPROC glad_glBlendEquation = NULL; +PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate = NULL; +PFNGLBLENDEQUATIONSEPARATEIEXTPROC glad_glBlendEquationSeparateiEXT = NULL; +PFNGLBLENDEQUATIONSEPARATEIOESPROC glad_glBlendEquationSeparateiOES = NULL; +PFNGLBLENDEQUATIONIEXTPROC glad_glBlendEquationiEXT = NULL; +PFNGLBLENDEQUATIONIOESPROC glad_glBlendEquationiOES = NULL; +PFNGLBLENDFUNCPROC glad_glBlendFunc = NULL; +PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate = NULL; +PFNGLBLENDFUNCSEPARATEIEXTPROC glad_glBlendFuncSeparateiEXT = NULL; +PFNGLBLENDFUNCSEPARATEIOESPROC glad_glBlendFuncSeparateiOES = NULL; +PFNGLBLENDFUNCIEXTPROC glad_glBlendFunciEXT = NULL; +PFNGLBLENDFUNCIOESPROC glad_glBlendFunciOES = NULL; +PFNGLBUFFERDATAPROC glad_glBufferData = NULL; +PFNGLBUFFERSTORAGEEXTPROC glad_glBufferStorageEXT = NULL; +PFNGLBUFFERSTORAGEEXTERNALEXTPROC glad_glBufferStorageExternalEXT = NULL; +PFNGLBUFFERSTORAGEMEMEXTPROC glad_glBufferStorageMemEXT = NULL; +PFNGLBUFFERSUBDATAPROC glad_glBufferSubData = NULL; +PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus = NULL; +PFNGLCLEARPROC glad_glClear = NULL; +PFNGLCLEARCOLORPROC glad_glClearColor = NULL; +PFNGLCLEARDEPTHFPROC glad_glClearDepthf = NULL; +PFNGLCLEARPIXELLOCALSTORAGEUIEXTPROC glad_glClearPixelLocalStorageuiEXT = NULL; +PFNGLCLEARSTENCILPROC glad_glClearStencil = NULL; +PFNGLCLEARTEXIMAGEEXTPROC glad_glClearTexImageEXT = NULL; +PFNGLCLEARTEXSUBIMAGEEXTPROC glad_glClearTexSubImageEXT = NULL; +PFNGLCLIPCONTROLEXTPROC glad_glClipControlEXT = NULL; +PFNGLCOLORMASKPROC glad_glColorMask = NULL; +PFNGLCOLORMASKIEXTPROC glad_glColorMaskiEXT = NULL; +PFNGLCOLORMASKIOESPROC glad_glColorMaskiOES = NULL; +PFNGLCOMPILESHADERPROC glad_glCompileShader = NULL; +PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D = NULL; +PFNGLCOMPRESSEDTEXIMAGE3DOESPROC glad_glCompressedTexImage3DOES = NULL; +PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D = NULL; +PFNGLCOMPRESSEDTEXSUBIMAGE3DOESPROC glad_glCompressedTexSubImage3DOES = NULL; +PFNGLCOPYIMAGESUBDATAEXTPROC glad_glCopyImageSubDataEXT = NULL; +PFNGLCOPYIMAGESUBDATAOESPROC glad_glCopyImageSubDataOES = NULL; +PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D = NULL; +PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D = NULL; +PFNGLCOPYTEXSUBIMAGE3DOESPROC glad_glCopyTexSubImage3DOES = NULL; +PFNGLCREATEMEMORYOBJECTSEXTPROC glad_glCreateMemoryObjectsEXT = NULL; +PFNGLCREATEPROGRAMPROC glad_glCreateProgram = NULL; +PFNGLCREATESHADERPROC glad_glCreateShader = NULL; +PFNGLCREATESHADERPROGRAMVEXTPROC glad_glCreateShaderProgramvEXT = NULL; +PFNGLCULLFACEPROC glad_glCullFace = NULL; +PFNGLDEBUGMESSAGECALLBACKKHRPROC glad_glDebugMessageCallbackKHR = NULL; +PFNGLDEBUGMESSAGECONTROLKHRPROC glad_glDebugMessageControlKHR = NULL; +PFNGLDEBUGMESSAGEINSERTKHRPROC glad_glDebugMessageInsertKHR = NULL; +PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers = NULL; +PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers = NULL; +PFNGLDELETEMEMORYOBJECTSEXTPROC glad_glDeleteMemoryObjectsEXT = NULL; +PFNGLDELETEPROGRAMPROC glad_glDeleteProgram = NULL; +PFNGLDELETEPROGRAMPIPELINESEXTPROC glad_glDeleteProgramPipelinesEXT = NULL; +PFNGLDELETEQUERIESEXTPROC glad_glDeleteQueriesEXT = NULL; +PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers = NULL; +PFNGLDELETESEMAPHORESEXTPROC glad_glDeleteSemaphoresEXT = NULL; +PFNGLDELETESHADERPROC glad_glDeleteShader = NULL; +PFNGLDELETETEXTURESPROC glad_glDeleteTextures = NULL; +PFNGLDELETEVERTEXARRAYSOESPROC glad_glDeleteVertexArraysOES = NULL; +PFNGLDEPTHFUNCPROC glad_glDepthFunc = NULL; +PFNGLDEPTHMASKPROC glad_glDepthMask = NULL; +PFNGLDEPTHRANGEARRAYFVOESPROC glad_glDepthRangeArrayfvOES = NULL; +PFNGLDEPTHRANGEINDEXEDFOESPROC glad_glDepthRangeIndexedfOES = NULL; +PFNGLDEPTHRANGEFPROC glad_glDepthRangef = NULL; +PFNGLDETACHSHADERPROC glad_glDetachShader = NULL; +PFNGLDISABLEPROC glad_glDisable = NULL; +PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray = NULL; +PFNGLDISABLEIEXTPROC glad_glDisableiEXT = NULL; +PFNGLDISABLEIOESPROC glad_glDisableiOES = NULL; +PFNGLDISCARDFRAMEBUFFEREXTPROC glad_glDiscardFramebufferEXT = NULL; +PFNGLDRAWARRAYSPROC glad_glDrawArrays = NULL; +PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEEXTPROC glad_glDrawArraysInstancedBaseInstanceEXT = NULL; +PFNGLDRAWARRAYSINSTANCEDEXTPROC glad_glDrawArraysInstancedEXT = NULL; +PFNGLDRAWBUFFERSEXTPROC glad_glDrawBuffersEXT = NULL; +PFNGLDRAWBUFFERSINDEXEDEXTPROC glad_glDrawBuffersIndexedEXT = NULL; +PFNGLDRAWELEMENTSPROC glad_glDrawElements = NULL; +PFNGLDRAWELEMENTSBASEVERTEXEXTPROC glad_glDrawElementsBaseVertexEXT = NULL; +PFNGLDRAWELEMENTSBASEVERTEXOESPROC glad_glDrawElementsBaseVertexOES = NULL; +PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEEXTPROC glad_glDrawElementsInstancedBaseInstanceEXT = NULL; +PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEEXTPROC glad_glDrawElementsInstancedBaseVertexBaseInstanceEXT = NULL; +PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXEXTPROC glad_glDrawElementsInstancedBaseVertexEXT = NULL; +PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXOESPROC glad_glDrawElementsInstancedBaseVertexOES = NULL; +PFNGLDRAWELEMENTSINSTANCEDEXTPROC glad_glDrawElementsInstancedEXT = NULL; +PFNGLDRAWRANGEELEMENTSBASEVERTEXEXTPROC glad_glDrawRangeElementsBaseVertexEXT = NULL; +PFNGLDRAWRANGEELEMENTSBASEVERTEXOESPROC glad_glDrawRangeElementsBaseVertexOES = NULL; +PFNGLDRAWTRANSFORMFEEDBACKEXTPROC glad_glDrawTransformFeedbackEXT = NULL; +PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDEXTPROC glad_glDrawTransformFeedbackInstancedEXT = NULL; +PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glad_glEGLImageTargetRenderbufferStorageOES = NULL; +PFNGLEGLIMAGETARGETTEXSTORAGEEXTPROC glad_glEGLImageTargetTexStorageEXT = NULL; +PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glad_glEGLImageTargetTexture2DOES = NULL; +PFNGLEGLIMAGETARGETTEXTURESTORAGEEXTPROC glad_glEGLImageTargetTextureStorageEXT = NULL; +PFNGLENABLEPROC glad_glEnable = NULL; +PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray = NULL; +PFNGLENABLEIEXTPROC glad_glEnableiEXT = NULL; +PFNGLENABLEIOESPROC glad_glEnableiOES = NULL; +PFNGLENDQUERYEXTPROC glad_glEndQueryEXT = NULL; +PFNGLFINISHPROC glad_glFinish = NULL; +PFNGLFLUSHPROC glad_glFlush = NULL; +PFNGLFLUSHMAPPEDBUFFERRANGEEXTPROC glad_glFlushMappedBufferRangeEXT = NULL; +PFNGLFRAMEBUFFERFETCHBARRIEREXTPROC glad_glFramebufferFetchBarrierEXT = NULL; +PFNGLFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC glad_glFramebufferPixelLocalStorageSizeEXT = NULL; +PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer = NULL; +PFNGLFRAMEBUFFERSHADINGRATEEXTPROC glad_glFramebufferShadingRateEXT = NULL; +PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D = NULL; +PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC glad_glFramebufferTexture2DMultisampleEXT = NULL; +PFNGLFRAMEBUFFERTEXTURE3DOESPROC glad_glFramebufferTexture3DOES = NULL; +PFNGLFRAMEBUFFERTEXTUREEXTPROC glad_glFramebufferTextureEXT = NULL; +PFNGLFRAMEBUFFERTEXTUREOESPROC glad_glFramebufferTextureOES = NULL; +PFNGLFRONTFACEPROC glad_glFrontFace = NULL; +PFNGLGENBUFFERSPROC glad_glGenBuffers = NULL; +PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers = NULL; +PFNGLGENPROGRAMPIPELINESEXTPROC glad_glGenProgramPipelinesEXT = NULL; +PFNGLGENQUERIESEXTPROC glad_glGenQueriesEXT = NULL; +PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers = NULL; +PFNGLGENSEMAPHORESEXTPROC glad_glGenSemaphoresEXT = NULL; +PFNGLGENTEXTURESPROC glad_glGenTextures = NULL; +PFNGLGENVERTEXARRAYSOESPROC glad_glGenVertexArraysOES = NULL; +PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap = NULL; +PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib = NULL; +PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform = NULL; +PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders = NULL; +PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation = NULL; +PFNGLGETBOOLEANVPROC glad_glGetBooleanv = NULL; +PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv = NULL; +PFNGLGETBUFFERPOINTERVOESPROC glad_glGetBufferPointervOES = NULL; +PFNGLGETDEBUGMESSAGELOGKHRPROC glad_glGetDebugMessageLogKHR = NULL; +PFNGLGETERRORPROC glad_glGetError = NULL; +PFNGLGETFLOATI_VOESPROC glad_glGetFloati_vOES = NULL; +PFNGLGETFLOATVPROC glad_glGetFloatv = NULL; +PFNGLGETFRAGDATAINDEXEXTPROC glad_glGetFragDataIndexEXT = NULL; +PFNGLGETFRAGMENTSHADINGRATESEXTPROC glad_glGetFragmentShadingRatesEXT = NULL; +PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv = NULL; +PFNGLGETFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC glad_glGetFramebufferPixelLocalStorageSizeEXT = NULL; +PFNGLGETGRAPHICSRESETSTATUSEXTPROC glad_glGetGraphicsResetStatusEXT = NULL; +PFNGLGETGRAPHICSRESETSTATUSKHRPROC glad_glGetGraphicsResetStatusKHR = NULL; +PFNGLGETINTEGER64VEXTPROC glad_glGetInteger64vEXT = NULL; +PFNGLGETINTEGERI_VEXTPROC glad_glGetIntegeri_vEXT = NULL; +PFNGLGETINTEGERVPROC glad_glGetIntegerv = NULL; +PFNGLGETMEMORYOBJECTPARAMETERIVEXTPROC glad_glGetMemoryObjectParameterivEXT = NULL; +PFNGLGETOBJECTLABELEXTPROC glad_glGetObjectLabelEXT = NULL; +PFNGLGETOBJECTLABELKHRPROC glad_glGetObjectLabelKHR = NULL; +PFNGLGETOBJECTPTRLABELKHRPROC glad_glGetObjectPtrLabelKHR = NULL; +PFNGLGETPOINTERVKHRPROC glad_glGetPointervKHR = NULL; +PFNGLGETPROGRAMBINARYOESPROC glad_glGetProgramBinaryOES = NULL; +PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog = NULL; +PFNGLGETPROGRAMPIPELINEINFOLOGEXTPROC glad_glGetProgramPipelineInfoLogEXT = NULL; +PFNGLGETPROGRAMPIPELINEIVEXTPROC glad_glGetProgramPipelineivEXT = NULL; +PFNGLGETPROGRAMRESOURCELOCATIONINDEXEXTPROC glad_glGetProgramResourceLocationIndexEXT = NULL; +PFNGLGETPROGRAMIVPROC glad_glGetProgramiv = NULL; +PFNGLGETQUERYOBJECTI64VEXTPROC glad_glGetQueryObjecti64vEXT = NULL; +PFNGLGETQUERYOBJECTIVEXTPROC glad_glGetQueryObjectivEXT = NULL; +PFNGLGETQUERYOBJECTUI64VEXTPROC glad_glGetQueryObjectui64vEXT = NULL; +PFNGLGETQUERYOBJECTUIVEXTPROC glad_glGetQueryObjectuivEXT = NULL; +PFNGLGETQUERYIVEXTPROC glad_glGetQueryivEXT = NULL; +PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv = NULL; +PFNGLGETSAMPLERPARAMETERIIVEXTPROC glad_glGetSamplerParameterIivEXT = NULL; +PFNGLGETSAMPLERPARAMETERIIVOESPROC glad_glGetSamplerParameterIivOES = NULL; +PFNGLGETSAMPLERPARAMETERIUIVEXTPROC glad_glGetSamplerParameterIuivEXT = NULL; +PFNGLGETSAMPLERPARAMETERIUIVOESPROC glad_glGetSamplerParameterIuivOES = NULL; +PFNGLGETSEMAPHOREPARAMETERUI64VEXTPROC glad_glGetSemaphoreParameterui64vEXT = NULL; +PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog = NULL; +PFNGLGETSHADERPRECISIONFORMATPROC glad_glGetShaderPrecisionFormat = NULL; +PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource = NULL; +PFNGLGETSHADERIVPROC glad_glGetShaderiv = NULL; +PFNGLGETSTRINGPROC glad_glGetString = NULL; +PFNGLGETTEXPARAMETERIIVEXTPROC glad_glGetTexParameterIivEXT = NULL; +PFNGLGETTEXPARAMETERIIVOESPROC glad_glGetTexParameterIivOES = NULL; +PFNGLGETTEXPARAMETERIUIVEXTPROC glad_glGetTexParameterIuivEXT = NULL; +PFNGLGETTEXPARAMETERIUIVOESPROC glad_glGetTexParameterIuivOES = NULL; +PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv = NULL; +PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv = NULL; +PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation = NULL; +PFNGLGETUNIFORMFVPROC glad_glGetUniformfv = NULL; +PFNGLGETUNIFORMIVPROC glad_glGetUniformiv = NULL; +PFNGLGETUNSIGNEDBYTEI_VEXTPROC glad_glGetUnsignedBytei_vEXT = NULL; +PFNGLGETUNSIGNEDBYTEVEXTPROC glad_glGetUnsignedBytevEXT = NULL; +PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv = NULL; +PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv = NULL; +PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv = NULL; +PFNGLGETNUNIFORMFVEXTPROC glad_glGetnUniformfvEXT = NULL; +PFNGLGETNUNIFORMFVKHRPROC glad_glGetnUniformfvKHR = NULL; +PFNGLGETNUNIFORMIVEXTPROC glad_glGetnUniformivEXT = NULL; +PFNGLGETNUNIFORMIVKHRPROC glad_glGetnUniformivKHR = NULL; +PFNGLGETNUNIFORMUIVKHRPROC glad_glGetnUniformuivKHR = NULL; +PFNGLHINTPROC glad_glHint = NULL; +PFNGLIMPORTMEMORYFDEXTPROC glad_glImportMemoryFdEXT = NULL; +PFNGLIMPORTMEMORYWIN32HANDLEEXTPROC glad_glImportMemoryWin32HandleEXT = NULL; +PFNGLIMPORTMEMORYWIN32NAMEEXTPROC glad_glImportMemoryWin32NameEXT = NULL; +PFNGLIMPORTSEMAPHOREFDEXTPROC glad_glImportSemaphoreFdEXT = NULL; +PFNGLIMPORTSEMAPHOREWIN32HANDLEEXTPROC glad_glImportSemaphoreWin32HandleEXT = NULL; +PFNGLIMPORTSEMAPHOREWIN32NAMEEXTPROC glad_glImportSemaphoreWin32NameEXT = NULL; +PFNGLINSERTEVENTMARKEREXTPROC glad_glInsertEventMarkerEXT = NULL; +PFNGLISBUFFERPROC glad_glIsBuffer = NULL; +PFNGLISENABLEDPROC glad_glIsEnabled = NULL; +PFNGLISENABLEDIEXTPROC glad_glIsEnablediEXT = NULL; +PFNGLISENABLEDIOESPROC glad_glIsEnablediOES = NULL; +PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer = NULL; +PFNGLISMEMORYOBJECTEXTPROC glad_glIsMemoryObjectEXT = NULL; +PFNGLISPROGRAMPROC glad_glIsProgram = NULL; +PFNGLISPROGRAMPIPELINEEXTPROC glad_glIsProgramPipelineEXT = NULL; +PFNGLISQUERYEXTPROC glad_glIsQueryEXT = NULL; +PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer = NULL; +PFNGLISSEMAPHOREEXTPROC glad_glIsSemaphoreEXT = NULL; +PFNGLISSHADERPROC glad_glIsShader = NULL; +PFNGLISTEXTUREPROC glad_glIsTexture = NULL; +PFNGLISVERTEXARRAYOESPROC glad_glIsVertexArrayOES = NULL; +PFNGLLABELOBJECTEXTPROC glad_glLabelObjectEXT = NULL; +PFNGLLINEWIDTHPROC glad_glLineWidth = NULL; +PFNGLLINKPROGRAMPROC glad_glLinkProgram = NULL; +PFNGLMAPBUFFEROESPROC glad_glMapBufferOES = NULL; +PFNGLMAPBUFFERRANGEEXTPROC glad_glMapBufferRangeEXT = NULL; +PFNGLMAXSHADERCOMPILERTHREADSKHRPROC glad_glMaxShaderCompilerThreadsKHR = NULL; +PFNGLMEMORYOBJECTPARAMETERIVEXTPROC glad_glMemoryObjectParameterivEXT = NULL; +PFNGLMINSAMPLESHADINGOESPROC glad_glMinSampleShadingOES = NULL; +PFNGLMULTIDRAWARRAYSEXTPROC glad_glMultiDrawArraysEXT = NULL; +PFNGLMULTIDRAWARRAYSINDIRECTEXTPROC glad_glMultiDrawArraysIndirectEXT = NULL; +PFNGLMULTIDRAWELEMENTSBASEVERTEXEXTPROC glad_glMultiDrawElementsBaseVertexEXT = NULL; +PFNGLMULTIDRAWELEMENTSEXTPROC glad_glMultiDrawElementsEXT = NULL; +PFNGLMULTIDRAWELEMENTSINDIRECTEXTPROC glad_glMultiDrawElementsIndirectEXT = NULL; +PFNGLNAMEDBUFFERSTORAGEEXTERNALEXTPROC glad_glNamedBufferStorageExternalEXT = NULL; +PFNGLNAMEDBUFFERSTORAGEMEMEXTPROC glad_glNamedBufferStorageMemEXT = NULL; +PFNGLOBJECTLABELKHRPROC glad_glObjectLabelKHR = NULL; +PFNGLOBJECTPTRLABELKHRPROC glad_glObjectPtrLabelKHR = NULL; +PFNGLPATCHPARAMETERIEXTPROC glad_glPatchParameteriEXT = NULL; +PFNGLPATCHPARAMETERIOESPROC glad_glPatchParameteriOES = NULL; +PFNGLPIXELSTOREIPROC glad_glPixelStorei = NULL; +PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset = NULL; +PFNGLPOLYGONOFFSETCLAMPEXTPROC glad_glPolygonOffsetClampEXT = NULL; +PFNGLPOPDEBUGGROUPKHRPROC glad_glPopDebugGroupKHR = NULL; +PFNGLPOPGROUPMARKEREXTPROC glad_glPopGroupMarkerEXT = NULL; +PFNGLPRIMITIVEBOUNDINGBOXEXTPROC glad_glPrimitiveBoundingBoxEXT = NULL; +PFNGLPRIMITIVEBOUNDINGBOXOESPROC glad_glPrimitiveBoundingBoxOES = NULL; +PFNGLPROGRAMBINARYOESPROC glad_glProgramBinaryOES = NULL; +PFNGLPROGRAMPARAMETERIEXTPROC glad_glProgramParameteriEXT = NULL; +PFNGLPROGRAMUNIFORM1FEXTPROC glad_glProgramUniform1fEXT = NULL; +PFNGLPROGRAMUNIFORM1FVEXTPROC glad_glProgramUniform1fvEXT = NULL; +PFNGLPROGRAMUNIFORM1IEXTPROC glad_glProgramUniform1iEXT = NULL; +PFNGLPROGRAMUNIFORM1IVEXTPROC glad_glProgramUniform1ivEXT = NULL; +PFNGLPROGRAMUNIFORM1UIEXTPROC glad_glProgramUniform1uiEXT = NULL; +PFNGLPROGRAMUNIFORM1UIVEXTPROC glad_glProgramUniform1uivEXT = NULL; +PFNGLPROGRAMUNIFORM2FEXTPROC glad_glProgramUniform2fEXT = NULL; +PFNGLPROGRAMUNIFORM2FVEXTPROC glad_glProgramUniform2fvEXT = NULL; +PFNGLPROGRAMUNIFORM2IEXTPROC glad_glProgramUniform2iEXT = NULL; +PFNGLPROGRAMUNIFORM2IVEXTPROC glad_glProgramUniform2ivEXT = NULL; +PFNGLPROGRAMUNIFORM2UIEXTPROC glad_glProgramUniform2uiEXT = NULL; +PFNGLPROGRAMUNIFORM2UIVEXTPROC glad_glProgramUniform2uivEXT = NULL; +PFNGLPROGRAMUNIFORM3FEXTPROC glad_glProgramUniform3fEXT = NULL; +PFNGLPROGRAMUNIFORM3FVEXTPROC glad_glProgramUniform3fvEXT = NULL; +PFNGLPROGRAMUNIFORM3IEXTPROC glad_glProgramUniform3iEXT = NULL; +PFNGLPROGRAMUNIFORM3IVEXTPROC glad_glProgramUniform3ivEXT = NULL; +PFNGLPROGRAMUNIFORM3UIEXTPROC glad_glProgramUniform3uiEXT = NULL; +PFNGLPROGRAMUNIFORM3UIVEXTPROC glad_glProgramUniform3uivEXT = NULL; +PFNGLPROGRAMUNIFORM4FEXTPROC glad_glProgramUniform4fEXT = NULL; +PFNGLPROGRAMUNIFORM4FVEXTPROC glad_glProgramUniform4fvEXT = NULL; +PFNGLPROGRAMUNIFORM4IEXTPROC glad_glProgramUniform4iEXT = NULL; +PFNGLPROGRAMUNIFORM4IVEXTPROC glad_glProgramUniform4ivEXT = NULL; +PFNGLPROGRAMUNIFORM4UIEXTPROC glad_glProgramUniform4uiEXT = NULL; +PFNGLPROGRAMUNIFORM4UIVEXTPROC glad_glProgramUniform4uivEXT = NULL; +PFNGLPROGRAMUNIFORMMATRIX2FVEXTPROC glad_glProgramUniformMatrix2fvEXT = NULL; +PFNGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC glad_glProgramUniformMatrix2x3fvEXT = NULL; +PFNGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC glad_glProgramUniformMatrix2x4fvEXT = NULL; +PFNGLPROGRAMUNIFORMMATRIX3FVEXTPROC glad_glProgramUniformMatrix3fvEXT = NULL; +PFNGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC glad_glProgramUniformMatrix3x2fvEXT = NULL; +PFNGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC glad_glProgramUniformMatrix3x4fvEXT = NULL; +PFNGLPROGRAMUNIFORMMATRIX4FVEXTPROC glad_glProgramUniformMatrix4fvEXT = NULL; +PFNGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC glad_glProgramUniformMatrix4x2fvEXT = NULL; +PFNGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC glad_glProgramUniformMatrix4x3fvEXT = NULL; +PFNGLPUSHDEBUGGROUPKHRPROC glad_glPushDebugGroupKHR = NULL; +PFNGLPUSHGROUPMARKEREXTPROC glad_glPushGroupMarkerEXT = NULL; +PFNGLQUERYCOUNTEREXTPROC glad_glQueryCounterEXT = NULL; +PFNGLRASTERSAMPLESEXTPROC glad_glRasterSamplesEXT = NULL; +PFNGLREADBUFFERINDEXEDEXTPROC glad_glReadBufferIndexedEXT = NULL; +PFNGLREADPIXELSPROC glad_glReadPixels = NULL; +PFNGLREADNPIXELSEXTPROC glad_glReadnPixelsEXT = NULL; +PFNGLREADNPIXELSKHRPROC glad_glReadnPixelsKHR = NULL; +PFNGLRELEASEKEYEDMUTEXWIN32EXTPROC glad_glReleaseKeyedMutexWin32EXT = NULL; +PFNGLRELEASESHADERCOMPILERPROC glad_glReleaseShaderCompiler = NULL; +PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage = NULL; +PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glad_glRenderbufferStorageMultisampleEXT = NULL; +PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage = NULL; +PFNGLSAMPLERPARAMETERIIVEXTPROC glad_glSamplerParameterIivEXT = NULL; +PFNGLSAMPLERPARAMETERIIVOESPROC glad_glSamplerParameterIivOES = NULL; +PFNGLSAMPLERPARAMETERIUIVEXTPROC glad_glSamplerParameterIuivEXT = NULL; +PFNGLSAMPLERPARAMETERIUIVOESPROC glad_glSamplerParameterIuivOES = NULL; +PFNGLSCISSORPROC glad_glScissor = NULL; +PFNGLSCISSORARRAYVOESPROC glad_glScissorArrayvOES = NULL; +PFNGLSCISSORINDEXEDOESPROC glad_glScissorIndexedOES = NULL; +PFNGLSCISSORINDEXEDVOESPROC glad_glScissorIndexedvOES = NULL; +PFNGLSEMAPHOREPARAMETERUI64VEXTPROC glad_glSemaphoreParameterui64vEXT = NULL; +PFNGLSHADERBINARYPROC glad_glShaderBinary = NULL; +PFNGLSHADERSOURCEPROC glad_glShaderSource = NULL; +PFNGLSHADINGRATECOMBINEROPSEXTPROC glad_glShadingRateCombinerOpsEXT = NULL; +PFNGLSHADINGRATEEXTPROC glad_glShadingRateEXT = NULL; +PFNGLSIGNALSEMAPHOREEXTPROC glad_glSignalSemaphoreEXT = NULL; +PFNGLSTENCILFUNCPROC glad_glStencilFunc = NULL; +PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate = NULL; +PFNGLSTENCILMASKPROC glad_glStencilMask = NULL; +PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate = NULL; +PFNGLSTENCILOPPROC glad_glStencilOp = NULL; +PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate = NULL; +PFNGLTEXBUFFEREXTPROC glad_glTexBufferEXT = NULL; +PFNGLTEXBUFFEROESPROC glad_glTexBufferOES = NULL; +PFNGLTEXBUFFERRANGEEXTPROC glad_glTexBufferRangeEXT = NULL; +PFNGLTEXBUFFERRANGEOESPROC glad_glTexBufferRangeOES = NULL; +PFNGLTEXIMAGE2DPROC glad_glTexImage2D = NULL; +PFNGLTEXIMAGE3DOESPROC glad_glTexImage3DOES = NULL; +PFNGLTEXPAGECOMMITMENTEXTPROC glad_glTexPageCommitmentEXT = NULL; +PFNGLTEXPARAMETERIIVEXTPROC glad_glTexParameterIivEXT = NULL; +PFNGLTEXPARAMETERIIVOESPROC glad_glTexParameterIivOES = NULL; +PFNGLTEXPARAMETERIUIVEXTPROC glad_glTexParameterIuivEXT = NULL; +PFNGLTEXPARAMETERIUIVOESPROC glad_glTexParameterIuivOES = NULL; +PFNGLTEXPARAMETERFPROC glad_glTexParameterf = NULL; +PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv = NULL; +PFNGLTEXPARAMETERIPROC glad_glTexParameteri = NULL; +PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv = NULL; +PFNGLTEXSTORAGE1DEXTPROC glad_glTexStorage1DEXT = NULL; +PFNGLTEXSTORAGE2DEXTPROC glad_glTexStorage2DEXT = NULL; +PFNGLTEXSTORAGE3DEXTPROC glad_glTexStorage3DEXT = NULL; +PFNGLTEXSTORAGE3DMULTISAMPLEOESPROC glad_glTexStorage3DMultisampleOES = NULL; +PFNGLTEXSTORAGEATTRIBS2DEXTPROC glad_glTexStorageAttribs2DEXT = NULL; +PFNGLTEXSTORAGEATTRIBS3DEXTPROC glad_glTexStorageAttribs3DEXT = NULL; +PFNGLTEXSTORAGEMEM2DEXTPROC glad_glTexStorageMem2DEXT = NULL; +PFNGLTEXSTORAGEMEM2DMULTISAMPLEEXTPROC glad_glTexStorageMem2DMultisampleEXT = NULL; +PFNGLTEXSTORAGEMEM3DEXTPROC glad_glTexStorageMem3DEXT = NULL; +PFNGLTEXSTORAGEMEM3DMULTISAMPLEEXTPROC glad_glTexStorageMem3DMultisampleEXT = NULL; +PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D = NULL; +PFNGLTEXSUBIMAGE3DOESPROC glad_glTexSubImage3DOES = NULL; +PFNGLTEXTURESTORAGE1DEXTPROC glad_glTextureStorage1DEXT = NULL; +PFNGLTEXTURESTORAGE2DEXTPROC glad_glTextureStorage2DEXT = NULL; +PFNGLTEXTURESTORAGE3DEXTPROC glad_glTextureStorage3DEXT = NULL; +PFNGLTEXTURESTORAGEMEM2DEXTPROC glad_glTextureStorageMem2DEXT = NULL; +PFNGLTEXTURESTORAGEMEM2DMULTISAMPLEEXTPROC glad_glTextureStorageMem2DMultisampleEXT = NULL; +PFNGLTEXTURESTORAGEMEM3DEXTPROC glad_glTextureStorageMem3DEXT = NULL; +PFNGLTEXTURESTORAGEMEM3DMULTISAMPLEEXTPROC glad_glTextureStorageMem3DMultisampleEXT = NULL; +PFNGLTEXTUREVIEWEXTPROC glad_glTextureViewEXT = NULL; +PFNGLTEXTUREVIEWOESPROC glad_glTextureViewOES = NULL; +PFNGLUNIFORM1FPROC glad_glUniform1f = NULL; +PFNGLUNIFORM1FVPROC glad_glUniform1fv = NULL; +PFNGLUNIFORM1IPROC glad_glUniform1i = NULL; +PFNGLUNIFORM1IVPROC glad_glUniform1iv = NULL; +PFNGLUNIFORM2FPROC glad_glUniform2f = NULL; +PFNGLUNIFORM2FVPROC glad_glUniform2fv = NULL; +PFNGLUNIFORM2IPROC glad_glUniform2i = NULL; +PFNGLUNIFORM2IVPROC glad_glUniform2iv = NULL; +PFNGLUNIFORM3FPROC glad_glUniform3f = NULL; +PFNGLUNIFORM3FVPROC glad_glUniform3fv = NULL; +PFNGLUNIFORM3IPROC glad_glUniform3i = NULL; +PFNGLUNIFORM3IVPROC glad_glUniform3iv = NULL; +PFNGLUNIFORM4FPROC glad_glUniform4f = NULL; +PFNGLUNIFORM4FVPROC glad_glUniform4fv = NULL; +PFNGLUNIFORM4IPROC glad_glUniform4i = NULL; +PFNGLUNIFORM4IVPROC glad_glUniform4iv = NULL; +PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv = NULL; +PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv = NULL; +PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv = NULL; +PFNGLUNMAPBUFFEROESPROC glad_glUnmapBufferOES = NULL; +PFNGLUSEPROGRAMPROC glad_glUseProgram = NULL; +PFNGLUSEPROGRAMSTAGESEXTPROC glad_glUseProgramStagesEXT = NULL; +PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram = NULL; +PFNGLVALIDATEPROGRAMPIPELINEEXTPROC glad_glValidateProgramPipelineEXT = NULL; +PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f = NULL; +PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv = NULL; +PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f = NULL; +PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv = NULL; +PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f = NULL; +PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv = NULL; +PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f = NULL; +PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv = NULL; +PFNGLVERTEXATTRIBDIVISOREXTPROC glad_glVertexAttribDivisorEXT = NULL; +PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer = NULL; +PFNGLVIEWPORTPROC glad_glViewport = NULL; +PFNGLVIEWPORTARRAYVOESPROC glad_glViewportArrayvOES = NULL; +PFNGLVIEWPORTINDEXEDFOESPROC glad_glViewportIndexedfOES = NULL; +PFNGLVIEWPORTINDEXEDFVOESPROC glad_glViewportIndexedfvOES = NULL; +PFNGLWAITSEMAPHOREEXTPROC glad_glWaitSemaphoreEXT = NULL; +PFNGLWINDOWRECTANGLESEXTPROC glad_glWindowRectanglesEXT = NULL; + + +static void glad_gl_load_GL_ES_VERSION_2_0( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_ES_VERSION_2_0) return; + glad_glActiveTexture = (PFNGLACTIVETEXTUREPROC) load(userptr, "glActiveTexture"); + glad_glAttachShader = (PFNGLATTACHSHADERPROC) load(userptr, "glAttachShader"); + glad_glBindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC) load(userptr, "glBindAttribLocation"); + glad_glBindBuffer = (PFNGLBINDBUFFERPROC) load(userptr, "glBindBuffer"); + glad_glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC) load(userptr, "glBindFramebuffer"); + glad_glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC) load(userptr, "glBindRenderbuffer"); + glad_glBindTexture = (PFNGLBINDTEXTUREPROC) load(userptr, "glBindTexture"); + glad_glBlendColor = (PFNGLBLENDCOLORPROC) load(userptr, "glBlendColor"); + glad_glBlendEquation = (PFNGLBLENDEQUATIONPROC) load(userptr, "glBlendEquation"); + glad_glBlendEquationSeparate = (PFNGLBLENDEQUATIONSEPARATEPROC) load(userptr, "glBlendEquationSeparate"); + glad_glBlendFunc = (PFNGLBLENDFUNCPROC) load(userptr, "glBlendFunc"); + glad_glBlendFuncSeparate = (PFNGLBLENDFUNCSEPARATEPROC) load(userptr, "glBlendFuncSeparate"); + glad_glBufferData = (PFNGLBUFFERDATAPROC) load(userptr, "glBufferData"); + glad_glBufferSubData = (PFNGLBUFFERSUBDATAPROC) load(userptr, "glBufferSubData"); + glad_glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC) load(userptr, "glCheckFramebufferStatus"); + glad_glClear = (PFNGLCLEARPROC) load(userptr, "glClear"); + glad_glClearColor = (PFNGLCLEARCOLORPROC) load(userptr, "glClearColor"); + glad_glClearDepthf = (PFNGLCLEARDEPTHFPROC) load(userptr, "glClearDepthf"); + glad_glClearStencil = (PFNGLCLEARSTENCILPROC) load(userptr, "glClearStencil"); + glad_glColorMask = (PFNGLCOLORMASKPROC) load(userptr, "glColorMask"); + glad_glCompileShader = (PFNGLCOMPILESHADERPROC) load(userptr, "glCompileShader"); + glad_glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC) load(userptr, "glCompressedTexImage2D"); + glad_glCompressedTexSubImage2D = (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) load(userptr, "glCompressedTexSubImage2D"); + glad_glCopyTexImage2D = (PFNGLCOPYTEXIMAGE2DPROC) load(userptr, "glCopyTexImage2D"); + glad_glCopyTexSubImage2D = (PFNGLCOPYTEXSUBIMAGE2DPROC) load(userptr, "glCopyTexSubImage2D"); + glad_glCreateProgram = (PFNGLCREATEPROGRAMPROC) load(userptr, "glCreateProgram"); + glad_glCreateShader = (PFNGLCREATESHADERPROC) load(userptr, "glCreateShader"); + glad_glCullFace = (PFNGLCULLFACEPROC) load(userptr, "glCullFace"); + glad_glDeleteBuffers = (PFNGLDELETEBUFFERSPROC) load(userptr, "glDeleteBuffers"); + glad_glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC) load(userptr, "glDeleteFramebuffers"); + glad_glDeleteProgram = (PFNGLDELETEPROGRAMPROC) load(userptr, "glDeleteProgram"); + glad_glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC) load(userptr, "glDeleteRenderbuffers"); + glad_glDeleteShader = (PFNGLDELETESHADERPROC) load(userptr, "glDeleteShader"); + glad_glDeleteTextures = (PFNGLDELETETEXTURESPROC) load(userptr, "glDeleteTextures"); + glad_glDepthFunc = (PFNGLDEPTHFUNCPROC) load(userptr, "glDepthFunc"); + glad_glDepthMask = (PFNGLDEPTHMASKPROC) load(userptr, "glDepthMask"); + glad_glDepthRangef = (PFNGLDEPTHRANGEFPROC) load(userptr, "glDepthRangef"); + glad_glDetachShader = (PFNGLDETACHSHADERPROC) load(userptr, "glDetachShader"); + glad_glDisable = (PFNGLDISABLEPROC) load(userptr, "glDisable"); + glad_glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC) load(userptr, "glDisableVertexAttribArray"); + glad_glDrawArrays = (PFNGLDRAWARRAYSPROC) load(userptr, "glDrawArrays"); + glad_glDrawElements = (PFNGLDRAWELEMENTSPROC) load(userptr, "glDrawElements"); + glad_glEnable = (PFNGLENABLEPROC) load(userptr, "glEnable"); + glad_glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC) load(userptr, "glEnableVertexAttribArray"); + glad_glFinish = (PFNGLFINISHPROC) load(userptr, "glFinish"); + glad_glFlush = (PFNGLFLUSHPROC) load(userptr, "glFlush"); + glad_glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC) load(userptr, "glFramebufferRenderbuffer"); + glad_glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC) load(userptr, "glFramebufferTexture2D"); + glad_glFrontFace = (PFNGLFRONTFACEPROC) load(userptr, "glFrontFace"); + glad_glGenBuffers = (PFNGLGENBUFFERSPROC) load(userptr, "glGenBuffers"); + glad_glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC) load(userptr, "glGenFramebuffers"); + glad_glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC) load(userptr, "glGenRenderbuffers"); + glad_glGenTextures = (PFNGLGENTEXTURESPROC) load(userptr, "glGenTextures"); + glad_glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC) load(userptr, "glGenerateMipmap"); + glad_glGetActiveAttrib = (PFNGLGETACTIVEATTRIBPROC) load(userptr, "glGetActiveAttrib"); + glad_glGetActiveUniform = (PFNGLGETACTIVEUNIFORMPROC) load(userptr, "glGetActiveUniform"); + glad_glGetAttachedShaders = (PFNGLGETATTACHEDSHADERSPROC) load(userptr, "glGetAttachedShaders"); + glad_glGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC) load(userptr, "glGetAttribLocation"); + glad_glGetBooleanv = (PFNGLGETBOOLEANVPROC) load(userptr, "glGetBooleanv"); + glad_glGetBufferParameteriv = (PFNGLGETBUFFERPARAMETERIVPROC) load(userptr, "glGetBufferParameteriv"); + glad_glGetError = (PFNGLGETERRORPROC) load(userptr, "glGetError"); + glad_glGetFloatv = (PFNGLGETFLOATVPROC) load(userptr, "glGetFloatv"); + glad_glGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC) load(userptr, "glGetFramebufferAttachmentParameteriv"); + glad_glGetIntegerv = (PFNGLGETINTEGERVPROC) load(userptr, "glGetIntegerv"); + glad_glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC) load(userptr, "glGetProgramInfoLog"); + glad_glGetProgramiv = (PFNGLGETPROGRAMIVPROC) load(userptr, "glGetProgramiv"); + glad_glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC) load(userptr, "glGetRenderbufferParameteriv"); + glad_glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC) load(userptr, "glGetShaderInfoLog"); + glad_glGetShaderPrecisionFormat = (PFNGLGETSHADERPRECISIONFORMATPROC) load(userptr, "glGetShaderPrecisionFormat"); + glad_glGetShaderSource = (PFNGLGETSHADERSOURCEPROC) load(userptr, "glGetShaderSource"); + glad_glGetShaderiv = (PFNGLGETSHADERIVPROC) load(userptr, "glGetShaderiv"); + glad_glGetString = (PFNGLGETSTRINGPROC) load(userptr, "glGetString"); + glad_glGetTexParameterfv = (PFNGLGETTEXPARAMETERFVPROC) load(userptr, "glGetTexParameterfv"); + glad_glGetTexParameteriv = (PFNGLGETTEXPARAMETERIVPROC) load(userptr, "glGetTexParameteriv"); + glad_glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC) load(userptr, "glGetUniformLocation"); + glad_glGetUniformfv = (PFNGLGETUNIFORMFVPROC) load(userptr, "glGetUniformfv"); + glad_glGetUniformiv = (PFNGLGETUNIFORMIVPROC) load(userptr, "glGetUniformiv"); + glad_glGetVertexAttribPointerv = (PFNGLGETVERTEXATTRIBPOINTERVPROC) load(userptr, "glGetVertexAttribPointerv"); + glad_glGetVertexAttribfv = (PFNGLGETVERTEXATTRIBFVPROC) load(userptr, "glGetVertexAttribfv"); + glad_glGetVertexAttribiv = (PFNGLGETVERTEXATTRIBIVPROC) load(userptr, "glGetVertexAttribiv"); + glad_glHint = (PFNGLHINTPROC) load(userptr, "glHint"); + glad_glIsBuffer = (PFNGLISBUFFERPROC) load(userptr, "glIsBuffer"); + glad_glIsEnabled = (PFNGLISENABLEDPROC) load(userptr, "glIsEnabled"); + glad_glIsFramebuffer = (PFNGLISFRAMEBUFFERPROC) load(userptr, "glIsFramebuffer"); + glad_glIsProgram = (PFNGLISPROGRAMPROC) load(userptr, "glIsProgram"); + glad_glIsRenderbuffer = (PFNGLISRENDERBUFFERPROC) load(userptr, "glIsRenderbuffer"); + glad_glIsShader = (PFNGLISSHADERPROC) load(userptr, "glIsShader"); + glad_glIsTexture = (PFNGLISTEXTUREPROC) load(userptr, "glIsTexture"); + glad_glLineWidth = (PFNGLLINEWIDTHPROC) load(userptr, "glLineWidth"); + glad_glLinkProgram = (PFNGLLINKPROGRAMPROC) load(userptr, "glLinkProgram"); + glad_glPixelStorei = (PFNGLPIXELSTOREIPROC) load(userptr, "glPixelStorei"); + glad_glPolygonOffset = (PFNGLPOLYGONOFFSETPROC) load(userptr, "glPolygonOffset"); + glad_glReadPixels = (PFNGLREADPIXELSPROC) load(userptr, "glReadPixels"); + glad_glReleaseShaderCompiler = (PFNGLRELEASESHADERCOMPILERPROC) load(userptr, "glReleaseShaderCompiler"); + glad_glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC) load(userptr, "glRenderbufferStorage"); + glad_glSampleCoverage = (PFNGLSAMPLECOVERAGEPROC) load(userptr, "glSampleCoverage"); + glad_glScissor = (PFNGLSCISSORPROC) load(userptr, "glScissor"); + glad_glShaderBinary = (PFNGLSHADERBINARYPROC) load(userptr, "glShaderBinary"); + glad_glShaderSource = (PFNGLSHADERSOURCEPROC) load(userptr, "glShaderSource"); + glad_glStencilFunc = (PFNGLSTENCILFUNCPROC) load(userptr, "glStencilFunc"); + glad_glStencilFuncSeparate = (PFNGLSTENCILFUNCSEPARATEPROC) load(userptr, "glStencilFuncSeparate"); + glad_glStencilMask = (PFNGLSTENCILMASKPROC) load(userptr, "glStencilMask"); + glad_glStencilMaskSeparate = (PFNGLSTENCILMASKSEPARATEPROC) load(userptr, "glStencilMaskSeparate"); + glad_glStencilOp = (PFNGLSTENCILOPPROC) load(userptr, "glStencilOp"); + glad_glStencilOpSeparate = (PFNGLSTENCILOPSEPARATEPROC) load(userptr, "glStencilOpSeparate"); + glad_glTexImage2D = (PFNGLTEXIMAGE2DPROC) load(userptr, "glTexImage2D"); + glad_glTexParameterf = (PFNGLTEXPARAMETERFPROC) load(userptr, "glTexParameterf"); + glad_glTexParameterfv = (PFNGLTEXPARAMETERFVPROC) load(userptr, "glTexParameterfv"); + glad_glTexParameteri = (PFNGLTEXPARAMETERIPROC) load(userptr, "glTexParameteri"); + glad_glTexParameteriv = (PFNGLTEXPARAMETERIVPROC) load(userptr, "glTexParameteriv"); + glad_glTexSubImage2D = (PFNGLTEXSUBIMAGE2DPROC) load(userptr, "glTexSubImage2D"); + glad_glUniform1f = (PFNGLUNIFORM1FPROC) load(userptr, "glUniform1f"); + glad_glUniform1fv = (PFNGLUNIFORM1FVPROC) load(userptr, "glUniform1fv"); + glad_glUniform1i = (PFNGLUNIFORM1IPROC) load(userptr, "glUniform1i"); + glad_glUniform1iv = (PFNGLUNIFORM1IVPROC) load(userptr, "glUniform1iv"); + glad_glUniform2f = (PFNGLUNIFORM2FPROC) load(userptr, "glUniform2f"); + glad_glUniform2fv = (PFNGLUNIFORM2FVPROC) load(userptr, "glUniform2fv"); + glad_glUniform2i = (PFNGLUNIFORM2IPROC) load(userptr, "glUniform2i"); + glad_glUniform2iv = (PFNGLUNIFORM2IVPROC) load(userptr, "glUniform2iv"); + glad_glUniform3f = (PFNGLUNIFORM3FPROC) load(userptr, "glUniform3f"); + glad_glUniform3fv = (PFNGLUNIFORM3FVPROC) load(userptr, "glUniform3fv"); + glad_glUniform3i = (PFNGLUNIFORM3IPROC) load(userptr, "glUniform3i"); + glad_glUniform3iv = (PFNGLUNIFORM3IVPROC) load(userptr, "glUniform3iv"); + glad_glUniform4f = (PFNGLUNIFORM4FPROC) load(userptr, "glUniform4f"); + glad_glUniform4fv = (PFNGLUNIFORM4FVPROC) load(userptr, "glUniform4fv"); + glad_glUniform4i = (PFNGLUNIFORM4IPROC) load(userptr, "glUniform4i"); + glad_glUniform4iv = (PFNGLUNIFORM4IVPROC) load(userptr, "glUniform4iv"); + glad_glUniformMatrix2fv = (PFNGLUNIFORMMATRIX2FVPROC) load(userptr, "glUniformMatrix2fv"); + glad_glUniformMatrix3fv = (PFNGLUNIFORMMATRIX3FVPROC) load(userptr, "glUniformMatrix3fv"); + glad_glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC) load(userptr, "glUniformMatrix4fv"); + glad_glUseProgram = (PFNGLUSEPROGRAMPROC) load(userptr, "glUseProgram"); + glad_glValidateProgram = (PFNGLVALIDATEPROGRAMPROC) load(userptr, "glValidateProgram"); + glad_glVertexAttrib1f = (PFNGLVERTEXATTRIB1FPROC) load(userptr, "glVertexAttrib1f"); + glad_glVertexAttrib1fv = (PFNGLVERTEXATTRIB1FVPROC) load(userptr, "glVertexAttrib1fv"); + glad_glVertexAttrib2f = (PFNGLVERTEXATTRIB2FPROC) load(userptr, "glVertexAttrib2f"); + glad_glVertexAttrib2fv = (PFNGLVERTEXATTRIB2FVPROC) load(userptr, "glVertexAttrib2fv"); + glad_glVertexAttrib3f = (PFNGLVERTEXATTRIB3FPROC) load(userptr, "glVertexAttrib3f"); + glad_glVertexAttrib3fv = (PFNGLVERTEXATTRIB3FVPROC) load(userptr, "glVertexAttrib3fv"); + glad_glVertexAttrib4f = (PFNGLVERTEXATTRIB4FPROC) load(userptr, "glVertexAttrib4f"); + glad_glVertexAttrib4fv = (PFNGLVERTEXATTRIB4FVPROC) load(userptr, "glVertexAttrib4fv"); + glad_glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC) load(userptr, "glVertexAttribPointer"); + glad_glViewport = (PFNGLVIEWPORTPROC) load(userptr, "glViewport"); +} +static void glad_gl_load_GL_EXT_EGL_image_storage( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_EGL_image_storage) return; + glad_glEGLImageTargetTexStorageEXT = (PFNGLEGLIMAGETARGETTEXSTORAGEEXTPROC) load(userptr, "glEGLImageTargetTexStorageEXT"); + glad_glEGLImageTargetTextureStorageEXT = (PFNGLEGLIMAGETARGETTEXTURESTORAGEEXTPROC) load(userptr, "glEGLImageTargetTextureStorageEXT"); +} +static void glad_gl_load_GL_EXT_base_instance( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_base_instance) return; + glad_glDrawArraysInstancedBaseInstanceEXT = (PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEEXTPROC) load(userptr, "glDrawArraysInstancedBaseInstanceEXT"); + glad_glDrawElementsInstancedBaseInstanceEXT = (PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEEXTPROC) load(userptr, "glDrawElementsInstancedBaseInstanceEXT"); + glad_glDrawElementsInstancedBaseVertexBaseInstanceEXT = (PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEEXTPROC) load(userptr, "glDrawElementsInstancedBaseVertexBaseInstanceEXT"); +} +static void glad_gl_load_GL_EXT_blend_func_extended( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_blend_func_extended) return; + glad_glBindFragDataLocationEXT = (PFNGLBINDFRAGDATALOCATIONEXTPROC) load(userptr, "glBindFragDataLocationEXT"); + glad_glBindFragDataLocationIndexedEXT = (PFNGLBINDFRAGDATALOCATIONINDEXEDEXTPROC) load(userptr, "glBindFragDataLocationIndexedEXT"); + glad_glGetFragDataIndexEXT = (PFNGLGETFRAGDATAINDEXEXTPROC) load(userptr, "glGetFragDataIndexEXT"); + glad_glGetProgramResourceLocationIndexEXT = (PFNGLGETPROGRAMRESOURCELOCATIONINDEXEXTPROC) load(userptr, "glGetProgramResourceLocationIndexEXT"); +} +static void glad_gl_load_GL_EXT_buffer_storage( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_buffer_storage) return; + glad_glBufferStorageEXT = (PFNGLBUFFERSTORAGEEXTPROC) load(userptr, "glBufferStorageEXT"); +} +static void glad_gl_load_GL_EXT_clear_texture( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_clear_texture) return; + glad_glClearTexImageEXT = (PFNGLCLEARTEXIMAGEEXTPROC) load(userptr, "glClearTexImageEXT"); + glad_glClearTexSubImageEXT = (PFNGLCLEARTEXSUBIMAGEEXTPROC) load(userptr, "glClearTexSubImageEXT"); +} +static void glad_gl_load_GL_EXT_clip_control( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_clip_control) return; + glad_glClipControlEXT = (PFNGLCLIPCONTROLEXTPROC) load(userptr, "glClipControlEXT"); +} +static void glad_gl_load_GL_EXT_copy_image( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_copy_image) return; + glad_glCopyImageSubDataEXT = (PFNGLCOPYIMAGESUBDATAEXTPROC) load(userptr, "glCopyImageSubDataEXT"); +} +static void glad_gl_load_GL_EXT_debug_label( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_debug_label) return; + glad_glGetObjectLabelEXT = (PFNGLGETOBJECTLABELEXTPROC) load(userptr, "glGetObjectLabelEXT"); + glad_glLabelObjectEXT = (PFNGLLABELOBJECTEXTPROC) load(userptr, "glLabelObjectEXT"); +} +static void glad_gl_load_GL_EXT_debug_marker( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_debug_marker) return; + glad_glInsertEventMarkerEXT = (PFNGLINSERTEVENTMARKEREXTPROC) load(userptr, "glInsertEventMarkerEXT"); + glad_glPopGroupMarkerEXT = (PFNGLPOPGROUPMARKEREXTPROC) load(userptr, "glPopGroupMarkerEXT"); + glad_glPushGroupMarkerEXT = (PFNGLPUSHGROUPMARKEREXTPROC) load(userptr, "glPushGroupMarkerEXT"); +} +static void glad_gl_load_GL_EXT_discard_framebuffer( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_discard_framebuffer) return; + glad_glDiscardFramebufferEXT = (PFNGLDISCARDFRAMEBUFFEREXTPROC) load(userptr, "glDiscardFramebufferEXT"); +} +static void glad_gl_load_GL_EXT_disjoint_timer_query( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_disjoint_timer_query) return; + glad_glBeginQueryEXT = (PFNGLBEGINQUERYEXTPROC) load(userptr, "glBeginQueryEXT"); + glad_glDeleteQueriesEXT = (PFNGLDELETEQUERIESEXTPROC) load(userptr, "glDeleteQueriesEXT"); + glad_glEndQueryEXT = (PFNGLENDQUERYEXTPROC) load(userptr, "glEndQueryEXT"); + glad_glGenQueriesEXT = (PFNGLGENQUERIESEXTPROC) load(userptr, "glGenQueriesEXT"); + glad_glGetInteger64vEXT = (PFNGLGETINTEGER64VEXTPROC) load(userptr, "glGetInteger64vEXT"); + glad_glGetQueryObjecti64vEXT = (PFNGLGETQUERYOBJECTI64VEXTPROC) load(userptr, "glGetQueryObjecti64vEXT"); + glad_glGetQueryObjectivEXT = (PFNGLGETQUERYOBJECTIVEXTPROC) load(userptr, "glGetQueryObjectivEXT"); + glad_glGetQueryObjectui64vEXT = (PFNGLGETQUERYOBJECTUI64VEXTPROC) load(userptr, "glGetQueryObjectui64vEXT"); + glad_glGetQueryObjectuivEXT = (PFNGLGETQUERYOBJECTUIVEXTPROC) load(userptr, "glGetQueryObjectuivEXT"); + glad_glGetQueryivEXT = (PFNGLGETQUERYIVEXTPROC) load(userptr, "glGetQueryivEXT"); + glad_glIsQueryEXT = (PFNGLISQUERYEXTPROC) load(userptr, "glIsQueryEXT"); + glad_glQueryCounterEXT = (PFNGLQUERYCOUNTEREXTPROC) load(userptr, "glQueryCounterEXT"); +} +static void glad_gl_load_GL_EXT_draw_buffers( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_draw_buffers) return; + glad_glDrawBuffersEXT = (PFNGLDRAWBUFFERSEXTPROC) load(userptr, "glDrawBuffersEXT"); +} +static void glad_gl_load_GL_EXT_draw_buffers_indexed( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_draw_buffers_indexed) return; + glad_glBlendEquationSeparateiEXT = (PFNGLBLENDEQUATIONSEPARATEIEXTPROC) load(userptr, "glBlendEquationSeparateiEXT"); + glad_glBlendEquationiEXT = (PFNGLBLENDEQUATIONIEXTPROC) load(userptr, "glBlendEquationiEXT"); + glad_glBlendFuncSeparateiEXT = (PFNGLBLENDFUNCSEPARATEIEXTPROC) load(userptr, "glBlendFuncSeparateiEXT"); + glad_glBlendFunciEXT = (PFNGLBLENDFUNCIEXTPROC) load(userptr, "glBlendFunciEXT"); + glad_glColorMaskiEXT = (PFNGLCOLORMASKIEXTPROC) load(userptr, "glColorMaskiEXT"); + glad_glDisableiEXT = (PFNGLDISABLEIEXTPROC) load(userptr, "glDisableiEXT"); + glad_glEnableiEXT = (PFNGLENABLEIEXTPROC) load(userptr, "glEnableiEXT"); + glad_glIsEnablediEXT = (PFNGLISENABLEDIEXTPROC) load(userptr, "glIsEnablediEXT"); +} +static void glad_gl_load_GL_EXT_draw_elements_base_vertex( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_draw_elements_base_vertex) return; + glad_glDrawElementsBaseVertexEXT = (PFNGLDRAWELEMENTSBASEVERTEXEXTPROC) load(userptr, "glDrawElementsBaseVertexEXT"); + glad_glDrawElementsInstancedBaseVertexEXT = (PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXEXTPROC) load(userptr, "glDrawElementsInstancedBaseVertexEXT"); + glad_glDrawRangeElementsBaseVertexEXT = (PFNGLDRAWRANGEELEMENTSBASEVERTEXEXTPROC) load(userptr, "glDrawRangeElementsBaseVertexEXT"); + glad_glMultiDrawElementsBaseVertexEXT = (PFNGLMULTIDRAWELEMENTSBASEVERTEXEXTPROC) load(userptr, "glMultiDrawElementsBaseVertexEXT"); +} +static void glad_gl_load_GL_EXT_draw_instanced( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_draw_instanced) return; + glad_glDrawArraysInstancedEXT = (PFNGLDRAWARRAYSINSTANCEDEXTPROC) load(userptr, "glDrawArraysInstancedEXT"); + glad_glDrawElementsInstancedEXT = (PFNGLDRAWELEMENTSINSTANCEDEXTPROC) load(userptr, "glDrawElementsInstancedEXT"); +} +static void glad_gl_load_GL_EXT_draw_transform_feedback( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_draw_transform_feedback) return; + glad_glDrawTransformFeedbackEXT = (PFNGLDRAWTRANSFORMFEEDBACKEXTPROC) load(userptr, "glDrawTransformFeedbackEXT"); + glad_glDrawTransformFeedbackInstancedEXT = (PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDEXTPROC) load(userptr, "glDrawTransformFeedbackInstancedEXT"); +} +static void glad_gl_load_GL_EXT_external_buffer( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_external_buffer) return; + glad_glBufferStorageExternalEXT = (PFNGLBUFFERSTORAGEEXTERNALEXTPROC) load(userptr, "glBufferStorageExternalEXT"); + glad_glNamedBufferStorageExternalEXT = (PFNGLNAMEDBUFFERSTORAGEEXTERNALEXTPROC) load(userptr, "glNamedBufferStorageExternalEXT"); +} +static void glad_gl_load_GL_EXT_fragment_shading_rate( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_fragment_shading_rate) return; + glad_glFramebufferShadingRateEXT = (PFNGLFRAMEBUFFERSHADINGRATEEXTPROC) load(userptr, "glFramebufferShadingRateEXT"); + glad_glGetFragmentShadingRatesEXT = (PFNGLGETFRAGMENTSHADINGRATESEXTPROC) load(userptr, "glGetFragmentShadingRatesEXT"); + glad_glShadingRateCombinerOpsEXT = (PFNGLSHADINGRATECOMBINEROPSEXTPROC) load(userptr, "glShadingRateCombinerOpsEXT"); + glad_glShadingRateEXT = (PFNGLSHADINGRATEEXTPROC) load(userptr, "glShadingRateEXT"); +} +static void glad_gl_load_GL_EXT_geometry_shader( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_geometry_shader) return; + glad_glFramebufferTextureEXT = (PFNGLFRAMEBUFFERTEXTUREEXTPROC) load(userptr, "glFramebufferTextureEXT"); +} +static void glad_gl_load_GL_EXT_instanced_arrays( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_instanced_arrays) return; + glad_glDrawArraysInstancedEXT = (PFNGLDRAWARRAYSINSTANCEDEXTPROC) load(userptr, "glDrawArraysInstancedEXT"); + glad_glDrawElementsInstancedEXT = (PFNGLDRAWELEMENTSINSTANCEDEXTPROC) load(userptr, "glDrawElementsInstancedEXT"); + glad_glVertexAttribDivisorEXT = (PFNGLVERTEXATTRIBDIVISOREXTPROC) load(userptr, "glVertexAttribDivisorEXT"); +} +static void glad_gl_load_GL_EXT_map_buffer_range( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_map_buffer_range) return; + glad_glFlushMappedBufferRangeEXT = (PFNGLFLUSHMAPPEDBUFFERRANGEEXTPROC) load(userptr, "glFlushMappedBufferRangeEXT"); + glad_glMapBufferRangeEXT = (PFNGLMAPBUFFERRANGEEXTPROC) load(userptr, "glMapBufferRangeEXT"); +} +static void glad_gl_load_GL_EXT_memory_object( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_memory_object) return; + glad_glBufferStorageMemEXT = (PFNGLBUFFERSTORAGEMEMEXTPROC) load(userptr, "glBufferStorageMemEXT"); + glad_glCreateMemoryObjectsEXT = (PFNGLCREATEMEMORYOBJECTSEXTPROC) load(userptr, "glCreateMemoryObjectsEXT"); + glad_glDeleteMemoryObjectsEXT = (PFNGLDELETEMEMORYOBJECTSEXTPROC) load(userptr, "glDeleteMemoryObjectsEXT"); + glad_glGetMemoryObjectParameterivEXT = (PFNGLGETMEMORYOBJECTPARAMETERIVEXTPROC) load(userptr, "glGetMemoryObjectParameterivEXT"); + glad_glGetUnsignedBytei_vEXT = (PFNGLGETUNSIGNEDBYTEI_VEXTPROC) load(userptr, "glGetUnsignedBytei_vEXT"); + glad_glGetUnsignedBytevEXT = (PFNGLGETUNSIGNEDBYTEVEXTPROC) load(userptr, "glGetUnsignedBytevEXT"); + glad_glIsMemoryObjectEXT = (PFNGLISMEMORYOBJECTEXTPROC) load(userptr, "glIsMemoryObjectEXT"); + glad_glMemoryObjectParameterivEXT = (PFNGLMEMORYOBJECTPARAMETERIVEXTPROC) load(userptr, "glMemoryObjectParameterivEXT"); + glad_glNamedBufferStorageMemEXT = (PFNGLNAMEDBUFFERSTORAGEMEMEXTPROC) load(userptr, "glNamedBufferStorageMemEXT"); + glad_glTexStorageMem2DEXT = (PFNGLTEXSTORAGEMEM2DEXTPROC) load(userptr, "glTexStorageMem2DEXT"); + glad_glTexStorageMem2DMultisampleEXT = (PFNGLTEXSTORAGEMEM2DMULTISAMPLEEXTPROC) load(userptr, "glTexStorageMem2DMultisampleEXT"); + glad_glTexStorageMem3DEXT = (PFNGLTEXSTORAGEMEM3DEXTPROC) load(userptr, "glTexStorageMem3DEXT"); + glad_glTexStorageMem3DMultisampleEXT = (PFNGLTEXSTORAGEMEM3DMULTISAMPLEEXTPROC) load(userptr, "glTexStorageMem3DMultisampleEXT"); + glad_glTextureStorageMem2DEXT = (PFNGLTEXTURESTORAGEMEM2DEXTPROC) load(userptr, "glTextureStorageMem2DEXT"); + glad_glTextureStorageMem2DMultisampleEXT = (PFNGLTEXTURESTORAGEMEM2DMULTISAMPLEEXTPROC) load(userptr, "glTextureStorageMem2DMultisampleEXT"); + glad_glTextureStorageMem3DEXT = (PFNGLTEXTURESTORAGEMEM3DEXTPROC) load(userptr, "glTextureStorageMem3DEXT"); + glad_glTextureStorageMem3DMultisampleEXT = (PFNGLTEXTURESTORAGEMEM3DMULTISAMPLEEXTPROC) load(userptr, "glTextureStorageMem3DMultisampleEXT"); +} +static void glad_gl_load_GL_EXT_memory_object_fd( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_memory_object_fd) return; + glad_glImportMemoryFdEXT = (PFNGLIMPORTMEMORYFDEXTPROC) load(userptr, "glImportMemoryFdEXT"); +} +static void glad_gl_load_GL_EXT_memory_object_win32( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_memory_object_win32) return; + glad_glImportMemoryWin32HandleEXT = (PFNGLIMPORTMEMORYWIN32HANDLEEXTPROC) load(userptr, "glImportMemoryWin32HandleEXT"); + glad_glImportMemoryWin32NameEXT = (PFNGLIMPORTMEMORYWIN32NAMEEXTPROC) load(userptr, "glImportMemoryWin32NameEXT"); +} +static void glad_gl_load_GL_EXT_multi_draw_arrays( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_multi_draw_arrays) return; + glad_glMultiDrawArraysEXT = (PFNGLMULTIDRAWARRAYSEXTPROC) load(userptr, "glMultiDrawArraysEXT"); + glad_glMultiDrawElementsEXT = (PFNGLMULTIDRAWELEMENTSEXTPROC) load(userptr, "glMultiDrawElementsEXT"); +} +static void glad_gl_load_GL_EXT_multi_draw_indirect( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_multi_draw_indirect) return; + glad_glMultiDrawArraysIndirectEXT = (PFNGLMULTIDRAWARRAYSINDIRECTEXTPROC) load(userptr, "glMultiDrawArraysIndirectEXT"); + glad_glMultiDrawElementsIndirectEXT = (PFNGLMULTIDRAWELEMENTSINDIRECTEXTPROC) load(userptr, "glMultiDrawElementsIndirectEXT"); +} +static void glad_gl_load_GL_EXT_multisampled_render_to_texture( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_multisampled_render_to_texture) return; + glad_glFramebufferTexture2DMultisampleEXT = (PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC) load(userptr, "glFramebufferTexture2DMultisampleEXT"); + glad_glRenderbufferStorageMultisampleEXT = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) load(userptr, "glRenderbufferStorageMultisampleEXT"); +} +static void glad_gl_load_GL_EXT_multiview_draw_buffers( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_multiview_draw_buffers) return; + glad_glDrawBuffersIndexedEXT = (PFNGLDRAWBUFFERSINDEXEDEXTPROC) load(userptr, "glDrawBuffersIndexedEXT"); + glad_glGetIntegeri_vEXT = (PFNGLGETINTEGERI_VEXTPROC) load(userptr, "glGetIntegeri_vEXT"); + glad_glReadBufferIndexedEXT = (PFNGLREADBUFFERINDEXEDEXTPROC) load(userptr, "glReadBufferIndexedEXT"); +} +static void glad_gl_load_GL_EXT_occlusion_query_boolean( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_occlusion_query_boolean) return; + glad_glBeginQueryEXT = (PFNGLBEGINQUERYEXTPROC) load(userptr, "glBeginQueryEXT"); + glad_glDeleteQueriesEXT = (PFNGLDELETEQUERIESEXTPROC) load(userptr, "glDeleteQueriesEXT"); + glad_glEndQueryEXT = (PFNGLENDQUERYEXTPROC) load(userptr, "glEndQueryEXT"); + glad_glGenQueriesEXT = (PFNGLGENQUERIESEXTPROC) load(userptr, "glGenQueriesEXT"); + glad_glGetQueryObjectuivEXT = (PFNGLGETQUERYOBJECTUIVEXTPROC) load(userptr, "glGetQueryObjectuivEXT"); + glad_glGetQueryivEXT = (PFNGLGETQUERYIVEXTPROC) load(userptr, "glGetQueryivEXT"); + glad_glIsQueryEXT = (PFNGLISQUERYEXTPROC) load(userptr, "glIsQueryEXT"); +} +static void glad_gl_load_GL_EXT_polygon_offset_clamp( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_polygon_offset_clamp) return; + glad_glPolygonOffsetClampEXT = (PFNGLPOLYGONOFFSETCLAMPEXTPROC) load(userptr, "glPolygonOffsetClampEXT"); +} +static void glad_gl_load_GL_EXT_primitive_bounding_box( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_primitive_bounding_box) return; + glad_glPrimitiveBoundingBoxEXT = (PFNGLPRIMITIVEBOUNDINGBOXEXTPROC) load(userptr, "glPrimitiveBoundingBoxEXT"); +} +static void glad_gl_load_GL_EXT_raster_multisample( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_raster_multisample) return; + glad_glRasterSamplesEXT = (PFNGLRASTERSAMPLESEXTPROC) load(userptr, "glRasterSamplesEXT"); +} +static void glad_gl_load_GL_EXT_robustness( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_robustness) return; + glad_glGetGraphicsResetStatusEXT = (PFNGLGETGRAPHICSRESETSTATUSEXTPROC) load(userptr, "glGetGraphicsResetStatusEXT"); + glad_glGetnUniformfvEXT = (PFNGLGETNUNIFORMFVEXTPROC) load(userptr, "glGetnUniformfvEXT"); + glad_glGetnUniformivEXT = (PFNGLGETNUNIFORMIVEXTPROC) load(userptr, "glGetnUniformivEXT"); + glad_glReadnPixelsEXT = (PFNGLREADNPIXELSEXTPROC) load(userptr, "glReadnPixelsEXT"); +} +static void glad_gl_load_GL_EXT_semaphore( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_semaphore) return; + glad_glDeleteSemaphoresEXT = (PFNGLDELETESEMAPHORESEXTPROC) load(userptr, "glDeleteSemaphoresEXT"); + glad_glGenSemaphoresEXT = (PFNGLGENSEMAPHORESEXTPROC) load(userptr, "glGenSemaphoresEXT"); + glad_glGetSemaphoreParameterui64vEXT = (PFNGLGETSEMAPHOREPARAMETERUI64VEXTPROC) load(userptr, "glGetSemaphoreParameterui64vEXT"); + glad_glGetUnsignedBytei_vEXT = (PFNGLGETUNSIGNEDBYTEI_VEXTPROC) load(userptr, "glGetUnsignedBytei_vEXT"); + glad_glGetUnsignedBytevEXT = (PFNGLGETUNSIGNEDBYTEVEXTPROC) load(userptr, "glGetUnsignedBytevEXT"); + glad_glIsSemaphoreEXT = (PFNGLISSEMAPHOREEXTPROC) load(userptr, "glIsSemaphoreEXT"); + glad_glSemaphoreParameterui64vEXT = (PFNGLSEMAPHOREPARAMETERUI64VEXTPROC) load(userptr, "glSemaphoreParameterui64vEXT"); + glad_glSignalSemaphoreEXT = (PFNGLSIGNALSEMAPHOREEXTPROC) load(userptr, "glSignalSemaphoreEXT"); + glad_glWaitSemaphoreEXT = (PFNGLWAITSEMAPHOREEXTPROC) load(userptr, "glWaitSemaphoreEXT"); +} +static void glad_gl_load_GL_EXT_semaphore_fd( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_semaphore_fd) return; + glad_glImportSemaphoreFdEXT = (PFNGLIMPORTSEMAPHOREFDEXTPROC) load(userptr, "glImportSemaphoreFdEXT"); +} +static void glad_gl_load_GL_EXT_semaphore_win32( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_semaphore_win32) return; + glad_glImportSemaphoreWin32HandleEXT = (PFNGLIMPORTSEMAPHOREWIN32HANDLEEXTPROC) load(userptr, "glImportSemaphoreWin32HandleEXT"); + glad_glImportSemaphoreWin32NameEXT = (PFNGLIMPORTSEMAPHOREWIN32NAMEEXTPROC) load(userptr, "glImportSemaphoreWin32NameEXT"); +} +static void glad_gl_load_GL_EXT_separate_shader_objects( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_separate_shader_objects) return; + glad_glActiveShaderProgramEXT = (PFNGLACTIVESHADERPROGRAMEXTPROC) load(userptr, "glActiveShaderProgramEXT"); + glad_glBindProgramPipelineEXT = (PFNGLBINDPROGRAMPIPELINEEXTPROC) load(userptr, "glBindProgramPipelineEXT"); + glad_glCreateShaderProgramvEXT = (PFNGLCREATESHADERPROGRAMVEXTPROC) load(userptr, "glCreateShaderProgramvEXT"); + glad_glDeleteProgramPipelinesEXT = (PFNGLDELETEPROGRAMPIPELINESEXTPROC) load(userptr, "glDeleteProgramPipelinesEXT"); + glad_glGenProgramPipelinesEXT = (PFNGLGENPROGRAMPIPELINESEXTPROC) load(userptr, "glGenProgramPipelinesEXT"); + glad_glGetProgramPipelineInfoLogEXT = (PFNGLGETPROGRAMPIPELINEINFOLOGEXTPROC) load(userptr, "glGetProgramPipelineInfoLogEXT"); + glad_glGetProgramPipelineivEXT = (PFNGLGETPROGRAMPIPELINEIVEXTPROC) load(userptr, "glGetProgramPipelineivEXT"); + glad_glIsProgramPipelineEXT = (PFNGLISPROGRAMPIPELINEEXTPROC) load(userptr, "glIsProgramPipelineEXT"); + glad_glProgramParameteriEXT = (PFNGLPROGRAMPARAMETERIEXTPROC) load(userptr, "glProgramParameteriEXT"); + glad_glProgramUniform1fEXT = (PFNGLPROGRAMUNIFORM1FEXTPROC) load(userptr, "glProgramUniform1fEXT"); + glad_glProgramUniform1fvEXT = (PFNGLPROGRAMUNIFORM1FVEXTPROC) load(userptr, "glProgramUniform1fvEXT"); + glad_glProgramUniform1iEXT = (PFNGLPROGRAMUNIFORM1IEXTPROC) load(userptr, "glProgramUniform1iEXT"); + glad_glProgramUniform1ivEXT = (PFNGLPROGRAMUNIFORM1IVEXTPROC) load(userptr, "glProgramUniform1ivEXT"); + glad_glProgramUniform1uiEXT = (PFNGLPROGRAMUNIFORM1UIEXTPROC) load(userptr, "glProgramUniform1uiEXT"); + glad_glProgramUniform1uivEXT = (PFNGLPROGRAMUNIFORM1UIVEXTPROC) load(userptr, "glProgramUniform1uivEXT"); + glad_glProgramUniform2fEXT = (PFNGLPROGRAMUNIFORM2FEXTPROC) load(userptr, "glProgramUniform2fEXT"); + glad_glProgramUniform2fvEXT = (PFNGLPROGRAMUNIFORM2FVEXTPROC) load(userptr, "glProgramUniform2fvEXT"); + glad_glProgramUniform2iEXT = (PFNGLPROGRAMUNIFORM2IEXTPROC) load(userptr, "glProgramUniform2iEXT"); + glad_glProgramUniform2ivEXT = (PFNGLPROGRAMUNIFORM2IVEXTPROC) load(userptr, "glProgramUniform2ivEXT"); + glad_glProgramUniform2uiEXT = (PFNGLPROGRAMUNIFORM2UIEXTPROC) load(userptr, "glProgramUniform2uiEXT"); + glad_glProgramUniform2uivEXT = (PFNGLPROGRAMUNIFORM2UIVEXTPROC) load(userptr, "glProgramUniform2uivEXT"); + glad_glProgramUniform3fEXT = (PFNGLPROGRAMUNIFORM3FEXTPROC) load(userptr, "glProgramUniform3fEXT"); + glad_glProgramUniform3fvEXT = (PFNGLPROGRAMUNIFORM3FVEXTPROC) load(userptr, "glProgramUniform3fvEXT"); + glad_glProgramUniform3iEXT = (PFNGLPROGRAMUNIFORM3IEXTPROC) load(userptr, "glProgramUniform3iEXT"); + glad_glProgramUniform3ivEXT = (PFNGLPROGRAMUNIFORM3IVEXTPROC) load(userptr, "glProgramUniform3ivEXT"); + glad_glProgramUniform3uiEXT = (PFNGLPROGRAMUNIFORM3UIEXTPROC) load(userptr, "glProgramUniform3uiEXT"); + glad_glProgramUniform3uivEXT = (PFNGLPROGRAMUNIFORM3UIVEXTPROC) load(userptr, "glProgramUniform3uivEXT"); + glad_glProgramUniform4fEXT = (PFNGLPROGRAMUNIFORM4FEXTPROC) load(userptr, "glProgramUniform4fEXT"); + glad_glProgramUniform4fvEXT = (PFNGLPROGRAMUNIFORM4FVEXTPROC) load(userptr, "glProgramUniform4fvEXT"); + glad_glProgramUniform4iEXT = (PFNGLPROGRAMUNIFORM4IEXTPROC) load(userptr, "glProgramUniform4iEXT"); + glad_glProgramUniform4ivEXT = (PFNGLPROGRAMUNIFORM4IVEXTPROC) load(userptr, "glProgramUniform4ivEXT"); + glad_glProgramUniform4uiEXT = (PFNGLPROGRAMUNIFORM4UIEXTPROC) load(userptr, "glProgramUniform4uiEXT"); + glad_glProgramUniform4uivEXT = (PFNGLPROGRAMUNIFORM4UIVEXTPROC) load(userptr, "glProgramUniform4uivEXT"); + glad_glProgramUniformMatrix2fvEXT = (PFNGLPROGRAMUNIFORMMATRIX2FVEXTPROC) load(userptr, "glProgramUniformMatrix2fvEXT"); + glad_glProgramUniformMatrix2x3fvEXT = (PFNGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC) load(userptr, "glProgramUniformMatrix2x3fvEXT"); + glad_glProgramUniformMatrix2x4fvEXT = (PFNGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC) load(userptr, "glProgramUniformMatrix2x4fvEXT"); + glad_glProgramUniformMatrix3fvEXT = (PFNGLPROGRAMUNIFORMMATRIX3FVEXTPROC) load(userptr, "glProgramUniformMatrix3fvEXT"); + glad_glProgramUniformMatrix3x2fvEXT = (PFNGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC) load(userptr, "glProgramUniformMatrix3x2fvEXT"); + glad_glProgramUniformMatrix3x4fvEXT = (PFNGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC) load(userptr, "glProgramUniformMatrix3x4fvEXT"); + glad_glProgramUniformMatrix4fvEXT = (PFNGLPROGRAMUNIFORMMATRIX4FVEXTPROC) load(userptr, "glProgramUniformMatrix4fvEXT"); + glad_glProgramUniformMatrix4x2fvEXT = (PFNGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC) load(userptr, "glProgramUniformMatrix4x2fvEXT"); + glad_glProgramUniformMatrix4x3fvEXT = (PFNGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC) load(userptr, "glProgramUniformMatrix4x3fvEXT"); + glad_glUseProgramStagesEXT = (PFNGLUSEPROGRAMSTAGESEXTPROC) load(userptr, "glUseProgramStagesEXT"); + glad_glValidateProgramPipelineEXT = (PFNGLVALIDATEPROGRAMPIPELINEEXTPROC) load(userptr, "glValidateProgramPipelineEXT"); +} +static void glad_gl_load_GL_EXT_shader_framebuffer_fetch_non_coherent( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_shader_framebuffer_fetch_non_coherent) return; + glad_glFramebufferFetchBarrierEXT = (PFNGLFRAMEBUFFERFETCHBARRIEREXTPROC) load(userptr, "glFramebufferFetchBarrierEXT"); +} +static void glad_gl_load_GL_EXT_shader_pixel_local_storage2( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_shader_pixel_local_storage2) return; + glad_glClearPixelLocalStorageuiEXT = (PFNGLCLEARPIXELLOCALSTORAGEUIEXTPROC) load(userptr, "glClearPixelLocalStorageuiEXT"); + glad_glFramebufferPixelLocalStorageSizeEXT = (PFNGLFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC) load(userptr, "glFramebufferPixelLocalStorageSizeEXT"); + glad_glGetFramebufferPixelLocalStorageSizeEXT = (PFNGLGETFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC) load(userptr, "glGetFramebufferPixelLocalStorageSizeEXT"); +} +static void glad_gl_load_GL_EXT_sparse_texture( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_sparse_texture) return; + glad_glTexPageCommitmentEXT = (PFNGLTEXPAGECOMMITMENTEXTPROC) load(userptr, "glTexPageCommitmentEXT"); +} +static void glad_gl_load_GL_EXT_tessellation_shader( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_tessellation_shader) return; + glad_glPatchParameteriEXT = (PFNGLPATCHPARAMETERIEXTPROC) load(userptr, "glPatchParameteriEXT"); +} +static void glad_gl_load_GL_EXT_texture_border_clamp( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_texture_border_clamp) return; + glad_glGetSamplerParameterIivEXT = (PFNGLGETSAMPLERPARAMETERIIVEXTPROC) load(userptr, "glGetSamplerParameterIivEXT"); + glad_glGetSamplerParameterIuivEXT = (PFNGLGETSAMPLERPARAMETERIUIVEXTPROC) load(userptr, "glGetSamplerParameterIuivEXT"); + glad_glGetTexParameterIivEXT = (PFNGLGETTEXPARAMETERIIVEXTPROC) load(userptr, "glGetTexParameterIivEXT"); + glad_glGetTexParameterIuivEXT = (PFNGLGETTEXPARAMETERIUIVEXTPROC) load(userptr, "glGetTexParameterIuivEXT"); + glad_glSamplerParameterIivEXT = (PFNGLSAMPLERPARAMETERIIVEXTPROC) load(userptr, "glSamplerParameterIivEXT"); + glad_glSamplerParameterIuivEXT = (PFNGLSAMPLERPARAMETERIUIVEXTPROC) load(userptr, "glSamplerParameterIuivEXT"); + glad_glTexParameterIivEXT = (PFNGLTEXPARAMETERIIVEXTPROC) load(userptr, "glTexParameterIivEXT"); + glad_glTexParameterIuivEXT = (PFNGLTEXPARAMETERIUIVEXTPROC) load(userptr, "glTexParameterIuivEXT"); +} +static void glad_gl_load_GL_EXT_texture_buffer( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_texture_buffer) return; + glad_glTexBufferEXT = (PFNGLTEXBUFFEREXTPROC) load(userptr, "glTexBufferEXT"); + glad_glTexBufferRangeEXT = (PFNGLTEXBUFFERRANGEEXTPROC) load(userptr, "glTexBufferRangeEXT"); +} +static void glad_gl_load_GL_EXT_texture_storage( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_texture_storage) return; + glad_glTexStorage1DEXT = (PFNGLTEXSTORAGE1DEXTPROC) load(userptr, "glTexStorage1DEXT"); + glad_glTexStorage2DEXT = (PFNGLTEXSTORAGE2DEXTPROC) load(userptr, "glTexStorage2DEXT"); + glad_glTexStorage3DEXT = (PFNGLTEXSTORAGE3DEXTPROC) load(userptr, "glTexStorage3DEXT"); + glad_glTextureStorage1DEXT = (PFNGLTEXTURESTORAGE1DEXTPROC) load(userptr, "glTextureStorage1DEXT"); + glad_glTextureStorage2DEXT = (PFNGLTEXTURESTORAGE2DEXTPROC) load(userptr, "glTextureStorage2DEXT"); + glad_glTextureStorage3DEXT = (PFNGLTEXTURESTORAGE3DEXTPROC) load(userptr, "glTextureStorage3DEXT"); +} +static void glad_gl_load_GL_EXT_texture_storage_compression( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_texture_storage_compression) return; + glad_glTexStorageAttribs2DEXT = (PFNGLTEXSTORAGEATTRIBS2DEXTPROC) load(userptr, "glTexStorageAttribs2DEXT"); + glad_glTexStorageAttribs3DEXT = (PFNGLTEXSTORAGEATTRIBS3DEXTPROC) load(userptr, "glTexStorageAttribs3DEXT"); +} +static void glad_gl_load_GL_EXT_texture_view( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_texture_view) return; + glad_glTextureViewEXT = (PFNGLTEXTUREVIEWEXTPROC) load(userptr, "glTextureViewEXT"); +} +static void glad_gl_load_GL_EXT_win32_keyed_mutex( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_win32_keyed_mutex) return; + glad_glAcquireKeyedMutexWin32EXT = (PFNGLACQUIREKEYEDMUTEXWIN32EXTPROC) load(userptr, "glAcquireKeyedMutexWin32EXT"); + glad_glReleaseKeyedMutexWin32EXT = (PFNGLRELEASEKEYEDMUTEXWIN32EXTPROC) load(userptr, "glReleaseKeyedMutexWin32EXT"); +} +static void glad_gl_load_GL_EXT_window_rectangles( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_EXT_window_rectangles) return; + glad_glWindowRectanglesEXT = (PFNGLWINDOWRECTANGLESEXTPROC) load(userptr, "glWindowRectanglesEXT"); +} +static void glad_gl_load_GL_KHR_blend_equation_advanced( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_KHR_blend_equation_advanced) return; + glad_glBlendBarrierKHR = (PFNGLBLENDBARRIERKHRPROC) load(userptr, "glBlendBarrierKHR"); +} +static void glad_gl_load_GL_KHR_debug( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_KHR_debug) return; + glad_glDebugMessageCallbackKHR = (PFNGLDEBUGMESSAGECALLBACKKHRPROC) load(userptr, "glDebugMessageCallbackKHR"); + glad_glDebugMessageControlKHR = (PFNGLDEBUGMESSAGECONTROLKHRPROC) load(userptr, "glDebugMessageControlKHR"); + glad_glDebugMessageInsertKHR = (PFNGLDEBUGMESSAGEINSERTKHRPROC) load(userptr, "glDebugMessageInsertKHR"); + glad_glGetDebugMessageLogKHR = (PFNGLGETDEBUGMESSAGELOGKHRPROC) load(userptr, "glGetDebugMessageLogKHR"); + glad_glGetObjectLabelKHR = (PFNGLGETOBJECTLABELKHRPROC) load(userptr, "glGetObjectLabelKHR"); + glad_glGetObjectPtrLabelKHR = (PFNGLGETOBJECTPTRLABELKHRPROC) load(userptr, "glGetObjectPtrLabelKHR"); + glad_glGetPointervKHR = (PFNGLGETPOINTERVKHRPROC) load(userptr, "glGetPointervKHR"); + glad_glObjectLabelKHR = (PFNGLOBJECTLABELKHRPROC) load(userptr, "glObjectLabelKHR"); + glad_glObjectPtrLabelKHR = (PFNGLOBJECTPTRLABELKHRPROC) load(userptr, "glObjectPtrLabelKHR"); + glad_glPopDebugGroupKHR = (PFNGLPOPDEBUGGROUPKHRPROC) load(userptr, "glPopDebugGroupKHR"); + glad_glPushDebugGroupKHR = (PFNGLPUSHDEBUGGROUPKHRPROC) load(userptr, "glPushDebugGroupKHR"); +} +static void glad_gl_load_GL_KHR_parallel_shader_compile( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_KHR_parallel_shader_compile) return; + glad_glMaxShaderCompilerThreadsKHR = (PFNGLMAXSHADERCOMPILERTHREADSKHRPROC) load(userptr, "glMaxShaderCompilerThreadsKHR"); +} +static void glad_gl_load_GL_KHR_robustness( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_KHR_robustness) return; + glad_glGetGraphicsResetStatusKHR = (PFNGLGETGRAPHICSRESETSTATUSKHRPROC) load(userptr, "glGetGraphicsResetStatusKHR"); + glad_glGetnUniformfvKHR = (PFNGLGETNUNIFORMFVKHRPROC) load(userptr, "glGetnUniformfvKHR"); + glad_glGetnUniformivKHR = (PFNGLGETNUNIFORMIVKHRPROC) load(userptr, "glGetnUniformivKHR"); + glad_glGetnUniformuivKHR = (PFNGLGETNUNIFORMUIVKHRPROC) load(userptr, "glGetnUniformuivKHR"); + glad_glReadnPixelsKHR = (PFNGLREADNPIXELSKHRPROC) load(userptr, "glReadnPixelsKHR"); +} +static void glad_gl_load_GL_OES_EGL_image( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_OES_EGL_image) return; + glad_glEGLImageTargetRenderbufferStorageOES = (PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) load(userptr, "glEGLImageTargetRenderbufferStorageOES"); + glad_glEGLImageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) load(userptr, "glEGLImageTargetTexture2DOES"); +} +static void glad_gl_load_GL_OES_copy_image( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_OES_copy_image) return; + glad_glCopyImageSubDataOES = (PFNGLCOPYIMAGESUBDATAOESPROC) load(userptr, "glCopyImageSubDataOES"); +} +static void glad_gl_load_GL_OES_draw_buffers_indexed( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_OES_draw_buffers_indexed) return; + glad_glBlendEquationSeparateiOES = (PFNGLBLENDEQUATIONSEPARATEIOESPROC) load(userptr, "glBlendEquationSeparateiOES"); + glad_glBlendEquationiOES = (PFNGLBLENDEQUATIONIOESPROC) load(userptr, "glBlendEquationiOES"); + glad_glBlendFuncSeparateiOES = (PFNGLBLENDFUNCSEPARATEIOESPROC) load(userptr, "glBlendFuncSeparateiOES"); + glad_glBlendFunciOES = (PFNGLBLENDFUNCIOESPROC) load(userptr, "glBlendFunciOES"); + glad_glColorMaskiOES = (PFNGLCOLORMASKIOESPROC) load(userptr, "glColorMaskiOES"); + glad_glDisableiOES = (PFNGLDISABLEIOESPROC) load(userptr, "glDisableiOES"); + glad_glEnableiOES = (PFNGLENABLEIOESPROC) load(userptr, "glEnableiOES"); + glad_glIsEnablediOES = (PFNGLISENABLEDIOESPROC) load(userptr, "glIsEnablediOES"); +} +static void glad_gl_load_GL_OES_draw_elements_base_vertex( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_OES_draw_elements_base_vertex) return; + glad_glDrawElementsBaseVertexOES = (PFNGLDRAWELEMENTSBASEVERTEXOESPROC) load(userptr, "glDrawElementsBaseVertexOES"); + glad_glDrawElementsInstancedBaseVertexOES = (PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXOESPROC) load(userptr, "glDrawElementsInstancedBaseVertexOES"); + glad_glDrawRangeElementsBaseVertexOES = (PFNGLDRAWRANGEELEMENTSBASEVERTEXOESPROC) load(userptr, "glDrawRangeElementsBaseVertexOES"); + glad_glMultiDrawElementsBaseVertexEXT = (PFNGLMULTIDRAWELEMENTSBASEVERTEXEXTPROC) load(userptr, "glMultiDrawElementsBaseVertexEXT"); +} +static void glad_gl_load_GL_OES_geometry_shader( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_OES_geometry_shader) return; + glad_glFramebufferTextureOES = (PFNGLFRAMEBUFFERTEXTUREOESPROC) load(userptr, "glFramebufferTextureOES"); +} +static void glad_gl_load_GL_OES_get_program_binary( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_OES_get_program_binary) return; + glad_glGetProgramBinaryOES = (PFNGLGETPROGRAMBINARYOESPROC) load(userptr, "glGetProgramBinaryOES"); + glad_glProgramBinaryOES = (PFNGLPROGRAMBINARYOESPROC) load(userptr, "glProgramBinaryOES"); +} +static void glad_gl_load_GL_OES_mapbuffer( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_OES_mapbuffer) return; + glad_glGetBufferPointervOES = (PFNGLGETBUFFERPOINTERVOESPROC) load(userptr, "glGetBufferPointervOES"); + glad_glMapBufferOES = (PFNGLMAPBUFFEROESPROC) load(userptr, "glMapBufferOES"); + glad_glUnmapBufferOES = (PFNGLUNMAPBUFFEROESPROC) load(userptr, "glUnmapBufferOES"); +} +static void glad_gl_load_GL_OES_primitive_bounding_box( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_OES_primitive_bounding_box) return; + glad_glPrimitiveBoundingBoxOES = (PFNGLPRIMITIVEBOUNDINGBOXOESPROC) load(userptr, "glPrimitiveBoundingBoxOES"); +} +static void glad_gl_load_GL_OES_sample_shading( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_OES_sample_shading) return; + glad_glMinSampleShadingOES = (PFNGLMINSAMPLESHADINGOESPROC) load(userptr, "glMinSampleShadingOES"); +} +static void glad_gl_load_GL_OES_tessellation_shader( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_OES_tessellation_shader) return; + glad_glPatchParameteriOES = (PFNGLPATCHPARAMETERIOESPROC) load(userptr, "glPatchParameteriOES"); +} +static void glad_gl_load_GL_OES_texture_3D( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_OES_texture_3D) return; + glad_glCompressedTexImage3DOES = (PFNGLCOMPRESSEDTEXIMAGE3DOESPROC) load(userptr, "glCompressedTexImage3DOES"); + glad_glCompressedTexSubImage3DOES = (PFNGLCOMPRESSEDTEXSUBIMAGE3DOESPROC) load(userptr, "glCompressedTexSubImage3DOES"); + glad_glCopyTexSubImage3DOES = (PFNGLCOPYTEXSUBIMAGE3DOESPROC) load(userptr, "glCopyTexSubImage3DOES"); + glad_glFramebufferTexture3DOES = (PFNGLFRAMEBUFFERTEXTURE3DOESPROC) load(userptr, "glFramebufferTexture3DOES"); + glad_glTexImage3DOES = (PFNGLTEXIMAGE3DOESPROC) load(userptr, "glTexImage3DOES"); + glad_glTexSubImage3DOES = (PFNGLTEXSUBIMAGE3DOESPROC) load(userptr, "glTexSubImage3DOES"); +} +static void glad_gl_load_GL_OES_texture_border_clamp( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_OES_texture_border_clamp) return; + glad_glGetSamplerParameterIivOES = (PFNGLGETSAMPLERPARAMETERIIVOESPROC) load(userptr, "glGetSamplerParameterIivOES"); + glad_glGetSamplerParameterIuivOES = (PFNGLGETSAMPLERPARAMETERIUIVOESPROC) load(userptr, "glGetSamplerParameterIuivOES"); + glad_glGetTexParameterIivOES = (PFNGLGETTEXPARAMETERIIVOESPROC) load(userptr, "glGetTexParameterIivOES"); + glad_glGetTexParameterIuivOES = (PFNGLGETTEXPARAMETERIUIVOESPROC) load(userptr, "glGetTexParameterIuivOES"); + glad_glSamplerParameterIivOES = (PFNGLSAMPLERPARAMETERIIVOESPROC) load(userptr, "glSamplerParameterIivOES"); + glad_glSamplerParameterIuivOES = (PFNGLSAMPLERPARAMETERIUIVOESPROC) load(userptr, "glSamplerParameterIuivOES"); + glad_glTexParameterIivOES = (PFNGLTEXPARAMETERIIVOESPROC) load(userptr, "glTexParameterIivOES"); + glad_glTexParameterIuivOES = (PFNGLTEXPARAMETERIUIVOESPROC) load(userptr, "glTexParameterIuivOES"); +} +static void glad_gl_load_GL_OES_texture_buffer( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_OES_texture_buffer) return; + glad_glTexBufferOES = (PFNGLTEXBUFFEROESPROC) load(userptr, "glTexBufferOES"); + glad_glTexBufferRangeOES = (PFNGLTEXBUFFERRANGEOESPROC) load(userptr, "glTexBufferRangeOES"); +} +static void glad_gl_load_GL_OES_texture_storage_multisample_2d_array( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_OES_texture_storage_multisample_2d_array) return; + glad_glTexStorage3DMultisampleOES = (PFNGLTEXSTORAGE3DMULTISAMPLEOESPROC) load(userptr, "glTexStorage3DMultisampleOES"); +} +static void glad_gl_load_GL_OES_texture_view( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_OES_texture_view) return; + glad_glTextureViewOES = (PFNGLTEXTUREVIEWOESPROC) load(userptr, "glTextureViewOES"); +} +static void glad_gl_load_GL_OES_vertex_array_object( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_OES_vertex_array_object) return; + glad_glBindVertexArrayOES = (PFNGLBINDVERTEXARRAYOESPROC) load(userptr, "glBindVertexArrayOES"); + glad_glDeleteVertexArraysOES = (PFNGLDELETEVERTEXARRAYSOESPROC) load(userptr, "glDeleteVertexArraysOES"); + glad_glGenVertexArraysOES = (PFNGLGENVERTEXARRAYSOESPROC) load(userptr, "glGenVertexArraysOES"); + glad_glIsVertexArrayOES = (PFNGLISVERTEXARRAYOESPROC) load(userptr, "glIsVertexArrayOES"); +} +static void glad_gl_load_GL_OES_viewport_array( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_OES_viewport_array) return; + glad_glDepthRangeArrayfvOES = (PFNGLDEPTHRANGEARRAYFVOESPROC) load(userptr, "glDepthRangeArrayfvOES"); + glad_glDepthRangeIndexedfOES = (PFNGLDEPTHRANGEINDEXEDFOESPROC) load(userptr, "glDepthRangeIndexedfOES"); + glad_glDisableiOES = (PFNGLDISABLEIOESPROC) load(userptr, "glDisableiOES"); + glad_glEnableiOES = (PFNGLENABLEIOESPROC) load(userptr, "glEnableiOES"); + glad_glGetFloati_vOES = (PFNGLGETFLOATI_VOESPROC) load(userptr, "glGetFloati_vOES"); + glad_glIsEnablediOES = (PFNGLISENABLEDIOESPROC) load(userptr, "glIsEnablediOES"); + glad_glScissorArrayvOES = (PFNGLSCISSORARRAYVOESPROC) load(userptr, "glScissorArrayvOES"); + glad_glScissorIndexedOES = (PFNGLSCISSORINDEXEDOESPROC) load(userptr, "glScissorIndexedOES"); + glad_glScissorIndexedvOES = (PFNGLSCISSORINDEXEDVOESPROC) load(userptr, "glScissorIndexedvOES"); + glad_glViewportArrayvOES = (PFNGLVIEWPORTARRAYVOESPROC) load(userptr, "glViewportArrayvOES"); + glad_glViewportIndexedfOES = (PFNGLVIEWPORTINDEXEDFOESPROC) load(userptr, "glViewportIndexedfOES"); + glad_glViewportIndexedfvOES = (PFNGLVIEWPORTINDEXEDFVOESPROC) load(userptr, "glViewportIndexedfvOES"); +} + + + +#if defined(GL_ES_VERSION_3_0) || defined(GL_VERSION_3_0) +#define GLAD_GL_IS_SOME_NEW_VERSION 1 +#else +#define GLAD_GL_IS_SOME_NEW_VERSION 0 +#endif + +static int glad_gl_get_extensions( int version, const char **out_exts, unsigned int *out_num_exts_i, char ***out_exts_i) { +#if GLAD_GL_IS_SOME_NEW_VERSION + if(GLAD_VERSION_MAJOR(version) < 3) { +#else + GLAD_UNUSED(version); + GLAD_UNUSED(out_num_exts_i); + GLAD_UNUSED(out_exts_i); +#endif + if (glad_glGetString == NULL) { + return 0; + } + *out_exts = (const char *)glad_glGetString(GL_EXTENSIONS); +#if GLAD_GL_IS_SOME_NEW_VERSION + } else { + unsigned int index = 0; + unsigned int num_exts_i = 0; + char **exts_i = NULL; + if (glad_glGetStringi == NULL || glad_glGetIntegerv == NULL) { + return 0; + } + glad_glGetIntegerv(GL_NUM_EXTENSIONS, (int*) &num_exts_i); + if (num_exts_i > 0) { + exts_i = (char **) malloc(num_exts_i * (sizeof *exts_i)); + } + if (exts_i == NULL) { + return 0; + } + for(index = 0; index < num_exts_i; index++) { + const char *gl_str_tmp = (const char*) glad_glGetStringi(GL_EXTENSIONS, index); + size_t len = strlen(gl_str_tmp) + 1; + + char *local_str = (char*) malloc(len * sizeof(char)); + if(local_str != NULL) { + memcpy(local_str, gl_str_tmp, len * sizeof(char)); + } + + exts_i[index] = local_str; + } + + *out_num_exts_i = num_exts_i; + *out_exts_i = exts_i; + } +#endif + return 1; +} +static void glad_gl_free_extensions(char **exts_i, unsigned int num_exts_i) { + if (exts_i != NULL) { + unsigned int index; + for(index = 0; index < num_exts_i; index++) { + free((void *) (exts_i[index])); + } + free((void *)exts_i); + exts_i = NULL; + } +} +static int glad_gl_has_extension(int version, const char *exts, unsigned int num_exts_i, char **exts_i, const char *ext) { + if(GLAD_VERSION_MAJOR(version) < 3 || !GLAD_GL_IS_SOME_NEW_VERSION) { + const char *extensions; + const char *loc; + const char *terminator; + extensions = exts; + if(extensions == NULL || ext == NULL) { + return 0; + } + while(1) { + loc = strstr(extensions, ext); + if(loc == NULL) { + return 0; + } + terminator = loc + strlen(ext); + if((loc == extensions || *(loc - 1) == ' ') && + (*terminator == ' ' || *terminator == '\0')) { + return 1; + } + extensions = terminator; + } + } else { + unsigned int index; + for(index = 0; index < num_exts_i; index++) { + const char *e = exts_i[index]; + if(strcmp(e, ext) == 0) { + return 1; + } + } + } + return 0; +} + +static GLADapiproc glad_gl_get_proc_from_userptr(void *userptr, const char* name) { + return (GLAD_GNUC_EXTENSION (GLADapiproc (*)(const char *name)) userptr)(name); +} + +static int glad_gl_find_extensions_gles2( int version) { + const char *exts = NULL; + unsigned int num_exts_i = 0; + char **exts_i = NULL; + if (!glad_gl_get_extensions(version, &exts, &num_exts_i, &exts_i)) return 0; + + GLAD_GL_EXT_EGL_image_array = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_EGL_image_array"); + GLAD_GL_EXT_EGL_image_storage = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_EGL_image_storage"); + GLAD_GL_EXT_EGL_image_storage_compression = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_EGL_image_storage_compression"); + GLAD_GL_EXT_YUV_target = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_YUV_target"); + GLAD_GL_EXT_base_instance = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_base_instance"); + GLAD_GL_EXT_blend_func_extended = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_blend_func_extended"); + GLAD_GL_EXT_blend_minmax = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_blend_minmax"); + GLAD_GL_EXT_buffer_storage = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_buffer_storage"); + GLAD_GL_EXT_clear_texture = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_clear_texture"); + GLAD_GL_EXT_clip_control = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_clip_control"); + GLAD_GL_EXT_clip_cull_distance = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_clip_cull_distance"); + GLAD_GL_EXT_color_buffer_float = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_color_buffer_float"); + GLAD_GL_EXT_color_buffer_half_float = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_color_buffer_half_float"); + GLAD_GL_EXT_conservative_depth = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_conservative_depth"); + GLAD_GL_EXT_copy_image = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_copy_image"); + GLAD_GL_EXT_debug_label = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_debug_label"); + GLAD_GL_EXT_debug_marker = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_debug_marker"); + GLAD_GL_EXT_depth_clamp = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_depth_clamp"); + GLAD_GL_EXT_discard_framebuffer = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_discard_framebuffer"); + GLAD_GL_EXT_disjoint_timer_query = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_disjoint_timer_query"); + GLAD_GL_EXT_draw_buffers = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_draw_buffers"); + GLAD_GL_EXT_draw_buffers_indexed = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_draw_buffers_indexed"); + GLAD_GL_EXT_draw_elements_base_vertex = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_draw_elements_base_vertex"); + GLAD_GL_EXT_draw_instanced = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_draw_instanced"); + GLAD_GL_EXT_draw_transform_feedback = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_draw_transform_feedback"); + GLAD_GL_EXT_external_buffer = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_external_buffer"); + GLAD_GL_EXT_float_blend = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_float_blend"); + GLAD_GL_EXT_fragment_shading_rate = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_fragment_shading_rate"); + GLAD_GL_EXT_geometry_point_size = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_geometry_point_size"); + GLAD_GL_EXT_geometry_shader = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_geometry_shader"); + GLAD_GL_EXT_gpu_shader5 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_gpu_shader5"); + GLAD_GL_EXT_instanced_arrays = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_instanced_arrays"); + GLAD_GL_EXT_map_buffer_range = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_map_buffer_range"); + GLAD_GL_EXT_memory_object = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_memory_object"); + GLAD_GL_EXT_memory_object_fd = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_memory_object_fd"); + GLAD_GL_EXT_memory_object_win32 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_memory_object_win32"); + GLAD_GL_EXT_multi_draw_arrays = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_multi_draw_arrays"); + GLAD_GL_EXT_multi_draw_indirect = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_multi_draw_indirect"); + GLAD_GL_EXT_multisampled_compatibility = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_multisampled_compatibility"); + GLAD_GL_EXT_multisampled_render_to_texture = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_multisampled_render_to_texture"); + GLAD_GL_EXT_multisampled_render_to_texture2 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_multisampled_render_to_texture2"); + GLAD_GL_EXT_multiview_draw_buffers = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_multiview_draw_buffers"); + GLAD_GL_EXT_multiview_tessellation_geometry_shader = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_multiview_tessellation_geometry_shader"); + GLAD_GL_EXT_multiview_texture_multisample = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_multiview_texture_multisample"); + GLAD_GL_EXT_multiview_timer_query = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_multiview_timer_query"); + GLAD_GL_EXT_occlusion_query_boolean = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_occlusion_query_boolean"); + GLAD_GL_EXT_polygon_offset_clamp = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_polygon_offset_clamp"); + GLAD_GL_EXT_post_depth_coverage = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_post_depth_coverage"); + GLAD_GL_EXT_primitive_bounding_box = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_primitive_bounding_box"); + GLAD_GL_EXT_protected_textures = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_protected_textures"); + GLAD_GL_EXT_pvrtc_sRGB = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_pvrtc_sRGB"); + GLAD_GL_EXT_raster_multisample = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_raster_multisample"); + GLAD_GL_EXT_read_format_bgra = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_read_format_bgra"); + GLAD_GL_EXT_render_snorm = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_render_snorm"); + GLAD_GL_EXT_robustness = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_robustness"); + GLAD_GL_EXT_sRGB = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_sRGB"); + GLAD_GL_EXT_sRGB_write_control = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_sRGB_write_control"); + GLAD_GL_EXT_semaphore = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_semaphore"); + GLAD_GL_EXT_semaphore_fd = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_semaphore_fd"); + GLAD_GL_EXT_semaphore_win32 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_semaphore_win32"); + GLAD_GL_EXT_separate_depth_stencil = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_separate_depth_stencil"); + GLAD_GL_EXT_separate_shader_objects = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_separate_shader_objects"); + GLAD_GL_EXT_shader_framebuffer_fetch = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_shader_framebuffer_fetch"); + GLAD_GL_EXT_shader_framebuffer_fetch_non_coherent = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_shader_framebuffer_fetch_non_coherent"); + GLAD_GL_EXT_shader_group_vote = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_shader_group_vote"); + GLAD_GL_EXT_shader_implicit_conversions = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_shader_implicit_conversions"); + GLAD_GL_EXT_shader_integer_mix = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_shader_integer_mix"); + GLAD_GL_EXT_shader_io_blocks = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_shader_io_blocks"); + GLAD_GL_EXT_shader_non_constant_global_initializers = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_shader_non_constant_global_initializers"); + GLAD_GL_EXT_shader_pixel_local_storage = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_shader_pixel_local_storage"); + GLAD_GL_EXT_shader_pixel_local_storage2 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_shader_pixel_local_storage2"); + GLAD_GL_EXT_shader_samples_identical = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_shader_samples_identical"); + GLAD_GL_EXT_shader_texture_lod = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_shader_texture_lod"); + GLAD_GL_EXT_shadow_samplers = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_shadow_samplers"); + GLAD_GL_EXT_sparse_texture = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_sparse_texture"); + GLAD_GL_EXT_sparse_texture2 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_sparse_texture2"); + GLAD_GL_EXT_tessellation_point_size = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_tessellation_point_size"); + GLAD_GL_EXT_tessellation_shader = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_tessellation_shader"); + GLAD_GL_EXT_texture_border_clamp = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_border_clamp"); + GLAD_GL_EXT_texture_buffer = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_buffer"); + GLAD_GL_EXT_texture_compression_astc_decode_mode = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_compression_astc_decode_mode"); + GLAD_GL_EXT_texture_compression_bptc = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_compression_bptc"); + GLAD_GL_EXT_texture_compression_dxt1 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_compression_dxt1"); + GLAD_GL_EXT_texture_compression_rgtc = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_compression_rgtc"); + GLAD_GL_EXT_texture_compression_s3tc = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_compression_s3tc"); + GLAD_GL_EXT_texture_compression_s3tc_srgb = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_compression_s3tc_srgb"); + GLAD_GL_EXT_texture_cube_map_array = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_cube_map_array"); + GLAD_GL_EXT_texture_filter_anisotropic = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_filter_anisotropic"); + GLAD_GL_EXT_texture_filter_minmax = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_filter_minmax"); + GLAD_GL_EXT_texture_format_BGRA8888 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_format_BGRA8888"); + GLAD_GL_EXT_texture_format_sRGB_override = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_format_sRGB_override"); + GLAD_GL_EXT_texture_mirror_clamp_to_edge = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_mirror_clamp_to_edge"); + GLAD_GL_EXT_texture_norm16 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_norm16"); + GLAD_GL_EXT_texture_query_lod = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_query_lod"); + GLAD_GL_EXT_texture_rg = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_rg"); + GLAD_GL_EXT_texture_sRGB_R8 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_sRGB_R8"); + GLAD_GL_EXT_texture_sRGB_RG8 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_sRGB_RG8"); + GLAD_GL_EXT_texture_sRGB_decode = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_sRGB_decode"); + GLAD_GL_EXT_texture_shadow_lod = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_shadow_lod"); + GLAD_GL_EXT_texture_storage = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_storage"); + GLAD_GL_EXT_texture_storage_compression = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_storage_compression"); + GLAD_GL_EXT_texture_type_2_10_10_10_REV = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_type_2_10_10_10_REV"); + GLAD_GL_EXT_texture_view = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_texture_view"); + GLAD_GL_EXT_unpack_subimage = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_unpack_subimage"); + GLAD_GL_EXT_win32_keyed_mutex = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_win32_keyed_mutex"); + GLAD_GL_EXT_window_rectangles = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_window_rectangles"); + GLAD_GL_KHR_blend_equation_advanced = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_KHR_blend_equation_advanced"); + GLAD_GL_KHR_blend_equation_advanced_coherent = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_KHR_blend_equation_advanced_coherent"); + GLAD_GL_KHR_context_flush_control = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_KHR_context_flush_control"); + GLAD_GL_KHR_debug = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_KHR_debug"); + GLAD_GL_KHR_no_error = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_KHR_no_error"); + GLAD_GL_KHR_parallel_shader_compile = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_KHR_parallel_shader_compile"); + GLAD_GL_KHR_robust_buffer_access_behavior = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_KHR_robust_buffer_access_behavior"); + GLAD_GL_KHR_robustness = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_KHR_robustness"); + GLAD_GL_KHR_shader_subgroup = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_KHR_shader_subgroup"); + GLAD_GL_KHR_texture_compression_astc_hdr = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_KHR_texture_compression_astc_hdr"); + GLAD_GL_KHR_texture_compression_astc_ldr = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_KHR_texture_compression_astc_ldr"); + GLAD_GL_KHR_texture_compression_astc_sliced_3d = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_KHR_texture_compression_astc_sliced_3d"); + GLAD_GL_OES_EGL_image = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_EGL_image"); + GLAD_GL_OES_EGL_image_external = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_EGL_image_external"); + GLAD_GL_OES_EGL_image_external_essl3 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_EGL_image_external_essl3"); + GLAD_GL_OES_compressed_ETC1_RGB8_sub_texture = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_compressed_ETC1_RGB8_sub_texture"); + GLAD_GL_OES_compressed_ETC1_RGB8_texture = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_compressed_ETC1_RGB8_texture"); + GLAD_GL_OES_compressed_paletted_texture = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_compressed_paletted_texture"); + GLAD_GL_OES_copy_image = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_copy_image"); + GLAD_GL_OES_depth24 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_depth24"); + GLAD_GL_OES_depth32 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_depth32"); + GLAD_GL_OES_depth_texture = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_depth_texture"); + GLAD_GL_OES_draw_buffers_indexed = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_draw_buffers_indexed"); + GLAD_GL_OES_draw_elements_base_vertex = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_draw_elements_base_vertex"); + GLAD_GL_OES_element_index_uint = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_element_index_uint"); + GLAD_GL_OES_fbo_render_mipmap = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_fbo_render_mipmap"); + GLAD_GL_OES_fragment_precision_high = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_fragment_precision_high"); + GLAD_GL_OES_geometry_point_size = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_geometry_point_size"); + GLAD_GL_OES_geometry_shader = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_geometry_shader"); + GLAD_GL_OES_get_program_binary = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_get_program_binary"); + GLAD_GL_OES_gpu_shader5 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_gpu_shader5"); + GLAD_GL_OES_mapbuffer = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_mapbuffer"); + GLAD_GL_OES_packed_depth_stencil = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_packed_depth_stencil"); + GLAD_GL_OES_primitive_bounding_box = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_primitive_bounding_box"); + GLAD_GL_OES_required_internalformat = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_required_internalformat"); + GLAD_GL_OES_rgb8_rgba8 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_rgb8_rgba8"); + GLAD_GL_OES_sample_shading = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_sample_shading"); + GLAD_GL_OES_sample_variables = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_sample_variables"); + GLAD_GL_OES_shader_image_atomic = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_shader_image_atomic"); + GLAD_GL_OES_shader_io_blocks = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_shader_io_blocks"); + GLAD_GL_OES_shader_multisample_interpolation = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_shader_multisample_interpolation"); + GLAD_GL_OES_standard_derivatives = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_standard_derivatives"); + GLAD_GL_OES_stencil1 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_stencil1"); + GLAD_GL_OES_stencil4 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_stencil4"); + GLAD_GL_OES_surfaceless_context = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_surfaceless_context"); + GLAD_GL_OES_tessellation_point_size = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_tessellation_point_size"); + GLAD_GL_OES_tessellation_shader = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_tessellation_shader"); + GLAD_GL_OES_texture_3D = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_texture_3D"); + GLAD_GL_OES_texture_border_clamp = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_texture_border_clamp"); + GLAD_GL_OES_texture_buffer = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_texture_buffer"); + GLAD_GL_OES_texture_compression_astc = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_texture_compression_astc"); + GLAD_GL_OES_texture_cube_map_array = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_texture_cube_map_array"); + GLAD_GL_OES_texture_float = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_texture_float"); + GLAD_GL_OES_texture_float_linear = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_texture_float_linear"); + GLAD_GL_OES_texture_half_float = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_texture_half_float"); + GLAD_GL_OES_texture_half_float_linear = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_texture_half_float_linear"); + GLAD_GL_OES_texture_npot = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_texture_npot"); + GLAD_GL_OES_texture_stencil8 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_texture_stencil8"); + GLAD_GL_OES_texture_storage_multisample_2d_array = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_texture_storage_multisample_2d_array"); + GLAD_GL_OES_texture_view = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_texture_view"); + GLAD_GL_OES_vertex_array_object = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_vertex_array_object"); + GLAD_GL_OES_vertex_half_float = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_vertex_half_float"); + GLAD_GL_OES_vertex_type_10_10_10_2 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_vertex_type_10_10_10_2"); + GLAD_GL_OES_viewport_array = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OES_viewport_array"); + + glad_gl_free_extensions(exts_i, num_exts_i); + + return 1; +} + +static int glad_gl_find_core_gles2(void) { + int i; + const char* version; + const char* prefixes[] = { + "OpenGL ES-CM ", + "OpenGL ES-CL ", + "OpenGL ES ", + "OpenGL SC ", + NULL + }; + int major = 0; + int minor = 0; + version = (const char*) glad_glGetString(GL_VERSION); + if (!version) return 0; + for (i = 0; prefixes[i]; i++) { + const size_t length = strlen(prefixes[i]); + if (strncmp(version, prefixes[i], length) == 0) { + version += length; + break; + } + } + + GLAD_IMPL_UTIL_SSCANF(version, "%d.%d", &major, &minor); + + GLAD_GL_ES_VERSION_2_0 = (major == 2 && minor >= 0) || major > 2; + + return GLAD_MAKE_VERSION(major, minor); +} + +int gladLoadGLES2UserPtr( GLADuserptrloadfunc load, void *userptr) { + int version; + + glad_glGetString = (PFNGLGETSTRINGPROC) load(userptr, "glGetString"); + if(glad_glGetString == NULL) return 0; + if(glad_glGetString(GL_VERSION) == NULL) return 0; + version = glad_gl_find_core_gles2(); + + glad_gl_load_GL_ES_VERSION_2_0(load, userptr); + + if (!glad_gl_find_extensions_gles2(version)) return 0; + glad_gl_load_GL_EXT_EGL_image_storage(load, userptr); + glad_gl_load_GL_EXT_base_instance(load, userptr); + glad_gl_load_GL_EXT_blend_func_extended(load, userptr); + glad_gl_load_GL_EXT_buffer_storage(load, userptr); + glad_gl_load_GL_EXT_clear_texture(load, userptr); + glad_gl_load_GL_EXT_clip_control(load, userptr); + glad_gl_load_GL_EXT_copy_image(load, userptr); + glad_gl_load_GL_EXT_debug_label(load, userptr); + glad_gl_load_GL_EXT_debug_marker(load, userptr); + glad_gl_load_GL_EXT_discard_framebuffer(load, userptr); + glad_gl_load_GL_EXT_disjoint_timer_query(load, userptr); + glad_gl_load_GL_EXT_draw_buffers(load, userptr); + glad_gl_load_GL_EXT_draw_buffers_indexed(load, userptr); + glad_gl_load_GL_EXT_draw_elements_base_vertex(load, userptr); + glad_gl_load_GL_EXT_draw_instanced(load, userptr); + glad_gl_load_GL_EXT_draw_transform_feedback(load, userptr); + glad_gl_load_GL_EXT_external_buffer(load, userptr); + glad_gl_load_GL_EXT_fragment_shading_rate(load, userptr); + glad_gl_load_GL_EXT_geometry_shader(load, userptr); + glad_gl_load_GL_EXT_instanced_arrays(load, userptr); + glad_gl_load_GL_EXT_map_buffer_range(load, userptr); + glad_gl_load_GL_EXT_memory_object(load, userptr); + glad_gl_load_GL_EXT_memory_object_fd(load, userptr); + glad_gl_load_GL_EXT_memory_object_win32(load, userptr); + glad_gl_load_GL_EXT_multi_draw_arrays(load, userptr); + glad_gl_load_GL_EXT_multi_draw_indirect(load, userptr); + glad_gl_load_GL_EXT_multisampled_render_to_texture(load, userptr); + glad_gl_load_GL_EXT_multiview_draw_buffers(load, userptr); + glad_gl_load_GL_EXT_occlusion_query_boolean(load, userptr); + glad_gl_load_GL_EXT_polygon_offset_clamp(load, userptr); + glad_gl_load_GL_EXT_primitive_bounding_box(load, userptr); + glad_gl_load_GL_EXT_raster_multisample(load, userptr); + glad_gl_load_GL_EXT_robustness(load, userptr); + glad_gl_load_GL_EXT_semaphore(load, userptr); + glad_gl_load_GL_EXT_semaphore_fd(load, userptr); + glad_gl_load_GL_EXT_semaphore_win32(load, userptr); + glad_gl_load_GL_EXT_separate_shader_objects(load, userptr); + glad_gl_load_GL_EXT_shader_framebuffer_fetch_non_coherent(load, userptr); + glad_gl_load_GL_EXT_shader_pixel_local_storage2(load, userptr); + glad_gl_load_GL_EXT_sparse_texture(load, userptr); + glad_gl_load_GL_EXT_tessellation_shader(load, userptr); + glad_gl_load_GL_EXT_texture_border_clamp(load, userptr); + glad_gl_load_GL_EXT_texture_buffer(load, userptr); + glad_gl_load_GL_EXT_texture_storage(load, userptr); + glad_gl_load_GL_EXT_texture_storage_compression(load, userptr); + glad_gl_load_GL_EXT_texture_view(load, userptr); + glad_gl_load_GL_EXT_win32_keyed_mutex(load, userptr); + glad_gl_load_GL_EXT_window_rectangles(load, userptr); + glad_gl_load_GL_KHR_blend_equation_advanced(load, userptr); + glad_gl_load_GL_KHR_debug(load, userptr); + glad_gl_load_GL_KHR_parallel_shader_compile(load, userptr); + glad_gl_load_GL_KHR_robustness(load, userptr); + glad_gl_load_GL_OES_EGL_image(load, userptr); + glad_gl_load_GL_OES_copy_image(load, userptr); + glad_gl_load_GL_OES_draw_buffers_indexed(load, userptr); + glad_gl_load_GL_OES_draw_elements_base_vertex(load, userptr); + glad_gl_load_GL_OES_geometry_shader(load, userptr); + glad_gl_load_GL_OES_get_program_binary(load, userptr); + glad_gl_load_GL_OES_mapbuffer(load, userptr); + glad_gl_load_GL_OES_primitive_bounding_box(load, userptr); + glad_gl_load_GL_OES_sample_shading(load, userptr); + glad_gl_load_GL_OES_tessellation_shader(load, userptr); + glad_gl_load_GL_OES_texture_3D(load, userptr); + glad_gl_load_GL_OES_texture_border_clamp(load, userptr); + glad_gl_load_GL_OES_texture_buffer(load, userptr); + glad_gl_load_GL_OES_texture_storage_multisample_2d_array(load, userptr); + glad_gl_load_GL_OES_texture_view(load, userptr); + glad_gl_load_GL_OES_vertex_array_object(load, userptr); + glad_gl_load_GL_OES_viewport_array(load, userptr); + + + + return version; +} + + +int gladLoadGLES2( GLADloadfunc load) { + return gladLoadGLES2UserPtr( glad_gl_get_proc_from_userptr, GLAD_GNUC_EXTENSION (void*) load); +} + + + + + + +#ifdef __cplusplus +} +#endif + +#endif /* GLAD_GLES2_IMPLEMENTATION */ + diff --git a/src/rlgl.h b/src/rlgl.h index a7226a818d31..ba0f08713360 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -789,10 +789,16 @@ RLAPI void rlLoadDrawQuad(void); // Load and draw a quad #endif #if defined(GRAPHICS_API_OPENGL_ES2) + + #if defined(PLATFORM_DESKTOP) + #define GLAD_GLES2_IMPLEMENTATION + #include "external/glad_gles2.h" + #else #define GL_GLEXT_PROTOTYPES //#include // EGL library -> not required, platform layer #include // OpenGL ES 2.0 library #include // OpenGL ES 2.0 extensions library + #endif // It seems OpenGL ES 2.0 instancing entry points are not defined on Raspberry Pi // provided headers (despite being defined in official Khronos GLES2 headers) @@ -2144,6 +2150,12 @@ void rlLoadExtensions(void *loader) #endif // GRAPHICS_API_OPENGL_33 #if defined(GRAPHICS_API_OPENGL_ES2) + + #if defined(PLATFORM_DESKTOP) + if (gladLoadGLES2((GLADloadfunc)loader) == 0) TRACELOG(RL_LOG_WARNING, "GLAD: Cannot load OpenGL ES2.0 functions"); + else TRACELOG(RL_LOG_INFO, "GLAD: OpenGL ES2.0 loaded successfully"); + #endif + // Get supported extensions list GLint numExt = 0; const char **extList = RL_MALLOC(512*sizeof(const char *)); // Allocate 512 strings pointers (2 KB) From 3028bffd4c39e622c0a2b95f275ae6156a86639f Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 10 Jan 2023 12:38:21 +0100 Subject: [PATCH 039/192] Minor tweaks --- src/rlgl.h | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/rlgl.h b/src/rlgl.h index ba0f08713360..fbf70051abc3 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -789,15 +789,16 @@ RLAPI void rlLoadDrawQuad(void); // Load and draw a quad #endif #if defined(GRAPHICS_API_OPENGL_ES2) - + // NOTE: OpenGL ES 2.0 can be enabled on PLATFORM_DESKTOP, + // in that case, functions are loaded from a custom glad for OpenGL ES 2.0 #if defined(PLATFORM_DESKTOP) - #define GLAD_GLES2_IMPLEMENTATION - #include "external/glad_gles2.h" + #define GLAD_GLES2_IMPLEMENTATION + #include "external/glad_gles2.h" #else - #define GL_GLEXT_PROTOTYPES - //#include // EGL library -> not required, platform layer - #include // OpenGL ES 2.0 library - #include // OpenGL ES 2.0 extensions library + #define GL_GLEXT_PROTOTYPES + //#include // EGL library -> not required, platform layer + #include // OpenGL ES 2.0 library + #include // OpenGL ES 2.0 extensions library #endif // It seems OpenGL ES 2.0 instancing entry points are not defined on Raspberry Pi From c6376acfc465d589db584ff36788a01360ec0771 Mon Sep 17 00:00:00 2001 From: Daijiro Fukuda Date: Tue, 10 Jan 2023 20:45:53 +0900 Subject: [PATCH 040/192] Set initial window position for display-sized fullscreen (#2742) --- src/rcore.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/rcore.c b/src/rcore.c index 2d68606d8673..27b1a1f33692 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -4091,8 +4091,18 @@ static bool InitGraphicsDevice(int width, int height) if (CORE.Window.fullscreen) { // remember center for switchinging from fullscreen to window - CORE.Window.position.x = CORE.Window.display.width/2 - CORE.Window.screen.width/2; - CORE.Window.position.y = CORE.Window.display.height/2 - CORE.Window.screen.height/2; + if ((CORE.Window.screen.height == CORE.Window.display.height) && (CORE.Window.screen.width == CORE.Window.display.width)) + { + // If screen width/height equal to the dislpay, we can't calclulate the window pos for toggling fullscreened/windowed. + // Toggling fullscreened/windowed with pos(0, 0) can cause problems in some platforms, such as X11. + CORE.Window.position.x = CORE.Window.display.width/4; + CORE.Window.position.y = CORE.Window.display.height/4; + } + else + { + CORE.Window.position.x = CORE.Window.display.width/2 - CORE.Window.screen.width/2; + CORE.Window.position.y = CORE.Window.display.height/2 - CORE.Window.screen.height/2; + } if (CORE.Window.position.x < 0) CORE.Window.position.x = 0; if (CORE.Window.position.y < 0) CORE.Window.position.y = 0; From d224414eb1fcbe93bcaf2ba02490bbd6f8db624a Mon Sep 17 00:00:00 2001 From: Tobias Mock Date: Wed, 11 Jan 2023 18:07:35 +0100 Subject: [PATCH 041/192] Update raylib-ocaml to 4.2.0 (#2853) --- BINDINGS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BINDINGS.md b/BINDINGS.md index 39a333e51907..80dc1b859dd4 100644 --- a/BINDINGS.md +++ b/BINDINGS.md @@ -42,7 +42,7 @@ Some people ported raylib to other languages in form of bindings or wrappers to | node-raylib | **4.0** | [Node.js](https://nodejs.org/en/) | Zlib | https://github.com/RobLoach/node-raylib | | raylib_odin_bindings | 4.0-dev | [Odin](https://odin-lang.org/) | MIT | https://github.com/Deathbat2190/raylib_odin_bindings | | raylib-odin | **4.0** | [Odin](https://odin-lang.org/) | BSD-3Clause | https://github.com/odin-lang/Odin/tree/master/vendor/raylib | -| raylib-ocaml | **4.0** | [OCaml](https://ocaml.org/) | MIT | https://github.com/tjammer/raylib-ocaml | +| raylib-ocaml | **4.2** | [OCaml](https://ocaml.org/) | MIT | https://github.com/tjammer/raylib-ocaml | | TurboRaylib | **4.2** | [Object Pascal](https://en.wikipedia.org/wiki/Object_Pascal) | MIT | https://github.com/turborium/TurboRaylib | | Ray4Laz | **4.2** | [Free Pascal](https://en.wikipedia.org/wiki/Free_Pascal)| Zlib | https://github.com/GuvaCode/Ray4Laz | | Raylib.4.0.Pascal | **4.0** | [Free Pascal](https://en.wikipedia.org/wiki/Free_Pascal)| Zlib | https://github.com/sysrpl/Raylib.4.0.Pascal | From aed131a8f0746065d97f2ff35f5a90713236efc0 Mon Sep 17 00:00:00 2001 From: Kenta <106167071+Its-Kenta@users.noreply.github.com> Date: Sat, 14 Jan 2023 18:40:48 +0000 Subject: [PATCH 042/192] Update BINDINGS.md (#2858) * Update BINDINGS.md Add Kaylib - Kotlin/Native binding for 4.5-dev (proper binding). Add Raylib-Nelua - Nelua binding for 4.5-dev with working wasm export. * Update BINDINGS.md --- BINDINGS.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/BINDINGS.md b/BINDINGS.md index 80dc1b859dd4..6eec7bb381d4 100644 --- a/BINDINGS.md +++ b/BINDINGS.md @@ -33,9 +33,11 @@ Some people ported raylib to other languages in form of bindings or wrappers to | raylib-j | **4.0** | [Java](https://en.wikipedia.org/wiki/Java_(programming_language)) | Zlib | https://github.com/CreedVI/Raylib-J | | raylib.jl | **4.2** | [Julia](https://julialang.org/) | Zlib | https://github.com/irishgreencitrus/raylib.jl | | kaylib | 3.7 | [Kotlin/native](https://kotlinlang.org) | ? | https://github.com/electronstudio/kaylib | +| kaylib | **4.5-dev**| [Kotlin/native](https://kotlinlang.org) | MIT | https://codeberg.org/Kenta/Kaylib | | raylib-lua | **4.2** | [Lua](http://www.lua.org/) | ISC | https://github.com/TSnake41/raylib-lua | | raylua | **4.0** | [Lua](http://www.lua.org/) | MIT | https://github.com/Rabios/raylua | | nelua-raylib | 4.0 | [nelua](https://nelua.io/) | MIT | https://github.com/AKDev21/nelua-raylib | +| Raylib-Nelua | **4.5-dev** | [nelua](https://nelua.io/) | MIT | https://github.com/Its-Kenta/Raylib-Nelua | | NimraylibNow! | 4.2 | [Nim](https://nim-lang.org/) | MIT | https://github.com/greenfork/nimraylib_now | | raylib-Forever | auto | [Nim](https://nim-lang.org/) | ? | https://github.com/Guevara-chan/Raylib-Forever | | naylib | auto | [Nim](https://nim-lang.org/) | MIT | https://github.com/planetis-m/naylib | From 2a2f2b20b8d918f9597334efad067683ae2328b0 Mon Sep 17 00:00:00 2001 From: Ghost <122651011+ImazighenGhost@users.noreply.github.com> Date: Sat, 14 Jan 2023 19:41:42 +0100 Subject: [PATCH 043/192] Fixed bug : touches become sticky (#2857) Touches became sticky and didn't disappear after using more than 2 fingers, fixed by getting the touch count of how many fingers are on the screen, and only looping through the available/pressed down touch points instead of looping through the maximum touch points. Tested with more than 10 touch points, and with different MAX points value, working perfectly. --- examples/core/core_input_multitouch.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/examples/core/core_input_multitouch.c b/examples/core/core_input_multitouch.c index 980af3801ad6..37817e5a0bcc 100644 --- a/examples/core/core_input_multitouch.c +++ b/examples/core/core_input_multitouch.c @@ -39,8 +39,12 @@ int main(void) { // Update //---------------------------------------------------------------------------------- - // Get multiple touchpoints - for (int i = 0; i < MAX_TOUCH_POINTS; ++i) touchPositions[i] = GetTouchPosition(i); + // Get the touch point count ( how many fingers are touching the screen ) + int tCount = GetTouchPointCount(); + // Clamp touch points available ( set the maximum touch points allowed ) + if(tCount > MAX_TOUCH_POINTS) tCount = MAX_TOUCH_POINTS; + // Get touch points positions + for (int i = 0; i < tCount; ++i) touchPositions[i] = GetTouchPosition(i); //---------------------------------------------------------------------------------- // Draw @@ -49,7 +53,7 @@ int main(void) ClearBackground(RAYWHITE); - for (int i = 0; i < MAX_TOUCH_POINTS; ++i) + for (int i = 0; i < tCount; ++i) { // Make sure point is not (0, 0) as this means there is no touch for it if ((touchPositions[i].x > 0) && (touchPositions[i].y > 0)) @@ -72,4 +76,4 @@ int main(void) //-------------------------------------------------------------------------------------- return 0; -} \ No newline at end of file +} From 76468bb8d8e4e588e1248df3a0db63f44605a24d Mon Sep 17 00:00:00 2001 From: Uneven Prankster <33995085+GithubPrankster@users.noreply.github.com> Date: Thu, 19 Jan 2023 16:53:30 -0300 Subject: [PATCH 044/192] Add rlCubemapParameters to rlgl.h (#2862) Co-authored-by: Uneven Prankster --- src/rlgl.h | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/rlgl.h b/src/rlgl.h index fbf70051abc3..3b055b23e803 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -596,6 +596,7 @@ RLAPI void rlDisableTexture(void); // Disable texture RLAPI void rlEnableTextureCubemap(unsigned int id); // Enable texture cubemap RLAPI void rlDisableTextureCubemap(void); // Disable texture cubemap RLAPI void rlTextureParameters(unsigned int id, int param, int value); // Set texture parameters (filter, wrap) +RLAPI void rlCubemapParameters(unsigned int id, int param, int value); // Set cubemap parameters (filter, wrap) // Shader state RLAPI void rlEnableShader(unsigned int id); // Enable shader program @@ -1624,6 +1625,54 @@ void rlTextureParameters(unsigned int id, int param, int value) glBindTexture(GL_TEXTURE_2D, 0); } +// Set cubemap parameters (wrap mode/filter mode) +void rlCubemapParameters(unsigned int id, int param, int value) +{ + glBindTexture(GL_TEXTURE_CUBE_MAP, id); + +#if !defined(GRAPHICS_API_OPENGL_11) + // Reset anisotropy filter, in case it was set + glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f); +#endif + + switch (param) + { + case RL_TEXTURE_WRAP_S: + case RL_TEXTURE_WRAP_T: + { + if (value == RL_TEXTURE_WRAP_MIRROR_CLAMP) + { +#if !defined(GRAPHICS_API_OPENGL_11) + if (RLGL.ExtSupported.texMirrorClamp) glTexParameteri(GL_TEXTURE_CUBE_MAP, param, value); + else TRACELOG(RL_LOG_WARNING, "GL: Clamp mirror wrap mode not supported (GL_MIRROR_CLAMP_EXT)"); +#endif + } + else glTexParameteri(GL_TEXTURE_CUBE_MAP, param, value); + + } break; + case RL_TEXTURE_MAG_FILTER: + case RL_TEXTURE_MIN_FILTER: glTexParameteri(GL_TEXTURE_CUBE_MAP, param, value); break; + case RL_TEXTURE_FILTER_ANISOTROPIC: + { +#if !defined(GRAPHICS_API_OPENGL_11) + if (value <= RLGL.ExtSupported.maxAnisotropyLevel) glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_ANISOTROPY_EXT, (float)value); + else if (RLGL.ExtSupported.maxAnisotropyLevel > 0.0f) + { + TRACELOG(RL_LOG_WARNING, "GL: Maximum anisotropic filter level supported is %iX", id, (int)RLGL.ExtSupported.maxAnisotropyLevel); + glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_ANISOTROPY_EXT, (float)value); + } + else TRACELOG(RL_LOG_WARNING, "GL: Anisotropic filtering not supported"); +#endif + } break; +#if defined(GRAPHICS_API_OPENGL_33) + case RL_TEXTURE_MIPMAP_BIAS_RATIO: glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_LOD_BIAS, value/100.0f); +#endif + default: break; + } + + glBindTexture(GL_TEXTURE_CUBE_MAP, 0); +} + // Enable shader program void rlEnableShader(unsigned int id) { From 116603e61c43ea272c6114c45f22faf924dafac9 Mon Sep 17 00:00:00 2001 From: Jeffery Myers Date: Thu, 19 Jan 2023 12:21:05 -0800 Subject: [PATCH 045/192] don't try to free a void* buffer as if it's a cgltf_data structure (#2867) --- src/rmodels.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rmodels.c b/src/rmodels.c index 786e5ac79bcf..2e7deb89a204 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -4658,7 +4658,7 @@ static Image LoadImageFromCgltfImage(cgltf_image *cgltfImage, const char *texPat if (result == cgltf_result_success) { image = LoadImageFromMemory(".png", (unsigned char *)data, outSize); - cgltf_free((cgltf_data*)data); + MemFree((cgltf_data*)data); } } } From edaca16d7c007846422cd6e098b117f6f8bab99d Mon Sep 17 00:00:00 2001 From: Jeffery Myers Date: Fri, 20 Jan 2023 07:05:19 -0800 Subject: [PATCH 046/192] Fix warnings in raylib project from MSVC (#2871) --- src/raudio.c | 17 +++++++++++++---- src/rmodels.c | 45 ++++++++++++++++++++++++++++----------------- src/rshapes.c | 12 ++++++------ src/rtextures.c | 9 +++++++++ 4 files changed, 56 insertions(+), 27 deletions(-) diff --git a/src/raudio.c b/src/raudio.c index 40b89106ac9f..34ab0702e781 100644 --- a/src/raudio.c +++ b/src/raudio.c @@ -198,7 +198,6 @@ typedef struct tagBITMAPINFOHEADER { #if defined(SUPPORT_FILEFORMAT_OGG) // TODO: Remap stb_vorbis malloc()/free() calls to RL_MALLOC/RL_FREE - #define STB_VORBIS_IMPLEMENTATION #include "external/stb_vorbis.h" // OGG loading functions #endif @@ -207,8 +206,18 @@ typedef struct tagBITMAPINFOHEADER { #define JARXM_MALLOC RL_MALLOC #define JARXM_FREE RL_FREE +#if defined(_MSC_VER ) // jar xm has warnings on windows, so disable them just for this file +#pragma warning( push ) +#pragma warning( disable : 4244) +#endif + #define JAR_XM_IMPLEMENTATION #include "external/jar_xm.h" // XM loading functions + +#if defined(_MSC_VER ) +#pragma warning( pop ) +#endif + #endif #if defined(SUPPORT_FILEFORMAT_MOD) @@ -1756,7 +1765,7 @@ void UpdateMusicStream(Music music) { while (true) { - int frameCountRed = drwav_read_pcm_frames_s16((drwav *)music.ctxData, frameCountStillNeeded, (short *)((char *)AUDIO.System.pcmBuffer + frameCountRedTotal*frameSize)); + int frameCountRed = (int)drwav_read_pcm_frames_s16((drwav *)music.ctxData, frameCountStillNeeded, (short *)((char *)AUDIO.System.pcmBuffer + frameCountRedTotal*frameSize)); frameCountRedTotal += frameCountRed; frameCountStillNeeded -= frameCountRed; if (frameCountStillNeeded == 0) break; @@ -1767,7 +1776,7 @@ void UpdateMusicStream(Music music) { while (true) { - int frameCountRed = drwav_read_pcm_frames_f32((drwav *)music.ctxData, frameCountStillNeeded, (float *)((char *)AUDIO.System.pcmBuffer + frameCountRedTotal*frameSize)); + int frameCountRed = (int)drwav_read_pcm_frames_f32((drwav *)music.ctxData, frameCountStillNeeded, (float *)((char *)AUDIO.System.pcmBuffer + frameCountRedTotal*frameSize)); frameCountRedTotal += frameCountRed; frameCountStillNeeded -= frameCountRed; if (frameCountStillNeeded == 0) break; @@ -1807,7 +1816,7 @@ void UpdateMusicStream(Music music) { while (true) { - int frameCountRed = drmp3_read_pcm_frames_f32((drmp3 *)music.ctxData, frameCountStillNeeded, (float *)((char *)AUDIO.System.pcmBuffer + frameCountRedTotal*frameSize)); + int frameCountRed = (int)drmp3_read_pcm_frames_f32((drmp3 *)music.ctxData, frameCountStillNeeded, (float *)((char *)AUDIO.System.pcmBuffer + frameCountRedTotal*frameSize)); frameCountRedTotal += frameCountRed; frameCountStillNeeded -= frameCountRed; if (frameCountStillNeeded == 0) break; diff --git a/src/rmodels.c b/src/rmodels.c index 2e7deb89a204..6b142cd14c89 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -102,8 +102,19 @@ #define PAR_REALLOC(T, BUF, N) ((T*)RL_REALLOC(BUF, sizeof(T)*(N))) #define PAR_FREE RL_FREE +#if defined(_MSC_VER ) // par shapes has 2 warnings on windows, so disable them just fof this file +#pragma warning( push ) +#pragma warning( disable : 4244) +#pragma warning( disable : 4305) +#endif + #define PAR_SHAPES_IMPLEMENTATION #include "external/par_shapes.h" // Shapes 3d parametric generation + +#if defined(_MSC_VER ) // disable MSVC warning suppression for par shapes +#pragma warning( pop ) +#endif + #endif #if defined(_WIN32) @@ -690,7 +701,7 @@ void DrawCapsule(Vector3 startPos, Vector3 endPos, float radius, int slices, int Vector3 capCenter = endPos; float baseSliceAngle = (2.0f*PI)/slices; - float baseRingAngle = PI * 0.5 / rings; + float baseRingAngle = PI * 0.5f / rings; rlBegin(RL_TRIANGLES); rlColor4ub(color.r, color.g, color.b, color.a); @@ -833,7 +844,7 @@ void DrawCapsuleWires(Vector3 startPos, Vector3 endPos, float radius, int slices Vector3 capCenter = endPos; float baseSliceAngle = (2.0f*PI)/slices; - float baseRingAngle = PI * 0.5 / rings; + float baseRingAngle = PI * 0.5f / rings; rlBegin(RL_LINES); rlColor4ub(color.r, color.g, color.b, color.a); @@ -4697,7 +4708,7 @@ static Image LoadImageFromCgltfImage(cgltf_image *cgltfImage, const char *texPat // Load bone info from GLTF skin data static BoneInfo *LoadBoneInfoGLTF(cgltf_skin skin, int *boneCount) { - *boneCount = skin.joints_count; + *boneCount = (int)skin.joints_count; BoneInfo *bones = RL_MALLOC(skin.joints_count*sizeof(BoneInfo)); for (unsigned int i = 0; i < skin.joints_count; i++) @@ -5097,7 +5108,7 @@ static Model LoadGLTF(const char *fileName) model.bones = LoadBoneInfoGLTF(skin, &model.boneCount); model.bindPose = RL_MALLOC(model.boneCount*sizeof(Transform)); - for (unsigned int i = 0; i < model.boneCount; i++) + for (int i = 0; i < model.boneCount; i++) { cgltf_node node = *skin.joints[i]; model.bindPose[i].translation.x = node.translation[0]; @@ -5275,7 +5286,7 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, unsigned in if (data->skins_count == 1) { cgltf_skin skin = data->skins[0]; - *animCount = data->animations_count; + *animCount = (int)data->animations_count; animations = RL_MALLOC(data->animations_count*sizeof(ModelAnimation)); for (unsigned int i = 0; i < data->animations_count; i++) @@ -5349,12 +5360,12 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, unsigned in animations[i].frameCount = (int)(animDuration*1000.0f/GLTF_ANIMDELAY); animations[i].framePoses = RL_MALLOC(animations[i].frameCount*sizeof(Transform *)); - for (unsigned int j = 0; j < animations[i].frameCount; j++) + for (int j = 0; j < animations[i].frameCount; j++) { animations[i].framePoses[j] = RL_MALLOC(animations[i].boneCount*sizeof(Transform)); float time = ((float) j*GLTF_ANIMDELAY)/1000.0f; - for (unsigned int k = 0; k < animations[i].boneCount; k++) + for (int k = 0; k < animations[i].boneCount; k++) { Vector3 translation = {0, 0, 0}; Quaternion rotation = {0, 0, 0, 1}; @@ -5567,7 +5578,7 @@ static Model LoadM3D(const char *fileName) // Map no material to index 0 with default shader, everything else materialid + 1 model.materials[0] = LoadMaterialDefault(); - for (i = l = 0, k = -1; i < m3d->numface; i++, l++) + for (i = l = 0, k = -1; i < (int)m3d->numface; i++, l++) { // Materials are grouped together if (mi != m3d->face[i].materialid) @@ -5584,7 +5595,7 @@ static Model LoadM3D(const char *fileName) k++; mi = m3d->face[i].materialid; - for (j = i, l = 0; (j < m3d->numface) && (mi == m3d->face[j].materialid); j++, l++); + for (j = i, l = 0; (j < (int)m3d->numface) && (mi == m3d->face[j].materialid); j++, l++); model.meshes[k].vertexCount = l*3; model.meshes[k].triangleCount = l; @@ -5636,11 +5647,11 @@ static Model LoadM3D(const char *fileName) if (m3d->face[i].texcoord[0] != M3D_UNDEF) { model.meshes[k].texcoords[l*6 + 0] = m3d->tmap[m3d->face[i].texcoord[0]].u; - model.meshes[k].texcoords[l*6 + 1] = 1.0 - m3d->tmap[m3d->face[i].texcoord[0]].v; + model.meshes[k].texcoords[l*6 + 1] = 1.0f - m3d->tmap[m3d->face[i].texcoord[0]].v; model.meshes[k].texcoords[l*6 + 2] = m3d->tmap[m3d->face[i].texcoord[1]].u; - model.meshes[k].texcoords[l*6 + 3] = 1.0 - m3d->tmap[m3d->face[i].texcoord[1]].v; + model.meshes[k].texcoords[l*6 + 3] = 1.0f - m3d->tmap[m3d->face[i].texcoord[1]].v; model.meshes[k].texcoords[l*6 + 4] = m3d->tmap[m3d->face[i].texcoord[2]].u; - model.meshes[k].texcoords[l*6 + 5] = 1.0 - m3d->tmap[m3d->face[i].texcoord[2]].v; + model.meshes[k].texcoords[l*6 + 5] = 1.0f - m3d->tmap[m3d->face[i].texcoord[2]].v; } if (m3d->face[i].normal[0] != M3D_UNDEF) @@ -5664,7 +5675,7 @@ static Model LoadM3D(const char *fileName) int skinid = m3d->vertex[m3d->face[i].vertex[n]].skinid; // Check if there is a skin for this mesh, should be, just failsafe - if (skinid != M3D_UNDEF && skinid < m3d->numskin) + if (skinid != M3D_UNDEF && skinid < (int)m3d->numskin) { for (j = 0; j < 4; j++) { @@ -5684,7 +5695,7 @@ static Model LoadM3D(const char *fileName) } // Load materials - for (i = 0; i < m3d->nummaterial; i++) + for (i = 0; i < (int)m3d->nummaterial; i++) { model.materials[i + 1] = LoadMaterialDefault(); @@ -5761,7 +5772,7 @@ static Model LoadM3D(const char *fileName) model.bones = RL_CALLOC(model.boneCount, sizeof(BoneInfo)); model.bindPose = RL_CALLOC(model.boneCount, sizeof(Transform)); - for (i = 0; i < m3d->numbone; i++) + for (i = 0; i < (int)m3d->numbone; i++) { model.bones[i].parent = m3d->bone[i].parent; strncpy(model.bones[i].name, m3d->bone[i].name, sizeof(model.bones[i].name)); @@ -5864,7 +5875,7 @@ static ModelAnimation *LoadModelAnimationsM3D(const char *fileName, unsigned int // strncpy(animations[a].name, m3d->action[a].name, sizeof(animations[a].name)); TRACELOG(LOG_INFO, "MODEL: [%s] animation #%i: %i msec, %i frames", fileName, a, m3d->action[a].durationmsec, animations[a].frameCount); - for (i = 0; i < m3d->numbone; i++) + for (i = 0; i < (int)m3d->numbone; i++) { animations[a].bones[i].parent = m3d->bone[i].parent; strncpy(animations[a].bones[i].name, m3d->bone[i].name, sizeof(animations[a].bones[i].name)); @@ -5884,7 +5895,7 @@ static ModelAnimation *LoadModelAnimationsM3D(const char *fileName, unsigned int if (pose != NULL) { - for (j = 0; j < m3d->numbone; j++) + for (j = 0; j < (int)m3d->numbone; j++) { animations[a].framePoses[i][j].translation.x = m3d->vertex[pose[j].pos].x*m3d->scale; animations[a].framePoses[i][j].translation.y = m3d->vertex[pose[j].pos].y*m3d->scale; diff --git a/src/rshapes.c b/src/rshapes.c index 371abe2c72a2..86e014e2ad42 100644 --- a/src/rshapes.c +++ b/src/rshapes.c @@ -105,7 +105,7 @@ void SetShapesTexture(Texture2D texture, Rectangle source) // Draw a pixel void DrawPixel(int posX, int posY, Color color) { - DrawPixelV((Vector2){ posX, posY }, color); + DrawPixelV((Vector2){ (float)posX, (float)posY }, color); } // Draw a pixel (Vector version) @@ -156,8 +156,8 @@ void DrawLine(int startPosX, int startPosY, int endPosX, int endPosY, Color colo { rlBegin(RL_LINES); rlColor4ub(color.r, color.g, color.b, color.a); - rlVertex2f(startPosX, startPosY); - rlVertex2f(endPosX, endPosY); + rlVertex2f((float)startPosX, (float)startPosY); + rlVertex2f((float)endPosX, (float)endPosY); rlEnd(); } @@ -209,7 +209,7 @@ void DrawLineBezier(Vector2 startPos, Vector2 endPos, float thick, Color color) float dy = current.y-previous.y; float dx = current.x-previous.x; - float size = 0.5*thick/sqrt(dx*dx+dy*dy); + float size = 0.5f*thick/sqrtf(dx*dx+dy*dy); if (i==1) { @@ -254,7 +254,7 @@ void DrawLineBezierQuad(Vector2 startPos, Vector2 endPos, Vector2 controlPos, fl float dy = current.y-previous.y; float dx = current.x-previous.x; - float size = 0.5*thick/sqrt(dx*dx+dy*dy); + float size = 0.5f*thick/sqrtf(dx*dx+dy*dy); if (i==1) { @@ -299,7 +299,7 @@ void DrawLineBezierCubic(Vector2 startPos, Vector2 endPos, Vector2 startControlP float dy = current.y-previous.y; float dx = current.x-previous.x; - float size = 0.5*thick/sqrt(dx*dx+dy*dy); + float size = 0.5f*thick/sqrtf(dx*dx+dy*dy); if (i==1) { diff --git a/src/rtextures.c b/src/rtextures.c index 5d17184897dc..05dacb21ad9f 100644 --- a/src/rtextures.c +++ b/src/rtextures.c @@ -163,8 +163,17 @@ #define QOI_MALLOC RL_MALLOC #define QOI_FREE RL_FREE +#if defined(_MSC_VER ) // qoi has warnings on windows, so disable them just for this file +#pragma warning( push ) +#pragma warning( disable : 4267) +#endif #define QOI_IMPLEMENTATION #include "external/qoi.h" + +#if defined(_MSC_VER ) +#pragma warning( pop ) +#endif + #endif #if defined(SUPPORT_IMAGE_EXPORT) From e64606a82f7cc66c57df31815371f0328c723bf4 Mon Sep 17 00:00:00 2001 From: Masoud Naservand Date: Fri, 20 Jan 2023 18:37:43 +0330 Subject: [PATCH 047/192] Correct the set paths in bat files in examples/ (#2870) Co-authored-by: Masoud Naservand --- examples/raylib_compile_execute.bat | 8 ++++---- examples/raylib_makefile_example.bat | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/examples/raylib_compile_execute.bat b/examples/raylib_compile_execute.bat index 59a25fc51af6..0dc43e187f36 100644 --- a/examples/raylib_compile_execute.bat +++ b/examples/raylib_compile_execute.bat @@ -4,10 +4,10 @@ :: . :: > Setup required Environment :: ------------------------------------- -set RAYLIB_INCLUDE_DIR=C:\raylib\src -set RAYLIB_LIB_DIR=C:\raylib\src -set RAYLIB_RES_FILE=C:\raylib\src\raylib.rc.data -set COMPILER_DIR=C:\raylib\mingw\bin +set RAYLIB_INCLUDE_DIR=C:\raylib\raylib\src +set RAYLIB_LIB_DIR=C:\raylib\raylib\src +set RAYLIB_RES_FILE=C:\raylib\raylib\src\raylib.rc.data +set COMPILER_DIR=C:\raylib\w64devkit\bin set PATH=%PATH%;%COMPILER_DIR% :: Get full filename path for input file %1 set FILENAME=%~f1 diff --git a/examples/raylib_makefile_example.bat b/examples/raylib_makefile_example.bat index 83fa06e102a5..cc2fdc225f17 100644 --- a/examples/raylib_makefile_example.bat +++ b/examples/raylib_makefile_example.bat @@ -4,10 +4,10 @@ :: . :: > Setup required Environment :: ------------------------------------- -set RAYLIB_INCLUDE_DIR=C:\raylib\src -set RAYLIB_LIB_DIR=C:\raylib\src -set RAYLIB_RES_FILE=C:\raylib\src\raylib.rc.data -set COMPILER_DIR=C:\raylib\mingw\bin +set RAYLIB_INCLUDE_DIR=C:\raylib\raylib\src +set RAYLIB_LIB_DIR=C:\raylib\raylib\src +set RAYLIB_RES_FILE=C:\raylib\raylib\src\raylib.rc.data +set COMPILER_DIR=C:\raylib\w64devkit\bin set PATH=%PATH%;%COMPILER_DIR% set FILENAME=%1 set FILENAME_FULL_PATH=%~f1 @@ -24,4 +24,4 @@ mingw32-make %FILENAME% -B PLATFORM=PLATFORM_DESKTOP :: . :: > Executing program :: ------------------------- -cmd /c if exist %FILENAME_FULL_PATH%.exe %FILENAME_FULL_PATH%.exe \ No newline at end of file +cmd /c if exist %FILENAME_FULL_PATH%.exe %FILENAME_FULL_PATH%.exe From c649bec26cafb5415d9becae3e39720692146d40 Mon Sep 17 00:00:00 2001 From: Jeffery Myers Date: Fri, 20 Jan 2023 07:13:19 -0800 Subject: [PATCH 048/192] Have LoadMaterials call the same code that OBJ loader does so that we can read MTL files (#2872) --- src/rmodels.c | 77 ++++++++++++++++++++++++++------------------------- 1 file changed, 39 insertions(+), 38 deletions(-) diff --git a/src/rmodels.c b/src/rmodels.c index 6b142cd14c89..89538d7a6722 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -1862,6 +1862,42 @@ bool ExportMesh(Mesh mesh, const char *fileName) return success; } +#if defined(SUPPORT_FILEFORMAT_MTL) +// Process obj materials + +static void ProcessOBJMaterials(Material* rayMaterials, tinyobj_material_t* materials, int materialCount) +{ + // Init model materials + for (unsigned int m = 0; m < materialCount; m++) + { + // Init material to default + // NOTE: Uses default shader, which only supports MATERIAL_MAP_DIFFUSE + rayMaterials[m] = LoadMaterialDefault(); + + // Get default texture, in case no texture is defined + // NOTE: rlgl default texture is a 1x1 pixel UNCOMPRESSED_R8G8B8A8 + rayMaterials[m].maps[MATERIAL_MAP_DIFFUSE].texture = (Texture2D){ rlGetTextureIdDefault(), 1, 1, 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 }; + + if (materials[m].diffuse_texname != NULL) rayMaterials[m].maps[MATERIAL_MAP_DIFFUSE].texture = LoadTexture(materials[m].diffuse_texname); //char *diffuse_texname; // map_Kd + + rayMaterials[m].maps[MATERIAL_MAP_DIFFUSE].color = (Color){ (unsigned char)(materials[m].diffuse[0] * 255.0f), (unsigned char)(materials[m].diffuse[1] * 255.0f), (unsigned char)(materials[m].diffuse[2] * 255.0f), 255 }; //float diffuse[3]; + rayMaterials[m].maps[MATERIAL_MAP_DIFFUSE].value = 0.0f; + + if (materials[m].specular_texname != NULL) rayMaterials[m].maps[MATERIAL_MAP_SPECULAR].texture = LoadTexture(materials[m].specular_texname); //char *specular_texname; // map_Ks + rayMaterials[m].maps[MATERIAL_MAP_SPECULAR].color = (Color){ (unsigned char)(materials[m].specular[0] * 255.0f), (unsigned char)(materials[m].specular[1] * 255.0f), (unsigned char)(materials[m].specular[2] * 255.0f), 255 }; //float specular[3]; + rayMaterials[m].maps[MATERIAL_MAP_SPECULAR].value = 0.0f; + + if (materials[m].bump_texname != NULL) rayMaterials[m].maps[MATERIAL_MAP_NORMAL].texture = LoadTexture(materials[m].bump_texname); //char *bump_texname; // map_bump, bump + rayMaterials[m].maps[MATERIAL_MAP_NORMAL].color = WHITE; + rayMaterials[m].maps[MATERIAL_MAP_NORMAL].value = materials[m].shininess; + + rayMaterials[m].maps[MATERIAL_MAP_EMISSION].color = (Color){ (unsigned char)(materials[m].emission[0] * 255.0f), (unsigned char)(materials[m].emission[1] * 255.0f), (unsigned char)(materials[m].emission[2] * 255.0f), 255 }; //float emission[3]; + + if (materials[m].displacement_texname != NULL) rayMaterials[m].maps[MATERIAL_MAP_HEIGHT].texture = LoadTexture(materials[m].displacement_texname); //char *displacement_texname; // disp + } +} +#endif + // Load materials from model file Material *LoadMaterials(const char *fileName, int *materialCount) { @@ -1878,7 +1914,8 @@ Material *LoadMaterials(const char *fileName, int *materialCount) int result = tinyobj_parse_mtl_file(&mats, &count, fileName); if (result != TINYOBJ_SUCCESS) TRACELOG(LOG_WARNING, "MATERIAL: [%s] Failed to parse materials file", fileName); - // TODO: Process materials to return + materials = MemAlloc(sizeof(Material) * count); + ProcessOBJMaterials(materials, mats, count); tinyobj_materials_free(mats, count); } @@ -1886,16 +1923,6 @@ Material *LoadMaterials(const char *fileName, int *materialCount) TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to load material file", fileName); #endif - // Set materials shader to default (DIFFUSE, SPECULAR, NORMAL) - if (materials != NULL) - { - for (unsigned int i = 0; i < count; i++) - { - materials[i].shader.id = rlGetShaderIdDefault(); - materials[i].shader.locs = rlGetShaderLocsDefault(); - } - } - *materialCount = count; return materials; } @@ -4000,33 +4027,7 @@ static Model LoadOBJ(const char *fileName) } // Init model materials - for (unsigned int m = 0; m < materialCount; m++) - { - // Init material to default - // NOTE: Uses default shader, which only supports MATERIAL_MAP_DIFFUSE - model.materials[m] = LoadMaterialDefault(); - - // Get default texture, in case no texture is defined - // NOTE: rlgl default texture is a 1x1 pixel UNCOMPRESSED_R8G8B8A8 - model.materials[m].maps[MATERIAL_MAP_DIFFUSE].texture = (Texture2D){ rlGetTextureIdDefault(), 1, 1, 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 }; - - if (materials[m].diffuse_texname != NULL) model.materials[m].maps[MATERIAL_MAP_DIFFUSE].texture = LoadTexture(materials[m].diffuse_texname); //char *diffuse_texname; // map_Kd - - model.materials[m].maps[MATERIAL_MAP_DIFFUSE].color = (Color){ (unsigned char)(materials[m].diffuse[0]*255.0f), (unsigned char)(materials[m].diffuse[1]*255.0f), (unsigned char)(materials[m].diffuse[2]*255.0f), 255 }; //float diffuse[3]; - model.materials[m].maps[MATERIAL_MAP_DIFFUSE].value = 0.0f; - - if (materials[m].specular_texname != NULL) model.materials[m].maps[MATERIAL_MAP_SPECULAR].texture = LoadTexture(materials[m].specular_texname); //char *specular_texname; // map_Ks - model.materials[m].maps[MATERIAL_MAP_SPECULAR].color = (Color){ (unsigned char)(materials[m].specular[0]*255.0f), (unsigned char)(materials[m].specular[1]*255.0f), (unsigned char)(materials[m].specular[2]*255.0f), 255 }; //float specular[3]; - model.materials[m].maps[MATERIAL_MAP_SPECULAR].value = 0.0f; - - if (materials[m].bump_texname != NULL) model.materials[m].maps[MATERIAL_MAP_NORMAL].texture = LoadTexture(materials[m].bump_texname); //char *bump_texname; // map_bump, bump - model.materials[m].maps[MATERIAL_MAP_NORMAL].color = WHITE; - model.materials[m].maps[MATERIAL_MAP_NORMAL].value = materials[m].shininess; - - model.materials[m].maps[MATERIAL_MAP_EMISSION].color = (Color){ (unsigned char)(materials[m].emission[0]*255.0f), (unsigned char)(materials[m].emission[1]*255.0f), (unsigned char)(materials[m].emission[2]*255.0f), 255 }; //float emission[3]; - - if (materials[m].displacement_texname != NULL) model.materials[m].maps[MATERIAL_MAP_HEIGHT].texture = LoadTexture(materials[m].displacement_texname); //char *displacement_texname; // disp - } + ProcessOBJMaterials(model.materials, materials, materialCount); tinyobj_attrib_free(&attrib); tinyobj_shapes_free(meshes, meshCount); From 342b18da034b34cb9d7713fd03e321e4049e79c2 Mon Sep 17 00:00:00 2001 From: KOLANICH Date: Sat, 21 Jan 2023 17:50:38 +0000 Subject: [PATCH 049/192] Add packaging for distros with deb- and rpm-based packages. (#2877) --- cmake/PackConfigurations.cmake | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/cmake/PackConfigurations.cmake b/cmake/PackConfigurations.cmake index 74eded02551e..ad00ca6b61e9 100644 --- a/cmake/PackConfigurations.cmake +++ b/cmake/PackConfigurations.cmake @@ -1,5 +1,6 @@ # Packaging SET(CPACK_PACKAGE_NAME "raylib") +SET(CPACK_PACKAGE_CONTACT "raysan5") SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Simple and easy-to-use library to enjoy videogames programming") SET(CPACK_PACKAGE_VERSION "${PROJECT_VERSION}") SET(CPACK_PACKAGE_VERSION_MAJOR "${PROJECT_VERSION_MAJOR}") @@ -9,5 +10,9 @@ SET(CPACK_PACKAGE_DESCRIPTION_FILE "${PROJECT_SOURCE_DIR}/../README.md") SET(CPACK_RESOURCE_FILE_WELCOME "${PROJECT_SOURCE_DIR}/../README.md") SET(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/../LICENSE") SET(CPACK_PACKAGE_FILE_NAME "raylib-${PROJECT_VERSION}$ENV{RAYLIB_PACKAGE_SUFFIX}") -SET(CPACK_GENERATOR "ZIP;TGZ") # Remove this, if you want the NSIS installer on Windows -include(CPack) \ No newline at end of file +SET(CPACK_GENERATOR "ZIP;TGZ;DEB;RPM") # Remove this, if you want the NSIS installer on Windows +SET(CPACK_DEBIAN_PACKAGE_SHLIBDEPS OFF) # can be used to generate deps, slow and requires tools. +SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libatomic1, libc6, libglfw3, libglu1-mesa | libglu1, libglx0, libopengl0") +SET(CPACK_DEBIAN_PACKAGE_NAME "lib${CPACK_PACKAGE_NAME}-dev") +SET(CPACK_RPM_PACKAGE_NAME "lib${CPACK_PACKAGE_NAME}-devel") +include(CPack) From 19715546b3eddb0d6171d6b68e3642497b007a4e Mon Sep 17 00:00:00 2001 From: Uneven Prankster <33995085+GithubPrankster@users.noreply.github.com> Date: Sat, 21 Jan 2023 14:51:33 -0300 Subject: [PATCH 050/192] Stub out rlCubemapParameters if under GL 1.1. (#2876) Co-authored-by: Uneven Prankster --- src/rlgl.h | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/rlgl.h b/src/rlgl.h index 3b055b23e803..12f62771ebcd 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -1628,12 +1628,11 @@ void rlTextureParameters(unsigned int id, int param, int value) // Set cubemap parameters (wrap mode/filter mode) void rlCubemapParameters(unsigned int id, int param, int value) { +#if !defined(GRAPHICS_API_OPENGL_11) glBindTexture(GL_TEXTURE_CUBE_MAP, id); -#if !defined(GRAPHICS_API_OPENGL_11) // Reset anisotropy filter, in case it was set glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f); -#endif switch (param) { @@ -1642,10 +1641,8 @@ void rlCubemapParameters(unsigned int id, int param, int value) { if (value == RL_TEXTURE_WRAP_MIRROR_CLAMP) { -#if !defined(GRAPHICS_API_OPENGL_11) if (RLGL.ExtSupported.texMirrorClamp) glTexParameteri(GL_TEXTURE_CUBE_MAP, param, value); else TRACELOG(RL_LOG_WARNING, "GL: Clamp mirror wrap mode not supported (GL_MIRROR_CLAMP_EXT)"); -#endif } else glTexParameteri(GL_TEXTURE_CUBE_MAP, param, value); @@ -1654,7 +1651,6 @@ void rlCubemapParameters(unsigned int id, int param, int value) case RL_TEXTURE_MIN_FILTER: glTexParameteri(GL_TEXTURE_CUBE_MAP, param, value); break; case RL_TEXTURE_FILTER_ANISOTROPIC: { -#if !defined(GRAPHICS_API_OPENGL_11) if (value <= RLGL.ExtSupported.maxAnisotropyLevel) glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_ANISOTROPY_EXT, (float)value); else if (RLGL.ExtSupported.maxAnisotropyLevel > 0.0f) { @@ -1662,7 +1658,6 @@ void rlCubemapParameters(unsigned int id, int param, int value) glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_ANISOTROPY_EXT, (float)value); } else TRACELOG(RL_LOG_WARNING, "GL: Anisotropic filtering not supported"); -#endif } break; #if defined(GRAPHICS_API_OPENGL_33) case RL_TEXTURE_MIPMAP_BIAS_RATIO: glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_LOD_BIAS, value/100.0f); @@ -1671,6 +1666,7 @@ void rlCubemapParameters(unsigned int id, int param, int value) } glBindTexture(GL_TEXTURE_CUBE_MAP, 0); +#endif } // Enable shader program From e539aad1184373fe32c4dd8052e888df9ab4d8fe Mon Sep 17 00:00:00 2001 From: Antonis Geralis <43617260+planetis-m@users.noreply.github.com> Date: Sat, 21 Jan 2023 19:52:31 +0200 Subject: [PATCH 051/192] Fix android sound issue #2118 (#2875) --- src/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Makefile b/src/Makefile index fdc52a8396e5..c2e227f7a464 100644 --- a/src/Makefile +++ b/src/Makefile @@ -389,7 +389,7 @@ ifeq ($(PLATFORM),PLATFORM_ANDROID) # -Werror=format-security CFLAGS += -Wa,--noexecstack -Wformat -no-canonical-prefixes # Preprocessor macro definitions - CFLAGS += -DANDROID -DPLATFORM_ANDROID -D__ANDROID_API__=$(ANDROID_API_VERSION) -DMAL_NO_OSS + CFLAGS += -D__ANDROID__ -DPLATFORM_ANDROID -D__ANDROID_API__=$(ANDROID_API_VERSION) -DMAL_NO_OSS endif # Define required compilation flags for raylib SHARED lib From 78ae3b38a6e7d1386d233da620e7b31aa1a0a94e Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 21 Jan 2023 19:31:47 +0100 Subject: [PATCH 052/192] minor format tweak --- src/rcore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rcore.c b/src/rcore.c index 27b1a1f33692..23a6597a4f40 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -4043,7 +4043,7 @@ static bool InitGraphicsDevice(int width, int height) glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE); // Enable OpenGL Debug Context #endif } - else if (rlGetVersion() == RL_OPENGL_ES_20) // Request OpenGL ES 2.0 context + else if (rlGetVersion() == RL_OPENGL_ES_20) // Request OpenGL ES 2.0 context { glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); From d8af76f67c54a6fa7b20c0fadff7c15ef5478945 Mon Sep 17 00:00:00 2001 From: Rob Loach Date: Sun, 22 Jan 2023 05:10:38 -0500 Subject: [PATCH 053/192] Fix to use TRACELOG() instead of TraceLog() for internal modules (#2881) There were a few raylib modules that continued to use TraceLog() instead of the TRACELOG() macro. This change ensures that all the internal raylib modules use the TRACELOG() pattern consistently. --- src/rcore.c | 6 +++--- src/rmodels.c | 4 ++-- src/rtext.c | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/rcore.c b/src/rcore.c index 23a6597a4f40..1f97edb2a0c5 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -3310,7 +3310,7 @@ unsigned char *CompressData(const unsigned char *data, int dataSize, int *compDa compData = (unsigned char *)RL_CALLOC(bounds, 1); *compDataSize = sdeflate(&sdefl, compData, data, dataSize, COMPRESSION_QUALITY_DEFLATE); // Compression level 8, same as stbwi - TraceLog(LOG_INFO, "SYSTEM: Compress data: Original size: %i -> Comp. size: %i", dataSize, *compDataSize); + TRACELOG(LOG_INFO, "SYSTEM: Compress data: Original size: %i -> Comp. size: %i", dataSize, *compDataSize); #endif return compData; @@ -3335,7 +3335,7 @@ unsigned char *DecompressData(const unsigned char *compData, int compDataSize, i *dataSize = length; - TraceLog(LOG_INFO, "SYSTEM: Decompress data: Comp. size: %i -> Original size: %i", compDataSize, *dataSize); + TRACELOG(LOG_INFO, "SYSTEM: Decompress data: Comp. size: %i -> Original size: %i", compDataSize, *dataSize); #endif return data; @@ -6854,7 +6854,7 @@ static void LoadAutomationEvents(const char *fileName) if ((fileId[0] == 'r') && (fileId[1] == 'E') && (fileId[2] == 'P') && (fileId[1] == ' ')) { fread(&eventCount, sizeof(int), 1, repFile); - TraceLog(LOG_WARNING, "Events loaded: %i\n", eventCount); + TRACELOG(LOG_WARNING, "Events loaded: %i\n", eventCount); fread(events, sizeof(AutomationEvent), eventCount, repFile); } diff --git a/src/rmodels.c b/src/rmodels.c index 89538d7a6722..80ea916445e3 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -3937,12 +3937,12 @@ static Model LoadOBJ(const char *fileName) { model.materialCount = materialCount; model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material)); - TraceLog(LOG_INFO, "MODEL: model has %i material meshes", materialCount); + TRACELOG(LOG_INFO, "MODEL: model has %i material meshes", materialCount); } else { model.meshCount = 1; - TraceLog(LOG_INFO, "MODEL: No materials, putting all meshes in a default material"); + TRACELOG(LOG_INFO, "MODEL: No materials, putting all meshes in a default material"); } model.meshes = (Mesh *)RL_CALLOC(model.meshCount, sizeof(Mesh)); diff --git a/src/rtext.c b/src/rtext.c index f98386702747..718fda04b767 100644 --- a/src/rtext.c +++ b/src/rtext.c @@ -669,7 +669,7 @@ Image GenImageFontAtlas(const GlyphInfo *chars, Rectangle **charRecs, int glyphC if (chars == NULL) { - TraceLog(LOG_WARNING, "FONT: Provided chars info not valid, returning empty image atlas"); + TRACELOG(LOG_WARNING, "FONT: Provided chars info not valid, returning empty image atlas"); return atlas; } From 4706891cae7d7b07ab7f85aee9d858bdd11d4f42 Mon Sep 17 00:00:00 2001 From: Rob Loach Date: Sun, 22 Jan 2023 09:29:29 -0500 Subject: [PATCH 054/192] Add RAYLIB_VERSION numbers to raylib.h (#2856) Ran into an issue in raylib-cpp where a user was using raylib 4.5-dev, even though the library currently only targets 4.2. With having RAYLIB_VERSION_MAJOR and RAYLIB_VERSION_MINOR, we will be able to target different versions of raylib in different ways, via C preprocessor conditionals. For example: ``` c newColor = ColorTint(BLUE, RED); TraceLog(LOG_INFO, "The color should be tinted, but this isn't supported in ryalib <= 4.2"); ``` --- src/raylib.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/raylib.h b/src/raylib.h index 1c3f77669ada..10e69acdf499 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -81,6 +81,9 @@ #include // Required for: va_list - Only used by TraceLogCallback +#define RAYLIB_VERSION_MAJOR 4 +#define RAYLIB_VERSION_MINOR 5 +#define RAYLIB_VERSION_PATCH 0 #define RAYLIB_VERSION "4.5-dev" // Function specifiers in case library is build/used as a shared library (Windows) From 393a03a46eec038d49606ef5f3459621decb27b9 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 23 Jan 2023 15:28:45 +0100 Subject: [PATCH 055/192] Removed twitter badge, twitter API seems to be limited --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 030cc93b045f..c66eed75e317 100644 --- a/README.md +++ b/README.md @@ -23,8 +23,6 @@ Ready to learn? Jump to [code examples!](https://www.raylib.com/examples.html) [![Subreddit Subscribers](https://img.shields.io/reddit/subreddit-subscribers/raylib?label=reddit%20r%2Fraylib&logo=reddit)](https://www.reddit.com/r/raylib/) [![Youtube Subscribers](https://img.shields.io/youtube/channel/subscribers/UC8WIBkhYb5sBNqXO1mZ7WSQ?style=flat&label=Youtube&logo=youtube)](https://www.youtube.com/c/raylib) [![Twitch Status](https://img.shields.io/twitch/status/raysan5?style=flat&label=Twitch&logo=twitch)](https://www.twitch.tv/raysan5) -[![Twitter Followers](https://img.shields.io/twitter/follow/raysan5?style=flat&label=@raysan5&color=1da1f2&logo=twitter)](https://twitter.com/raysan5) - [![Windows](https://github.com/raysan5/raylib/workflows/Windows/badge.svg)](https://github.com/raysan5/raylib/actions?query=workflow%3AWindows) [![Linux](https://github.com/raysan5/raylib/workflows/Linux/badge.svg)](https://github.com/raysan5/raylib/actions?query=workflow%3ALinux) From 542ef8904a2ce9d87ab53289026da7a715907b87 Mon Sep 17 00:00:00 2001 From: PencilAmazing Date: Mon, 23 Jan 2023 13:55:02 -0500 Subject: [PATCH 056/192] [models] Load bone names from IQM file if available (#2882) * Load bone names from IQM file if available * Formatting and default bone name --- src/rmodels.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/rmodels.c b/src/rmodels.c index 80ea916445e3..78219a70e057 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -4450,6 +4450,12 @@ static ModelAnimation *LoadModelAnimationsIQM(const char *fileName, unsigned int unsigned int num_extensions, ofs_extensions; } IQMHeader; + typedef struct IQMJoint { + unsigned int name; + int parent; + float translate[3], rotate[4], scale[3]; + } IQMJoint; + typedef struct IQMPose { int parent; unsigned int mask; @@ -4503,6 +4509,10 @@ static ModelAnimation *LoadModelAnimationsIQM(const char *fileName, unsigned int //fread(framedata, iqmHeader->num_frames*iqmHeader->num_framechannels*sizeof(unsigned short), 1, iqmFile); memcpy(framedata, fileDataPtr + iqmHeader->ofs_frames, iqmHeader->num_frames*iqmHeader->num_framechannels*sizeof(unsigned short)); + // joints + IQMJoint *joints = RL_MALLOC(iqmHeader->num_joints*sizeof(IQMJoint)); + memcpy(joints, fileDataPtr + iqmHeader->ofs_joints, iqmHeader->num_joints*sizeof(IQMJoint)); + for (unsigned int a = 0; a < iqmHeader->num_anims; a++) { animations[a].frameCount = anim[a].num_frames; @@ -4513,7 +4523,11 @@ static ModelAnimation *LoadModelAnimationsIQM(const char *fileName, unsigned int for (unsigned int j = 0; j < iqmHeader->num_poses; j++) { - strcpy(animations[a].bones[j].name, "ANIMJOINTNAME"); + // If animations and skeleton are in the same file, copy bone names to anim + if (iqmHeader->num_joints > 0) + memcpy(animations[a].bones[j].name, fileDataPtr + iqmHeader->ofs_text + joints[j].name, BONE_NAME_LENGTH*sizeof(char)); + else + strcpy(animations[a].bones[j].name, "ANIMJOINTNAME"); // default bone name otherwise animations[a].bones[j].parent = poses[j].parent; } @@ -4627,6 +4641,7 @@ static ModelAnimation *LoadModelAnimationsIQM(const char *fileName, unsigned int RL_FREE(fileData); + RL_FREE(joints); RL_FREE(framedata); RL_FREE(poses); RL_FREE(anim); From 5b3c5e1a16c2d0f97e407542f1a0837b9d5b7c71 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 24 Jan 2023 17:16:35 +0100 Subject: [PATCH 057/192] REVIEWED: `ProcessMaterialsOBJ()` available when required --- src/rmodels.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/rmodels.c b/src/rmodels.c index 89538d7a6722..b500e1e856f0 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -166,6 +166,9 @@ static Model LoadVOX(const char *filename); // Load VOX mesh data static Model LoadM3D(const char *filename); // Load M3D mesh data static ModelAnimation *LoadModelAnimationsM3D(const char *fileName, unsigned int *animCount); // Load M3D animation data #endif +#if defined(SUPPORT_FILEFORMAT_OBJ) || defined(SUPPORT_FILEFORMAT_MTL) +static void ProcessMaterialsOBJ(Material *rayMaterials, tinyobj_material_t *materials, int materialCount); // Process obj materials +#endif //---------------------------------------------------------------------------------- // Module Functions Definition @@ -1862,10 +1865,9 @@ bool ExportMesh(Mesh mesh, const char *fileName) return success; } -#if defined(SUPPORT_FILEFORMAT_MTL) +#if defined(SUPPORT_FILEFORMAT_OBJ) || defined(SUPPORT_FILEFORMAT_MTL) // Process obj materials - -static void ProcessOBJMaterials(Material* rayMaterials, tinyobj_material_t* materials, int materialCount) +static void ProcessMaterialsOBJ(Material *rayMaterials, tinyobj_material_t *materials, int materialCount) { // Init model materials for (unsigned int m = 0; m < materialCount; m++) @@ -1880,23 +1882,23 @@ static void ProcessOBJMaterials(Material* rayMaterials, tinyobj_material_t* mate if (materials[m].diffuse_texname != NULL) rayMaterials[m].maps[MATERIAL_MAP_DIFFUSE].texture = LoadTexture(materials[m].diffuse_texname); //char *diffuse_texname; // map_Kd - rayMaterials[m].maps[MATERIAL_MAP_DIFFUSE].color = (Color){ (unsigned char)(materials[m].diffuse[0] * 255.0f), (unsigned char)(materials[m].diffuse[1] * 255.0f), (unsigned char)(materials[m].diffuse[2] * 255.0f), 255 }; //float diffuse[3]; + rayMaterials[m].maps[MATERIAL_MAP_DIFFUSE].color = (Color){ (unsigned char)(materials[m].diffuse[0]*255.0f), (unsigned char)(materials[m].diffuse[1]*255.0f), (unsigned char)(materials[m].diffuse[2] * 255.0f), 255 }; //float diffuse[3]; rayMaterials[m].maps[MATERIAL_MAP_DIFFUSE].value = 0.0f; if (materials[m].specular_texname != NULL) rayMaterials[m].maps[MATERIAL_MAP_SPECULAR].texture = LoadTexture(materials[m].specular_texname); //char *specular_texname; // map_Ks - rayMaterials[m].maps[MATERIAL_MAP_SPECULAR].color = (Color){ (unsigned char)(materials[m].specular[0] * 255.0f), (unsigned char)(materials[m].specular[1] * 255.0f), (unsigned char)(materials[m].specular[2] * 255.0f), 255 }; //float specular[3]; + rayMaterials[m].maps[MATERIAL_MAP_SPECULAR].color = (Color){ (unsigned char)(materials[m].specular[0]*255.0f), (unsigned char)(materials[m].specular[1]*255.0f), (unsigned char)(materials[m].specular[2] * 255.0f), 255 }; //float specular[3]; rayMaterials[m].maps[MATERIAL_MAP_SPECULAR].value = 0.0f; if (materials[m].bump_texname != NULL) rayMaterials[m].maps[MATERIAL_MAP_NORMAL].texture = LoadTexture(materials[m].bump_texname); //char *bump_texname; // map_bump, bump rayMaterials[m].maps[MATERIAL_MAP_NORMAL].color = WHITE; rayMaterials[m].maps[MATERIAL_MAP_NORMAL].value = materials[m].shininess; - rayMaterials[m].maps[MATERIAL_MAP_EMISSION].color = (Color){ (unsigned char)(materials[m].emission[0] * 255.0f), (unsigned char)(materials[m].emission[1] * 255.0f), (unsigned char)(materials[m].emission[2] * 255.0f), 255 }; //float emission[3]; + rayMaterials[m].maps[MATERIAL_MAP_EMISSION].color = (Color){ (unsigned char)(materials[m].emission[0]*255.0f), (unsigned char)(materials[m].emission[1]*255.0f), (unsigned char)(materials[m].emission[2] * 255.0f), 255 }; //float emission[3]; if (materials[m].displacement_texname != NULL) rayMaterials[m].maps[MATERIAL_MAP_HEIGHT].texture = LoadTexture(materials[m].displacement_texname); //char *displacement_texname; // disp } } -#endif +#endif // Load materials from model file Material *LoadMaterials(const char *fileName, int *materialCount) @@ -1914,8 +1916,8 @@ Material *LoadMaterials(const char *fileName, int *materialCount) int result = tinyobj_parse_mtl_file(&mats, &count, fileName); if (result != TINYOBJ_SUCCESS) TRACELOG(LOG_WARNING, "MATERIAL: [%s] Failed to parse materials file", fileName); - materials = MemAlloc(sizeof(Material) * count); - ProcessOBJMaterials(materials, mats, count); + materials = MemAlloc(count*sizeof(Material)); + ProcessMaterialsOBJ(materials, mats, count); tinyobj_materials_free(mats, count); } @@ -3951,7 +3953,7 @@ static Model LoadOBJ(const char *fileName) // Count the faces for each material int *matFaces = RL_CALLOC(model.meshCount, sizeof(int)); - // iff no materials are present use all faces on one mesh + // if no materials are present use all faces on one mesh if (materialCount > 0) { for (unsigned int fi = 0; fi < attrib.num_faces; fi++) @@ -4027,7 +4029,7 @@ static Model LoadOBJ(const char *fileName) } // Init model materials - ProcessOBJMaterials(model.materials, materials, materialCount); + ProcessMaterialsOBJ(model.materials, materials, materialCount); tinyobj_attrib_free(&attrib); tinyobj_shapes_free(meshes, meshCount); From f68bb8c7077a080cd878c3887cab1b4950b2acca Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 24 Jan 2023 17:17:25 +0100 Subject: [PATCH 058/192] REVIEWED: `rlGenTextureMipmaps()`, GPU generation only --- src/rlgl.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/rlgl.h b/src/rlgl.h index 12f62771ebcd..2f1847e0d8b0 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -3248,6 +3248,7 @@ void rlUnloadTexture(unsigned int id) // NOTE: Only supports GPU mipmap generation void rlGenTextureMipmaps(unsigned int id, int width, int height, int format, int *mipmaps) { +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) glBindTexture(GL_TEXTURE_2D, id); // Check if texture is power-of-two (POT) @@ -3256,7 +3257,6 @@ void rlGenTextureMipmaps(unsigned int id, int width, int height, int format, int if (((width > 0) && ((width & (width - 1)) == 0)) && ((height > 0) && ((height & (height - 1)) == 0))) texIsPOT = true; -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) if ((texIsPOT) || (RLGL.ExtSupported.texNPOT)) { //glHint(GL_GENERATE_MIPMAP_HINT, GL_DONT_CARE); // Hint for mipmaps generation algorithm: GL_FASTEST, GL_NICEST, GL_DONT_CARE @@ -3268,10 +3268,12 @@ void rlGenTextureMipmaps(unsigned int id, int width, int height, int format, int *mipmaps = 1 + (int)floor(log(MAX(width, height))/log(2)); TRACELOG(RL_LOG_INFO, "TEXTURE: [ID %i] Mipmaps generated automatically, total: %i", id, *mipmaps); } -#endif else TRACELOG(RL_LOG_WARNING, "TEXTURE: [ID %i] Failed to generate mipmaps", id); glBindTexture(GL_TEXTURE_2D, 0); +#else + TRACELOG(RL_LOG_WARNING, "TEXTURE: [ID %i] GPU mipmap generation not supported", id); +#endif } From 7cdffcec5274b1ea4505909bc01058091fe906c3 Mon Sep 17 00:00:00 2001 From: Dor Shapira <107134807+sDos280@users.noreply.github.com> Date: Wed, 25 Jan 2023 00:43:09 +0200 Subject: [PATCH 059/192] fixed typo (#2886) pilepine=>pipeline chosing=>choosing additioanlly=>additionally attachmment=>attachment initialize=>inititialize Binded=>Bound lattest=>latest hi @raysan5, I ran rlgl.h into some "typo checking" program(basically a JetBrains IDE), and here are all the things that the program was able to spot and fix. as my English isn't really well I would like it if you could check that I didn't make any mistakes in the typo fixing... --- src/rlgl.h | 57 +++++++++++++++++++++++++++--------------------------- 1 file changed, 28 insertions(+), 29 deletions(-) diff --git a/src/rlgl.h b/src/rlgl.h index 2f1847e0d8b0..2b982a9a1fb7 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -5,11 +5,11 @@ * An abstraction layer for multiple OpenGL versions (1.1, 2.1, 3.3 Core, 4.3 Core, ES 2.0) * that provides a pseudo-OpenGL 1.1 immediate-mode style API (rlVertex, rlTranslate, rlRotate...) * -* When chosing an OpenGL backend different than OpenGL 1.1, some internal buffer are +* When choosing an OpenGL backend different than OpenGL 1.1, some internal buffer are * initialized on rlglInit() to accumulate vertex data. * * When an internal state change is required all the stored vertex data is renderer in batch, -* additioanlly, rlDrawRenderBatchActive() could be called to force flushing of the batch. +* additionally, rlDrawRenderBatchActive() could be called to force flushing of the batch. * * Some additional resources are also loaded for convenience, here the complete list: * - Default batch (RLGL.defaultBatch): RenderBatch system to accumulate vertex data @@ -61,12 +61,11 @@ * When loading a shader, the following vertex attribute and uniform * location names are tried to be set automatically: * -* #define RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION "vertexPosition" // Binded by default to shader location: 0 -* #define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD "vertexTexCoord" // Binded by default to shader location: 1 -* #define RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL "vertexNormal" // Binded by default to shader location: 2 -* #define RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR "vertexColor" // Binded by default to shader location: 3 -* #define RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT "vertexTangent" // Binded by default to shader location: 4 -* #define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 "vertexTexCoord2" // Binded by default to shader location: 5 +* #define RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION "vertexPosition" // Bound by default to shader location: 0 +* #define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD "vertexTexCoord" // Bound by default to shader location: 1 +* #define RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL "vertexNormal" // Bound by default to shader location: 2 +* #define RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR "vertexColor" // Bound by default to shader location: 3 +* #define RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT "vertexTangent" // Bound by default to shader location: 4 * #define RL_DEFAULT_SHADER_UNIFORM_NAME_MVP "mvp" // model-view-projection matrix * #define RL_DEFAULT_SHADER_UNIFORM_NAME_VIEW "matView" // view matrix * #define RL_DEFAULT_SHADER_UNIFORM_NAME_PROJECTION "matProjection" // projection matrix @@ -505,16 +504,16 @@ typedef enum { // Framebuffer attachment type // NOTE: By default up to 8 color channels defined but it can be more typedef enum { - RL_ATTACHMENT_COLOR_CHANNEL0 = 0, // Framebuffer attachmment type: color 0 - RL_ATTACHMENT_COLOR_CHANNEL1, // Framebuffer attachmment type: color 1 - RL_ATTACHMENT_COLOR_CHANNEL2, // Framebuffer attachmment type: color 2 - RL_ATTACHMENT_COLOR_CHANNEL3, // Framebuffer attachmment type: color 3 - RL_ATTACHMENT_COLOR_CHANNEL4, // Framebuffer attachmment type: color 4 - RL_ATTACHMENT_COLOR_CHANNEL5, // Framebuffer attachmment type: color 5 - RL_ATTACHMENT_COLOR_CHANNEL6, // Framebuffer attachmment type: color 6 - RL_ATTACHMENT_COLOR_CHANNEL7, // Framebuffer attachmment type: color 7 - RL_ATTACHMENT_DEPTH = 100, // Framebuffer attachmment type: depth - RL_ATTACHMENT_STENCIL = 200, // Framebuffer attachmment type: stencil + RL_ATTACHMENT_COLOR_CHANNEL0 = 0, // Framebuffer attachment type: color 0 + RL_ATTACHMENT_COLOR_CHANNEL1, // Framebuffer attachment type: color 1 + RL_ATTACHMENT_COLOR_CHANNEL2, // Framebuffer attachment type: color 2 + RL_ATTACHMENT_COLOR_CHANNEL3, // Framebuffer attachment type: color 3 + RL_ATTACHMENT_COLOR_CHANNEL4, // Framebuffer attachment type: color 4 + RL_ATTACHMENT_COLOR_CHANNEL5, // Framebuffer attachment type: color 5 + RL_ATTACHMENT_COLOR_CHANNEL6, // Framebuffer attachment type: color 6 + RL_ATTACHMENT_COLOR_CHANNEL7, // Framebuffer attachment type: color 7 + RL_ATTACHMENT_DEPTH = 100, // Framebuffer attachment type: depth + RL_ATTACHMENT_STENCIL = 200, // Framebuffer attachment type: stencil } rlFramebufferAttachType; // Framebuffer texture attachment type @@ -545,7 +544,7 @@ extern "C" { // Prevents name mangling of functions RLAPI void rlMatrixMode(int mode); // Choose the current matrix to be transformed RLAPI void rlPushMatrix(void); // Push the current matrix to stack -RLAPI void rlPopMatrix(void); // Pop lattest inserted matrix from stack +RLAPI void rlPopMatrix(void); // Pop latest inserted matrix from stack RLAPI void rlLoadIdentity(void); // Reset current matrix to identity matrix RLAPI void rlTranslatef(float x, float y, float z); // Multiply the current matrix by a translation matrix RLAPI void rlRotatef(float angle, float x, float y, float z); // Multiply the current matrix by a rotation matrix @@ -642,7 +641,7 @@ RLAPI void rlSetBlendFactorsSeparate(int glSrcRGB, int glDstRGB, int glSrcAlpha, //------------------------------------------------------------------------------------ // rlgl initialization functions RLAPI void rlglInit(int width, int height); // Initialize rlgl (buffers, shaders, textures, states) -RLAPI void rlglClose(void); // De-inititialize rlgl (buffers, shaders, textures) +RLAPI void rlglClose(void); // De-initialize rlgl (buffers, shaders, textures) RLAPI void rlLoadExtensions(void *loader); // Load OpenGL extensions (loader function required) RLAPI int rlGetVersion(void); // Get current OpenGL version RLAPI void rlSetFramebufferWidth(int width); // Set current framebuffer width @@ -716,7 +715,7 @@ RLAPI void rlSetShader(unsigned int id, int *locs); // Compute shader management RLAPI unsigned int rlLoadComputeShaderProgram(unsigned int shaderId); // Load compute shader program -RLAPI void rlComputeShaderDispatch(unsigned int groupX, unsigned int groupY, unsigned int groupZ); // Dispatch compute shader (equivalent to *draw* for graphics pilepine) +RLAPI void rlComputeShaderDispatch(unsigned int groupX, unsigned int groupY, unsigned int groupZ); // Dispatch compute shader (equivalent to *draw* for graphics pipeline) // Shader buffer storage object management (ssbo) RLAPI unsigned int rlLoadShaderBuffer(unsigned int size, const void *data, int usageHint); // Load shader storage buffer object (SSBO) @@ -892,22 +891,22 @@ RLAPI void rlLoadDrawQuad(void); // Load and draw a quad // Default shader vertex attribute names to set location points #ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION - #define RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION "vertexPosition" // Binded by default to shader location: 0 + #define RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION "vertexPosition" // Bound by default to shader location: 0 #endif #ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD - #define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD "vertexTexCoord" // Binded by default to shader location: 1 + #define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD "vertexTexCoord" // Bound by default to shader location: 1 #endif #ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL - #define RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL "vertexNormal" // Binded by default to shader location: 2 + #define RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL "vertexNormal" // Bound by default to shader location: 2 #endif #ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR - #define RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR "vertexColor" // Binded by default to shader location: 3 + #define RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR "vertexColor" // Bound by default to shader location: 3 #endif #ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT - #define RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT "vertexTangent" // Binded by default to shader location: 4 + #define RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT "vertexTangent" // Bound by default to shader location: 4 #endif #ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 - #define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 "vertexTexCoord2" // Binded by default to shader location: 5 + #define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 "vertexTexCoord2" // Bound by default to shader location: 5 #endif #ifndef RL_DEFAULT_SHADER_UNIFORM_NAME_MVP @@ -2767,7 +2766,7 @@ void rlDrawRenderBatch(rlRenderBatch *batch) for (int i = 0, vertexOffset = 0; i < batch->drawCounter; i++) { - // Bind current draw call texture, activated as GL_TEXTURE0 and binded to sampler2D texture0 by default + // Bind current draw call texture, activated as GL_TEXTURE0 and Bound to sampler2D texture0 by default glBindTexture(GL_TEXTURE_2D, batch->draws[i].textureId); if ((batch->draws[i].mode == RL_LINES) || (batch->draws[i].mode == RL_TRIANGLES)) glDrawArrays(batch->draws[i].mode, vertexOffset, batch->draws[i].vertexCount); @@ -3856,7 +3855,7 @@ unsigned int rlLoadShaderProgram(unsigned int vShaderId, unsigned int fShaderId) glAttachShader(program, vShaderId); glAttachShader(program, fShaderId); - // NOTE: Default attribute shader locations must be binded before linking + // NOTE: Default attribute shader locations must be Bound before linking glBindAttribLocation(program, 0, RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION); glBindAttribLocation(program, 1, RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD); glBindAttribLocation(program, 2, RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL); From 4adba0d3c3df93592346a592e7a2b79d5b76bd90 Mon Sep 17 00:00:00 2001 From: Antonis Geralis <43617260+planetis-m@users.noreply.github.com> Date: Wed, 25 Jan 2023 23:25:25 +0200 Subject: [PATCH 060/192] Add wayland support (#2883) --- src/Makefile | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/Makefile b/src/Makefile index c2e227f7a464..4d9c8723b73f 100644 --- a/src/Makefile +++ b/src/Makefile @@ -409,6 +409,24 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP) ifeq ($(PLATFORM_OS), LINUX) ifeq ($(USE_WAYLAND_DISPLAY),TRUE) CFLAGS += -D_GLFW_WAYLAND + LDFLAGS += $(shell pkg-config wayland-client wayland-cursor wayland-egl xkbcommon --libs) + + WL_PROTOCOLS_DIR := $(shell pkg-config wayland-protocols --variable=pkgdatadir) + WL_CLIENT_DIR := $(shell pkg-config wayland-client --variable=pkgdatadir) + + wl_generate = \ + $(eval protocol=$(1)) \ + $(eval basename=$(2)) \ + $(shell wayland-scanner client-header $(protocol) $(RAYLIB_SRC_PATH)/$(basename).h) \ + $(shell wayland-scanner private-code $(protocol) $(RAYLIB_SRC_PATH)/$(basename)-code.h) + + $(call wl_generate, $(WL_CLIENT_DIR)/wayland.xml, wayland-client-protocol) + $(call wl_generate, $(WL_PROTOCOLS_DIR)/stable/xdg-shell/xdg-shell.xml, wayland-xdg-shell-client-protocol) + $(call wl_generate, $(WL_PROTOCOLS_DIR)/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml, wayland-xdg-decoration-client-protocol) + $(call wl_generate, $(WL_PROTOCOLS_DIR)/stable/viewporter/viewporter.xml, wayland-viewporter-client-protocol) + $(call wl_generate, $(WL_PROTOCOLS_DIR)/unstable/relative-pointer/relative-pointer-unstable-v1.xml, wayland-relative-pointer-unstable-v1-client-protocol) + $(call wl_generate, $(WL_PROTOCOLS_DIR)/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml, wayland-pointer-constraints-unstable-v1-client-protocol) + $(call wl_generate, $(WL_PROTOCOLS_DIR)/unstable/idle-inhibit/idle-inhibit-unstable-v1.xml, wayland-idle-inhibit-unstable-v1-client-protocol) endif endif endif From 63da7cdec6209b0a7b29cbdc12afe97c18be6aac Mon Sep 17 00:00:00 2001 From: Jeffery Myers Date: Wed, 25 Jan 2023 13:26:03 -0800 Subject: [PATCH 061/192] add include guards on config.h (#2888) --- src/config.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/config.h b/src/config.h index 17334b8acb61..f67ea3cb02c8 100644 --- a/src/config.h +++ b/src/config.h @@ -24,7 +24,8 @@ * 3. This notice may not be removed or altered from any source distribution. * **********************************************************************************************/ - +#ifndef CONFIG_H +#define CONFIG_H //------------------------------------------------------------------------------------ // Module selection - Some modules could be avoided // Mandatory modules: rcore, rlgl, utils @@ -236,3 +237,5 @@ // utils: Configuration values //------------------------------------------------------------------------------------ #define MAX_TRACELOG_MSG_LENGTH 128 // Max length of one trace-log message + +#endif // CONFIG_H From 01257908015f816cc6301565633cfc7d5b72f5a5 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 25 Jan 2023 23:13:17 +0100 Subject: [PATCH 062/192] Update rmodels.c --- src/rmodels.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rmodels.c b/src/rmodels.c index 91ae68a3bec6..953d016ad44e 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -4687,7 +4687,7 @@ static Image LoadImageFromCgltfImage(cgltf_image *cgltfImage, const char *texPat if (result == cgltf_result_success) { image = LoadImageFromMemory(".png", (unsigned char *)data, outSize); - MemFree((cgltf_data*)data); + MemFree(data); } } } From f088548261fd894d7b607b7896f8ff7f00629420 Mon Sep 17 00:00:00 2001 From: Kenta <106167071+Its-Kenta@users.noreply.github.com> Date: Thu, 26 Jan 2023 09:52:59 +0000 Subject: [PATCH 063/192] Update BINDINGS.md (#2889) Update Kaylib license to Zlib --- BINDINGS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BINDINGS.md b/BINDINGS.md index 6eec7bb381d4..1bc2c57acd01 100644 --- a/BINDINGS.md +++ b/BINDINGS.md @@ -33,7 +33,7 @@ Some people ported raylib to other languages in form of bindings or wrappers to | raylib-j | **4.0** | [Java](https://en.wikipedia.org/wiki/Java_(programming_language)) | Zlib | https://github.com/CreedVI/Raylib-J | | raylib.jl | **4.2** | [Julia](https://julialang.org/) | Zlib | https://github.com/irishgreencitrus/raylib.jl | | kaylib | 3.7 | [Kotlin/native](https://kotlinlang.org) | ? | https://github.com/electronstudio/kaylib | -| kaylib | **4.5-dev**| [Kotlin/native](https://kotlinlang.org) | MIT | https://codeberg.org/Kenta/Kaylib | +| kaylib | **4.5-dev**| [Kotlin/native](https://kotlinlang.org) | Zlib | https://codeberg.org/Kenta/Kaylib | | raylib-lua | **4.2** | [Lua](http://www.lua.org/) | ISC | https://github.com/TSnake41/raylib-lua | | raylua | **4.0** | [Lua](http://www.lua.org/) | MIT | https://github.com/Rabios/raylua | | nelua-raylib | 4.0 | [nelua](https://nelua.io/) | MIT | https://github.com/AKDev21/nelua-raylib | From 000cb5a47d8487a899fc7c55b3aeb6fdf328a884 Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 26 Jan 2023 23:18:06 +0100 Subject: [PATCH 064/192] Update CHANGELOG --- CHANGELOG | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index f1207ae5ce76..5900ff80358d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -3,6 +3,146 @@ changelog Current Release: raylib 4.2.0 (11 August 2022) +------------------------------------------------------------------------- +Release: raylib 4.5 (xx February 2022?) -WIP- +------------------------------------------------------------------------- +KEY CHANGES: + - ADDED: M3D model format support with animations + - ADDED: GLTF animation support + - rlgl redesign to avoid render batch triangles limits pre-check: rlCheckRenderBatchLimit() + - rshapes simplification to minimize the requirement of rlgl functionality, now it only depends on 6 functions + - rl_gputex.h: Compressed textures loading, required by rtextures module, has been moved to a separate self-contained library + - raygui 3.5: New version of the immediate-mode gui system for tools development with raylib + + +Detailed changes: + +[core] ADDED: RAYLIB_VERSION_* values to raylib.h (#2856) by @RobLoach +[core] ADDED: Basic gamepad support for Android (#2709) by @deniska +[core] ADDED: Support CAPS/NUM lock keys registering if locked +[core] ADDED: _GNU_SOURCE define on Linux (#2729) +[core] `WARNING`: RENAMED: Exported raylib version symbol to raylib_version #2671 +[core] REMOVED: Touch points on touch up events on Android (#2711) by @deniska +[core] REVIEWED: Window position setup on InitWindow() (#2732) by @RandomErrorMessage +[core] REVIEWED: Touchscreen input related functions on Android (#2702) by @deniska +[core] REVIEWED: Viewport scaling on Android after context rebind (#2703) by @deniska +[core] REVIEWED: ScanDirectoryFilesRecursively() (#2704) +[core] REVIEWED: Gamepad mappings with latest gamecontrollerdb (#2725) +[core] REVIEWED: Monitor order check on app initialization +[core] REVIEWED: Application monitor when opening (#2728, #2731) by @RandomErrorMessage +[core] REVIEWED: Gestures module to use GetTime() if available (#2733) by @RobLoach +[core] REVIEWED: Resolve GLFW3 some symbols re-definition of windows.h in glfw3native (#2643) by @daipom +[core] REVIEWED: OpenURL(), string buffer too short sometimes +[core] REVIEWED: GetRandomValue() range limit warning (#2800) by @Pere001 +[core] REVIEWED: UnloadDirectoryFiles() +[core] REVIEWED: GetKeyPressed(), out of range issue (#2814) by @daipom +[core] REVIEWED: GetTime(), renamed variable 'time' to 'nanoSeconds' (#2816) by @jtainer +[core] REVIEWED: LoadShaderFromMemory(), issue with shader linkage +[core] REVIEWED: Avoid possible gamepad index as -1 (#2839) +[core] REVIEWED: SetShaderValue*(), avoid setup uniforms for invalid locations +[core] REVIEWED: GetClipboardText() on PLATFORM_WEB, permissions issues +[core] REVIEWED: Initial window position for display-sized fullscreen (#2742) by @daipom +[core] REVIEWED: Sticky touches input (#2857) by @ImazighenGhost +[rlgl] ADDED: OpenGL ES 2.0 support on PLATFORM_DESKTOP (#2840) by @wtnbgo +[rlgl] ADDED: Separate blending modes for color and alpha, BLEND_CUSTOM_SEPARATE (#2741) +[rlgl] ADDED: rlSetBlendFactorsSeparate and custom blend mode modification checks (#2741) by @pure01fx +[rlgl] ADDED: RL_TEXTURE_MIPMAP_BIAS_RATIO support to `rlTextureParameters()` for OpenGL 3.3 #2674 +[rlgl] ADDED: rlCubemapParameters() (#2862) by @GithubPrankster +[rlgl] ADDED: rlSetCullFace() (#2797) by @jtainer +[rlgl] REMOVED: Mipmaps software generation for OpenGL 1.1 +[rlgl] REVIEWED: Check for extensions before enabling them (#2706) by @Not-Nik +[rlgl] REVIEWED: SSBO usage to avoid long long data types +[rlgl] REVIEWED: Enable DXT compression on __APPLE__ targets (#2694) by @Not-Nik +[rlgl] REVIEWED: enums exposed and description comments +[rlgl] REVIEWED: rlBindImageTexture(), correct data types (#2808) by @planetis-m +[rlgl] REVIEWED: rlMultMatrixf(), use const pointer (#2807) by @planetis-m +[rlgl] REVIEWED: Expose OpenGL blending mode factors and functions/equations +[rlgl] REVIEWED: rLoadTextureDepth(), issue with depth textures on WebGL (#2824) +[raymath] REVIEWED: Vector2Angle() (#2829, #2832) by @AlxHnr and @planetis-m +[shapes] ADDED: CheckCollisionPointPoly() (#2685) by @acejacek +[shapes] REVIEWED: DrawPixel*(), use RL_QUADS/RL_TRIANGLES (#2750) by @hatkidchan +[shapes] REVIEWED: DrawLineBezier*(), fix bezier line breaking (#2735, #2767) by @nobytesgiven +[textures] ADDED: ColorBrightness() +[textures] ADDED: ColorTint() +[textures] ADDED: ColorContrast() +[textures] ADDED: Support for PNM images (.ppm, .pgm) +[textures] ADDED: GenImagePerlinNoise() +[textures] ADDED: GenImageText(), generate grayscale image from text byte data +[textures] ADDED: ImageDrawCircleLines(), ImageDrawCircleLinesV() (#2713) by @RobLoach +[textures] ADDED: ImageBlurGaussian() (#2770) by @nobytesgiven +[textures] REVIEWED: Image fileformat support: PIC, PNM +[textures] REVIEWED: ImageTextEx() and ImageDrawTextEx() scaling (#2756) by @hatkidchan +[textures] `WARNING`: REMOVED: DrawTextureQuad() +[textures] `WARNING`: REMOVED: DrawTexturePoly(), function moved to example: `textures_polygon` +[textures] `WARNING`: REMOVED: DrawTextureTiled(),function implementation moved to the textures_tiled.c +[text] ADDED: GetCodepointPrevious() +[text] ADDED: UnloadUTF8(), aligned with LoadUTF8() +[text] `WARNING`: RENAMED: TextCodepointsToUTF8() to LoadUTF8() +[text] `WARNING`: RENAMED: GetCodepoint() -> GetCodepointNext() +[text] REDESIGNED: GetCodepointNext() +[text] REVIEWED text_codepoints_loading.c +[text] REVIEWED: MeasureTextEx(), avoid crash on bad data +[text] REVIEWED: UnloadFontData(), avoid crash on invalid font data +[models] ADDED: Support M3D model file format (meshes and materials) (#2648) by @bztsrc +[models] ADDED: Support for M3D animations (#2648) by @bztsrc +[models] ADDED: GLTF animation support (#2844) by @charles-l +[models] ADDED: DrawCapsule() and DrawCapsuleWires() (#2761) by @IanBand +[models] ADDED: LoadMaterials(), MTL files loading, same code as OBJ loader (#2872) by @JeffM2501 +[models] REVIEWED: GenMeshHeightmap() (#2716) +[models] REVIEWED: LoadIQM() (#2676) +[models] REVIEWED: Simplify .vox signature check (#2752) by @CrezyDud +[models] REVIEWED: LoadIQM(), support bone names loading if available (#2882) by @PencilAmazing +[models] `WARNING`: REMOVED: DrawCubeTexture(), DrawCubeTextureRec(), functions moved to new example: `models_draw_cube_texture` +[audio] REVIEWED: Clear PCM buffer state when closing audio device (#2736) by @veins1 +[audio] REVIEWED: Android backend selected (#2118, #2875) by @planetis-m +[multi] REVIEWED: Multiple code/comment typos by @sDos280 +[multi] REVIEWED: Use TRACELOG() macro instead of TraceLog() in internal modules (#2881) by @RobLoach +[examples] ADDED: textures_textured_curve (#2821) by @JeffM2501 +[examples] ADDED: shaders_write_depth (#2836) by @BugraAlptekinSari +[examples] RENAMED: Several shaders for naming consistency (#2707) +[examples] RENAMED: lighting_instanced.fs to lighting_instancing.fs (glsl100) (#2805) by @gtrxAC +[examples] REVIEWED: core_custom_logging.c (#2692) by @hartmannathan +[examples] REVIEWED: core_camera_2d_platformer (#2687) by @skylar779 +[examples] REVIEWED: core_custom_frame_control +[examples] REVIEWED: text_rectangle_bounds (#2746) by @SzieberthAdam +[examples] REVIEWED: textures_image_processing, added gaussian blurring (#2775) by @nobytesgiven +[examples] REVIEWED: models_billboard, highlighting rotation and draw order (#2779) by @nobytesgiven +[examples] REVIEWED: core_loading_thread, join thread on completion (#2845) by @planetis-m +[examples] REVIEWED: models_loading_gltf +[examples] REVIEWED: Shader lighting.fs for GLSL120 (#2651) +[parser] REVIEWED: raylib-parser Makefile (#2765) by @Peter0x44 +[build] ADDED: Packaging for distros with deb-based and rpm-based packages (#2877) by @KOLANICH +[build] ADDED: Linkage library -latomic on Linux (only required for ARM32) +[build] ADDED: Required frameworks on macOS (#2793) by @SpexGuy +[build] REVIEWED: CMake project template to easily target raylib version (#2700) by @RobLoach +[build] REVIEWED: PATH for PLATFORM_WEB target (#2647) by @futureapricot +[build] REVIEWED: build.zig to let user decide how to set build mode and linker fixes by @InKryption +[build] REVIEWED: Deprecation error on Android API higher than 23 (#2778) by @anggape +[build] REVIEWED: Android x86 Architecture name (#2783) by @IsaacTCB +[build] REVIEWED: examples/build.zig for the latest Zig version (#2786) by @RomanAkberov +[utils] REVIEWED: ExportDataAsCode() data types (#2787) by @RGDTAB +[build] REVIEWED: Makefile emscripten path (#2785) by @Julianiolo +[build] REVIEWED: Several compilation warnings (for strict rules) +[build] REVIEWED: All github workflows using deprecated actions +[build] REVIEWED: CMake when compiling for web (#2820) by @object71 +[build] REVIEWED: Avoid MSVC warnings in raylib project (#2871) by @JeffM2501 +[build] REVIEWED: Paths in .bat files to build examples (#2870) by @masoudd +[build] REVIEWED: CMake, use GLVND for old cmake versions (#2826) by @simendsjo +[build] REVIEWED: Makefile, multiple tweaks +[build] REVIEWED: CI action: linux_examples.yml +[build] REVIEWED: CI action: cmake.yml +[bindings] ADDED: h-raylib (Haskell) by @Anut-py +[bindings] ADDED: raylib-c3 (C3) by @Its-Kenta +[bindings] ADDED: raylib-umka (Umka) by @RobLoach +[bindings] ADDED: chez-raylib (Chez Scheme) by @Yunoinsky +[bindings] ADDED: raylib-python-ctypes (Python) by @sDos280 +[bindings] ADDED: claylib (Common Lisp) by @shelvick +[bindings] ADDED: raylib-vapi (Vala) by @lxmcf +[bindings] ADDED: TurboRaylib (Object Pascal) by @turborium +[bindings] ADDED: Kaylib (Kotlin/Native) by @Its-Kenta +[bindings] ADDED: Raylib-Nelua (Nelua) by @Its-Kenta +[misc] REVIEWED: Update some external libraries to latest versions + ------------------------------------------------------------------------- Release: raylib 4.2 (11 August 2022) ------------------------------------------------------------------------- From af66e751db58b0576eb50865aac0842f6df153ea Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 26 Jan 2023 23:20:14 +0100 Subject: [PATCH 065/192] Update CHANGELOG --- CHANGELOG | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 5900ff80358d..602e9a4e003a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -4,7 +4,7 @@ changelog Current Release: raylib 4.2.0 (11 August 2022) ------------------------------------------------------------------------- -Release: raylib 4.5 (xx February 2022?) -WIP- +Release: raylib 4.5 (xx February 2023) -WIP- ------------------------------------------------------------------------- KEY CHANGES: - ADDED: M3D model format support with animations From 81ca2f0bf36e59623084d583f3e26c3709b96a27 Mon Sep 17 00:00:00 2001 From: Jeffery Myers Date: Fri, 27 Jan 2023 10:20:42 -0800 Subject: [PATCH 066/192] Fix warnings and bad project settings for 4.5 release (#2894) --- examples/audio/audio_raw_stream.c | 2 +- examples/core/core_custom_frame_control.c | 6 +- examples/core/core_drop_files.c | 2 +- examples/shaders/shaders_hot_reloading.c | 2 +- examples/shapes/raygui.h | 8 +-- examples/text/text_draw_3d.c | 6 +- examples/textures/textures_fog_of_war.c | 22 +++---- examples/textures/textures_polygon.c | 2 +- .../examples/rlgl_compute_shaders.vcxproj | 63 +++++++++---------- .../VS2022/examples/rlgl_standalone.vcxproj | 16 ++--- .../examples/shaders_hot_reloading.vcxproj | 16 ++--- .../shapes_draw_circle_sector.vcxproj | 16 ++--- .../shapes_draw_rectangle_rounded.vcxproj | 16 ++--- .../VS2022/examples/shapes_draw_ring.vcxproj | 16 ++--- projects/VS2022/examples/text_draw_3d.vcxproj | 16 ++--- .../examples/textures_fog_of_war.vcxproj | 16 ++--- .../VS2022/examples/textures_polygon.vcxproj | 16 ++--- src/rmodels.c | 2 +- 18 files changed, 120 insertions(+), 123 deletions(-) diff --git a/examples/audio/audio_raw_stream.c b/examples/audio/audio_raw_stream.c index 142450e83d76..6befa765a7d3 100644 --- a/examples/audio/audio_raw_stream.c +++ b/examples/audio/audio_raw_stream.c @@ -43,7 +43,7 @@ void AudioInputCallback(void *buffer, unsigned int frames) float incr = audioFrequency/44100.0f; short *d = (short *)buffer; - for (int i = 0; i < frames; i++) + for (unsigned int i = 0; i < frames; i++) { d[i] = (short)(32000.0f*sinf(2*PI*sineIdx)); sineIdx += incr; diff --git a/examples/core/core_custom_frame_control.c b/examples/core/core_custom_frame_control.c index ed0dbc661cd0..9bfd25d3eb97 100644 --- a/examples/core/core_custom_frame_control.c +++ b/examples/core/core_custom_frame_control.c @@ -86,8 +86,8 @@ int main(void) DrawCircle((int)position, GetScreenHeight()/2 - 25, 50, RED); - DrawText(TextFormat("%03.0f ms", timeCounter*1000.0f), position - 40, GetScreenHeight()/2 - 100, 20, MAROON); - DrawText(TextFormat("PosX: %03.0f", position), position - 50, GetScreenHeight()/2 + 40, 20, BLACK); + DrawText(TextFormat("%03.0f ms", timeCounter*1000.0f), (int)position - 40, GetScreenHeight()/2 - 100, 20, MAROON); + DrawText(TextFormat("PosX: %03.0f", position), (int)position - 50, GetScreenHeight()/2 + 40, 20, BLACK); DrawText("Circle is moving at a constant 200 pixels/sec,\nindependently of the frame rate.", 10, 10, 20, DARKGRAY); DrawText("PRESS SPACE to PAUSE MOVEMENT", 10, GetScreenHeight() - 60, 20, GRAY); @@ -115,7 +115,7 @@ int main(void) deltaTime = (float)(currentTime - previousTime); } } - else deltaTime = updateDrawTime; // Framerate could be variable + else deltaTime = (float)updateDrawTime; // Framerate could be variable previousTime = currentTime; //---------------------------------------------------------------------------------- diff --git a/examples/core/core_drop_files.c b/examples/core/core_drop_files.c index 9ebe0f957d2d..cfe03e1968bc 100644 --- a/examples/core/core_drop_files.c +++ b/examples/core/core_drop_files.c @@ -58,7 +58,7 @@ int main(void) { DrawText("Dropped files:", 100, 40, 20, DARKGRAY); - for (int i = 0; i < droppedFiles.count; i++) + for (unsigned int i = 0; i < droppedFiles.count; i++) { if (i%2 == 0) DrawRectangle(0, 85 + 40*i, screenWidth, 40, Fade(LIGHTGRAY, 0.5f)); else DrawRectangle(0, 85 + 40*i, screenWidth, 40, Fade(LIGHTGRAY, 0.3f)); diff --git a/examples/shaders/shaders_hot_reloading.c b/examples/shaders/shaders_hot_reloading.c index e58c45f3c1c0..395d44cfe587 100644 --- a/examples/shaders/shaders_hot_reloading.c +++ b/examples/shaders/shaders_hot_reloading.c @@ -38,7 +38,7 @@ int main(void) InitWindow(screenWidth, screenHeight, "raylib [shaders] example - hot reloading"); const char *fragShaderFileName = "resources/shaders/glsl%i/reload.fs"; - long fragShaderFileModTime = GetFileModTime(TextFormat(fragShaderFileName, GLSL_VERSION)); + time_t fragShaderFileModTime = GetFileModTime(TextFormat(fragShaderFileName, GLSL_VERSION)); // Load raymarching shader // NOTE: Defining 0 (NULL) for vertex shader forces usage of internal default vertex shader diff --git a/examples/shapes/raygui.h b/examples/shapes/raygui.h index 3e7dea442fe9..112370aca795 100644 --- a/examples/shapes/raygui.h +++ b/examples/shapes/raygui.h @@ -1511,7 +1511,7 @@ Rectangle GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, 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 : -1; + float verticalMin = hasVerticalScrollBar? 0 : -1.0f; float verticalMax = hasVerticalScrollBar? content.height - bounds.height + (float)horizontalScrollBarWidth + (float)GuiGetStyle(DEFAULT, BORDER_WIDTH) : (float)-GuiGetStyle(DEFAULT, BORDER_WIDTH); // Update control @@ -3205,8 +3205,8 @@ Vector2 GuiGrid(Rectangle bounds, const char *text, float spacing, int subdivs) if (CheckCollisionPointRec(mousePoint, bounds)) { // NOTE: Cell values must be rounded to int - currentCell.x = (int)((mousePoint.x - bounds.x)/spacing); - currentCell.y = (int)((mousePoint.y - bounds.y)/spacing); + currentCell.x = (float)((mousePoint.x - bounds.x)/spacing); + currentCell.y = (float)((mousePoint.y - bounds.y)/spacing); } } //-------------------------------------------------------------------- @@ -3842,7 +3842,7 @@ static void GuiDrawText(const char *text, Rectangle bounds, int alignment, Color // NOTE: We get text size after icon has been processed // TODO: REVIEW: We consider text size in case of line breaks! -> MeasureTextEx() depends on raylib! - Vector2 textSize = MeasureTextEx(GuiGetFont(), text, GuiGetStyle(DEFAULT, TEXT_SIZE), GuiGetStyle(DEFAULT, TEXT_SPACING)); + Vector2 textSize = MeasureTextEx(GuiGetFont(), text, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), (float)GuiGetStyle(DEFAULT, TEXT_SPACING)); //int textWidth = GetTextWidth(text); //int textHeight = GuiGetStyle(DEFAULT, TEXT_SIZE); diff --git a/examples/text/text_draw_3d.c b/examples/text/text_draw_3d.c index 0711d54cde6f..127eb7c6a278 100644 --- a/examples/text/text_draw_3d.c +++ b/examples/text/text_draw_3d.c @@ -152,13 +152,13 @@ int main(void) if (IsFileExtension(droppedFiles.paths[0], ".ttf")) { UnloadFont(font); - font = LoadFontEx(droppedFiles.paths[0], fontSize, 0, 0); + font = LoadFontEx(droppedFiles.paths[0], (int)fontSize, 0, 0); } else if (IsFileExtension(droppedFiles.paths[0], ".fnt")) { UnloadFont(font); font = LoadFont(droppedFiles.paths[0]); - fontSize = font.baseSize; + fontSize = (float)font.baseSize; } UnloadDroppedFiles(droppedFiles); // Unload filepaths from memory @@ -742,7 +742,7 @@ static Vector3 MeasureTextWave3D(Font font, const char* text, float fontSize, fl static Color GenerateRandomColor(float s, float v) { const float Phi = 0.618033988749895f; // Golden ratio conjugate - float h = GetRandomValue(0, 360); + float h = (float)GetRandomValue(0, 360); h = fmodf((h + h*Phi), 360.0f); return ColorFromHSV(h, s, v); } diff --git a/examples/textures/textures_fog_of_war.c b/examples/textures/textures_fog_of_war.c index 7c3d666424ad..433f364a651b 100644 --- a/examples/textures/textures_fog_of_war.c +++ b/examples/textures/textures_fog_of_war.c @@ -51,7 +51,7 @@ int main(void) // Load map tiles (generating 2 random tile ids for testing) // NOTE: Map tile ids should be probably loaded from an external map file - for (int i = 0; i < map.tilesY*map.tilesX; i++) map.tileIds[i] = GetRandomValue(0, 1); + for (unsigned int i = 0; i < map.tilesY*map.tilesX; i++) map.tileIds[i] = GetRandomValue(0, 1); // Player position on the screen (pixel coordinates, not tile coordinates) Vector2 playerPosition = { 180, 130 }; @@ -80,12 +80,12 @@ int main(void) // Check player position to avoid moving outside tilemap limits if (playerPosition.x < 0) playerPosition.x = 0; - else if ((playerPosition.x + PLAYER_SIZE) > (map.tilesX*MAP_TILE_SIZE)) playerPosition.x = map.tilesX*MAP_TILE_SIZE - PLAYER_SIZE; + else if ((playerPosition.x + PLAYER_SIZE) > (map.tilesX*MAP_TILE_SIZE)) playerPosition.x = (float)map.tilesX*MAP_TILE_SIZE - PLAYER_SIZE; if (playerPosition.y < 0) playerPosition.y = 0; - else if ((playerPosition.y + PLAYER_SIZE) > (map.tilesY*MAP_TILE_SIZE)) playerPosition.y = map.tilesY*MAP_TILE_SIZE - PLAYER_SIZE; + else if ((playerPosition.y + PLAYER_SIZE) > (map.tilesY*MAP_TILE_SIZE)) playerPosition.y = (float)map.tilesY*MAP_TILE_SIZE - PLAYER_SIZE; // Previous visited tiles are set to partial fog - for (int i = 0; i < map.tilesX*map.tilesY; i++) if (map.tileFog[i] == 1) map.tileFog[i] = 2; + for (unsigned int i = 0; i < map.tilesX*map.tilesY; i++) if (map.tileFog[i] == 1) map.tileFog[i] = 2; // Get current tile position from player pixel position playerTileX = (int)((playerPosition.x + MAP_TILE_SIZE/2)/MAP_TILE_SIZE); @@ -95,7 +95,7 @@ int main(void) // NOTE: We check tilemap limits to avoid processing tiles out-of-array-bounds (it could crash program) for (int y = (playerTileY - PLAYER_TILE_VISIBILITY); y < (playerTileY + PLAYER_TILE_VISIBILITY); y++) for (int x = (playerTileX - PLAYER_TILE_VISIBILITY); x < (playerTileX + PLAYER_TILE_VISIBILITY); x++) - if ((x >= 0) && (x < map.tilesX) && (y >= 0) && (y < map.tilesY)) map.tileFog[y*map.tilesX + x] = 1; + if ((x >= 0) && (x < (int)map.tilesX) && (y >= 0) && (y < (int)map.tilesY)) map.tileFog[y*map.tilesX + x] = 1; //---------------------------------------------------------------------------------- // Draw @@ -103,8 +103,8 @@ int main(void) // Draw fog of war to a small render texture for automatic smoothing on scaling BeginTextureMode(fogOfWar); ClearBackground(BLANK); - for (int y = 0; y < map.tilesY; y++) - for (int x = 0; x < map.tilesX; x++) + for (unsigned int y = 0; y < map.tilesY; y++) + for (unsigned int x = 0; x < map.tilesX; x++) if (map.tileFog[y*map.tilesX + x] == 0) DrawRectangle(x, y, 1, 1, BLACK); else if (map.tileFog[y*map.tilesX + x] == 2) DrawRectangle(x, y, 1, 1, Fade(BLACK, 0.8f)); EndTextureMode(); @@ -113,9 +113,9 @@ int main(void) ClearBackground(RAYWHITE); - for (int y = 0; y < map.tilesY; y++) + for (unsigned int y = 0; y < map.tilesY; y++) { - for (int x = 0; x < map.tilesX; x++) + for (unsigned int x = 0; x < map.tilesX; x++) { // Draw tiles from id (and tile borders) DrawRectangle(x*MAP_TILE_SIZE, y*MAP_TILE_SIZE, MAP_TILE_SIZE, MAP_TILE_SIZE, @@ -129,8 +129,8 @@ int main(void) // Draw fog of war (scaled to full map, bilinear filtering) - DrawTexturePro(fogOfWar.texture, (Rectangle){ 0, 0, fogOfWar.texture.width, -fogOfWar.texture.height }, - (Rectangle){ 0, 0, map.tilesX*MAP_TILE_SIZE, map.tilesY*MAP_TILE_SIZE }, + DrawTexturePro(fogOfWar.texture, (Rectangle){ 0, 0, (float)fogOfWar.texture.width, (float)-fogOfWar.texture.height }, + (Rectangle){ 0, 0, (float)map.tilesX*MAP_TILE_SIZE, (float)map.tilesY*MAP_TILE_SIZE }, (Vector2){ 0, 0 }, 0.0f, WHITE); // Draw player current tile diff --git a/examples/textures/textures_polygon.c b/examples/textures/textures_polygon.c index 18fc952490fc..cf59af9798a9 100644 --- a/examples/textures/textures_polygon.c +++ b/examples/textures/textures_polygon.c @@ -91,7 +91,7 @@ int main(void) DrawText("textured polygon", 20, 20, 20, DARKGRAY); - DrawTexturePoly(texture, (Vector2){ GetScreenWidth()/2, GetScreenHeight()/2 }, + DrawTexturePoly(texture, (Vector2){ GetScreenWidth()/2.0f, GetScreenHeight()/2.0f }, positions, texcoords, MAX_POINTS, WHITE); EndDrawing(); diff --git a/projects/VS2022/examples/rlgl_compute_shaders.vcxproj b/projects/VS2022/examples/rlgl_compute_shaders.vcxproj index 14fe2f4ee4c6..2e514f3d4516 100644 --- a/projects/VS2022/examples/rlgl_compute_shaders.vcxproj +++ b/projects/VS2022/examples/rlgl_compute_shaders.vcxproj @@ -202,16 +202,15 @@ Level3 Disabled - WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) CompileAsC $(SolutionDir)..\..\src;$(SolutionDir)..\..\examples\others\external\include;%(AdditionalIncludeDirectories) Console true - - - opengl32.lib;kernel32.lib;user32.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)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) @@ -220,7 +219,7 @@ Level3 Disabled - WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) CompileAsC $(SolutionDir)..\..\src;$(SolutionDir)..\..\examples\others\external\include;%(AdditionalIncludeDirectories) /FS %(AdditionalOptions) @@ -228,9 +227,8 @@ Console true - - - opengl32.lib;kernel32.lib;user32.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)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) @@ -239,16 +237,15 @@ Level3 Disabled - WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) CompileAsC $(SolutionDir)..\..\src;$(SolutionDir)..\..\examples\others\external\include;%(AdditionalIncludeDirectories) Console true - - - opengl32.lib;kernel32.lib;user32.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)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.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)" @@ -261,16 +258,15 @@ Level3 Disabled - WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) CompileAsC $(SolutionDir)..\..\src;$(SolutionDir)..\..\examples\others\external\include;%(AdditionalIncludeDirectories) Console true - - - opengl32.lib;kernel32.lib;user32.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)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.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)" @@ -285,7 +281,7 @@ MaxSpeed true true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP $(SolutionDir)..\..\src;$(SolutionDir)..\..\examples\others\external\include;%(AdditionalIncludeDirectories) CompileAsC true @@ -295,9 +291,8 @@ true true true - opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - - + raylib.lib;opengl32.lib;kernel32.lib;user32.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)\ @@ -308,7 +303,7 @@ MaxSpeed true true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP $(SolutionDir)..\..\src;$(SolutionDir)..\..\examples\others\external\include;%(AdditionalIncludeDirectories) CompileAsC true @@ -318,9 +313,8 @@ true true true - opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - - + raylib.lib;opengl32.lib;kernel32.lib;user32.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)\ @@ -331,7 +325,7 @@ MaxSpeed true true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP $(SolutionDir)..\..\src;$(SolutionDir)..\..\examples\others\external\include;%(AdditionalIncludeDirectories) CompileAsC true @@ -341,9 +335,8 @@ true true true - opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - - + raylib.lib;opengl32.lib;kernel32.lib;user32.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)" @@ -360,7 +353,7 @@ MaxSpeed true true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP $(SolutionDir)..\..\src;$(SolutionDir)..\..\examples\others\external\include;%(AdditionalIncludeDirectories) CompileAsC true @@ -370,9 +363,8 @@ true true true - opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - - + raylib.lib;opengl32.lib;kernel32.lib;user32.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)" @@ -382,9 +374,14 @@ - + + + + {e89d61ac-55de-4482-afd4-df7242ebc859} + + diff --git a/projects/VS2022/examples/rlgl_standalone.vcxproj b/projects/VS2022/examples/rlgl_standalone.vcxproj index 466740431eb2..707a73a919f3 100644 --- a/projects/VS2022/examples/rlgl_standalone.vcxproj +++ b/projects/VS2022/examples/rlgl_standalone.vcxproj @@ -202,7 +202,7 @@ Level3 Disabled - WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) CompileAsC $(SolutionDir)..\..\src;$(SolutionDir)..\..\examples\others\external\include;%(AdditionalIncludeDirectories) @@ -220,7 +220,7 @@ Level3 Disabled - WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) CompileAsC $(SolutionDir)..\..\src;$(SolutionDir)..\..\examples\others\external\include;%(AdditionalIncludeDirectories) /FS %(AdditionalOptions) @@ -239,7 +239,7 @@ Level3 Disabled - WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) CompileAsC $(SolutionDir)..\..\src;$(SolutionDir)..\..\examples\others\external\include;%(AdditionalIncludeDirectories) @@ -261,7 +261,7 @@ Level3 Disabled - WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) CompileAsC $(SolutionDir)..\..\src;$(SolutionDir)..\..\examples\others\external\include;%(AdditionalIncludeDirectories) @@ -285,7 +285,7 @@ MaxSpeed true true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP $(SolutionDir)..\..\src;$(SolutionDir)..\..\examples\others\external\include;%(AdditionalIncludeDirectories) CompileAsC true @@ -308,7 +308,7 @@ MaxSpeed true true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP $(SolutionDir)..\..\src;$(SolutionDir)..\..\examples\others\external\include;%(AdditionalIncludeDirectories) CompileAsC true @@ -331,7 +331,7 @@ MaxSpeed true true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP $(SolutionDir)..\..\src;$(SolutionDir)..\..\examples\others\external\include;%(AdditionalIncludeDirectories) CompileAsC true @@ -360,7 +360,7 @@ MaxSpeed true true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP $(SolutionDir)..\..\src;$(SolutionDir)..\..\examples\others\external\include;%(AdditionalIncludeDirectories) CompileAsC true diff --git a/projects/VS2022/examples/shaders_hot_reloading.vcxproj b/projects/VS2022/examples/shaders_hot_reloading.vcxproj index e10ec74e57aa..900246dafe92 100644 --- a/projects/VS2022/examples/shaders_hot_reloading.vcxproj +++ b/projects/VS2022/examples/shaders_hot_reloading.vcxproj @@ -202,7 +202,7 @@ Level3 Disabled - WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) CompileAsC $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) @@ -219,7 +219,7 @@ Level3 Disabled - WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) CompileAsC $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) /FS %(AdditionalOptions) @@ -237,7 +237,7 @@ Level3 Disabled - WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) CompileAsC $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) @@ -258,7 +258,7 @@ Level3 Disabled - WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) CompileAsC $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) @@ -281,7 +281,7 @@ MaxSpeed true true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) CompileAsC true @@ -303,7 +303,7 @@ MaxSpeed true true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) CompileAsC true @@ -325,7 +325,7 @@ MaxSpeed true true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) CompileAsC true @@ -353,7 +353,7 @@ MaxSpeed true true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) CompileAsC true diff --git a/projects/VS2022/examples/shapes_draw_circle_sector.vcxproj b/projects/VS2022/examples/shapes_draw_circle_sector.vcxproj index be37881fc071..df61cdb1e1e7 100644 --- a/projects/VS2022/examples/shapes_draw_circle_sector.vcxproj +++ b/projects/VS2022/examples/shapes_draw_circle_sector.vcxproj @@ -202,7 +202,7 @@ Level3 Disabled - WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) CompileAsC $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) @@ -219,7 +219,7 @@ Level3 Disabled - WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) CompileAsC $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) /FS %(AdditionalOptions) @@ -237,7 +237,7 @@ Level3 Disabled - WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) CompileAsC $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) @@ -258,7 +258,7 @@ Level3 Disabled - WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) CompileAsC $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) @@ -281,7 +281,7 @@ MaxSpeed true true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) CompileAsC true @@ -303,7 +303,7 @@ MaxSpeed true true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) CompileAsC true @@ -325,7 +325,7 @@ MaxSpeed true true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) CompileAsC true @@ -353,7 +353,7 @@ MaxSpeed true true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) CompileAsC true diff --git a/projects/VS2022/examples/shapes_draw_rectangle_rounded.vcxproj b/projects/VS2022/examples/shapes_draw_rectangle_rounded.vcxproj index af8ce6fd58db..207d38f542aa 100644 --- a/projects/VS2022/examples/shapes_draw_rectangle_rounded.vcxproj +++ b/projects/VS2022/examples/shapes_draw_rectangle_rounded.vcxproj @@ -202,7 +202,7 @@ Level3 Disabled - WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) CompileAsC $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) @@ -219,7 +219,7 @@ Level3 Disabled - WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) CompileAsC $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) /FS %(AdditionalOptions) @@ -237,7 +237,7 @@ Level3 Disabled - WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) CompileAsC $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) @@ -258,7 +258,7 @@ Level3 Disabled - WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) CompileAsC $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) @@ -281,7 +281,7 @@ MaxSpeed true true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) CompileAsC true @@ -303,7 +303,7 @@ MaxSpeed true true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) CompileAsC true @@ -325,7 +325,7 @@ MaxSpeed true true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) CompileAsC true @@ -353,7 +353,7 @@ MaxSpeed true true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) CompileAsC true diff --git a/projects/VS2022/examples/shapes_draw_ring.vcxproj b/projects/VS2022/examples/shapes_draw_ring.vcxproj index 1488c9522eed..490e8e2c8580 100644 --- a/projects/VS2022/examples/shapes_draw_ring.vcxproj +++ b/projects/VS2022/examples/shapes_draw_ring.vcxproj @@ -202,7 +202,7 @@ Level3 Disabled - WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) CompileAsC $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) @@ -219,7 +219,7 @@ Level3 Disabled - WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) CompileAsC $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) /FS %(AdditionalOptions) @@ -237,7 +237,7 @@ Level3 Disabled - WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) CompileAsC $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) @@ -258,7 +258,7 @@ Level3 Disabled - WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) CompileAsC $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) @@ -281,7 +281,7 @@ MaxSpeed true true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) CompileAsC true @@ -303,7 +303,7 @@ MaxSpeed true true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) CompileAsC true @@ -325,7 +325,7 @@ MaxSpeed true true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) CompileAsC true @@ -353,7 +353,7 @@ MaxSpeed true true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) CompileAsC true diff --git a/projects/VS2022/examples/text_draw_3d.vcxproj b/projects/VS2022/examples/text_draw_3d.vcxproj index c078bb010b6b..0ea41840c88e 100644 --- a/projects/VS2022/examples/text_draw_3d.vcxproj +++ b/projects/VS2022/examples/text_draw_3d.vcxproj @@ -202,7 +202,7 @@ Level3 Disabled - WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) CompileAsC $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) @@ -219,7 +219,7 @@ Level3 Disabled - WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) CompileAsC $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) /FS %(AdditionalOptions) @@ -237,7 +237,7 @@ Level3 Disabled - WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) CompileAsC $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) @@ -258,7 +258,7 @@ Level3 Disabled - WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) CompileAsC $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) @@ -281,7 +281,7 @@ MaxSpeed true true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) CompileAsC true @@ -303,7 +303,7 @@ MaxSpeed true true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) CompileAsC true @@ -325,7 +325,7 @@ MaxSpeed true true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) CompileAsC true @@ -353,7 +353,7 @@ MaxSpeed true true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) CompileAsC true diff --git a/projects/VS2022/examples/textures_fog_of_war.vcxproj b/projects/VS2022/examples/textures_fog_of_war.vcxproj index aa93c01a8f9c..344a38cc5248 100644 --- a/projects/VS2022/examples/textures_fog_of_war.vcxproj +++ b/projects/VS2022/examples/textures_fog_of_war.vcxproj @@ -202,7 +202,7 @@ Level3 Disabled - WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) CompileAsC $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) @@ -219,7 +219,7 @@ Level3 Disabled - WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) CompileAsC $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) /FS %(AdditionalOptions) @@ -237,7 +237,7 @@ Level3 Disabled - WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) CompileAsC $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) @@ -258,7 +258,7 @@ Level3 Disabled - WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) CompileAsC $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) @@ -281,7 +281,7 @@ MaxSpeed true true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) CompileAsC true @@ -303,7 +303,7 @@ MaxSpeed true true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) CompileAsC true @@ -325,7 +325,7 @@ MaxSpeed true true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) CompileAsC true @@ -353,7 +353,7 @@ MaxSpeed true true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) CompileAsC true diff --git a/projects/VS2022/examples/textures_polygon.vcxproj b/projects/VS2022/examples/textures_polygon.vcxproj index 9467c8aebd78..1788f426a7db 100644 --- a/projects/VS2022/examples/textures_polygon.vcxproj +++ b/projects/VS2022/examples/textures_polygon.vcxproj @@ -202,7 +202,7 @@ Level3 Disabled - WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) CompileAsC $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) @@ -219,7 +219,7 @@ Level3 Disabled - WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) CompileAsC $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) /FS %(AdditionalOptions) @@ -237,7 +237,7 @@ Level3 Disabled - WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) CompileAsC $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) @@ -258,7 +258,7 @@ Level3 Disabled - WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) CompileAsC $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) @@ -281,7 +281,7 @@ MaxSpeed true true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) CompileAsC true @@ -303,7 +303,7 @@ MaxSpeed true true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) CompileAsC true @@ -325,7 +325,7 @@ MaxSpeed true true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) CompileAsC true @@ -353,7 +353,7 @@ MaxSpeed true true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) CompileAsC true diff --git a/src/rmodels.c b/src/rmodels.c index 953d016ad44e..efbe431cf044 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -1870,7 +1870,7 @@ bool ExportMesh(Mesh mesh, const char *fileName) static void ProcessMaterialsOBJ(Material *rayMaterials, tinyobj_material_t *materials, int materialCount) { // Init model materials - for (unsigned int m = 0; m < materialCount; m++) + for (int m = 0; m < materialCount; m++) { // Init material to default // NOTE: Uses default shader, which only supports MATERIAL_MAP_DIFFUSE From 83ff7b246613c57dd5703d24965b4036332a100f Mon Sep 17 00:00:00 2001 From: Rob Loach Date: Fri, 27 Jan 2023 13:24:03 -0500 Subject: [PATCH 067/192] ADDED: `IsShaderReady()`, `IsImageReady()`, `IsFontReady()`, `IsWaveReady()`, `IsSoundReady()`, `IsMusicReady()` (#2892) These IsReady() functions provide a method in order to verify whether or not the object was loaded successfully. They're useful to make sure the assets are there prior to using them. --- src/raudio.c | 24 ++++++++++++++++++++++++ src/raylib.h | 7 +++++++ src/rcore.c | 6 ++++++ src/rtext.c | 6 ++++++ src/rtextures.c | 6 ++++++ 5 files changed, 49 insertions(+) diff --git a/src/raudio.c b/src/raudio.c index 34ab0702e781..46d8223d9d1e 100644 --- a/src/raudio.c +++ b/src/raudio.c @@ -836,6 +836,12 @@ Wave LoadWaveFromMemory(const char *fileType, const unsigned char *fileData, int return wave; } +// Checks if wave data is ready +bool IsWaveReady(Wave wave) +{ + return wave.data != NULL; +} + // Load sound from file // NOTE: The entire file is loaded to memory to be played (no-streaming) Sound LoadSound(const char *fileName) @@ -892,6 +898,12 @@ Sound LoadSoundFromWave(Wave wave) return sound; } +// Checks if a sound is ready +bool IsSoundReady(Sound sound) +{ + return sound.stream.buffer != NULL; +} + // Unload wave data void UnloadWave(Wave wave) { @@ -1614,6 +1626,12 @@ Music LoadMusicStreamFromMemory(const char *fileType, const unsigned char *data, return music; } +// Checks if a music stream is ready +bool IsMusicReady(Music music) +{ + return music.ctxData != NULL; +} + // Unload music stream void UnloadMusicStream(Music music) { @@ -1967,6 +1985,12 @@ AudioStream LoadAudioStream(unsigned int sampleRate, unsigned int sampleSize, un return stream; } +// Checks if an audio stream is ready +RLAPI bool IsAudioStreamReady(AudioStream stream) +{ + return stream.buffer != NULL; +} + // Unload audio stream and free memory void UnloadAudioStream(AudioStream stream) { diff --git a/src/raylib.h b/src/raylib.h index 10e69acdf499..168b10443622 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1012,6 +1012,7 @@ RLAPI void UnloadVrStereoConfig(VrStereoConfig config); // Unload VR s // NOTE: Shader functionality is not available on OpenGL 1.1 RLAPI Shader LoadShader(const char *vsFileName, const char *fsFileName); // Load shader from files and bind default locations RLAPI Shader LoadShaderFromMemory(const char *vsCode, const char *fsCode); // Load shader from code strings and bind default locations +RLAPI bool IsShaderReady(Shader shader); // Check if a shader is ready RLAPI int GetShaderLocation(Shader shader, const char *uniformName); // Get shader uniform location RLAPI int GetShaderLocationAttrib(Shader shader, const char *attribName); // Get shader attribute location RLAPI void SetShaderValue(Shader shader, int locIndex, const void *value, int uniformType); // Set shader uniform value @@ -1234,6 +1235,7 @@ RLAPI Image LoadImageAnim(const char *fileName, int *frames); RLAPI Image LoadImageFromMemory(const char *fileType, const unsigned char *fileData, int dataSize); // Load image from memory buffer, fileType refers to extension: i.e. '.png' RLAPI Image LoadImageFromTexture(Texture2D texture); // Load image from GPU texture data RLAPI Image LoadImageFromScreen(void); // Load image from screen buffer and (screenshot) +RLAPI bool IsImageReady(Image image); // Check if an image is ready RLAPI void UnloadImage(Image image); // Unload image from CPU memory (RAM) RLAPI bool ExportImage(Image image, const char *fileName); // Export image data to file, returns true on success RLAPI bool ExportImageAsCode(Image image, const char *fileName); // Export image as code file defining an array of bytes, returns true on success @@ -1354,6 +1356,7 @@ RLAPI Font LoadFont(const char *fileName); RLAPI Font LoadFontEx(const char *fileName, int fontSize, int *fontChars, int glyphCount); // Load font from file with extended parameters, use NULL for fontChars and 0 for glyphCount to load the default character set RLAPI Font LoadFontFromImage(Image image, Color key, int firstChar); // Load font from Image (XNA style) RLAPI Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int dataSize, int fontSize, int *fontChars, int glyphCount); // Load font from memory buffer, fileType refers to extension: i.e. '.ttf' +RLAPI bool IsFontReady(Font font); // Check if a font is ready RLAPI GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSize, int *fontChars, int glyphCount, int type); // Load font data for further use RLAPI Image GenImageFontAtlas(const GlyphInfo *chars, Rectangle **recs, int glyphCount, int fontSize, int padding, int packMethod); // Generate image font atlas using chars info RLAPI void UnloadFontData(GlyphInfo *chars, int glyphCount); // Unload font chars info data (RAM) @@ -1513,8 +1516,10 @@ RLAPI void SetMasterVolume(float volume); // Set mas // Wave/Sound loading/unloading functions RLAPI Wave LoadWave(const char *fileName); // Load wave data from file RLAPI Wave LoadWaveFromMemory(const char *fileType, const unsigned char *fileData, int dataSize); // Load wave from memory buffer, fileType refers to extension: i.e. '.wav' +RLAPI bool IsWaveReady(Wave wave); // Checks if wave data is ready RLAPI Sound LoadSound(const char *fileName); // Load sound from file RLAPI Sound LoadSoundFromWave(Wave wave); // Load sound from wave data +RLAPI bool IsSoundReady(Sound sound); // Checks if a sound is ready RLAPI void UpdateSound(Sound sound, const void *data, int sampleCount); // Update sound buffer with new data RLAPI void UnloadWave(Wave wave); // Unload wave data RLAPI void UnloadSound(Sound sound); // Unload sound @@ -1542,6 +1547,7 @@ RLAPI void UnloadWaveSamples(float *samples); // Unload // Music management functions RLAPI Music LoadMusicStream(const char *fileName); // Load music stream from file RLAPI Music LoadMusicStreamFromMemory(const char *fileType, const unsigned char *data, int dataSize); // Load music stream from data +RLAPI bool IsMusicReady(Music music); // Checks if a music stream is ready RLAPI void UnloadMusicStream(Music music); // Unload music stream RLAPI void PlayMusicStream(Music music); // Start music playing RLAPI bool IsMusicStreamPlaying(Music music); // Check if music is playing @@ -1558,6 +1564,7 @@ RLAPI float GetMusicTimePlayed(Music music); // Get cur // AudioStream management functions RLAPI AudioStream LoadAudioStream(unsigned int sampleRate, unsigned int sampleSize, unsigned int channels); // Load audio stream (to stream raw audio pcm data) +RLAPI bool IsAudioStreamReady(AudioStream stream); // Checks if an audio stream is ready RLAPI void UnloadAudioStream(AudioStream stream); // Unload audio stream and free memory RLAPI void UpdateAudioStream(AudioStream stream, const void *data, int frameCount); // Update audio stream buffers with data RLAPI bool IsAudioStreamProcessed(AudioStream stream); // Check if any audio stream buffers requires refill diff --git a/src/rcore.c b/src/rcore.c index 1f97edb2a0c5..f2f0cbbe0b97 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -2509,6 +2509,12 @@ Shader LoadShaderFromMemory(const char *vsCode, const char *fsCode) return shader; } +// Check if a shader is ready +bool IsShaderReady(Shader shader) +{ + return shader.locs != NULL; +} + // Unload shader from GPU memory (VRAM) void UnloadShader(Shader shader) { diff --git a/src/rtext.c b/src/rtext.c index 718fda04b767..9908b44dfc70 100644 --- a/src/rtext.c +++ b/src/rtext.c @@ -535,6 +535,12 @@ Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int return font; } +// Check if a font is ready +bool IsFontReady(Font font) +{ + return font.glyphs != NULL; +} + // Load font data for further use // NOTE: Requires TTF font memory data and can generate SDF data GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSize, int *fontChars, int glyphCount, int type) diff --git a/src/rtextures.c b/src/rtextures.c index 05dacb21ad9f..e2d5ca083da0 100644 --- a/src/rtextures.c +++ b/src/rtextures.c @@ -502,6 +502,12 @@ Image LoadImageFromScreen(void) return image; } +// Check if an image is ready +bool IsImageReady(Image image) +{ + return image.data != NULL; +} + // Unload image from CPU memory (RAM) void UnloadImage(Image image) { From 0b42da4085e4ef840c069e9de8f694d1540b573d Mon Sep 17 00:00:00 2001 From: Antonis Geralis <43617260+planetis-m@users.noreply.github.com> Date: Sat, 28 Jan 2023 00:33:15 +0200 Subject: [PATCH 068/192] Raylib.h has exceeded 512 functions! (#2896) --- parser/raylib_parser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parser/raylib_parser.c b/parser/raylib_parser.c index 97e1e79a9748..7bb8cf7fad86 100644 --- a/parser/raylib_parser.c +++ b/parser/raylib_parser.c @@ -70,7 +70,7 @@ #define MAX_ALIASES_TO_PARSE 64 // Maximum number of aliases to parse #define MAX_ENUMS_TO_PARSE 64 // Maximum number of enums to parse #define MAX_CALLBACKS_TO_PARSE 64 // Maximum number of callbacks to parse -#define MAX_FUNCS_TO_PARSE 512 // Maximum number of functions to parse +#define MAX_FUNCS_TO_PARSE 1024 // Maximum number of functions to parse #define MAX_LINE_LENGTH 512 // Maximum length of one line (including comments) From 7fff1ba0b035cc4f9ac5d1711686299b074baea1 Mon Sep 17 00:00:00 2001 From: Rob Loach Date: Sat, 28 Jan 2023 06:13:09 -0500 Subject: [PATCH 069/192] ADDED: IsModelReady(), IsMaterialReady(), IsTextureReady(), IsRenderTextureReady() (#2895) --- src/raylib.h | 4 ++++ src/rmodels.c | 12 ++++++++++++ src/rtextures.c | 14 +++++++++++++- 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/raylib.h b/src/raylib.h index 168b10443622..e0b7a31598dd 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1311,7 +1311,9 @@ RLAPI Texture2D LoadTexture(const char *fileName); RLAPI Texture2D LoadTextureFromImage(Image image); // Load texture from image data RLAPI TextureCubemap LoadTextureCubemap(Image image, int layout); // Load cubemap from image, multiple image cubemap layouts supported RLAPI RenderTexture2D LoadRenderTexture(int width, int height); // Load texture for rendering (framebuffer) +RLAPI bool IsTextureReady(Texture2D texture); // Check if a texture is ready RLAPI void UnloadTexture(Texture2D texture); // Unload texture from GPU memory (VRAM) +RLAPI bool IsRenderTextureReady(RenderTexture2D target); // Check if a render texture is ready RLAPI void UnloadRenderTexture(RenderTexture2D target); // Unload render texture from GPU memory (VRAM) RLAPI void UpdateTexture(Texture2D texture, const void *pixels); // Update GPU texture with new data RLAPI void UpdateTextureRec(Texture2D texture, Rectangle rec, const void *pixels); // Update GPU texture rectangle with new data @@ -1441,6 +1443,7 @@ RLAPI void DrawGrid(int slices, float spacing); // Model management functions RLAPI Model LoadModel(const char *fileName); // Load model from files (meshes and materials) RLAPI Model LoadModelFromMesh(Mesh mesh); // Load model from generated mesh (default material) +RLAPI bool IsModelReady(Model model); // Check if a model is ready RLAPI void UnloadModel(Model model); // Unload model (including meshes) from memory (RAM and/or VRAM) RLAPI void UnloadModelKeepMeshes(Model model); // Unload model (but not meshes) from memory (RAM and/or VRAM) RLAPI BoundingBox GetModelBoundingBox(Model model); // Compute model bounding box limits (considers all meshes) @@ -1481,6 +1484,7 @@ RLAPI Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize); // Material loading/unloading functions RLAPI Material *LoadMaterials(const char *fileName, int *materialCount); // Load materials from model file RLAPI Material LoadMaterialDefault(void); // Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps) +RLAPI bool IsMaterialReady(Material material); // Check if a material is ready RLAPI void UnloadMaterial(Material material); // Unload material from GPU memory (VRAM) RLAPI void SetMaterialTexture(Material *material, int mapType, Texture2D texture); // Set texture for a material map type (MATERIAL_MAP_DIFFUSE, MATERIAL_MAP_SPECULAR...) RLAPI void SetModelMeshMaterial(Model *model, int meshId, int materialId); // Set material for a mesh diff --git a/src/rmodels.c b/src/rmodels.c index efbe431cf044..15de05c09913 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -1109,6 +1109,12 @@ Model LoadModelFromMesh(Mesh mesh) return model; } +// Check if a model is ready +bool IsModelReady(Model model) +{ + return model.meshes != NULL && model.materials != NULL && model.meshMaterial != NULL && model.meshCount > 0 && model.materialCount > 0; +} + // Unload model (meshes/materials) from memory (RAM and/or VRAM) // NOTE: This function takes care of all model elements, for a detailed control // over them, use UnloadMesh() and UnloadMaterial() @@ -1950,6 +1956,12 @@ Material LoadMaterialDefault(void) return material; } +// Check if a material is ready +bool IsMaterialReady(Material material) +{ + return material.maps != NULL; +} + // Unload material from memory void UnloadMaterial(Material material) { diff --git a/src/rtextures.c b/src/rtextures.c index e2d5ca083da0..89a91b0519a4 100644 --- a/src/rtextures.c +++ b/src/rtextures.c @@ -505,7 +505,7 @@ Image LoadImageFromScreen(void) // Check if an image is ready bool IsImageReady(Image image) { - return image.data != NULL; + return image.data != NULL && image.width > 0 && image.height > 0 && image.format > 0; } // Unload image from CPU memory (RAM) @@ -3330,6 +3330,12 @@ RenderTexture2D LoadRenderTexture(int width, int height) return target; } +// Check if a texture is ready +bool IsTextureReady(Texture2D texture) +{ + return texture.id > 0 && texture.width > 0 && texture.height > 0 && texture.format > 0; +} + // Unload texture from GPU memory (VRAM) void UnloadTexture(Texture2D texture) { @@ -3341,6 +3347,12 @@ void UnloadTexture(Texture2D texture) } } +// Check if a render texture is ready +bool IsRenderTextureReady(RenderTexture2D target) +{ + return target.id > 0 && IsTextureReady(target.depth) && IsTextureReady(target.texture); +} + // Unload render texture from GPU memory (VRAM) void UnloadRenderTexture(RenderTexture2D target) { From df5a736c009d98187e703a55c604345e12777bb7 Mon Sep 17 00:00:00 2001 From: Dor Shapira <107134807+sDos280@users.noreply.github.com> Date: Sat, 28 Jan 2023 20:26:41 +0200 Subject: [PATCH 070/192] fix typo (#2899) patrix=>matrix --- src/raymath.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/raymath.h b/src/raymath.h index 435ea3c6e076..eb244ad44977 100644 --- a/src/raymath.h +++ b/src/raymath.h @@ -903,7 +903,7 @@ RMAPI Vector3 Vector3Unproject(Vector3 source, Matrix projection, Matrix view) { Vector3 result = { 0 }; - // Calculate unproject matrix (multiply view patrix by projection matrix) and invert it + // Calculate unproject matrix (multiply view matrix by projection matrix) and invert it Matrix matViewProj = { // MatrixMultiply(view, projection); view.m0*projection.m0 + view.m1*projection.m4 + view.m2*projection.m8 + view.m3*projection.m12, view.m0*projection.m1 + view.m1*projection.m5 + view.m2*projection.m9 + view.m3*projection.m13, From 929a46cbab648955ddad1a04d1ed848c488fc9d4 Mon Sep 17 00:00:00 2001 From: Uneven Prankster <33995085+GithubPrankster@users.noreply.github.com> Date: Mon, 30 Jan 2023 13:00:39 -0300 Subject: [PATCH 071/192] [models] Fix M3D vertex color import. (#2878) * Fix vertex color import for .m3d * Only load vertex colors when color map and/or materials are present * Only execute when color array is present --------- Co-authored-by: Uneven Prankster --- src/rmodels.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/rmodels.c b/src/rmodels.c index 15de05c09913..af61b8e5d2e6 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -5633,11 +5633,9 @@ static Model LoadM3D(const char *fileName) model.meshes[k].texcoords = (float *)RL_CALLOC(model.meshes[k].vertexCount*2, sizeof(float)); model.meshes[k].normals = (float *)RL_CALLOC(model.meshes[k].vertexCount*3, sizeof(float)); - // without material, we rely on vertex colors - if (mi == M3D_UNDEF && model.meshes[k].colors == NULL) + if(m3d->cmap != NULL || mi != M3D_UNDEF) { model.meshes[k].colors = RL_CALLOC(model.meshes[k].vertexCount*4, sizeof(unsigned char)); - for (j = 0; j < model.meshes[k].vertexCount*4; j += 4) memcpy(&model.meshes[k].colors[j], &WHITE, 4); } if (m3d->numbone && m3d->numskin) @@ -5662,10 +5660,10 @@ static Model LoadM3D(const char *fileName) model.meshes[k].vertices[l * 9 + 6] = m3d->vertex[m3d->face[i].vertex[2]].x*m3d->scale; model.meshes[k].vertices[l * 9 + 7] = m3d->vertex[m3d->face[i].vertex[2]].y*m3d->scale; model.meshes[k].vertices[l * 9 + 8] = m3d->vertex[m3d->face[i].vertex[2]].z*m3d->scale; - - if (mi == M3D_UNDEF) + + // without vertex color (full transparency), we use the default color + if(model.meshes[k].colors != NULL) { - // without vertex color (full transparency), we use the default color if (m3d->vertex[m3d->face[i].vertex[0]].color & 0xFF000000) memcpy(&model.meshes[k].colors[l * 12 + 0], &m3d->vertex[m3d->face[i].vertex[0]].color, 4); if (m3d->vertex[m3d->face[i].vertex[1]].color & 0xFF000000) From c94c666d0493fa32a810863d579d34289d2bfc1b Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 30 Jan 2023 17:05:12 +0100 Subject: [PATCH 072/192] Review formatting for M3D loading vertex colors --- src/rmodels.c | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/src/rmodels.c b/src/rmodels.c index af61b8e5d2e6..b5d8578f6ea6 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -5633,11 +5633,9 @@ static Model LoadM3D(const char *fileName) model.meshes[k].texcoords = (float *)RL_CALLOC(model.meshes[k].vertexCount*2, sizeof(float)); model.meshes[k].normals = (float *)RL_CALLOC(model.meshes[k].vertexCount*3, sizeof(float)); - if(m3d->cmap != NULL || mi != M3D_UNDEF) - { - model.meshes[k].colors = RL_CALLOC(model.meshes[k].vertexCount*4, sizeof(unsigned char)); - } - + // If color map is provided, we allocate storage for vertex colors + if (m3d->cmap != NULL) model.meshes[k].colors = RL_CALLOC(model.meshes[k].vertexCount*4, sizeof(unsigned char)); + if (m3d->numbone && m3d->numskin) { model.meshes[k].boneIds = (unsigned char *)RL_CALLOC(model.meshes[k].vertexCount*4, sizeof(unsigned char)); @@ -5651,25 +5649,25 @@ static Model LoadM3D(const char *fileName) } // Process meshes per material, add triangles - model.meshes[k].vertices[l * 9 + 0] = m3d->vertex[m3d->face[i].vertex[0]].x*m3d->scale; - model.meshes[k].vertices[l * 9 + 1] = m3d->vertex[m3d->face[i].vertex[0]].y*m3d->scale; - model.meshes[k].vertices[l * 9 + 2] = m3d->vertex[m3d->face[i].vertex[0]].z*m3d->scale; - model.meshes[k].vertices[l * 9 + 3] = m3d->vertex[m3d->face[i].vertex[1]].x*m3d->scale; - model.meshes[k].vertices[l * 9 + 4] = m3d->vertex[m3d->face[i].vertex[1]].y*m3d->scale; - model.meshes[k].vertices[l * 9 + 5] = m3d->vertex[m3d->face[i].vertex[1]].z*m3d->scale; - model.meshes[k].vertices[l * 9 + 6] = m3d->vertex[m3d->face[i].vertex[2]].x*m3d->scale; - model.meshes[k].vertices[l * 9 + 7] = m3d->vertex[m3d->face[i].vertex[2]].y*m3d->scale; - model.meshes[k].vertices[l * 9 + 8] = m3d->vertex[m3d->face[i].vertex[2]].z*m3d->scale; + model.meshes[k].vertices[l*9 + 0] = m3d->vertex[m3d->face[i].vertex[0]].x*m3d->scale; + model.meshes[k].vertices[l*9 + 1] = m3d->vertex[m3d->face[i].vertex[0]].y*m3d->scale; + model.meshes[k].vertices[l*9 + 2] = m3d->vertex[m3d->face[i].vertex[0]].z*m3d->scale; + model.meshes[k].vertices[l*9 + 3] = m3d->vertex[m3d->face[i].vertex[1]].x*m3d->scale; + model.meshes[k].vertices[l*9 + 4] = m3d->vertex[m3d->face[i].vertex[1]].y*m3d->scale; + model.meshes[k].vertices[l*9 + 5] = m3d->vertex[m3d->face[i].vertex[1]].z*m3d->scale; + model.meshes[k].vertices[l*9 + 6] = m3d->vertex[m3d->face[i].vertex[2]].x*m3d->scale; + model.meshes[k].vertices[l*9 + 7] = m3d->vertex[m3d->face[i].vertex[2]].y*m3d->scale; + model.meshes[k].vertices[l*9 + 8] = m3d->vertex[m3d->face[i].vertex[2]].z*m3d->scale; // without vertex color (full transparency), we use the default color - if(model.meshes[k].colors != NULL) + if (model.meshes[k].colors != NULL) { if (m3d->vertex[m3d->face[i].vertex[0]].color & 0xFF000000) - memcpy(&model.meshes[k].colors[l * 12 + 0], &m3d->vertex[m3d->face[i].vertex[0]].color, 4); + memcpy(&model.meshes[k].colors[l*12 + 0], &m3d->vertex[m3d->face[i].vertex[0]].color, 4); if (m3d->vertex[m3d->face[i].vertex[1]].color & 0xFF000000) - memcpy(&model.meshes[k].colors[l * 12 + 4], &m3d->vertex[m3d->face[i].vertex[1]].color, 4); + memcpy(&model.meshes[k].colors[l*12 + 4], &m3d->vertex[m3d->face[i].vertex[1]].color, 4); if (m3d->vertex[m3d->face[i].vertex[2]].color & 0xFF000000) - memcpy(&model.meshes[k].colors[l * 12 + 8], &m3d->vertex[m3d->face[i].vertex[2]].color, 4); + memcpy(&model.meshes[k].colors[l*12 + 8], &m3d->vertex[m3d->face[i].vertex[2]].color, 4); } if (m3d->face[i].texcoord[0] != M3D_UNDEF) From 89171a26083da40a3a78dc0f1dee466542ed7668 Mon Sep 17 00:00:00 2001 From: Nikolas Date: Wed, 1 Feb 2023 11:09:03 +0100 Subject: [PATCH 073/192] Add WASM support for Zig build (#2901) * Add WASM support for Zig build * Improve Web example building * Remove emscript example building with Zig again * Readd windows emscripten variables --- examples/Makefile | 29 +++++++++++++++++------------ examples/build.zig | 20 +++++++++++++------- examples/shapes/resources/.gitkeep | 0 src/build.zig | 27 +++++++++++++++++++++++++-- 4 files changed, 55 insertions(+), 21 deletions(-) create mode 100644 examples/shapes/resources/.gitkeep diff --git a/examples/Makefile b/examples/Makefile index bc2c8d711838..dce02218a8ca 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -67,8 +67,8 @@ ifeq ($(PLATFORM),PLATFORM_RPI) endif endif -# Determine PLATFORM_OS in case PLATFORM_DESKTOP selected -ifeq ($(PLATFORM),PLATFORM_DESKTOP) +# Determine PLATFORM_OS in case PLATFORM_DESKTOP or PLATFORM_WEB selected +ifeq ($(PLATFORM),$(filter $(PLATFORM),PLATFORM_DESKTOP PLATFORM_WEB)) # No uname.exe on MinGW!, but OS=Windows_NT on Windows! # ifeq ($(UNAME),Msys) -> Windows ifeq ($(OS),Windows_NT) @@ -126,16 +126,18 @@ ifeq ($(PLATFORM),PLATFORM_DRM) endif # Define raylib release directory for compiled library -RAYLIB_RELEASE_PATH ?= $(RAYLIB_PATH)/src +RAYLIB_RELEASE_PATH ?= $(RAYLIB_PATH)/src ifeq ($(PLATFORM),PLATFORM_WEB) - # Emscripten required variables - EMSDK_PATH ?= C:/emsdk - EMSCRIPTEN_PATH ?= $(EMSDK_PATH)/upstream/emscripten - CLANG_PATH = $(EMSDK_PATH)/upstream/bin - PYTHON_PATH = $(EMSDK_PATH)/python/3.9.2-1_64bit - NODE_PATH = $(EMSDK_PATH)/node/14.15.5_64bit/bin - export PATH = $(EMSDK_PATH);$(EMSCRIPTEN_PATH);$(CLANG_PATH);$(NODE_PATH);$(PYTHON_PATH):$$(PATH) + ifeq ($(PLATFORM_OS),WINDOWS) + # Emscripten required variables + EMSDK_PATH ?= C:/emsdk + EMSCRIPTEN_PATH ?= $(EMSDK_PATH)/upstream/emscripten + CLANG_PATH = $(EMSDK_PATH)/upstream/bin + PYTHON_PATH = $(EMSDK_PATH)/python/3.9.2-1_64bit + NODE_PATH = $(EMSDK_PATH)/node/14.15.5_64bit/bin + export PATH = $(EMSDK_PATH);$(EMSCRIPTEN_PATH);$(CLANG_PATH);$(NODE_PATH);$(PYTHON_PATH):$$(PATH) + endif endif # Define default C compiler: CC @@ -579,7 +581,10 @@ ifeq ($(PLATFORM),PLATFORM_DRM) rm -fv *.o endif ifeq ($(PLATFORM),PLATFORM_WEB) - del *.o *.html *.js + ifeq ($(PLATFORM_OS),WINDOWS) + del *.wasm *.html *.js *.data + else + rm -f */*.wasm */*.html */*.js */*.data + endif endif @echo Cleaning done - diff --git a/examples/build.zig b/examples/build.zig index cb211aefd8bb..eb040fd2ffcd 100644 --- a/examples/build.zig +++ b/examples/build.zig @@ -2,6 +2,10 @@ const std = @import("std"); const builtin = @import("builtin"); fn add_module(comptime module: []const u8, b: *std.build.Builder, target: std.zig.CrossTarget) !*std.build.Step { + if (target.getOsTag() == .emscripten) { + @panic("Emscripten building via Zig unsupported"); + } + // Standard release options allow the person running `zig build` to select // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. const mode = b.standardReleaseOptions(); @@ -19,12 +23,7 @@ fn add_module(comptime module: []const u8, b: *std.build.Builder, target: std.zi if (std.mem.eql(u8, "core_loading_thread", name) and target.getOsTag() == .windows) continue; const exe = b.addExecutable(name, null); - exe.addCSourceFile(path, switch (target.getOsTag()) { - .windows => &[_][]const u8{}, - .linux => &[_][]const u8{}, - .macos => &[_][]const u8{"-DPLATFORM_DESKTOP"}, - else => @panic("Unsupported OS"), - }); + exe.addCSourceFile(path, &[_][]const u8{}); exe.setTarget(target); exe.setBuildMode(mode); exe.linkLibC(); @@ -32,6 +31,7 @@ fn add_module(comptime module: []const u8, b: *std.build.Builder, target: std.zi .windows => "../src/raylib.lib", .linux => "../src/libraylib.a", .macos => "../src/libraylib.a", + .emscripten => "../src/libraylib.a", else => @panic("Unsupported OS"), }); @@ -39,12 +39,14 @@ fn add_module(comptime module: []const u8, b: *std.build.Builder, target: std.zi exe.addIncludePath("../src/external"); exe.addIncludePath("../src/external/glfw/include"); - switch (exe.target.toTarget().os.tag) { + switch (target.getOsTag()) { .windows => { exe.linkSystemLibrary("winmm"); exe.linkSystemLibrary("gdi32"); exe.linkSystemLibrary("opengl32"); exe.addIncludePath("external/glfw/deps/mingw"); + + exe.defineCMacro("PLATFORM_DESKTOP", null); }, .linux => { exe.linkSystemLibrary("GL"); @@ -52,6 +54,8 @@ fn add_module(comptime module: []const u8, b: *std.build.Builder, target: std.zi exe.linkSystemLibrary("dl"); exe.linkSystemLibrary("m"); exe.linkSystemLibrary("X11"); + + exe.defineCMacro("PLATFORM_DESKTOP", null); }, .macos => { exe.linkFramework("Foundation"); @@ -60,6 +64,8 @@ fn add_module(comptime module: []const u8, b: *std.build.Builder, target: std.zi exe.linkFramework("CoreAudio"); exe.linkFramework("CoreVideo"); exe.linkFramework("IOKit"); + + exe.defineCMacro("PLATFORM_DESKTOP", null); }, else => { @panic("Unsupported OS"); diff --git a/examples/shapes/resources/.gitkeep b/examples/shapes/resources/.gitkeep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/src/build.zig b/src/build.zig index e44271e8dbdf..919db3e9fbcf 100644 --- a/src/build.zig +++ b/src/build.zig @@ -3,7 +3,6 @@ const std = @import("std"); pub fn addRaylib(b: *std.build.Builder, target: std.zig.CrossTarget) *std.build.LibExeObjStep { const raylib_flags = &[_][]const u8{ "-std=gnu99", - "-DPLATFORM_DESKTOP", "-D_GNU_SOURCE", "-DGL_SILENCE_DEPRECATION=199309L", "-fno-sanitize=undefined", // https://github.com/raysan5/raylib/issues/1891 @@ -25,13 +24,15 @@ pub fn addRaylib(b: *std.build.Builder, target: std.zig.CrossTarget) *std.build. srcdir ++ "/utils.c", }, raylib_flags); - switch (raylib.target.toTarget().os.tag) { + switch (target.getOsTag()) { .windows => { raylib.addCSourceFiles(&.{srcdir ++ "/rglfw.c"}, raylib_flags); raylib.linkSystemLibrary("winmm"); raylib.linkSystemLibrary("gdi32"); raylib.linkSystemLibrary("opengl32"); raylib.addIncludePath("external/glfw/deps/mingw"); + + raylib.defineCMacro("PLATFORM_DESKTOP", null); }, .linux => { raylib.addCSourceFiles(&.{srcdir ++ "/rglfw.c"}, raylib_flags); @@ -40,6 +41,8 @@ pub fn addRaylib(b: *std.build.Builder, target: std.zig.CrossTarget) *std.build. raylib.linkSystemLibrary("dl"); raylib.linkSystemLibrary("m"); raylib.linkSystemLibrary("X11"); + + raylib.defineCMacro("PLATFORM_DESKTOP", null); }, .freebsd, .openbsd, .netbsd, .dragonfly => { raylib.addCSourceFiles(&.{srcdir ++ "/rglfw.c"}, raylib_flags); @@ -53,6 +56,8 @@ pub fn addRaylib(b: *std.build.Builder, target: std.zig.CrossTarget) *std.build. raylib.linkSystemLibrary("Xi"); raylib.linkSystemLibrary("Xxf86vm"); raylib.linkSystemLibrary("Xcursor"); + + raylib.defineCMacro("PLATFORM_DESKTOP", null); }, .macos => { // On macos rglfw.c include Objective-C files. @@ -68,6 +73,24 @@ pub fn addRaylib(b: *std.build.Builder, target: std.zig.CrossTarget) *std.build. raylib.linkFramework("CoreGraphics"); raylib.linkFramework("AppKit"); raylib.linkFramework("IOKit"); + + raylib.defineCMacro("PLATFORM_DESKTOP", null); + }, + .emscripten => { + raylib.defineCMacro("PLATFORM_WEB", null); + raylib.defineCMacro("GRAPHICS_API_OPENGL_ES2", null); + + if (b.sysroot == null) { + @panic("Pass '--sysroot \"$EMSDK/upstream/emscripten\"'"); + } + + const cache_include = std.fs.path.join(b.allocator, &.{ b.sysroot.?, "cache", "sysroot", "include" }) catch @panic("Out of memory"); + defer b.allocator.free(cache_include); + + var dir = std.fs.openDirAbsolute(cache_include, std.fs.Dir.OpenDirOptions{.access_sub_paths = true, .no_follow = true}) catch @panic("No emscripten cache. Generate it!"); + dir.close(); + + raylib.addIncludePath(cache_include); }, else => { @panic("Unsupported OS"); From a151cbd37ace03a377fd582a29f660dd0ea9f97a Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 1 Feb 2023 11:18:55 +0100 Subject: [PATCH 074/192] ADDED: `Vector2LineAngle()` #2887 REVIEWED: `Vector2Angle()` --- src/raymath.h | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/raymath.h b/src/raymath.h index eb244ad44977..96c241843a6e 100644 --- a/src/raymath.h +++ b/src/raymath.h @@ -306,24 +306,33 @@ RMAPI float Vector2DistanceSqr(Vector2 v1, Vector2 v2) return result; } -// Calculate angle from two vectors +// Calculate angle between two vectors +// NOTE: Angle is calculated from origin point (0, 0) +RMAPI float Vector2Angle(Vector2 v1, Vector2 v2) +{ + float result = atan2f(v2.y - v1.y, v2.x - v1.x); + + return result; +} + +// Calculate angle defined by a two vectors line // NOTE: Parameters need to be normalized // Current implementation should be aligned with glm::angle -RMAPI float Vector2Angle(Vector2 v1, Vector2 v2) +RMAPI float Vector2LineAngle(Vector2 start, Vector2 end) { float result = 0.0f; - float dot = v1.x*v2.x + v1.y*v2.y; // Dot product + float dot = start.x*end.x + start.y*end.y; // Dot product - float dotClamp = (dot < -1.0f)? -1.0f : dot; // Clamp + float dotClamp = (dot < -1.0f)? -1.0f : dot; // Clamp if (dotClamp > 1.0f) dotClamp = 1.0f; result = acosf(dotClamp); // Alternative implementation, more costly - //float v1Length = sqrtf((v1.x*v1.x) + (v1.y*v1.y)); - //float v2Length = sqrtf((v2.x*v2.x) + (v2.y*v2.y)); - //float result = -acosf((v1.x*v2.x + v1.y*v2.y)/(v1Length*v2Length)); + //float v1Length = sqrtf((start.x*start.x) + (start.y*start.y)); + //float v2Length = sqrtf((end.x*end.x) + (end.y*end.y)); + //float result = -acosf((start.x*end.x + start.y*end.y)/(v1Length*v2Length)); return result; } From d827a65e59c8474b4899ff7034dcc4d17b2fb4c0 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 1 Feb 2023 11:45:42 +0100 Subject: [PATCH 075/192] Update external libraries Switch to official `stb_vorbis.c` instead of using an outdated fork --- src/external/cgltf.h | 265 +- src/external/dr_flac.h | 576 +++-- src/external/dr_mp3.h | 84 +- src/external/dr_wav.h | 111 +- src/external/miniaudio.h | 106 +- src/external/stb_image.h | 144 +- src/external/{stb_vorbis.h => stb_vorbis.c} | 2505 ++++++++++--------- src/raudio.c | 3 +- 8 files changed, 2228 insertions(+), 1566 deletions(-) rename src/external/{stb_vorbis.h => stb_vorbis.c} (68%) diff --git a/src/external/cgltf.h b/src/external/cgltf.h index 02064103d8c4..a4d9c72de1f7 100644 --- a/src/external/cgltf.h +++ b/src/external/cgltf.h @@ -1,7 +1,7 @@ /** * cgltf - a single-file glTF 2.0 parser written in C99. * - * Version: 1.12 + * Version: 1.13 * * Website: https://github.com/jkuhlmann/cgltf * @@ -80,19 +80,16 @@ * `cgltf_accessor_read_index` is similar to its floating-point counterpart, but it returns size_t * and only works with single-component data types. * - * `cgltf_result cgltf_copy_extras_json(const cgltf_data*, const cgltf_extras*, - * char* dest, cgltf_size* dest_size)` allows users to retrieve the "extras" data that - * can be attached to many glTF objects (which can be arbitrary JSON data). The - * `cgltf_extras` struct stores the offsets of the start and end of the extras JSON data - * as it appears in the complete glTF JSON data. This function copies the extras data - * into the provided buffer. If `dest` is NULL, the length of the data is written into - * `dest_size`. You can then parse this data using your own JSON parser + * `cgltf_copy_extras_json` allows users to retrieve the "extras" data that can be attached to many + * glTF objects (which can be arbitrary JSON data). This is a legacy function, consider using + * cgltf_extras::data directly instead. You can parse this data using your own JSON parser * or, if you've included the cgltf implementation using the integrated JSMN JSON parser. */ #ifndef CGLTF_H_INCLUDED__ #define CGLTF_H_INCLUDED__ #include +#include /* For uint8_t, uint32_t */ #ifdef __cplusplus extern "C" { @@ -256,8 +253,10 @@ typedef enum cgltf_data_free_method { } cgltf_data_free_method; typedef struct cgltf_extras { - cgltf_size start_offset; - cgltf_size end_offset; + cgltf_size start_offset; /* this field is deprecated and will be removed in the future; use data instead */ + cgltf_size end_offset; /* this field is deprecated and will be removed in the future; use data instead */ + + char* data; } cgltf_extras; typedef struct cgltf_extension { @@ -432,8 +431,6 @@ typedef struct cgltf_pbr_metallic_roughness cgltf_float base_color_factor[4]; cgltf_float metallic_factor; cgltf_float roughness_factor; - - cgltf_extras extras; } cgltf_pbr_metallic_roughness; typedef struct cgltf_pbr_specular_glossiness @@ -833,6 +830,8 @@ void cgltf_free(cgltf_data* data); void cgltf_node_transform_local(const cgltf_node* node, cgltf_float* out_matrix); void cgltf_node_transform_world(const cgltf_node* node, cgltf_float* out_matrix); +const uint8_t* cgltf_buffer_view_data(const cgltf_buffer_view* view); + cgltf_bool cgltf_accessor_read_float(const cgltf_accessor* accessor, cgltf_size index, cgltf_float* out, cgltf_size element_size); cgltf_bool cgltf_accessor_read_uint(const cgltf_accessor* accessor, cgltf_size index, cgltf_uint* out, cgltf_size element_size); cgltf_size cgltf_accessor_read_index(const cgltf_accessor* accessor, cgltf_size index); @@ -841,6 +840,7 @@ cgltf_size cgltf_num_components(cgltf_type type); cgltf_size cgltf_accessor_unpack_floats(const cgltf_accessor* accessor, cgltf_float* out, cgltf_size float_count); +/* this function is deprecated and will be removed in the future; use cgltf_extras::data instead */ cgltf_result cgltf_copy_extras_json(const cgltf_data* data, const cgltf_extras* extras, char* dest, cgltf_size* dest_size); #ifdef __cplusplus @@ -863,7 +863,6 @@ cgltf_result cgltf_copy_extras_json(const cgltf_data* data, const cgltf_extras* #ifdef CGLTF_IMPLEMENTATION -#include /* For uint8_t, uint32_t */ #include /* For strncpy */ #include /* For fopen */ #include /* For UINT_MAX etc */ @@ -905,15 +904,15 @@ enum jsmnerr { }; typedef struct { jsmntype_t type; - int start; - int end; + ptrdiff_t start; + ptrdiff_t end; int size; #ifdef JSMN_PARENT_LINKS int parent; #endif } jsmntok_t; typedef struct { - unsigned int pos; /* offset in the JSON string */ + size_t pos; /* offset in the JSON string */ unsigned int toknext; /* next token to allocate */ int toksuper; /* superior token node, e.g parent object or array */ } jsmn_parser; @@ -924,12 +923,15 @@ static int jsmn_parse(jsmn_parser *parser, const char *js, size_t len, jsmntok_t */ +#ifndef CGLTF_CONSTS static const cgltf_size GlbHeaderSize = 12; static const cgltf_size GlbChunkHeaderSize = 8; static const uint32_t GlbVersion = 2; static const uint32_t GlbMagic = 0x46546C67; static const uint32_t GlbMagicJsonChunk = 0x4E4F534A; static const uint32_t GlbMagicBinChunk = 0x004E4942; +#define CGLTF_CONSTS +#endif #ifndef CGLTF_MALLOC #define CGLTF_MALLOC(size) malloc(size) @@ -1745,7 +1747,12 @@ cgltf_result cgltf_copy_extras_json(const cgltf_data* data, const cgltf_extras* return cgltf_result_success; } -void cgltf_free_extensions(cgltf_data* data, cgltf_extension* extensions, cgltf_size extensions_count) +static void cgltf_free_extras(cgltf_data* data, cgltf_extras* extras) +{ + data->memory.free_func(data->memory.user_data, extras->data); +} + +static void cgltf_free_extensions(cgltf_data* data, cgltf_extension* extensions, cgltf_size extensions_count) { for (cgltf_size i = 0; i < extensions_count; ++i) { @@ -1755,6 +1762,12 @@ void cgltf_free_extensions(cgltf_data* data, cgltf_extension* extensions, cgltf_ data->memory.free_func(data->memory.user_data, extensions); } +static void cgltf_free_texture_view(cgltf_data* data, cgltf_texture_view* view) +{ + cgltf_free_extensions(data, view->extensions, view->extensions_count); + cgltf_free_extras(data, &view->extras); +} + void cgltf_free(cgltf_data* data) { if (!data) @@ -1770,6 +1783,7 @@ void cgltf_free(cgltf_data* data) data->memory.free_func(data->memory.user_data, data->asset.min_version); cgltf_free_extensions(data, data->asset.extensions, data->asset.extensions_count); + cgltf_free_extras(data, &data->asset.extras); for (cgltf_size i = 0; i < data->accessors_count; ++i) { @@ -1780,8 +1794,12 @@ void cgltf_free(cgltf_data* data) cgltf_free_extensions(data, data->accessors[i].sparse.extensions, data->accessors[i].sparse.extensions_count); cgltf_free_extensions(data, data->accessors[i].sparse.indices_extensions, data->accessors[i].sparse.indices_extensions_count); cgltf_free_extensions(data, data->accessors[i].sparse.values_extensions, data->accessors[i].sparse.values_extensions_count); + cgltf_free_extras(data, &data->accessors[i].sparse.extras); + cgltf_free_extras(data, &data->accessors[i].sparse.indices_extras); + cgltf_free_extras(data, &data->accessors[i].sparse.values_extras); } cgltf_free_extensions(data, data->accessors[i].extensions, data->accessors[i].extensions_count); + cgltf_free_extras(data, &data->accessors[i].extras); } data->memory.free_func(data->memory.user_data, data->accessors); @@ -1791,6 +1809,7 @@ void cgltf_free(cgltf_data* data) data->memory.free_func(data->memory.user_data, data->buffer_views[i].data); cgltf_free_extensions(data, data->buffer_views[i].extensions, data->buffer_views[i].extensions_count); + cgltf_free_extras(data, &data->buffer_views[i].extras); } data->memory.free_func(data->memory.user_data, data->buffer_views); @@ -1810,8 +1829,8 @@ void cgltf_free(cgltf_data* data) data->memory.free_func(data->memory.user_data, data->buffers[i].uri); cgltf_free_extensions(data, data->buffers[i].extensions, data->buffers[i].extensions_count); + cgltf_free_extras(data, &data->buffers[i].extras); } - data->memory.free_func(data->memory.user_data, data->buffers); for (cgltf_size i = 0; i < data->meshes_count; ++i) @@ -1849,9 +1868,15 @@ void cgltf_free(cgltf_data* data) data->memory.free_func(data->memory.user_data, data->meshes[i].primitives[j].draco_mesh_compression.attributes); } + for (cgltf_size k = 0; k < data->meshes[i].primitives[j].mappings_count; ++k) + { + cgltf_free_extras(data, &data->meshes[i].primitives[j].mappings[k].extras); + } + data->memory.free_func(data->memory.user_data, data->meshes[i].primitives[j].mappings); cgltf_free_extensions(data, data->meshes[i].primitives[j].extensions, data->meshes[i].primitives[j].extensions_count); + cgltf_free_extras(data, &data->meshes[i].primitives[j].extras); } data->memory.free_func(data->memory.user_data, data->meshes[i].primitives); @@ -1863,6 +1888,7 @@ void cgltf_free(cgltf_data* data) } cgltf_free_extensions(data, data->meshes[i].extensions, data->meshes[i].extensions_count); + cgltf_free_extras(data, &data->meshes[i].extras); data->memory.free_func(data->memory.user_data, data->meshes[i].target_names); } @@ -1875,49 +1901,50 @@ void cgltf_free(cgltf_data* data) if(data->materials[i].has_pbr_metallic_roughness) { - cgltf_free_extensions(data, data->materials[i].pbr_metallic_roughness.metallic_roughness_texture.extensions, data->materials[i].pbr_metallic_roughness.metallic_roughness_texture.extensions_count); - cgltf_free_extensions(data, data->materials[i].pbr_metallic_roughness.base_color_texture.extensions, data->materials[i].pbr_metallic_roughness.base_color_texture.extensions_count); + cgltf_free_texture_view(data, &data->materials[i].pbr_metallic_roughness.metallic_roughness_texture); + cgltf_free_texture_view(data, &data->materials[i].pbr_metallic_roughness.base_color_texture); } if(data->materials[i].has_pbr_specular_glossiness) { - cgltf_free_extensions(data, data->materials[i].pbr_specular_glossiness.diffuse_texture.extensions, data->materials[i].pbr_specular_glossiness.diffuse_texture.extensions_count); - cgltf_free_extensions(data, data->materials[i].pbr_specular_glossiness.specular_glossiness_texture.extensions, data->materials[i].pbr_specular_glossiness.specular_glossiness_texture.extensions_count); + cgltf_free_texture_view(data, &data->materials[i].pbr_specular_glossiness.diffuse_texture); + cgltf_free_texture_view(data, &data->materials[i].pbr_specular_glossiness.specular_glossiness_texture); } if(data->materials[i].has_clearcoat) { - cgltf_free_extensions(data, data->materials[i].clearcoat.clearcoat_texture.extensions, data->materials[i].clearcoat.clearcoat_texture.extensions_count); - cgltf_free_extensions(data, data->materials[i].clearcoat.clearcoat_roughness_texture.extensions, data->materials[i].clearcoat.clearcoat_roughness_texture.extensions_count); - cgltf_free_extensions(data, data->materials[i].clearcoat.clearcoat_normal_texture.extensions, data->materials[i].clearcoat.clearcoat_normal_texture.extensions_count); + cgltf_free_texture_view(data, &data->materials[i].clearcoat.clearcoat_texture); + cgltf_free_texture_view(data, &data->materials[i].clearcoat.clearcoat_roughness_texture); + cgltf_free_texture_view(data, &data->materials[i].clearcoat.clearcoat_normal_texture); } if(data->materials[i].has_specular) { - cgltf_free_extensions(data, data->materials[i].specular.specular_texture.extensions, data->materials[i].specular.specular_texture.extensions_count); - cgltf_free_extensions(data, data->materials[i].specular.specular_color_texture.extensions, data->materials[i].specular.specular_color_texture.extensions_count); + cgltf_free_texture_view(data, &data->materials[i].specular.specular_texture); + cgltf_free_texture_view(data, &data->materials[i].specular.specular_color_texture); } if(data->materials[i].has_transmission) { - cgltf_free_extensions(data, data->materials[i].transmission.transmission_texture.extensions, data->materials[i].transmission.transmission_texture.extensions_count); + cgltf_free_texture_view(data, &data->materials[i].transmission.transmission_texture); } if (data->materials[i].has_volume) { - cgltf_free_extensions(data, data->materials[i].volume.thickness_texture.extensions, data->materials[i].volume.thickness_texture.extensions_count); + cgltf_free_texture_view(data, &data->materials[i].volume.thickness_texture); } if(data->materials[i].has_sheen) { - cgltf_free_extensions(data, data->materials[i].sheen.sheen_color_texture.extensions, data->materials[i].sheen.sheen_color_texture.extensions_count); - cgltf_free_extensions(data, data->materials[i].sheen.sheen_roughness_texture.extensions, data->materials[i].sheen.sheen_roughness_texture.extensions_count); + cgltf_free_texture_view(data, &data->materials[i].sheen.sheen_color_texture); + cgltf_free_texture_view(data, &data->materials[i].sheen.sheen_roughness_texture); } if(data->materials[i].has_iridescence) { - cgltf_free_extensions(data, data->materials[i].iridescence.iridescence_texture.extensions, data->materials[i].iridescence.iridescence_texture.extensions_count); - cgltf_free_extensions(data, data->materials[i].iridescence.iridescence_thickness_texture.extensions, data->materials[i].iridescence.iridescence_thickness_texture.extensions_count); + cgltf_free_texture_view(data, &data->materials[i].iridescence.iridescence_texture); + cgltf_free_texture_view(data, &data->materials[i].iridescence.iridescence_thickness_texture); } - cgltf_free_extensions(data, data->materials[i].normal_texture.extensions, data->materials[i].normal_texture.extensions_count); - cgltf_free_extensions(data, data->materials[i].occlusion_texture.extensions, data->materials[i].occlusion_texture.extensions_count); - cgltf_free_extensions(data, data->materials[i].emissive_texture.extensions, data->materials[i].emissive_texture.extensions_count); + cgltf_free_texture_view(data, &data->materials[i].normal_texture); + cgltf_free_texture_view(data, &data->materials[i].occlusion_texture); + cgltf_free_texture_view(data, &data->materials[i].emissive_texture); cgltf_free_extensions(data, data->materials[i].extensions, data->materials[i].extensions_count); + cgltf_free_extras(data, &data->materials[i].extras); } data->memory.free_func(data->memory.user_data, data->materials); @@ -1929,6 +1956,7 @@ void cgltf_free(cgltf_data* data) data->memory.free_func(data->memory.user_data, data->images[i].mime_type); cgltf_free_extensions(data, data->images[i].extensions, data->images[i].extensions_count); + cgltf_free_extras(data, &data->images[i].extras); } data->memory.free_func(data->memory.user_data, data->images); @@ -1936,7 +1964,9 @@ void cgltf_free(cgltf_data* data) for (cgltf_size i = 0; i < data->textures_count; ++i) { data->memory.free_func(data->memory.user_data, data->textures[i].name); + cgltf_free_extensions(data, data->textures[i].extensions, data->textures[i].extensions_count); + cgltf_free_extras(data, &data->textures[i].extras); } data->memory.free_func(data->memory.user_data, data->textures); @@ -1944,7 +1974,9 @@ void cgltf_free(cgltf_data* data) for (cgltf_size i = 0; i < data->samplers_count; ++i) { data->memory.free_func(data->memory.user_data, data->samplers[i].name); + cgltf_free_extensions(data, data->samplers[i].extensions, data->samplers[i].extensions_count); + cgltf_free_extras(data, &data->samplers[i].extras); } data->memory.free_func(data->memory.user_data, data->samplers); @@ -1955,6 +1987,7 @@ void cgltf_free(cgltf_data* data) data->memory.free_func(data->memory.user_data, data->skins[i].joints); cgltf_free_extensions(data, data->skins[i].extensions, data->skins[i].extensions_count); + cgltf_free_extras(data, &data->skins[i].extras); } data->memory.free_func(data->memory.user_data, data->skins); @@ -1962,7 +1995,18 @@ void cgltf_free(cgltf_data* data) for (cgltf_size i = 0; i < data->cameras_count; ++i) { data->memory.free_func(data->memory.user_data, data->cameras[i].name); + + if (data->cameras[i].type == cgltf_camera_type_perspective) + { + cgltf_free_extras(data, &data->cameras[i].data.perspective.extras); + } + else if (data->cameras[i].type == cgltf_camera_type_orthographic) + { + cgltf_free_extras(data, &data->cameras[i].data.orthographic.extras); + } + cgltf_free_extensions(data, data->cameras[i].extensions, data->cameras[i].extensions_count); + cgltf_free_extras(data, &data->cameras[i].extras); } data->memory.free_func(data->memory.user_data, data->cameras); @@ -1970,6 +2014,8 @@ void cgltf_free(cgltf_data* data) for (cgltf_size i = 0; i < data->lights_count; ++i) { data->memory.free_func(data->memory.user_data, data->lights[i].name); + + cgltf_free_extras(data, &data->lights[i].extras); } data->memory.free_func(data->memory.user_data, data->lights); @@ -1979,7 +2025,19 @@ void cgltf_free(cgltf_data* data) data->memory.free_func(data->memory.user_data, data->nodes[i].name); data->memory.free_func(data->memory.user_data, data->nodes[i].children); data->memory.free_func(data->memory.user_data, data->nodes[i].weights); + + if (data->nodes[i].has_mesh_gpu_instancing) + { + for (cgltf_size j = 0; j < data->nodes[i].mesh_gpu_instancing.attributes_count; ++j) + { + data->memory.free_func(data->memory.user_data, data->nodes[i].mesh_gpu_instancing.attributes[j].name); + } + + data->memory.free_func(data->memory.user_data, data->nodes[i].mesh_gpu_instancing.attributes); + } + cgltf_free_extensions(data, data->nodes[i].extensions, data->nodes[i].extensions_count); + cgltf_free_extras(data, &data->nodes[i].extras); } data->memory.free_func(data->memory.user_data, data->nodes); @@ -1990,6 +2048,7 @@ void cgltf_free(cgltf_data* data) data->memory.free_func(data->memory.user_data, data->scenes[i].nodes); cgltf_free_extensions(data, data->scenes[i].extensions, data->scenes[i].extensions_count); + cgltf_free_extras(data, &data->scenes[i].extras); } data->memory.free_func(data->memory.user_data, data->scenes); @@ -2000,16 +2059,19 @@ void cgltf_free(cgltf_data* data) for (cgltf_size j = 0; j < data->animations[i].samplers_count; ++j) { cgltf_free_extensions(data, data->animations[i].samplers[j].extensions, data->animations[i].samplers[j].extensions_count); + cgltf_free_extras(data, &data->animations[i].samplers[j].extras); } data->memory.free_func(data->memory.user_data, data->animations[i].samplers); for (cgltf_size j = 0; j < data->animations[i].channels_count; ++j) { cgltf_free_extensions(data, data->animations[i].channels[j].extensions, data->animations[i].channels[j].extensions_count); + cgltf_free_extras(data, &data->animations[i].channels[j].extras); } data->memory.free_func(data->memory.user_data, data->animations[i].channels); cgltf_free_extensions(data, data->animations[i].extensions, data->animations[i].extensions_count); + cgltf_free_extras(data, &data->animations[i].extras); } data->memory.free_func(data->memory.user_data, data->animations); @@ -2017,11 +2079,14 @@ void cgltf_free(cgltf_data* data) for (cgltf_size i = 0; i < data->variants_count; ++i) { data->memory.free_func(data->memory.user_data, data->variants[i].name); + + cgltf_free_extras(data, &data->variants[i].extras); } data->memory.free_func(data->memory.user_data, data->variants); cgltf_free_extensions(data, data->data_extensions, data->data_extensions_count); + cgltf_free_extras(data, &data->extras); for (cgltf_size i = 0; i < data->extensions_used_count; ++i) { @@ -2440,7 +2505,7 @@ static int cgltf_json_strcmp(jsmntok_t const* tok, const uint8_t* json_chunk, co { CGLTF_CHECK_TOKTYPE(*tok, JSMN_STRING); size_t const str_len = strlen(str); - size_t const name_length = tok->end - tok->start; + size_t const name_length = (size_t)(tok->end - tok->start); return (str_len == name_length) ? strncmp((const char*)json_chunk + tok->start, str, str_len) : 128; } @@ -2448,7 +2513,7 @@ static int cgltf_json_to_int(jsmntok_t const* tok, const uint8_t* json_chunk) { CGLTF_CHECK_TOKTYPE(*tok, JSMN_PRIMITIVE); char tmp[128]; - int size = (cgltf_size)(tok->end - tok->start) < sizeof(tmp) ? tok->end - tok->start : (int)(sizeof(tmp) - 1); + int size = (size_t)(tok->end - tok->start) < sizeof(tmp) ? (int)(tok->end - tok->start) : (int)(sizeof(tmp) - 1); strncpy(tmp, (const char*)json_chunk + tok->start, size); tmp[size] = 0; return CGLTF_ATOI(tmp); @@ -2458,7 +2523,7 @@ static cgltf_size cgltf_json_to_size(jsmntok_t const* tok, const uint8_t* json_c { CGLTF_CHECK_TOKTYPE_RETTYPE(*tok, JSMN_PRIMITIVE, cgltf_size); char tmp[128]; - int size = (cgltf_size)(tok->end - tok->start) < sizeof(tmp) ? tok->end - tok->start : (int)(sizeof(tmp) - 1); + int size = (size_t)(tok->end - tok->start) < sizeof(tmp) ? (int)(tok->end - tok->start) : (int)(sizeof(tmp) - 1); strncpy(tmp, (const char*)json_chunk + tok->start, size); tmp[size] = 0; return (cgltf_size)CGLTF_ATOLL(tmp); @@ -2468,7 +2533,7 @@ static cgltf_float cgltf_json_to_float(jsmntok_t const* tok, const uint8_t* json { CGLTF_CHECK_TOKTYPE(*tok, JSMN_PRIMITIVE); char tmp[128]; - int size = (cgltf_size)(tok->end - tok->start) < sizeof(tmp) ? tok->end - tok->start : (int)(sizeof(tmp) - 1); + int size = (size_t)(tok->end - tok->start) < sizeof(tmp) ? (int)(tok->end - tok->start) : (int)(sizeof(tmp) - 1); strncpy(tmp, (const char*)json_chunk + tok->start, size); tmp[size] = 0; return (cgltf_float)CGLTF_ATOF(tmp); @@ -2476,7 +2541,7 @@ static cgltf_float cgltf_json_to_float(jsmntok_t const* tok, const uint8_t* json static cgltf_bool cgltf_json_to_bool(jsmntok_t const* tok, const uint8_t* json_chunk) { - int size = tok->end - tok->start; + int size = (int)(tok->end - tok->start); return size == 4 && memcmp(json_chunk + tok->start, "true", 4) == 0; } @@ -2542,7 +2607,7 @@ static int cgltf_parse_json_string(cgltf_options* options, jsmntok_t const* toke { return CGLTF_ERROR_JSON; } - int size = tokens[i].end - tokens[i].start; + int size = (int)(tokens[i].end - tokens[i].start); char* result = (char*)options->memory.alloc_func(options->memory.user_data, size + 1); if (!result) { @@ -2683,11 +2748,27 @@ static int cgltf_parse_json_attribute_list(cgltf_options* options, jsmntok_t con return i; } -static int cgltf_parse_json_extras(jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_extras* out_extras) +static int cgltf_parse_json_extras(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_extras* out_extras) { - (void)json_chunk; + if (out_extras->data) + { + return CGLTF_ERROR_JSON; + } + + /* fill deprecated fields for now, this will be removed in the future */ out_extras->start_offset = tokens[i].start; out_extras->end_offset = tokens[i].end; + + size_t start = tokens[i].start; + size_t size = tokens[i].end - start; + out_extras->data = (char*)options->memory.alloc_func(options->memory.user_data, size + 1); + if (!out_extras->data) + { + return CGLTF_ERROR_NOMEM; + } + strncpy(out_extras->data, (const char*)json_chunk + start, size); + out_extras->data[size] = '\0'; + i = cgltf_skip_json(tokens, i); return i; } @@ -2842,7 +2923,7 @@ static int cgltf_parse_json_material_mapping_data(cgltf_options* options, jsmnto int material = -1; int variants_tok = -1; - cgltf_extras extras = {0, 0}; + int extras_tok = -1; for (int k = 0; k < obj_size; ++k) { @@ -2863,7 +2944,8 @@ static int cgltf_parse_json_material_mapping_data(cgltf_options* options, jsmnto } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) { - i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &extras); + extras_tok = i + 1; + i = cgltf_skip_json(tokens, extras_tok); } else { @@ -2891,7 +2973,13 @@ static int cgltf_parse_json_material_mapping_data(cgltf_options* options, jsmnto out_mappings[*offset].material = CGLTF_PTRINDEX(cgltf_material, material); out_mappings[*offset].variant = variant; - out_mappings[*offset].extras = extras; + + if (extras_tok >= 0) + { + int e = cgltf_parse_json_extras(options, tokens, extras_tok, json_chunk, &out_mappings[*offset].extras); + if (e < 0) + return e; + } (*offset)++; } @@ -3006,7 +3094,7 @@ static int cgltf_parse_json_primitive(cgltf_options* options, jsmntok_t const* t } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) { - i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_prim->extras); + i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_prim->extras); } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) { @@ -3253,7 +3341,7 @@ static int cgltf_parse_json_accessor_sparse(cgltf_options* options, jsmntok_t co } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) { - i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_sparse->indices_extras); + i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_sparse->indices_extras); } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) { @@ -3296,7 +3384,7 @@ static int cgltf_parse_json_accessor_sparse(cgltf_options* options, jsmntok_t co } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) { - i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_sparse->values_extras); + i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_sparse->values_extras); } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) { @@ -3315,7 +3403,7 @@ static int cgltf_parse_json_accessor_sparse(cgltf_options* options, jsmntok_t co } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) { - i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_sparse->extras); + i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_sparse->extras); } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) { @@ -3438,7 +3526,7 @@ static int cgltf_parse_json_accessor(cgltf_options* options, jsmntok_t const* to } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) { - i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_accessor->extras); + i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_accessor->extras); } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) { @@ -3544,7 +3632,7 @@ static int cgltf_parse_json_texture_view(cgltf_options* options, jsmntok_t const } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) { - i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_texture_view->extras); + i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_texture_view->extras); } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) { @@ -3640,10 +3728,6 @@ static int cgltf_parse_json_pbr_metallic_roughness(cgltf_options* options, jsmnt i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_pbr->metallic_roughness_texture); } - else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) - { - i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_pbr->extras); - } else { i = cgltf_skip_json(tokens, i+1); @@ -4076,7 +4160,7 @@ static int cgltf_parse_json_image(cgltf_options* options, jsmntok_t const* token } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) { - i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_image->extras); + i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_image->extras); } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) { @@ -4145,7 +4229,7 @@ static int cgltf_parse_json_sampler(cgltf_options* options, jsmntok_t const* tok } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) { - i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_sampler->extras); + i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_sampler->extras); } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) { @@ -4194,7 +4278,7 @@ static int cgltf_parse_json_texture(cgltf_options* options, jsmntok_t const* tok } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) { - i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_texture->extras); + i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_texture->extras); } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) { @@ -4357,7 +4441,7 @@ static int cgltf_parse_json_material(cgltf_options* options, jsmntok_t const* to } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) { - i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_material->extras); + i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_material->extras); } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) { @@ -4710,7 +4794,7 @@ static int cgltf_parse_json_buffer_view(cgltf_options* options, jsmntok_t const* } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) { - i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_buffer_view->extras); + i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_buffer_view->extras); } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) { @@ -4813,7 +4897,7 @@ static int cgltf_parse_json_buffer(cgltf_options* options, jsmntok_t const* toke } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) { - i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_buffer->extras); + i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_buffer->extras); } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) { @@ -4897,7 +4981,7 @@ static int cgltf_parse_json_skin(cgltf_options* options, jsmntok_t const* tokens } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) { - i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_skin->extras); + i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_skin->extras); } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) { @@ -4951,19 +5035,6 @@ static int cgltf_parse_json_camera(cgltf_options* options, jsmntok_t const* toke { i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_camera->name); } - else if (cgltf_json_strcmp(tokens+i, json_chunk, "type") == 0) - { - ++i; - if (cgltf_json_strcmp(tokens + i, json_chunk, "perspective") == 0) - { - out_camera->type = cgltf_camera_type_perspective; - } - else if (cgltf_json_strcmp(tokens + i, json_chunk, "orthographic") == 0) - { - out_camera->type = cgltf_camera_type_orthographic; - } - ++i; - } else if (cgltf_json_strcmp(tokens+i, json_chunk, "perspective") == 0) { ++i; @@ -4973,6 +5044,11 @@ static int cgltf_parse_json_camera(cgltf_options* options, jsmntok_t const* toke int data_size = tokens[i].size; ++i; + if (out_camera->type != cgltf_camera_type_invalid) + { + return CGLTF_ERROR_JSON; + } + out_camera->type = cgltf_camera_type_perspective; for (int k = 0; k < data_size; ++k) @@ -5007,7 +5083,7 @@ static int cgltf_parse_json_camera(cgltf_options* options, jsmntok_t const* toke } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) { - i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_camera->data.perspective.extras); + i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_camera->data.perspective.extras); } else { @@ -5029,6 +5105,11 @@ static int cgltf_parse_json_camera(cgltf_options* options, jsmntok_t const* toke int data_size = tokens[i].size; ++i; + if (out_camera->type != cgltf_camera_type_invalid) + { + return CGLTF_ERROR_JSON; + } + out_camera->type = cgltf_camera_type_orthographic; for (int k = 0; k < data_size; ++k) @@ -5061,7 +5142,7 @@ static int cgltf_parse_json_camera(cgltf_options* options, jsmntok_t const* toke } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) { - i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_camera->data.orthographic.extras); + i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_camera->data.orthographic.extras); } else { @@ -5076,7 +5157,7 @@ static int cgltf_parse_json_camera(cgltf_options* options, jsmntok_t const* toke } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) { - i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_camera->extras); + i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_camera->extras); } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) { @@ -5209,7 +5290,7 @@ static int cgltf_parse_json_light(cgltf_options* options, jsmntok_t const* token } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) { - i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_light->extras); + i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_light->extras); } else { @@ -5335,7 +5416,7 @@ static int cgltf_parse_json_node(cgltf_options* options, jsmntok_t const* tokens } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) { - i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_node->extras); + i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_node->extras); } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) { @@ -5473,7 +5554,7 @@ static int cgltf_parse_json_scene(cgltf_options* options, jsmntok_t const* token } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) { - i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_scene->extras); + i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_scene->extras); } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) { @@ -5555,7 +5636,7 @@ static int cgltf_parse_json_animation_sampler(cgltf_options* options, jsmntok_t } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) { - i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_sampler->extras); + i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_sampler->extras); } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) { @@ -5635,7 +5716,7 @@ static int cgltf_parse_json_animation_channel(cgltf_options* options, jsmntok_t } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) { - i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_channel->extras); + i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_channel->extras); } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) { @@ -5717,7 +5798,7 @@ static int cgltf_parse_json_animation(cgltf_options* options, jsmntok_t const* t } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) { - i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_animation->extras); + i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_animation->extras); } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) { @@ -5773,7 +5854,7 @@ static int cgltf_parse_json_variant(cgltf_options* options, jsmntok_t const* tok } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) { - i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_variant->extras); + i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_variant->extras); } else { @@ -5837,7 +5918,7 @@ static int cgltf_parse_json_asset(cgltf_options* options, jsmntok_t const* token } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) { - i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_asset->extras); + i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_asset->extras); } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) { @@ -5993,7 +6074,7 @@ static int cgltf_parse_json_root(cgltf_options* options, jsmntok_t const* tokens } else if (cgltf_json_strcmp(tokens+i, json_chunk, "extras") == 0) { - i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_data->extras); + i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_data->extras); } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) { @@ -6420,7 +6501,7 @@ static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, * Fills token type and boundaries. */ static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type, - int start, int end) { + ptrdiff_t start, ptrdiff_t end) { token->type = type; token->start = start; token->end = end; @@ -6433,7 +6514,7 @@ static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type, static int jsmn_parse_primitive(jsmn_parser *parser, const char *js, size_t len, jsmntok_t *tokens, size_t num_tokens) { jsmntok_t *token; - int start; + ptrdiff_t start; start = parser->pos; @@ -6483,7 +6564,7 @@ static int jsmn_parse_string(jsmn_parser *parser, const char *js, size_t len, jsmntok_t *tokens, size_t num_tokens) { jsmntok_t *token; - int start = parser->pos; + ptrdiff_t start = parser->pos; parser->pos++; diff --git a/src/external/dr_flac.h b/src/external/dr_flac.h index e0b3649a20b2..0c43eed7f559 100644 --- a/src/external/dr_flac.h +++ b/src/external/dr_flac.h @@ -1,6 +1,6 @@ /* FLAC audio decoder. Choice of public domain or MIT-0. See license statements at the end of this file. -dr_flac - v0.12.31 - 2021-08-16 +dr_flac - v0.12.39 - 2022-09-17 David Reid - mackron@gmail.com @@ -210,6 +210,9 @@ Build Options #define DR_FLAC_NO_SIMD Disables SIMD optimizations (SSE on x86/x64 architectures, NEON on ARM architectures). Use this if you are having compatibility issues with your compiler. +#define DR_FLAC_NO_WCHAR + Disables all functions ending with `_w`. Use this if your compiler does not provide wchar.h. Not required if DR_FLAC_NO_STDIO is also defined. + Notes @@ -232,7 +235,7 @@ extern "C" { #define DRFLAC_VERSION_MAJOR 0 #define DRFLAC_VERSION_MINOR 12 -#define DRFLAC_VERSION_REVISION 31 +#define DRFLAC_VERSION_REVISION 39 #define DRFLAC_VERSION_STRING DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MAJOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MINOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_REVISION) #include /* For size_t. */ @@ -244,7 +247,7 @@ typedef signed short drflac_int16; typedef unsigned short drflac_uint16; typedef signed int drflac_int32; typedef unsigned int drflac_uint32; -#if defined(_MSC_VER) +#if defined(_MSC_VER) && !defined(__clang__) typedef signed __int64 drflac_int64; typedef unsigned __int64 drflac_uint64; #else @@ -261,7 +264,7 @@ typedef unsigned int drflac_uint32; #pragma GCC diagnostic pop #endif #endif -#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(_M_ARM64) || defined(__powerpc64__) +#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined(_M_IA64) || defined(__aarch64__) || defined(_M_ARM64) || defined(__powerpc64__) typedef drflac_uint64 drflac_uintptr; #else typedef drflac_uint32 drflac_uintptr; @@ -383,15 +386,13 @@ typedef enum drflac_seek_origin_current } drflac_seek_origin; -/* Packing is important on this structure because we map this directly to the raw data within the SEEKTABLE metadata block. */ -#pragma pack(2) +/* The order of members in this structure is important because we map this directly to the raw data within the SEEKTABLE metadata block. */ typedef struct { drflac_uint64 firstPCMFrame; drflac_uint64 flacFrameOffset; /* The offset from the first byte of the header of the first frame. */ drflac_uint16 pcmFrameCount; } drflac_seekpoint; -#pragma pack() typedef struct { @@ -1280,15 +1281,13 @@ typedef struct const char* pRunningData; } drflac_cuesheet_track_iterator; -/* Packing is important on this structure because we map this directly to the raw data within the CUESHEET metadata block. */ -#pragma pack(4) +/* The order of members here is important because we map this directly to the raw data within the CUESHEET metadata block. */ typedef struct { drflac_uint64 offset; drflac_uint8 index; drflac_uint8 reserved[3]; } drflac_cuesheet_track_index; -#pragma pack() typedef struct { @@ -1363,9 +1362,15 @@ DRFLAC_API drflac_bool32 drflac_next_cuesheet_track(drflac_cuesheet_track_iterat I am using "__inline__" only when we're compiling in strict ANSI mode. */ #if defined(__STRICT_ANSI__) - #define DRFLAC_INLINE __inline__ __attribute__((always_inline)) + #define DRFLAC_GNUC_INLINE_HINT __inline__ #else - #define DRFLAC_INLINE inline __attribute__((always_inline)) + #define DRFLAC_GNUC_INLINE_HINT inline + #endif + + #if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 2)) || defined(__clang__) + #define DRFLAC_INLINE DRFLAC_GNUC_INLINE_HINT __attribute__((always_inline)) + #else + #define DRFLAC_INLINE DRFLAC_GNUC_INLINE_HINT #endif #elif defined(__WATCOMC__) #define DRFLAC_INLINE __inline @@ -1378,7 +1383,7 @@ DRFLAC_API drflac_bool32 drflac_next_cuesheet_track(drflac_cuesheet_track_iterat #define DRFLAC_X64 #elif defined(__i386) || defined(_M_IX86) #define DRFLAC_X86 -#elif defined(__arm__) || defined(_M_ARM) || defined(_M_ARM64) +#elif defined(__arm__) || defined(_M_ARM) || defined(__arm64) || defined(__arm64__) || defined(__aarch64__) || defined(_M_ARM64) #define DRFLAC_ARM #endif @@ -1431,16 +1436,6 @@ Unfortuantely dr_flac depends on this for a few things so we're just going to di #if defined(DRFLAC_ARM) #if !defined(DRFLAC_NO_NEON) && (defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64)) #define DRFLAC_SUPPORT_NEON - #endif - - /* Fall back to looking for the #include file. */ - #if !defined(__GNUC__) && !defined(__clang__) && defined(__has_include) - #if !defined(DRFLAC_SUPPORT_NEON) && !defined(DRFLAC_NO_NEON) && __has_include() - #define DRFLAC_SUPPORT_NEON - #endif - #endif - - #if defined(DRFLAC_SUPPORT_NEON) #include #endif #endif @@ -1519,9 +1514,7 @@ static DRFLAC_INLINE drflac_bool32 drflac_has_sse41(void) { #if defined(DRFLAC_SUPPORT_SSE41) #if (defined(DRFLAC_X64) || defined(DRFLAC_X86)) && !defined(DRFLAC_NO_SSE41) - #if defined(DRFLAC_X64) - return DRFLAC_TRUE; /* 64-bit targets always support SSE4.1. */ - #elif (defined(_M_IX86_FP) && _M_IX86_FP == 2) || defined(__SSE4_1__) + #if defined(__SSE4_1__) || defined(__AVX__) return DRFLAC_TRUE; /* If the compiler is allowed to freely generate SSE41 code we can assume support. */ #else #if defined(DRFLAC_NO_CPUID) @@ -1586,18 +1579,21 @@ static DRFLAC_INLINE drflac_bool32 drflac_has_sse41(void) extern __inline drflac_uint64 _watcom_bswap64(drflac_uint64); #pragma aux _watcom_bswap16 = \ "xchg al, ah" \ - parm [ax] \ - modify [ax]; + parm [ax] \ + value [ax] \ + modify nomemory; #pragma aux _watcom_bswap32 = \ - "bswap eax" \ - parm [eax] \ - modify [eax]; + "bswap eax" \ + parm [eax] \ + value [eax] \ + modify nomemory; #pragma aux _watcom_bswap64 = \ "bswap eax" \ "bswap edx" \ "xchg eax,edx" \ parm [eax edx] \ - modify [eax edx]; + value [eax edx] \ + modify nomemory; #endif @@ -1698,6 +1694,10 @@ typedef drflac_int32 drflac_result; #define DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE 9 #define DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE 10 +#define DRFLAC_SEEKPOINT_SIZE_IN_BYTES 18 +#define DRFLAC_CUESHEET_TRACK_SIZE_IN_BYTES 36 +#define DRFLAC_CUESHEET_TRACK_INDEX_SIZE_IN_BYTES 12 + #define drflac_align(x, a) ((((x) + (a) - 1) / (a)) * (a)) @@ -1909,6 +1909,12 @@ static DRFLAC_INLINE drflac_uint32 drflac__be2host_32(drflac_uint32 n) return n; } +static DRFLAC_INLINE drflac_uint32 drflac__be2host_32_ptr_unaligned(const void* pData) +{ + const drflac_uint8* pNum = (drflac_uint8*)pData; + return *(pNum) << 24 | *(pNum+1) << 16 | *(pNum+2) << 8 | *(pNum+3); +} + static DRFLAC_INLINE drflac_uint64 drflac__be2host_64(drflac_uint64 n) { if (drflac__is_little_endian()) { @@ -1928,6 +1934,12 @@ static DRFLAC_INLINE drflac_uint32 drflac__le2host_32(drflac_uint32 n) return n; } +static DRFLAC_INLINE drflac_uint32 drflac__le2host_32_ptr_unaligned(const void* pData) +{ + const drflac_uint8* pNum = (drflac_uint8*)pData; + return *pNum | *(pNum+1) << 8 | *(pNum+2) << 16 | *(pNum+3) << 24; +} + static DRFLAC_INLINE drflac_uint32 drflac__unsynchsafe_32(drflac_uint32 n) { @@ -2429,6 +2441,10 @@ static DRFLAC_INLINE drflac_bool32 drflac__read_uint32(drflac_bs* bs, unsigned i if (!drflac__reload_cache(bs)) { return DRFLAC_FALSE; } + if (bitCountLo > DRFLAC_CACHE_L1_BITS_REMAINING(bs)) { + /* This happens when we get to end of stream */ + return DRFLAC_FALSE; + } *pResultOut = (resultHi << bitCountLo) | (drflac_uint32)DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCountLo); bs->consumedBits += bitCountLo; @@ -2684,6 +2700,10 @@ static drflac_bool32 drflac__find_and_seek_to_next_sync_code(drflac_bs* bs) #if defined(__WATCOMC__) && defined(__386__) #define DRFLAC_IMPLEMENT_CLZ_WATCOM #endif +#ifdef __MRC__ +#include +#define DRFLAC_IMPLEMENT_CLZ_MRC +#endif static DRFLAC_INLINE drflac_uint32 drflac__clz_software(drflac_cache_t x) { @@ -2724,6 +2744,8 @@ static DRFLAC_INLINE drflac_bool32 drflac__is_lzcnt_supported(void) /* Fast compile time check for ARM. */ #if defined(DRFLAC_HAS_LZCNT_INTRINSIC) && defined(DRFLAC_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 5) return DRFLAC_TRUE; +#elif defined(__MRC__) + return DRFLAC_TRUE; #else /* If the compiler itself does not support the intrinsic then we'll need to return false. */ #ifdef DRFLAC_HAS_LZCNT_INTRINSIC @@ -2833,6 +2855,15 @@ static DRFLAC_INLINE drflac_uint32 drflac__clz_msvc(drflac_cache_t x) #ifdef DRFLAC_IMPLEMENT_CLZ_WATCOM static __inline drflac_uint32 drflac__clz_watcom (drflac_uint32); +#ifdef DRFLAC_IMPLEMENT_CLZ_WATCOM_LZCNT +/* Use the LZCNT instruction (only available on some processors since the 2010s). */ +#pragma aux drflac__clz_watcom_lzcnt = \ + "db 0F3h, 0Fh, 0BDh, 0C0h" /* lzcnt eax, eax */ \ + parm [eax] \ + value [eax] \ + modify nomemory; +#else +/* Use the 386+-compatible implementation. */ #pragma aux drflac__clz_watcom = \ "bsr eax, eax" \ "xor eax, 31" \ @@ -2840,6 +2871,7 @@ static __inline drflac_uint32 drflac__clz_watcom (drflac_uint32); value [eax] \ modify exact [eax] nomemory; #endif +#endif static DRFLAC_INLINE drflac_uint32 drflac__clz(drflac_cache_t x) { @@ -2851,8 +2883,12 @@ static DRFLAC_INLINE drflac_uint32 drflac__clz(drflac_cache_t x) { #ifdef DRFLAC_IMPLEMENT_CLZ_MSVC return drflac__clz_msvc(x); +#elif defined(DRFLAC_IMPLEMENT_CLZ_WATCOM_LZCNT) + return drflac__clz_watcom_lzcnt(x); #elif defined(DRFLAC_IMPLEMENT_CLZ_WATCOM) return (x == 0) ? sizeof(x)*8 : drflac__clz_watcom(x); +#elif defined(__MRC__) + return __cntlzw(x); #else return drflac__clz_software(x); #endif @@ -2872,9 +2908,24 @@ static DRFLAC_INLINE drflac_bool32 drflac__seek_past_next_set_bit(drflac_bs* bs, } } + if (bs->cache == 1) { + /* Not catching this would lead to undefined behaviour: a shift of a 32-bit number by 32 or more is undefined */ + *pOffsetOut = zeroCounter + (drflac_uint32)DRFLAC_CACHE_L1_BITS_REMAINING(bs) - 1; + if (!drflac__reload_cache(bs)) { + return DRFLAC_FALSE; + } + + return DRFLAC_TRUE; + } + setBitOffsetPlus1 = drflac__clz(bs->cache); setBitOffsetPlus1 += 1; + if (setBitOffsetPlus1 > DRFLAC_CACHE_L1_BITS_REMAINING(bs)) { + /* This happens when we get to end of stream */ + return DRFLAC_FALSE; + } + bs->consumedBits += setBitOffsetPlus1; bs->cache <<= setBitOffsetPlus1; @@ -2989,6 +3040,25 @@ static drflac_result drflac__read_utf8_coded_number(drflac_bs* bs, drflac_uint64 } +static DRFLAC_INLINE drflac_uint32 drflac__ilog2_u32(drflac_uint32 x) +{ +#if 1 /* Needs optimizing. */ + drflac_uint32 result = 0; + while (x > 0) { + result += 1; + x >>= 1; + } + + return result; +#endif +} + +static DRFLAC_INLINE drflac_bool32 drflac__use_64_bit_prediction(drflac_uint32 bitsPerSample, drflac_uint32 order, drflac_uint32 precision) +{ + /* https://web.archive.org/web/20220205005724/https://github.com/ietf-wg-cellar/flac-specification/blob/37a49aa48ba4ba12e8757badfc59c0df35435fec/rfc_backmatter.md */ + return bitsPerSample + precision + drflac__ilog2_u32(order) > 32; +} + /* The next two functions are responsible for calculating the prediction. @@ -2996,6 +3066,9 @@ The next two functions are responsible for calculating the prediction. When the bits per sample is >16 we need to use 64-bit integer arithmetic because otherwise we'll run out of precision. It's safe to assume this will be slower on 32-bit platforms so we use a more optimal solution when the bits per sample is <=16. */ +#if defined(__clang__) +__attribute__((no_sanitize("signed-integer-overflow"))) +#endif static DRFLAC_INLINE drflac_int32 drflac__calculate_prediction_32(drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pDecodedSamples) { drflac_int32 prediction = 0; @@ -3231,7 +3304,7 @@ static DRFLAC_INLINE drflac_int32 drflac__calculate_prediction_64(drflac_uint32 Reference implementation for reading and decoding samples with residual. This is intentionally left unoptimized for the sake of readability and should only be used as a reference. */ -static drflac_bool32 drflac__decode_samples_with_residual__rice__reference(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) +static drflac_bool32 drflac__decode_samples_with_residual__rice__reference(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 lpcOrder, drflac_int32 lpcShift, drflac_uint32 lpcPrecision, const drflac_int32* coefficients, drflac_int32* pSamplesOut) { drflac_uint32 i; @@ -3270,10 +3343,10 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__reference(drfla } - if (bitsPerSample+shift >= 32) { - pSamplesOut[i] = decodedRice + drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + i); + if (drflac__use_64_bit_prediction(bitsPerSample, lpcOrder, lpcPrecision)) { + pSamplesOut[i] = decodedRice + drflac__calculate_prediction_64(lpcOrder, lpcShift, coefficients, pSamplesOut + i); } else { - pSamplesOut[i] = decodedRice + drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + i); + pSamplesOut[i] = decodedRice + drflac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + i); } } @@ -3370,6 +3443,10 @@ static DRFLAC_INLINE drflac_bool32 drflac__read_rice_parts(drflac_bs* bs, drflac if (!drflac__reload_cache(bs)) { return DRFLAC_FALSE; } + if (bitCountLo > DRFLAC_CACHE_L1_BITS_REMAINING(bs)) { + /* This happens when we get to end of stream */ + return DRFLAC_FALSE; + } } riceParamPart = (drflac_uint32)(resultHi | DRFLAC_CACHE_L1_SELECT_AND_SHIFT_SAFE(bs, bitCountLo)); @@ -3450,6 +3527,10 @@ static DRFLAC_INLINE drflac_bool32 drflac__read_rice_parts_x1(drflac_bs* bs, drf if (!drflac__reload_cache(bs)) { return DRFLAC_FALSE; } + if (riceParamPartLoBitCount > DRFLAC_CACHE_L1_BITS_REMAINING(bs)) { + /* This happens when we get to end of stream */ + return DRFLAC_FALSE; + } bs_cache = bs->cache; bs_consumedBits = bs->consumedBits + riceParamPartLoBitCount; @@ -3560,6 +3641,11 @@ static DRFLAC_INLINE drflac_bool32 drflac__seek_rice_parts(drflac_bs* bs, drflac return DRFLAC_FALSE; } + if (riceParamPartLoBitCount > DRFLAC_CACHE_L1_BITS_REMAINING(bs)) { + /* This happens when we get to end of stream */ + return DRFLAC_FALSE; + } + bs_cache = bs->cache; bs_consumedBits = bs->consumedBits + riceParamPartLoBitCount; } @@ -3646,7 +3732,7 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__scalar_zeroorde return DRFLAC_TRUE; } -static drflac_bool32 drflac__decode_samples_with_residual__rice__scalar(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) +static drflac_bool32 drflac__decode_samples_with_residual__rice__scalar(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 lpcOrder, drflac_int32 lpcShift, drflac_uint32 lpcPrecision, const drflac_int32* coefficients, drflac_int32* pSamplesOut) { drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF}; drflac_uint32 zeroCountPart0 = 0; @@ -3664,14 +3750,14 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__scalar(drflac_b DRFLAC_ASSERT(bs != NULL); DRFLAC_ASSERT(pSamplesOut != NULL); - if (order == 0) { - return drflac__decode_samples_with_residual__rice__scalar_zeroorder(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut); + if (lpcOrder == 0) { + return drflac__decode_samples_with_residual__rice__scalar_zeroorder(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, coefficients, pSamplesOut); } riceParamMask = (drflac_uint32)~((~0UL) << riceParam); pSamplesOutEnd = pSamplesOut + (count & ~3); - if (bitsPerSample+shift > 32) { + if (drflac__use_64_bit_prediction(bitsPerSample, lpcOrder, lpcPrecision)) { while (pSamplesOut < pSamplesOutEnd) { /* Rice extraction. It's faster to do this one at a time against local variables than it is to use the x4 version @@ -3699,10 +3785,10 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__scalar(drflac_b riceParamPart2 = (riceParamPart2 >> 1) ^ t[riceParamPart2 & 0x01]; riceParamPart3 = (riceParamPart3 >> 1) ^ t[riceParamPart3 & 0x01]; - pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + 0); - pSamplesOut[1] = riceParamPart1 + drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + 1); - pSamplesOut[2] = riceParamPart2 + drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + 2); - pSamplesOut[3] = riceParamPart3 + drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + 3); + pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_64(lpcOrder, lpcShift, coefficients, pSamplesOut + 0); + pSamplesOut[1] = riceParamPart1 + drflac__calculate_prediction_64(lpcOrder, lpcShift, coefficients, pSamplesOut + 1); + pSamplesOut[2] = riceParamPart2 + drflac__calculate_prediction_64(lpcOrder, lpcShift, coefficients, pSamplesOut + 2); + pSamplesOut[3] = riceParamPart3 + drflac__calculate_prediction_64(lpcOrder, lpcShift, coefficients, pSamplesOut + 3); pSamplesOut += 4; } @@ -3730,10 +3816,10 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__scalar(drflac_b riceParamPart2 = (riceParamPart2 >> 1) ^ t[riceParamPart2 & 0x01]; riceParamPart3 = (riceParamPart3 >> 1) ^ t[riceParamPart3 & 0x01]; - pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + 0); - pSamplesOut[1] = riceParamPart1 + drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + 1); - pSamplesOut[2] = riceParamPart2 + drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + 2); - pSamplesOut[3] = riceParamPart3 + drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + 3); + pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + 0); + pSamplesOut[1] = riceParamPart1 + drflac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + 1); + pSamplesOut[2] = riceParamPart2 + drflac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + 2); + pSamplesOut[3] = riceParamPart3 + drflac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + 3); pSamplesOut += 4; } @@ -3753,10 +3839,10 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__scalar(drflac_b /*riceParamPart0 = (riceParamPart0 >> 1) ^ (~(riceParamPart0 & 0x01) + 1);*/ /* Sample reconstruction. */ - if (bitsPerSample+shift > 32) { - pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + 0); + if (drflac__use_64_bit_prediction(bitsPerSample, lpcOrder, lpcPrecision)) { + pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_64(lpcOrder, lpcShift, coefficients, pSamplesOut + 0); } else { - pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + 0); + pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + 0); } i += 1; @@ -4212,20 +4298,20 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__sse41_64(drflac return DRFLAC_TRUE; } -static drflac_bool32 drflac__decode_samples_with_residual__rice__sse41(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) +static drflac_bool32 drflac__decode_samples_with_residual__rice__sse41(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 lpcOrder, drflac_int32 lpcShift, drflac_uint32 lpcPrecision, const drflac_int32* coefficients, drflac_int32* pSamplesOut) { DRFLAC_ASSERT(bs != NULL); DRFLAC_ASSERT(pSamplesOut != NULL); /* In my testing the order is rarely > 12, so in this case I'm going to simplify the SSE implementation by only handling order <= 12. */ - if (order > 0 && order <= 12) { - if (bitsPerSample+shift > 32) { - return drflac__decode_samples_with_residual__rice__sse41_64(bs, count, riceParam, order, shift, coefficients, pSamplesOut); + if (lpcOrder > 0 && lpcOrder <= 12) { + if (drflac__use_64_bit_prediction(bitsPerSample, lpcOrder, lpcPrecision)) { + return drflac__decode_samples_with_residual__rice__sse41_64(bs, count, riceParam, lpcOrder, lpcShift, coefficients, pSamplesOut); } else { - return drflac__decode_samples_with_residual__rice__sse41_32(bs, count, riceParam, order, shift, coefficients, pSamplesOut); + return drflac__decode_samples_with_residual__rice__sse41_32(bs, count, riceParam, lpcOrder, lpcShift, coefficients, pSamplesOut); } } else { - return drflac__decode_samples_with_residual__rice__scalar(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut); + return drflac__decode_samples_with_residual__rice__scalar(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, lpcPrecision, coefficients, pSamplesOut); } } #endif @@ -4364,7 +4450,7 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__neon_32(drflac_ const drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF}; - riceParamMask = ~((~0UL) << riceParam); + riceParamMask = (drflac_uint32)~((~0UL) << riceParam); riceParamMask128 = vdupq_n_u32(riceParamMask); riceParam128 = vdupq_n_s32(riceParam); @@ -4550,10 +4636,13 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__neon_64(drflac_ int32x4_t riceParam128; int64x1_t shift64; uint32x4_t one128; + int64x2_t prediction128 = { 0 }; + uint32x4_t zeroCountPart128; + uint32x4_t riceParamPart128; const drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF}; - riceParamMask = ~((~0UL) << riceParam); + riceParamMask = (drflac_uint32)~((~0UL) << riceParam); riceParamMask128 = vdupq_n_u32(riceParamMask); riceParam128 = vdupq_n_s32(riceParam); @@ -4562,7 +4651,7 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__neon_64(drflac_ /* Pre-loading the coefficients and prior samples is annoying because we need to ensure we don't try reading more than - what's available in the input buffers. It would be conenient to use a fall-through switch to do this, but this results + what's available in the input buffers. It would be convenient to use a fall-through switch to do this, but this results in strict aliasing warnings with GCC. To work around this I'm just doing something hacky. This feels a bit convoluted so I think there's opportunity for this to be simplified. */ @@ -4630,10 +4719,6 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__neon_64(drflac_ /* For this version we are doing one sample at a time. */ while (pDecodedSamples < pDecodedSamplesEnd) { - int64x2_t prediction128; - uint32x4_t zeroCountPart128; - uint32x4_t riceParamPart128; - if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[0], &riceParamParts[0]) || !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[1], &riceParamParts[1]) || !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[2], &riceParamParts[2]) || @@ -4710,41 +4795,41 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__neon_64(drflac_ return DRFLAC_TRUE; } -static drflac_bool32 drflac__decode_samples_with_residual__rice__neon(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) +static drflac_bool32 drflac__decode_samples_with_residual__rice__neon(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 lpcOrder, drflac_int32 lpcShift, drflac_uint32 lpcPrecision, const drflac_int32* coefficients, drflac_int32* pSamplesOut) { DRFLAC_ASSERT(bs != NULL); DRFLAC_ASSERT(pSamplesOut != NULL); /* In my testing the order is rarely > 12, so in this case I'm going to simplify the NEON implementation by only handling order <= 12. */ - if (order > 0 && order <= 12) { - if (bitsPerSample+shift > 32) { - return drflac__decode_samples_with_residual__rice__neon_64(bs, count, riceParam, order, shift, coefficients, pSamplesOut); + if (lpcOrder > 0 && lpcOrder <= 12) { + if (drflac__use_64_bit_prediction(bitsPerSample, lpcOrder, lpcPrecision)) { + return drflac__decode_samples_with_residual__rice__neon_64(bs, count, riceParam, lpcOrder, lpcShift, coefficients, pSamplesOut); } else { - return drflac__decode_samples_with_residual__rice__neon_32(bs, count, riceParam, order, shift, coefficients, pSamplesOut); + return drflac__decode_samples_with_residual__rice__neon_32(bs, count, riceParam, lpcOrder, lpcShift, coefficients, pSamplesOut); } } else { - return drflac__decode_samples_with_residual__rice__scalar(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut); + return drflac__decode_samples_with_residual__rice__scalar(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, lpcPrecision, coefficients, pSamplesOut); } } #endif -static drflac_bool32 drflac__decode_samples_with_residual__rice(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) +static drflac_bool32 drflac__decode_samples_with_residual__rice(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 lpcOrder, drflac_int32 lpcShift, drflac_uint32 lpcPrecision, const drflac_int32* coefficients, drflac_int32* pSamplesOut) { #if defined(DRFLAC_SUPPORT_SSE41) if (drflac__gIsSSE41Supported) { - return drflac__decode_samples_with_residual__rice__sse41(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut); + return drflac__decode_samples_with_residual__rice__sse41(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, lpcPrecision, coefficients, pSamplesOut); } else #elif defined(DRFLAC_SUPPORT_NEON) if (drflac__gIsNEONSupported) { - return drflac__decode_samples_with_residual__rice__neon(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut); + return drflac__decode_samples_with_residual__rice__neon(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, lpcPrecision, coefficients, pSamplesOut); } else #endif { /* Scalar fallback. */ #if 0 - return drflac__decode_samples_with_residual__rice__reference(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut); + return drflac__decode_samples_with_residual__rice__reference(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, lpcPrecision, coefficients, pSamplesOut); #else - return drflac__decode_samples_with_residual__rice__scalar(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut); + return drflac__decode_samples_with_residual__rice__scalar(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, lpcPrecision, coefficients, pSamplesOut); #endif } } @@ -4765,7 +4850,10 @@ static drflac_bool32 drflac__read_and_seek_residual__rice(drflac_bs* bs, drflac_ return DRFLAC_TRUE; } -static drflac_bool32 drflac__decode_samples_with_residual__unencoded(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 unencodedBitsPerSample, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) +#if defined(__clang__) +__attribute__((no_sanitize("signed-integer-overflow"))) +#endif +static drflac_bool32 drflac__decode_samples_with_residual__unencoded(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 unencodedBitsPerSample, drflac_uint32 lpcOrder, drflac_int32 lpcShift, drflac_uint32 lpcPrecision, const drflac_int32* coefficients, drflac_int32* pSamplesOut) { drflac_uint32 i; @@ -4782,10 +4870,10 @@ static drflac_bool32 drflac__decode_samples_with_residual__unencoded(drflac_bs* pSamplesOut[i] = 0; } - if (bitsPerSample >= 24) { - pSamplesOut[i] += drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + i); + if (drflac__use_64_bit_prediction(bitsPerSample, lpcOrder, lpcPrecision)) { + pSamplesOut[i] += drflac__calculate_prediction_64(lpcOrder, lpcShift, coefficients, pSamplesOut + i); } else { - pSamplesOut[i] += drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + i); + pSamplesOut[i] += drflac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + i); } } @@ -4798,7 +4886,7 @@ Reads and decodes the residual for the sub-frame the decoder is currently sittin when the decoder is sitting at the very start of the RESIDUAL block. The first residuals will be ignored. The and parameters are used to determine how many residual values need to be decoded. */ -static drflac_bool32 drflac__decode_samples_with_residual(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 blockSize, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pDecodedSamples) +static drflac_bool32 drflac__decode_samples_with_residual(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 blockSize, drflac_uint32 lpcOrder, drflac_int32 lpcShift, drflac_uint32 lpcPrecision, const drflac_int32* coefficients, drflac_int32* pDecodedSamples) { drflac_uint8 residualMethod; drflac_uint8 partitionOrder; @@ -4818,7 +4906,7 @@ static drflac_bool32 drflac__decode_samples_with_residual(drflac_bs* bs, drflac_ } /* Ignore the first values. */ - pDecodedSamples += order; + pDecodedSamples += lpcOrder; if (!drflac__read_uint8(bs, 4, &partitionOrder)) { return DRFLAC_FALSE; @@ -4833,11 +4921,11 @@ static drflac_bool32 drflac__decode_samples_with_residual(drflac_bs* bs, drflac_ } /* Validation check. */ - if ((blockSize / (1 << partitionOrder)) < order) { + if ((blockSize / (1 << partitionOrder)) < lpcOrder) { return DRFLAC_FALSE; } - samplesInPartition = (blockSize / (1 << partitionOrder)) - order; + samplesInPartition = (blockSize / (1 << partitionOrder)) - lpcOrder; partitionsRemaining = (1 << partitionOrder); for (;;) { drflac_uint8 riceParam = 0; @@ -4858,7 +4946,7 @@ static drflac_bool32 drflac__decode_samples_with_residual(drflac_bs* bs, drflac_ } if (riceParam != 0xFF) { - if (!drflac__decode_samples_with_residual__rice(bs, bitsPerSample, samplesInPartition, riceParam, order, shift, coefficients, pDecodedSamples)) { + if (!drflac__decode_samples_with_residual__rice(bs, bitsPerSample, samplesInPartition, riceParam, lpcOrder, lpcShift, lpcPrecision, coefficients, pDecodedSamples)) { return DRFLAC_FALSE; } } else { @@ -4867,7 +4955,7 @@ static drflac_bool32 drflac__decode_samples_with_residual(drflac_bs* bs, drflac_ return DRFLAC_FALSE; } - if (!drflac__decode_samples_with_residual__unencoded(bs, bitsPerSample, samplesInPartition, unencodedBitsPerSample, order, shift, coefficients, pDecodedSamples)) { + if (!drflac__decode_samples_with_residual__unencoded(bs, bitsPerSample, samplesInPartition, unencodedBitsPerSample, lpcOrder, lpcShift, lpcPrecision, coefficients, pDecodedSamples)) { return DRFLAC_FALSE; } } @@ -5036,7 +5124,7 @@ static drflac_bool32 drflac__decode_samples__fixed(drflac_bs* bs, drflac_uint32 pDecodedSamples[i] = sample; } - if (!drflac__decode_samples_with_residual(bs, subframeBitsPerSample, blockSize, lpcOrder, 0, lpcCoefficientsTable[lpcOrder], pDecodedSamples)) { + if (!drflac__decode_samples_with_residual(bs, subframeBitsPerSample, blockSize, lpcOrder, 0, 4, lpcCoefficientsTable[lpcOrder], pDecodedSamples)) { return DRFLAC_FALSE; } @@ -5091,7 +5179,7 @@ static drflac_bool32 drflac__decode_samples__lpc(drflac_bs* bs, drflac_uint32 bl } } - if (!drflac__decode_samples_with_residual(bs, bitsPerSample, blockSize, lpcOrder, lpcShift, coefficients, pDecodedSamples)) { + if (!drflac__decode_samples_with_residual(bs, bitsPerSample, blockSize, lpcOrder, lpcShift, lpcPrecision, coefficients, pDecodedSamples)) { return DRFLAC_FALSE; } @@ -5219,6 +5307,9 @@ static drflac_bool32 drflac__read_next_flac_frame_header(drflac_bs* bs, drflac_u return DRFLAC_FALSE; } crc8 = drflac_crc8(crc8, header->blockSizeInPCMFrames, 16); + if (header->blockSizeInPCMFrames == 0xFFFF) { + return DRFLAC_FALSE; /* Frame is too big. This is the size of the frame minus 1. The STREAMINFO block defines the max block size which is 16-bits. Adding one will make it 17 bits and therefore too big. */ + } header->blockSizeInPCMFrames += 1; } else { DRFLAC_ASSERT(blockSize >= 8); @@ -5257,6 +5348,11 @@ static drflac_bool32 drflac__read_next_flac_frame_header(drflac_bs* bs, drflac_u header->bitsPerSample = streaminfoBitsPerSample; } + if (header->bitsPerSample != streaminfoBitsPerSample) { + /* If this subframe has a different bitsPerSample then streaminfo or the first frame, reject it */ + return DRFLAC_FALSE; + } + if (!drflac__read_uint8(bs, 8, &header->crc8)) { return DRFLAC_FALSE; } @@ -5343,6 +5439,11 @@ static drflac_bool32 drflac__decode_subframe(drflac_bs* bs, drflac_frame* frame, subframeBitsPerSample += 1; } + if (subframeBitsPerSample > 32) { + /* libFLAC and ffmpeg reject 33-bit subframes as well */ + return DRFLAC_FALSE; + } + /* Need to handle wasted bits per sample. */ if (pSubframe->wastedBitsPerSample >= subframeBitsPerSample) { return DRFLAC_FALSE; @@ -6013,6 +6114,11 @@ static drflac_bool32 drflac__seek_to_pcm_frame__seek_table(drflac* pFlac, drflac return DRFLAC_FALSE; } + /* Do not use the seektable if pcmFramIndex is not coverd by it. */ + if (pFlac->pSeekpoints[0].firstPCMFrame > pcmFrameIndex) { + return DRFLAC_FALSE; + } + for (iSeekpoint = 0; iSeekpoint < pFlac->seekpointCount; ++iSeekpoint) { if (pFlac->pSeekpoints[iSeekpoint].firstPCMFrame >= pcmFrameIndex) { break; @@ -6360,7 +6466,7 @@ static void drflac__free_from_callbacks(void* p, const drflac_allocation_callbac } -static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD, drflac_uint64* pFirstFramePos, drflac_uint64* pSeektablePos, drflac_uint32* pSeektableSize, drflac_allocation_callbacks* pAllocationCallbacks) +static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD, drflac_uint64* pFirstFramePos, drflac_uint64* pSeektablePos, drflac_uint32* pSeekpointCount, drflac_allocation_callbacks* pAllocationCallbacks) { /* We want to keep track of the byte position in the stream of the seektable. At the time of calling this function we know that @@ -6420,32 +6526,37 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d seektableSize = blockSize; if (onMeta) { + drflac_uint32 seekpointCount; drflac_uint32 iSeekpoint; void* pRawData; - pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks); + seekpointCount = blockSize/DRFLAC_SEEKPOINT_SIZE_IN_BYTES; + + pRawData = drflac__malloc_from_callbacks(seekpointCount * sizeof(drflac_seekpoint), pAllocationCallbacks); if (pRawData == NULL) { return DRFLAC_FALSE; } - if (onRead(pUserData, pRawData, blockSize) != blockSize) { - drflac__free_from_callbacks(pRawData, pAllocationCallbacks); - return DRFLAC_FALSE; - } + /* We need to read seekpoint by seekpoint and do some processing. */ + for (iSeekpoint = 0; iSeekpoint < seekpointCount; ++iSeekpoint) { + drflac_seekpoint* pSeekpoint = (drflac_seekpoint*)pRawData + iSeekpoint; - metadata.pRawData = pRawData; - metadata.rawDataSize = blockSize; - metadata.data.seektable.seekpointCount = blockSize/sizeof(drflac_seekpoint); - metadata.data.seektable.pSeekpoints = (const drflac_seekpoint*)pRawData; + if (onRead(pUserData, pSeekpoint, DRFLAC_SEEKPOINT_SIZE_IN_BYTES) != DRFLAC_SEEKPOINT_SIZE_IN_BYTES) { + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + return DRFLAC_FALSE; + } - /* Endian swap. */ - for (iSeekpoint = 0; iSeekpoint < metadata.data.seektable.seekpointCount; ++iSeekpoint) { - drflac_seekpoint* pSeekpoint = (drflac_seekpoint*)pRawData + iSeekpoint; + /* Endian swap. */ pSeekpoint->firstPCMFrame = drflac__be2host_64(pSeekpoint->firstPCMFrame); pSeekpoint->flacFrameOffset = drflac__be2host_64(pSeekpoint->flacFrameOffset); pSeekpoint->pcmFrameCount = drflac__be2host_16(pSeekpoint->pcmFrameCount); } + metadata.pRawData = pRawData; + metadata.rawDataSize = blockSize; + metadata.data.seektable.seekpointCount = seekpointCount; + metadata.data.seektable.pSeekpoints = (const drflac_seekpoint*)pRawData; + onMeta(pUserDataMD, &metadata); drflac__free_from_callbacks(pRawData, pAllocationCallbacks); @@ -6480,7 +6591,7 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d pRunningData = (const char*)pRawData; pRunningDataEnd = (const char*)pRawData + blockSize; - metadata.data.vorbis_comment.vendorLength = drflac__le2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + metadata.data.vorbis_comment.vendorLength = drflac__le2host_32_ptr_unaligned(pRunningData); pRunningData += 4; /* Need space for the rest of the block */ if ((pRunningDataEnd - pRunningData) - 4 < (drflac_int64)metadata.data.vorbis_comment.vendorLength) { /* <-- Note the order of operations to avoid overflow to a valid value */ @@ -6488,7 +6599,7 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d return DRFLAC_FALSE; } metadata.data.vorbis_comment.vendor = pRunningData; pRunningData += metadata.data.vorbis_comment.vendorLength; - metadata.data.vorbis_comment.commentCount = drflac__le2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + metadata.data.vorbis_comment.commentCount = drflac__le2host_32_ptr_unaligned(pRunningData); pRunningData += 4; /* Need space for 'commentCount' comments after the block, which at minimum is a drflac_uint32 per comment */ if ((pRunningDataEnd - pRunningData) / sizeof(drflac_uint32) < metadata.data.vorbis_comment.commentCount) { /* <-- Note the order of operations to avoid overflow to a valid value */ @@ -6506,7 +6617,7 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d return DRFLAC_FALSE; } - commentLength = drflac__le2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + commentLength = drflac__le2host_32_ptr_unaligned(pRunningData); pRunningData += 4; if (pRunningDataEnd - pRunningData < (drflac_int64)commentLength) { /* <-- Note the order of operations to avoid overflow to a valid value */ drflac__free_from_callbacks(pRawData, pAllocationCallbacks); return DRFLAC_FALSE; @@ -6530,9 +6641,15 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d void* pRawData; const char* pRunningData; const char* pRunningDataEnd; + size_t bufferSize; drflac_uint8 iTrack; drflac_uint8 iIndex; + void* pTrackData; + /* + This needs to be loaded in two passes. The first pass is used to calculate the size of the memory allocation + we need for storing the necessary data. The second pass will fill that buffer with usable data. + */ pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks); if (pRawData == NULL) { return DRFLAC_FALSE; @@ -6553,38 +6670,91 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d metadata.data.cuesheet.leadInSampleCount = drflac__be2host_64(*(const drflac_uint64*)pRunningData); pRunningData += 8; metadata.data.cuesheet.isCD = (pRunningData[0] & 0x80) != 0; pRunningData += 259; metadata.data.cuesheet.trackCount = pRunningData[0]; pRunningData += 1; - metadata.data.cuesheet.pTrackData = pRunningData; + metadata.data.cuesheet.pTrackData = NULL; /* Will be filled later. */ - /* Check that the cuesheet tracks are valid before passing it to the callback */ - for (iTrack = 0; iTrack < metadata.data.cuesheet.trackCount; ++iTrack) { - drflac_uint8 indexCount; - drflac_uint32 indexPointSize; + /* Pass 1: Calculate the size of the buffer for the track data. */ + { + const char* pRunningDataSaved = pRunningData; /* Will be restored at the end in preparation for the second pass. */ - if (pRunningDataEnd - pRunningData < 36) { - drflac__free_from_callbacks(pRawData, pAllocationCallbacks); - return DRFLAC_FALSE; + bufferSize = metadata.data.cuesheet.trackCount * DRFLAC_CUESHEET_TRACK_SIZE_IN_BYTES; + + for (iTrack = 0; iTrack < metadata.data.cuesheet.trackCount; ++iTrack) { + drflac_uint8 indexCount; + drflac_uint32 indexPointSize; + + if (pRunningDataEnd - pRunningData < DRFLAC_CUESHEET_TRACK_SIZE_IN_BYTES) { + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + return DRFLAC_FALSE; + } + + /* Skip to the index point count */ + pRunningData += 35; + + indexCount = pRunningData[0]; + pRunningData += 1; + + bufferSize += indexCount * sizeof(drflac_cuesheet_track_index); + + /* Quick validation check. */ + indexPointSize = indexCount * DRFLAC_CUESHEET_TRACK_INDEX_SIZE_IN_BYTES; + if (pRunningDataEnd - pRunningData < (drflac_int64)indexPointSize) { + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + return DRFLAC_FALSE; + } + + pRunningData += indexPointSize; } - /* Skip to the index point count */ - pRunningData += 35; - indexCount = pRunningData[0]; pRunningData += 1; - indexPointSize = indexCount * sizeof(drflac_cuesheet_track_index); - if (pRunningDataEnd - pRunningData < (drflac_int64)indexPointSize) { + pRunningData = pRunningDataSaved; + } + + /* Pass 2: Allocate a buffer and fill the data. Validation was done in the step above so can be skipped. */ + { + char* pRunningTrackData; + + pTrackData = drflac__malloc_from_callbacks(bufferSize, pAllocationCallbacks); + if (pTrackData == NULL) { drflac__free_from_callbacks(pRawData, pAllocationCallbacks); return DRFLAC_FALSE; } - /* Endian swap. */ - for (iIndex = 0; iIndex < indexCount; ++iIndex) { - drflac_cuesheet_track_index* pTrack = (drflac_cuesheet_track_index*)pRunningData; - pRunningData += sizeof(drflac_cuesheet_track_index); - pTrack->offset = drflac__be2host_64(pTrack->offset); + pRunningTrackData = (char*)pTrackData; + + for (iTrack = 0; iTrack < metadata.data.cuesheet.trackCount; ++iTrack) { + drflac_uint8 indexCount; + + DRFLAC_COPY_MEMORY(pRunningTrackData, pRunningData, DRFLAC_CUESHEET_TRACK_SIZE_IN_BYTES); + pRunningData += DRFLAC_CUESHEET_TRACK_SIZE_IN_BYTES-1; /* Skip forward, but not beyond the last byte in the CUESHEET_TRACK block which is the index count. */ + pRunningTrackData += DRFLAC_CUESHEET_TRACK_SIZE_IN_BYTES-1; + + /* Grab the index count for the next part. */ + indexCount = pRunningData[0]; + pRunningData += 1; + pRunningTrackData += 1; + + /* Extract each track index. */ + for (iIndex = 0; iIndex < indexCount; ++iIndex) { + drflac_cuesheet_track_index* pTrackIndex = (drflac_cuesheet_track_index*)pRunningTrackData; + + DRFLAC_COPY_MEMORY(pRunningTrackData, pRunningData, DRFLAC_CUESHEET_TRACK_INDEX_SIZE_IN_BYTES); + pRunningData += DRFLAC_CUESHEET_TRACK_INDEX_SIZE_IN_BYTES; + pRunningTrackData += sizeof(drflac_cuesheet_track_index); + + pTrackIndex->offset = drflac__be2host_64(pTrackIndex->offset); + } } + + metadata.data.cuesheet.pTrackData = pTrackData; } + /* The original data is no longer needed. */ + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + pRawData = NULL; + onMeta(pUserDataMD, &metadata); - drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + drflac__free_from_callbacks(pTrackData, pAllocationCallbacks); + pTrackData = NULL; } } break; @@ -6615,28 +6785,28 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d pRunningData = (const char*)pRawData; pRunningDataEnd = (const char*)pRawData + blockSize; - metadata.data.picture.type = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; - metadata.data.picture.mimeLength = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + metadata.data.picture.type = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; + metadata.data.picture.mimeLength = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; /* Need space for the rest of the block */ if ((pRunningDataEnd - pRunningData) - 24 < (drflac_int64)metadata.data.picture.mimeLength) { /* <-- Note the order of operations to avoid overflow to a valid value */ drflac__free_from_callbacks(pRawData, pAllocationCallbacks); return DRFLAC_FALSE; } - metadata.data.picture.mime = pRunningData; pRunningData += metadata.data.picture.mimeLength; - metadata.data.picture.descriptionLength = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + metadata.data.picture.mime = pRunningData; pRunningData += metadata.data.picture.mimeLength; + metadata.data.picture.descriptionLength = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; /* Need space for the rest of the block */ if ((pRunningDataEnd - pRunningData) - 20 < (drflac_int64)metadata.data.picture.descriptionLength) { /* <-- Note the order of operations to avoid overflow to a valid value */ drflac__free_from_callbacks(pRawData, pAllocationCallbacks); return DRFLAC_FALSE; } - metadata.data.picture.description = pRunningData; pRunningData += metadata.data.picture.descriptionLength; - metadata.data.picture.width = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; - metadata.data.picture.height = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; - metadata.data.picture.colorDepth = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; - metadata.data.picture.indexColorCount = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; - metadata.data.picture.pictureDataSize = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + metadata.data.picture.description = pRunningData; pRunningData += metadata.data.picture.descriptionLength; + metadata.data.picture.width = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; + metadata.data.picture.height = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; + metadata.data.picture.colorDepth = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; + metadata.data.picture.indexColorCount = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; + metadata.data.picture.pictureDataSize = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; metadata.data.picture.pPictureData = (const drflac_uint8*)pRunningData; /* Need space for the picture after the block */ @@ -6714,9 +6884,9 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d } } - *pSeektablePos = seektablePos; - *pSeektableSize = seektableSize; - *pFirstFramePos = runningFilePos; + *pSeektablePos = seektablePos; + *pSeekpointCount = seektableSize / DRFLAC_SEEKPOINT_SIZE_IN_BYTES; + *pFirstFramePos = runningFilePos; return DRFLAC_TRUE; } @@ -7746,11 +7916,11 @@ static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac drflac_uint32 wholeSIMDVectorCountPerChannel; drflac_uint32 decodedSamplesAllocationSize; #ifndef DR_FLAC_NO_OGG - drflac_oggbs oggbs; + drflac_oggbs* pOggbs = NULL; #endif drflac_uint64 firstFramePos; drflac_uint64 seektablePos; - drflac_uint32 seektableSize; + drflac_uint32 seekpointCount; drflac_allocation_callbacks allocationCallbacks; drflac* pFlac; @@ -7804,18 +7974,21 @@ static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac /* There's additional data required for Ogg streams. */ if (init.container == drflac_container_ogg) { allocationSize += sizeof(drflac_oggbs); - } - DRFLAC_ZERO_MEMORY(&oggbs, sizeof(oggbs)); - if (init.container == drflac_container_ogg) { - oggbs.onRead = onRead; - oggbs.onSeek = onSeek; - oggbs.pUserData = pUserData; - oggbs.currentBytePos = init.oggFirstBytePos; - oggbs.firstBytePos = init.oggFirstBytePos; - oggbs.serialNumber = init.oggSerial; - oggbs.bosPageHeader = init.oggBosHeader; - oggbs.bytesRemainingInPage = 0; + pOggbs = (drflac_oggbs*)drflac__malloc_from_callbacks(sizeof(*pOggbs), &allocationCallbacks); + if (pOggbs == NULL) { + return NULL; /*DRFLAC_OUT_OF_MEMORY;*/ + } + + DRFLAC_ZERO_MEMORY(pOggbs, sizeof(*pOggbs)); + pOggbs->onRead = onRead; + pOggbs->onSeek = onSeek; + pOggbs->pUserData = pUserData; + pOggbs->currentBytePos = init.oggFirstBytePos; + pOggbs->firstBytePos = init.oggFirstBytePos; + pOggbs->serialNumber = init.oggSerial; + pOggbs->bosPageHeader = init.oggBosHeader; + pOggbs->bytesRemainingInPage = 0; } #endif @@ -7824,9 +7997,9 @@ static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac consist of only a single heap allocation. To this, the size of the seek table needs to be known, which we determine when reading and decoding the metadata. */ - firstFramePos = 42; /* <-- We know we are at byte 42 at this point. */ - seektablePos = 0; - seektableSize = 0; + firstFramePos = 42; /* <-- We know we are at byte 42 at this point. */ + seektablePos = 0; + seekpointCount = 0; if (init.hasMetadataBlocks) { drflac_read_proc onReadOverride = onRead; drflac_seek_proc onSeekOverride = onSeek; @@ -7836,20 +8009,26 @@ static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac if (init.container == drflac_container_ogg) { onReadOverride = drflac__on_read_ogg; onSeekOverride = drflac__on_seek_ogg; - pUserDataOverride = (void*)&oggbs; + pUserDataOverride = (void*)pOggbs; } #endif - if (!drflac__read_and_decode_metadata(onReadOverride, onSeekOverride, onMeta, pUserDataOverride, pUserDataMD, &firstFramePos, &seektablePos, &seektableSize, &allocationCallbacks)) { + if (!drflac__read_and_decode_metadata(onReadOverride, onSeekOverride, onMeta, pUserDataOverride, pUserDataMD, &firstFramePos, &seektablePos, &seekpointCount, &allocationCallbacks)) { + #ifndef DR_FLAC_NO_OGG + drflac__free_from_callbacks(pOggbs, &allocationCallbacks); + #endif return NULL; } - allocationSize += seektableSize; + allocationSize += seekpointCount * sizeof(drflac_seekpoint); } pFlac = (drflac*)drflac__malloc_from_callbacks(allocationSize, &allocationCallbacks); if (pFlac == NULL) { + #ifndef DR_FLAC_NO_OGG + drflac__free_from_callbacks(pOggbs, &allocationCallbacks); + #endif return NULL; } @@ -7859,8 +8038,12 @@ static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac #ifndef DR_FLAC_NO_OGG if (init.container == drflac_container_ogg) { - drflac_oggbs* pInternalOggbs = (drflac_oggbs*)((drflac_uint8*)pFlac->pDecodedSamples + decodedSamplesAllocationSize + seektableSize); - *pInternalOggbs = oggbs; + drflac_oggbs* pInternalOggbs = (drflac_oggbs*)((drflac_uint8*)pFlac->pDecodedSamples + decodedSamplesAllocationSize + (seekpointCount * sizeof(drflac_seekpoint))); + DRFLAC_COPY_MEMORY(pInternalOggbs, pOggbs, sizeof(*pOggbs)); + + /* At this point the pOggbs object has been handed over to pInternalOggbs and can be freed. */ + drflac__free_from_callbacks(pOggbs, &allocationCallbacks); + pOggbs = NULL; /* The Ogg bistream needs to be layered on top of the original bitstream. */ pFlac->bs.onRead = drflac__on_read_ogg; @@ -7884,7 +8067,7 @@ static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac { /* If we have a seektable we need to load it now, making sure we move back to where we were previously. */ if (seektablePos != 0) { - pFlac->seekpointCount = seektableSize / sizeof(*pFlac->pSeekpoints); + pFlac->seekpointCount = seekpointCount; pFlac->pSeekpoints = (drflac_seekpoint*)((drflac_uint8*)pFlac->pDecodedSamples + decodedSamplesAllocationSize); DRFLAC_ASSERT(pFlac->bs.onSeek != NULL); @@ -7892,18 +8075,20 @@ static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac /* Seek to the seektable, then just read directly into our seektable buffer. */ if (pFlac->bs.onSeek(pFlac->bs.pUserData, (int)seektablePos, drflac_seek_origin_start)) { - if (pFlac->bs.onRead(pFlac->bs.pUserData, pFlac->pSeekpoints, seektableSize) == seektableSize) { - /* Endian swap. */ - drflac_uint32 iSeekpoint; - for (iSeekpoint = 0; iSeekpoint < pFlac->seekpointCount; ++iSeekpoint) { + drflac_uint32 iSeekpoint; + + for (iSeekpoint = 0; iSeekpoint < seekpointCount; iSeekpoint += 1) { + if (pFlac->bs.onRead(pFlac->bs.pUserData, pFlac->pSeekpoints + iSeekpoint, DRFLAC_SEEKPOINT_SIZE_IN_BYTES) == DRFLAC_SEEKPOINT_SIZE_IN_BYTES) { + /* Endian swap. */ pFlac->pSeekpoints[iSeekpoint].firstPCMFrame = drflac__be2host_64(pFlac->pSeekpoints[iSeekpoint].firstPCMFrame); pFlac->pSeekpoints[iSeekpoint].flacFrameOffset = drflac__be2host_64(pFlac->pSeekpoints[iSeekpoint].flacFrameOffset); pFlac->pSeekpoints[iSeekpoint].pcmFrameCount = drflac__be2host_16(pFlac->pSeekpoints[iSeekpoint].pcmFrameCount); + } else { + /* Failed to read the seektable. Pretend we don't have one. */ + pFlac->pSeekpoints = NULL; + pFlac->seekpointCount = 0; + break; } - } else { - /* Failed to read the seektable. Pretend we don't have one. */ - pFlac->pSeekpoints = NULL; - pFlac->seekpointCount = 0; } /* We need to seek back to where we were. If this fails it's a critical error. */ @@ -7952,7 +8137,9 @@ static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac #ifndef DR_FLAC_NO_STDIO #include +#ifndef DR_FLAC_NO_WCHAR #include /* For wcslen(), wcsrtombs() */ +#endif /* drflac_result_from_errno() is only used for fopen() and wfopen() so putting it inside DR_WAV_NO_STDIO for now. If something else needs this later we can move it out. */ #include @@ -8418,6 +8605,7 @@ fallback, so if you notice your compiler not detecting this properly I'm happy t #endif #endif +#ifndef DR_FLAC_NO_WCHAR static drflac_result drflac_wfopen(FILE** ppFile, const wchar_t* pFilePath, const wchar_t* pOpenMode, const drflac_allocation_callbacks* pAllocationCallbacks) { if (ppFile != NULL) { @@ -8446,10 +8634,23 @@ static drflac_result drflac_wfopen(FILE** ppFile, const wchar_t* pFilePath, cons } #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. */ + + /* + Some compilers don't support wchar_t or wcsrtombs() which we're using below. In this case we just + need to abort with an error. If you encounter a compiler lacking such support, add it to this list + and submit a bug report and it'll be added to the library upstream. + */ + #if defined(__DJGPP__) + { + /* Nothing to do here. This will fall through to the error check below. */ + } + #else { mbstate_t mbs; size_t lenMB; @@ -8491,6 +8692,7 @@ static drflac_result drflac_wfopen(FILE** ppFile, const wchar_t* pFilePath, cons drflac__free_from_callbacks(pFilePathMB, pAllocationCallbacks); } + #endif if (*ppFile == NULL) { return DRFLAC_ERROR; @@ -8499,6 +8701,7 @@ static drflac_result drflac_wfopen(FILE** ppFile, const wchar_t* pFilePath, cons return DRFLAC_SUCCESS; } +#endif static size_t drflac__on_read_stdio(void* pUserData, void* bufferOut, size_t bytesToRead) { @@ -8531,6 +8734,7 @@ DRFLAC_API drflac* drflac_open_file(const char* pFileName, const drflac_allocati return pFlac; } +#ifndef DR_FLAC_NO_WCHAR DRFLAC_API drflac* drflac_open_file_w(const wchar_t* pFileName, const drflac_allocation_callbacks* pAllocationCallbacks) { drflac* pFlac; @@ -8548,6 +8752,7 @@ DRFLAC_API drflac* drflac_open_file_w(const wchar_t* pFileName, const drflac_all return pFlac; } +#endif DRFLAC_API drflac* drflac_open_file_with_metadata(const char* pFileName, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks) { @@ -8567,6 +8772,7 @@ DRFLAC_API drflac* drflac_open_file_with_metadata(const char* pFileName, drflac_ return pFlac; } +#ifndef DR_FLAC_NO_WCHAR DRFLAC_API drflac* drflac_open_file_with_metadata_w(const wchar_t* pFileName, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks) { drflac* pFlac; @@ -8584,6 +8790,7 @@ DRFLAC_API drflac* drflac_open_file_with_metadata_w(const wchar_t* pFileName, dr return pFlac; } +#endif #endif /* DR_FLAC_NO_STDIO */ static size_t drflac__on_read_memory(void* pUserData, void* bufferOut, size_t bytesToRead) @@ -11781,7 +11988,7 @@ DRFLAC_API const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator return NULL; } - length = drflac__le2host_32(*(const drflac_uint32*)pIter->pRunningData); + length = drflac__le2host_32_ptr_unaligned(pIter->pRunningData); pIter->pRunningData += 4; pComment = pIter->pRunningData; @@ -11851,6 +12058,37 @@ DRFLAC_API drflac_bool32 drflac_next_cuesheet_track(drflac_cuesheet_track_iterat /* REVISION HISTORY ================ +v0.12.39 - 2022-09-17 + - Fix compilation with DJGPP. + - Fix compilation error with Visual Studio 2019 and the ARM build. + - Fix an error with SSE 4.1 detection. + - Add support for disabling wchar_t with DR_WAV_NO_WCHAR. + - Improve compatibility with compilers which lack support for explicit struct packing. + - Improve compatibility with low-end and embedded hardware by reducing the amount of stack + allocation when loading an Ogg encapsulated file. + +v0.12.38 - 2022-04-10 + - Fix compilation error on older versions of GCC. + +v0.12.37 - 2022-02-12 + - Improve ARM detection. + +v0.12.36 - 2022-02-07 + - Fix a compilation error with the ARM build. + +v0.12.35 - 2022-02-06 + - Fix a bug due to underestimating the amount of precision required for the prediction stage. + - Fix some bugs found from fuzz testing. + +v0.12.34 - 2022-01-07 + - Fix some misalignment bugs when reading metadata. + +v0.12.33 - 2021-12-22 + - Fix a bug with seeking when the seek table does not start at PCM frame 0. + +v0.12.32 - 2021-12-11 + - Fix a warning with Clang. + v0.12.31 - 2021-08-16 - Silence some warnings. diff --git a/src/external/dr_mp3.h b/src/external/dr_mp3.h index 7d752d0729b6..59876c877390 100644 --- a/src/external/dr_mp3.h +++ b/src/external/dr_mp3.h @@ -1,6 +1,6 @@ /* MP3 audio decoder. Choice of public domain or MIT-0. See license statements at the end of this file. -dr_mp3 - v0.6.31 - 2021-08-22 +dr_mp3 - v0.6.34 - 2022-09-17 David Reid - mackron@gmail.com @@ -95,7 +95,7 @@ extern "C" { #define DRMP3_VERSION_MAJOR 0 #define DRMP3_VERSION_MINOR 6 -#define DRMP3_VERSION_REVISION 31 +#define DRMP3_VERSION_REVISION 34 #define DRMP3_VERSION_STRING DRMP3_XSTRINGIFY(DRMP3_VERSION_MAJOR) "." DRMP3_XSTRINGIFY(DRMP3_VERSION_MINOR) "." DRMP3_XSTRINGIFY(DRMP3_VERSION_REVISION) #include /* For size_t. */ @@ -107,7 +107,7 @@ typedef signed short drmp3_int16; typedef unsigned short drmp3_uint16; typedef signed int drmp3_int32; typedef unsigned int drmp3_uint32; -#if defined(_MSC_VER) +#if defined(_MSC_VER) && !defined(__clang__) typedef signed __int64 drmp3_int64; typedef unsigned __int64 drmp3_uint64; #else @@ -235,9 +235,15 @@ typedef drmp3_int32 drmp3_result; I am using "__inline__" only when we're compiling in strict ANSI mode. */ #if defined(__STRICT_ANSI__) - #define DRMP3_INLINE __inline__ __attribute__((always_inline)) + #define DRMP3_GNUC_INLINE_HINT __inline__ + #else + #define DRMP3_GNUC_INLINE_HINT inline + #endif + + #if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 2)) || defined(__clang__) + #define DRMP3_INLINE DRMP3_GNUC_INLINE_HINT __attribute__((always_inline)) #else - #define DRMP3_INLINE inline __attribute__((always_inline)) + #define DRMP3_INLINE DRMP3_GNUC_INLINE_HINT #endif #elif defined(__WATCOMC__) #define DRMP3_INLINE __inline @@ -340,7 +346,6 @@ typedef struct typedef struct { drmp3dec decoder; - drmp3dec_frame_info frameInfo; drmp3_uint32 channels; drmp3_uint32 sampleRate; drmp3_read_proc onRead; @@ -595,7 +600,7 @@ DRMP3_API const char* drmp3_version_string(void) #define DR_MP3_ONLY_SIMD #endif -#if ((defined(_MSC_VER) && _MSC_VER >= 1400) && (defined(_M_IX86) || defined(_M_X64))) || ((defined(__i386__) || defined(__x86_64__)) && defined(__SSE2__)) +#if ((defined(_MSC_VER) && _MSC_VER >= 1400) && defined(_M_X64)) || ((defined(__i386) || defined(_M_IX86) || defined(__i386__) || defined(__x86_64__)) && ((defined(_M_IX86_FP) && _M_IX86_FP == 2) || defined(__SSE2__))) #if defined(_MSC_VER) #include #endif @@ -1296,7 +1301,7 @@ static void drmp3_L3_huffman(float *dst, drmp3_bs *bs, const drmp3_L3_gr_info *g static const drmp3_int16 tabindex[2*16] = { 0,32,64,98,0,132,180,218,292,364,426,538,648,746,0,1126,1460,1460,1460,1460,1460,1460,1460,1460,1842,1842,1842,1842,1842,1842,1842,1842 }; static const drmp3_uint8 g_linbits[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3,4,6,8,10,13,4,5,6,7,8,9,11,13 }; -#define DRMP3_PEEK_BITS(n) (bs_cache >> (32 - n)) +#define DRMP3_PEEK_BITS(n) (bs_cache >> (32 - (n))) #define DRMP3_FLUSH_BITS(n) { bs_cache <<= (n); bs_sh += (n); } #define DRMP3_CHECK_BITS while (bs_sh >= 0) { bs_cache |= (drmp3_uint32)*bs_next_ptr++ << bs_sh; bs_sh -= 8; } #define DRMP3_BSPOS ((bs_next_ptr - bs->buf)*8 - 24 + bs_sh) @@ -1864,7 +1869,7 @@ static void drmp3d_DCT_II(float *grbuf, int n) #if DRMP3_HAVE_SSE #define DRMP3_VSAVE2(i, v) _mm_storel_pi((__m64 *)(void*)&y[i*18], v) #else -#define DRMP3_VSAVE2(i, v) vst1_f32((float32_t *)&y[i*18], vget_low_f32(v)) +#define DRMP3_VSAVE2(i, v) vst1_f32((float32_t *)&y[(i)*18], vget_low_f32(v)) #endif for (i = 0; i < 7; i++, y += 4*18) { @@ -1880,7 +1885,7 @@ static void drmp3d_DCT_II(float *grbuf, int n) DRMP3_VSAVE2(3, t[3][7]); } else { -#define DRMP3_VSAVE4(i, v) DRMP3_VSTORE(&y[i*18], v) +#define DRMP3_VSAVE4(i, v) DRMP3_VSTORE(&y[(i)*18], v) for (i = 0; i < 7; i++, y += 4*18) { drmp3_f4 s = DRMP3_VADD(t[3][i], t[3][i + 1]); @@ -2103,7 +2108,11 @@ static void drmp3d_synth(float *xl, drmp3d_sample_t *dstl, int nch, float *lins) vst1_lane_s16(dstl + (49 + i)*nch, pcmb, 2); #endif #else + #if DRMP3_HAVE_SSE static const drmp3_f4 g_scale = { 1.0f/32768.0f, 1.0f/32768.0f, 1.0f/32768.0f, 1.0f/32768.0f }; + #else + const drmp3_f4 g_scale = vdupq_n_f32(1.0f/32768.0f); + #endif a = DRMP3_VMUL(a, g_scale); b = DRMP3_VMUL(b, g_scale); #if DRMP3_HAVE_SSE @@ -2406,8 +2415,6 @@ DRMP3_API void drmp3dec_f32_to_s16(const float *in, drmp3_int16 *out, size_t num Main Public API ************************************************************************************************************************************************************/ -#include /* For sin() and exp(). */ - #if defined(SIZE_MAX) #define DRMP3_SIZE_MAX SIZE_MAX #else @@ -2427,7 +2434,7 @@ DRMP3_API void drmp3dec_f32_to_s16(const float *in, drmp3_int16 *out, size_t num /* The size in bytes of each chunk of data to read from the MP3 stream. minimp3 recommends at least 16K, but in an attempt to reduce data movement I'm making this slightly larger. */ #ifndef DRMP3_DATA_CHUNK_SIZE -#define DRMP3_DATA_CHUNK_SIZE DRMP3_MIN_DATA_CHUNK_SIZE*4 +#define DRMP3_DATA_CHUNK_SIZE (DRMP3_MIN_DATA_CHUNK_SIZE*4) #endif @@ -2472,24 +2479,6 @@ static DRMP3_INLINE drmp3_uint32 drmp3_gcf_u32(drmp3_uint32 a, drmp3_uint32 b) } -static DRMP3_INLINE double drmp3_sin(double x) -{ - /* TODO: Implement custom sin(x). */ - return sin(x); -} - -static DRMP3_INLINE double drmp3_exp(double x) -{ - /* TODO: Implement custom exp(x). */ - return exp(x); -} - -static DRMP3_INLINE double drmp3_cos(double x) -{ - return drmp3_sin((DRMP3_PI_D*0.5) - x); -} - - static void* drmp3__malloc_default(size_t sz, void* pUserData) { (void)pUserData; @@ -3434,10 +3423,23 @@ static drmp3_result drmp3_wfopen(FILE** ppFile, const wchar_t* pFilePath, const } #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. */ + + /* + Some compilers don't support wchar_t or wcsrtombs() which we're using below. In this case we just + need to abort with an error. If you encounter a compiler lacking such support, add it to this list + and submit a bug report and it'll be added to the library upstream. + */ + #if defined(__DJGPP__) + { + /* Nothing to do here. This will fall through to the error check below. */ + } + #else { mbstate_t mbs; size_t lenMB; @@ -3479,6 +3481,7 @@ static drmp3_result drmp3_wfopen(FILE** ppFile, const wchar_t* pFilePath, const drmp3__free_from_callbacks(pFilePathMB, pAllocationCallbacks); } + #endif if (*ppFile == NULL) { return DRMP3_ERROR; @@ -4473,6 +4476,19 @@ counts rather than sample counts. /* REVISION HISTORY ================ +v0.6.34 - 2022-09-17 + - Fix compilation with DJGPP. + - Fix compilation when compiling with x86 with no SSE2. + - Remove an unnecessary variable from the drmp3 structure. + +v0.6.33 - 2022-04-10 + - Fix compilation error with the MSVC ARM64 build. + - Fix compilation error on older versions of GCC. + - Remove some unused functions. + +v0.6.32 - 2021-12-11 + - Fix a warning with Clang. + v0.6.31 - 2021-08-22 - Fix a bug when loading from memory. diff --git a/src/external/dr_wav.h b/src/external/dr_wav.h index a119d66afd7a..2f885a04ce07 100644 --- a/src/external/dr_wav.h +++ b/src/external/dr_wav.h @@ -1,6 +1,6 @@ /* WAV audio loader and writer. Choice of public domain or MIT-0. See license statements at the end of this file. -dr_wav - v0.13.4 - 2021-12-08 +dr_wav - v0.13.7 - 2022-09-17 David Reid - mackron@gmail.com @@ -92,6 +92,9 @@ Build Options #define DR_WAV_NO_STDIO Disables APIs that initialize a decoder from a file such as `drwav_init_file()`, `drwav_init_file_write()`, etc. +#define DR_WAV_NO_WCHAR + Disables all functions ending with `_w`. Use this if your compiler does not provide wchar.h. Not required if DR_WAV_NO_STDIO is also defined. + Notes @@ -125,7 +128,7 @@ extern "C" { #define DRWAV_VERSION_MAJOR 0 #define DRWAV_VERSION_MINOR 13 -#define DRWAV_VERSION_REVISION 4 +#define DRWAV_VERSION_REVISION 7 #define DRWAV_VERSION_STRING DRWAV_XSTRINGIFY(DRWAV_VERSION_MAJOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_MINOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_REVISION) #include /* For size_t. */ @@ -1297,14 +1300,21 @@ DRWAV_API drwav_bool32 drwav_fourcc_equal(const drwav_uint8* a, const char* b); #ifndef dr_wav_c #define dr_wav_c +#ifdef __MRC__ +/* MrC currently doesn't compile dr_wav correctly with any optimizations enabled. */ +#pragma options opt off +#endif + #include -#include /* For memcpy(), memset() */ +#include #include /* For INT_MAX */ #ifndef DR_WAV_NO_STDIO #include +#ifndef DR_WAV_NO_WCHAR #include #endif +#endif /* Standard library stuff. */ #ifndef DRWAV_ASSERT @@ -1359,9 +1369,15 @@ DRWAV_API drwav_bool32 drwav_fourcc_equal(const drwav_uint8* a, const char* b); I am using "__inline__" only when we're compiling in strict ANSI mode. */ #if defined(__STRICT_ANSI__) - #define DRWAV_INLINE __inline__ __attribute__((always_inline)) + #define DRWAV_GNUC_INLINE_HINT __inline__ #else - #define DRWAV_INLINE inline __attribute__((always_inline)) + #define DRWAV_GNUC_INLINE_HINT inline + #endif + + #if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 2)) || defined(__clang__) + #define DRWAV_INLINE DRWAV_GNUC_INLINE_HINT __attribute__((always_inline)) + #else + #define DRWAV_INLINE DRWAV_GNUC_INLINE_HINT #endif #elif defined(__WATCOMC__) #define DRWAV_INLINE __inline @@ -1966,7 +1982,7 @@ DRWAV_PRIVATE drwav_bool32 drwav__read_fmt(drwav_read_proc onRead, drwav_seek_pr fmtOut->extendedSize = 0; fmtOut->validBitsPerSample = 0; fmtOut->channelMask = 0; - memset(fmtOut->subFormat, 0, sizeof(fmtOut->subFormat)); + DRWAV_ZERO_MEMORY(fmtOut->subFormat, sizeof(fmtOut->subFormat)); if (header.sizeInBytes > 16) { drwav_uint8 fmt_cbSize[2]; @@ -2137,7 +2153,7 @@ DRWAV_PRIVATE void drwav__metadata_request_extra_memory_for_stage_2(drwav__metad DRWAV_PRIVATE drwav_result drwav__metadata_alloc(drwav__metadata_parser* pParser, drwav_allocation_callbacks* pAllocationCallbacks) { if (pParser->extraCapacity != 0 || pParser->metadataCount != 0) { - free(pParser->pData); + pAllocationCallbacks->onFree(pParser->pData, pAllocationCallbacks->pUserData); pParser->pData = (drwav_uint8*)pAllocationCallbacks->onMalloc(drwav__metadata_memory_capacity(pParser), pAllocationCallbacks->pUserData); pParser->pDataCursor = pParser->pData; @@ -2316,6 +2332,17 @@ DRWAV_PRIVATE drwav_uint64 drwav__read_acid_to_metadata_obj(drwav__metadata_pars return bytesRead; } +DRWAV_PRIVATE size_t drwav__strlen(const char* str) +{ + size_t result = 0; + + while (*str++) { + result += 1; + } + + return result; +} + DRWAV_PRIVATE size_t drwav__strlen_clamped(const char* str, size_t maxToRead) { size_t result = 0; @@ -2335,7 +2362,7 @@ DRWAV_PRIVATE char* drwav__metadata_copy_string(drwav__metadata_parser* pParser, char* result = (char*)drwav__metadata_get_memory(pParser, len + 1, 1); DRWAV_ASSERT(result != NULL); - memcpy(result, str, len); + DRWAV_COPY_MEMORY(result, str, len); result[len] = '\0'; return result; @@ -2516,7 +2543,7 @@ DRWAV_PRIVATE drwav_uint64 drwav__read_bext_to_metadata_obj(drwav__metadata_pars DRWAV_ASSERT(pMetadata->data.bext.pCodingHistory != NULL); bytesRead += drwav__metadata_parser_read(pParser, pMetadata->data.bext.pCodingHistory, extraBytes, NULL); - pMetadata->data.bext.codingHistorySize = (drwav_uint32)strlen(pMetadata->data.bext.pCodingHistory); + pMetadata->data.bext.codingHistorySize = (drwav_uint32)drwav__strlen(pMetadata->data.bext.pCodingHistory); } else { pMetadata->data.bext.pCodingHistory = NULL; pMetadata->data.bext.codingHistorySize = 0; @@ -2780,21 +2807,21 @@ DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_chunk(drwav__metadata_parser* if (bytesJustRead != DRWAV_BEXT_DESCRIPTION_BYTES) { return bytesRead; } - allocSizeNeeded += strlen(buffer) + 1; + allocSizeNeeded += drwav__strlen(buffer) + 1; buffer[DRWAV_BEXT_ORIGINATOR_NAME_BYTES] = '\0'; bytesJustRead = drwav__metadata_parser_read(pParser, buffer, DRWAV_BEXT_ORIGINATOR_NAME_BYTES, &bytesRead); if (bytesJustRead != DRWAV_BEXT_ORIGINATOR_NAME_BYTES) { return bytesRead; } - allocSizeNeeded += strlen(buffer) + 1; + allocSizeNeeded += drwav__strlen(buffer) + 1; buffer[DRWAV_BEXT_ORIGINATOR_REF_BYTES] = '\0'; bytesJustRead = drwav__metadata_parser_read(pParser, buffer, DRWAV_BEXT_ORIGINATOR_REF_BYTES, &bytesRead); if (bytesJustRead != DRWAV_BEXT_ORIGINATOR_REF_BYTES) { return bytesRead; } - allocSizeNeeded += strlen(buffer) + 1; + allocSizeNeeded += drwav__strlen(buffer) + 1; allocSizeNeeded += (size_t)pChunkHeader->sizeInBytes - DRWAV_BEXT_BYTES; /* Coding history. */ drwav__metadata_request_extra_memory_for_stage_2(pParser, allocSizeNeeded, 1); @@ -3157,7 +3184,7 @@ DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc on translatedFormatTag = drwav_bytes_to_u16(fmt.subFormat + 0); } - memset(&metadataParser, 0, sizeof(metadataParser)); + DRWAV_ZERO_MEMORY(&metadataParser, sizeof(metadataParser)); /* Not tested on W64. */ if (!sequential && pWav->allowedMetadataTypes != drwav_metadata_type_none && (pWav->container == drwav_container_riff || pWav->container == drwav_container_rf64)) { @@ -3746,7 +3773,7 @@ DRWAV_PRIVATE size_t drwav__write_or_count_metadata(drwav* pWav, drwav_metadata* bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.bext.maxMomentaryLoudness); bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.bext.maxShortTermLoudness); - memset(reservedBuf, 0, sizeof(reservedBuf)); + DRWAV_ZERO_MEMORY(reservedBuf, sizeof(reservedBuf)); bytesWritten += drwav__write_or_count(pWav, reservedBuf, sizeof(reservedBuf)); if (pMetadata->data.bext.codingHistorySize > 0) { @@ -4704,6 +4731,7 @@ fallback, so if you notice your compiler not detecting this properly I'm happy t #endif #endif +#ifndef DR_WAV_NO_WCHAR DRWAV_PRIVATE drwav_result drwav_wfopen(FILE** ppFile, const wchar_t* pFilePath, const wchar_t* pOpenMode, const drwav_allocation_callbacks* pAllocationCallbacks) { if (ppFile != NULL) { @@ -4731,11 +4759,24 @@ DRWAV_PRIVATE drwav_result drwav_wfopen(FILE** ppFile, const wchar_t* pFilePath, (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. + /* + 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. */ + + /* + Some compilers don't support wchar_t or wcsrtombs() which we're using below. In this case we just + need to abort with an error. If you encounter a compiler lacking such support, add it to this list + and submit a bug report and it'll be added to the library upstream. + */ + #if defined(__DJGPP__) + { + /* Nothing to do here. This will fall through to the error check below. */ + } + #else { mbstate_t mbs; size_t lenMB; @@ -4777,6 +4818,7 @@ DRWAV_PRIVATE drwav_result drwav_wfopen(FILE** ppFile, const wchar_t* pFilePath, drwav__free_from_callbacks(pFilePathMB, pAllocationCallbacks); } + #endif if (*ppFile == NULL) { return DRWAV_ERROR; @@ -4785,6 +4827,7 @@ DRWAV_PRIVATE drwav_result drwav_wfopen(FILE** ppFile, const wchar_t* pFilePath, return DRWAV_SUCCESS; } +#endif DRWAV_PRIVATE size_t drwav__on_read_stdio(void* pUserData, void* pBufferOut, size_t bytesToRead) @@ -4840,6 +4883,7 @@ DRWAV_API drwav_bool32 drwav_init_file_ex(drwav* pWav, const char* filename, drw return drwav_init_file__internal_FILE(pWav, pFile, onChunk, pChunkUserData, flags, drwav_metadata_type_none, pAllocationCallbacks); } +#ifndef DR_WAV_NO_WCHAR DRWAV_API drwav_bool32 drwav_init_file_w(drwav* pWav, const wchar_t* filename, const drwav_allocation_callbacks* pAllocationCallbacks) { return drwav_init_file_ex_w(pWav, filename, NULL, NULL, 0, pAllocationCallbacks); @@ -4855,6 +4899,7 @@ DRWAV_API drwav_bool32 drwav_init_file_ex_w(drwav* pWav, const wchar_t* filename /* This takes ownership of the FILE* object. */ return drwav_init_file__internal_FILE(pWav, pFile, onChunk, pChunkUserData, flags, drwav_metadata_type_none, pAllocationCallbacks); } +#endif DRWAV_API drwav_bool32 drwav_init_file_with_metadata(drwav* pWav, const char* filename, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks) { @@ -4867,6 +4912,7 @@ DRWAV_API drwav_bool32 drwav_init_file_with_metadata(drwav* pWav, const char* fi return drwav_init_file__internal_FILE(pWav, pFile, NULL, NULL, flags, drwav_metadata_type_all_including_unknown, pAllocationCallbacks); } +#ifndef DR_WAV_NO_WCHAR DRWAV_API drwav_bool32 drwav_init_file_with_metadata_w(drwav* pWav, const wchar_t* filename, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks) { FILE* pFile; @@ -4877,6 +4923,7 @@ DRWAV_API drwav_bool32 drwav_init_file_with_metadata_w(drwav* pWav, const wchar_ /* This takes ownership of the FILE* object. */ return drwav_init_file__internal_FILE(pWav, pFile, NULL, NULL, flags, drwav_metadata_type_all_including_unknown, pAllocationCallbacks); } +#endif DRWAV_PRIVATE drwav_bool32 drwav_init_file_write__internal_FILE(drwav* pWav, FILE* pFile, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_bool32 isSequential, const drwav_allocation_callbacks* pAllocationCallbacks) @@ -4909,6 +4956,7 @@ DRWAV_PRIVATE drwav_bool32 drwav_init_file_write__internal(drwav* pWav, const ch return drwav_init_file_write__internal_FILE(pWav, pFile, pFormat, totalSampleCount, isSequential, pAllocationCallbacks); } +#ifndef DR_WAV_NO_WCHAR DRWAV_PRIVATE drwav_bool32 drwav_init_file_write_w__internal(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_bool32 isSequential, const drwav_allocation_callbacks* pAllocationCallbacks) { FILE* pFile; @@ -4919,6 +4967,7 @@ DRWAV_PRIVATE drwav_bool32 drwav_init_file_write_w__internal(drwav* pWav, const /* This takes ownership of the FILE* object. */ return drwav_init_file_write__internal_FILE(pWav, pFile, pFormat, totalSampleCount, isSequential, pAllocationCallbacks); } +#endif DRWAV_API drwav_bool32 drwav_init_file_write(drwav* pWav, const char* filename, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks) { @@ -4939,6 +4988,7 @@ DRWAV_API drwav_bool32 drwav_init_file_write_sequential_pcm_frames(drwav* pWav, return drwav_init_file_write_sequential(pWav, filename, pFormat, totalPCMFrameCount*pFormat->channels, pAllocationCallbacks); } +#ifndef DR_WAV_NO_WCHAR DRWAV_API drwav_bool32 drwav_init_file_write_w(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks) { return drwav_init_file_write_w__internal(pWav, filename, pFormat, 0, DRWAV_FALSE, pAllocationCallbacks); @@ -4957,6 +5007,7 @@ DRWAV_API drwav_bool32 drwav_init_file_write_sequential_pcm_frames_w(drwav* pWav return drwav_init_file_write_sequential_w(pWav, filename, pFormat, totalPCMFrameCount*pFormat->channels, pAllocationCallbacks); } +#endif #endif /* DR_WAV_NO_STDIO */ @@ -5441,8 +5492,8 @@ DRWAV_API drwav_bool32 drwav_seek_to_pcm_frame(drwav* pWav, drwav_uint64 targetF } /* Make sure the sample is clamped. */ - if (targetFrameIndex >= pWav->totalPCMFrameCount) { - targetFrameIndex = pWav->totalPCMFrameCount - 1; + if (targetFrameIndex > pWav->totalPCMFrameCount) { + targetFrameIndex = pWav->totalPCMFrameCount; } /* @@ -7650,6 +7701,7 @@ DRWAV_API drwav_int32* drwav_open_file_and_read_pcm_frames_s32(const char* filen } +#ifndef DR_WAV_NO_WCHAR DRWAV_API drwav_int16* drwav_open_file_and_read_pcm_frames_s16_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks) { drwav wav; @@ -7712,7 +7764,8 @@ DRWAV_API drwav_int32* drwav_open_file_and_read_pcm_frames_s32_w(const wchar_t* return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); } -#endif +#endif /* DR_WAV_NO_WCHAR */ +#endif /* DR_WAV_NO_STDIO */ DRWAV_API drwav_int16* drwav_open_memory_and_read_pcm_frames_s16(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks) { @@ -7853,12 +7906,28 @@ DRWAV_API drwav_bool32 drwav_fourcc_equal(const drwav_uint8* a, const char* b) a[3] == b[3]; } +#ifdef __MRC__ +/* Undo the pragma at the beginning of this file. */ +#pragma options opt reset +#endif + #endif /* dr_wav_c */ #endif /* DR_WAV_IMPLEMENTATION */ /* REVISION HISTORY ================ +v0.13.7 - 2022-09-17 + - Fix compilation with DJGPP. + - Add support for disabling wchar_t with DR_WAV_NO_WCHAR. + +v0.13.6 - 2022-04-10 + - Fix compilation error on older versions of GCC. + - Remove some dependencies on the standard library. + +v0.13.5 - 2022-01-26 + - Fix an error when seeking to the end of the file. + v0.13.4 - 2021-12-08 - Fix some static analysis warnings. diff --git a/src/external/miniaudio.h b/src/external/miniaudio.h index d454c49788a5..ad3651503150 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.11 - TBD +miniaudio - v0.11.11 - 2022-11-04 David Reid - mackron@gmail.com @@ -1273,6 +1273,14 @@ When streaming sounds, 2 seconds worth of audio data is stored in memory. Althou fine, it's inefficient to use streaming for short sounds. Streaming is useful for things like music tracks in games. +When loading a sound from a file path, the engine will reference count the file to prevent it from +being loaded if it's already in memory. When you uninitialize a sound, the reference count will be +decremented, and if it hits zero, the sound will be unloaded from memory. This reference counting +system is not used for streams. The engine will use a 64-bit hash of the file name when comparing +file paths which means there's a small chance you might encounter a name collision. If this is an +issue, you'll need to use a different name for one of the colliding file paths, or just not load +from files and instead load from a data source. + When you initialize a sound, if you specify a sound group the sound will be attached to that group automatically. If you set it to NULL, it will be automatically attached to the engine's endpoint. If you would instead rather leave the sound unattached by default, you can can specify the @@ -1870,9 +1878,11 @@ A binary search tree (BST) is used for storing data buffers as it has good balan efficiency and simplicity. The key of the BST is a 64-bit hash of the file path that was passed into `ma_resource_manager_data_source_init()`. The advantage of using a hash is that it saves memory over storing the entire path, has faster comparisons, and results in a mostly balanced BST -due to the random nature of the hash. The disadvantage is that file names are case-sensitive. If -this is an issue, you should normalize your file names to upper- or lower-case before initializing -your data sources. +due to the random nature of the hash. The disadvantages are that file names are case-sensitive and +there's a small chance of name collisions. If case-sensitivity is an issue, you should normalize +your file names to upper- or lower-case before initializing your data sources. If name collisions +become an issue, you'll need to change the name of one of the colliding names or just not use the +resource manager. When a sound file has not already been loaded and the `MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC` flag is excluded, the file will be decoded synchronously by the calling thread. There are two @@ -22223,50 +22233,100 @@ static ma_result ma_device_read__wasapi(ma_device* pDevice, void* pFrames, ma_ui } else { /* We don't have any cached data pointer, so grab another one. */ HRESULT hr; - DWORD flags; + DWORD flags = 0; /* First just ask WASAPI for a data buffer. If it's not available, we'll wait for more. */ hr = ma_IAudioCaptureClient_GetBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, (BYTE**)&pDevice->wasapi.pMappedBufferCapture, &pDevice->wasapi.mappedBufferCaptureCap, &flags, NULL, NULL); if (hr == S_OK) { /* We got a data buffer. Continue to the next loop iteration which will then read from the mapped pointer. */ + pDevice->wasapi.mappedBufferCaptureLen = pDevice->wasapi.mappedBufferCaptureCap; + + /* + There have been reports that indicate that at times the AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY is reported for every + call to IAudioCaptureClient_GetBuffer() above which results in spamming of the debug messages below. To partially + work around this, I'm only outputting these messages when MA_DEBUG_OUTPUT is explicitly defined. The better solution + would be to figure out why the flag is always getting reported. + */ + #if defined(MA_DEBUG_OUTPUT) + { + if (flags != 0) { + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Capture Flags: %ld\n", flags); + + if ((flags & MA_AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY) != 0) { + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Data discontinuity (possible overrun). Attempting recovery. mappedBufferCaptureCap=%d\n", pDevice->wasapi.mappedBufferCaptureCap); + } + } + } + #endif /* Overrun detection. */ if ((flags & MA_AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY) != 0) { /* Glitched. Probably due to an overrun. */ - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Data discontinuity (possible overrun). Attempting recovery. mappedBufferCaptureCap=%d\n", pDevice->wasapi.mappedBufferCaptureCap); /* - If we got an overrun it probably means we're straddling the end of the buffer. In order to prevent - a never-ending sequence of glitches we're going to recover by completely clearing out the capture - buffer. + If we got an overrun it probably means we're straddling the end of the buffer. In normal capture + mode this is the fault of the client application because they're responsible for ensuring data is + processed fast enough. In duplex mode, however, the processing of audio is tied to the playback + device, so this can possibly be the result of a timing de-sync. + + In capture mode we're not going to do any kind of recovery because the real fix is for the client + application to process faster. In duplex mode, we'll treat this as a desync and reset the buffers + to prevent a never-ending sequence of glitches due to straddling the end of the buffer. */ - { - ma_uint32 iterationCount = 4; /* Safety to prevent an infinite loop. */ + if (pDevice->type == ma_device_type_duplex) { + /* + Experiment: + + If we empty out the *entire* buffer we may end up putting ourselves into an underrun position + which isn't really any better than the overrun we're probably in right now. Instead we'll just + empty out about half. + */ ma_uint32 i; + ma_uint32 periodCount = (pDevice->wasapi.actualBufferSizeInFramesCapture / pDevice->wasapi.periodSizeInFramesCapture); + ma_uint32 iterationCount = periodCount / 2; + if ((periodCount % 2) > 0) { + iterationCount += 1; + } for (i = 0; i < iterationCount; i += 1) { hr = ma_IAudioCaptureClient_ReleaseBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, pDevice->wasapi.mappedBufferCaptureCap); if (FAILED(hr)) { + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Data discontinuity recovery: IAudioCaptureClient_ReleaseBuffer() failed with %d.\n", hr); break; } + flags = 0; hr = ma_IAudioCaptureClient_GetBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, (BYTE**)&pDevice->wasapi.pMappedBufferCapture, &pDevice->wasapi.mappedBufferCaptureCap, &flags, NULL, NULL); if (hr == MA_AUDCLNT_S_BUFFER_EMPTY || FAILED(hr)) { + /* + The buffer has been completely emptied or an error occurred. In this case we'll need + to reset the state of the mapped buffer which will trigger the next iteration to get + a fresh buffer from WASAPI. + */ + pDevice->wasapi.pMappedBufferCapture = NULL; + pDevice->wasapi.mappedBufferCaptureCap = 0; + pDevice->wasapi.mappedBufferCaptureLen = 0; + + if (hr == MA_AUDCLNT_S_BUFFER_EMPTY) { + if ((flags & MA_AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY) != 0) { + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Data discontinuity recovery: Buffer emptied, and data discontinuity still reported.\n"); + } else { + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Data discontinuity recovery: Buffer emptied.\n"); + } + } + + if (FAILED(hr)) { + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Data discontinuity recovery: IAudioCaptureClient_GetBuffer() failed with %d.\n", hr); + } + break; } } - } - - /* We should not have a valid buffer at this point so make sure everything is empty. */ - pDevice->wasapi.pMappedBufferCapture = NULL; - pDevice->wasapi.mappedBufferCaptureCap = 0; - pDevice->wasapi.mappedBufferCaptureLen = 0; - } else { - /* The data is clean. */ - pDevice->wasapi.mappedBufferCaptureLen = pDevice->wasapi.mappedBufferCaptureCap; - if (flags != 0) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Capture Flags: %ld\n", flags); + /* If at this point we have a valid buffer mapped, make sure the buffer length is set appropriately. */ + if (pDevice->wasapi.pMappedBufferCapture != NULL) { + pDevice->wasapi.mappedBufferCaptureLen = pDevice->wasapi.mappedBufferCaptureCap; + } } } @@ -22279,7 +22339,7 @@ static ma_result ma_device_read__wasapi(ma_device* pDevice, void* pFrames, ma_ui microphone isn't delivering data for whatever reason. In this case we'll just abort the read and return whatever we were able to get. The other situations is loopback mode, in which case a timeout probably just means the nothing is playing - through the speakers. + through the speakers. */ /* Experiment: Use a shorter timeout for loopback mode. */ diff --git a/src/external/stb_image.h b/src/external/stb_image.h index d60371b95f50..5e807a0a6e7c 100644 --- a/src/external/stb_image.h +++ b/src/external/stb_image.h @@ -1,4 +1,4 @@ -/* stb_image - v2.27 - public domain image loader - http://nothings.org/stb +/* stb_image - v2.28 - public domain image loader - http://nothings.org/stb no warranty implied; use at your own risk Do this: @@ -48,6 +48,7 @@ LICENSE RECENT REVISION HISTORY: + 2.28 (2023-01-29) many error fixes, security errors, just tons of stuff 2.27 (2021-07-11) document stbi_info better, 16-bit PNM support, bug fixes 2.26 (2020-07-13) many minor fixes 2.25 (2020-02-02) fix warnings @@ -108,7 +109,7 @@ RECENT REVISION HISTORY: Cass Everitt Ryamond Barbiero github:grim210 Paul Du Bois Engin Manap Aldo Culquicondor github:sammyhw Philipp Wiesemann Dale Weiler Oriol Ferrer Mesia github:phprus - Josh Tobin Matthew Gregan github:poppolopoppo + Josh Tobin Neil Bickford Matthew Gregan github:poppolopoppo Julian Raschke Gregory Mullen Christian Floisand github:darealshinji Baldur Karlsson Kevin Schmidt JR Smith github:Michaelangel007 Brad Weinberger Matvey Cherevko github:mosra @@ -140,7 +141,7 @@ RECENT REVISION HISTORY: // // ... x = width, y = height, n = # 8-bit components per pixel ... // // ... replace '0' with '1'..'4' to force that many components per pixel // // ... but 'n' will always be the number that it would have been if you said 0 -// stbi_image_free(data) +// stbi_image_free(data); // // Standard parameters: // int *x -- outputs image width in pixels @@ -635,7 +636,7 @@ STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const ch #endif #endif -#ifdef _MSC_VER +#if defined(_MSC_VER) || defined(__SYMBIAN32__) typedef unsigned short stbi__uint16; typedef signed short stbi__int16; typedef unsigned int stbi__uint32; @@ -1063,6 +1064,23 @@ static void *stbi__malloc_mad4(int a, int b, int c, int d, int add) } #endif +// returns 1 if the sum of two signed ints is valid (between -2^31 and 2^31-1 inclusive), 0 on overflow. +static int stbi__addints_valid(int a, int b) +{ + if ((a >= 0) != (b >= 0)) return 1; // a and b have different signs, so no overflow + if (a < 0 && b < 0) return a >= INT_MIN - b; // same as a + b >= INT_MIN; INT_MIN - b cannot overflow since b < 0. + return a <= INT_MAX - b; +} + +// returns 1 if the product of two signed shorts is valid, 0 on overflow. +static int stbi__mul2shorts_valid(short a, short b) +{ + if (b == 0 || b == -1) return 1; // multiplication by 0 is always 0; check for -1 so SHRT_MIN/b doesn't overflow + if ((a >= 0) == (b >= 0)) return a <= SHRT_MAX/b; // product is positive, so similar to mul2sizes_valid + if (b < 0) return a <= SHRT_MIN / b; // same as a * b >= SHRT_MIN + return a >= SHRT_MIN / b; +} + // stbi__err - error // stbi__errpf - error returning pointer to float // stbi__errpuc - error returning pointer to unsigned char @@ -1985,9 +2003,12 @@ static int stbi__build_huffman(stbi__huffman *h, int *count) int i,j,k=0; unsigned int code; // build size list for each symbol (from JPEG spec) - for (i=0; i < 16; ++i) - for (j=0; j < count[i]; ++j) + for (i=0; i < 16; ++i) { + for (j=0; j < count[i]; ++j) { h->size[k++] = (stbi_uc) (i+1); + if(k >= 257) return stbi__err("bad size list","Corrupt JPEG"); + } + } h->size[k] = 0; // compute actual symbols (from jpeg spec) @@ -2112,6 +2133,8 @@ stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h) // convert the huffman code to the symbol id c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k]; + if(c < 0 || c >= 256) // symbol id out of bounds! + return -1; STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]); // convert the id to a symbol @@ -2130,6 +2153,7 @@ stbi_inline static int stbi__extend_receive(stbi__jpeg *j, int n) unsigned int k; int sgn; if (j->code_bits < n) stbi__grow_buffer_unsafe(j); + if (j->code_bits < n) return 0; // ran out of bits from stream, return 0s intead of continuing sgn = j->code_buffer >> 31; // sign bit always in MSB; 0 if MSB clear (positive), 1 if MSB set (negative) k = stbi_lrot(j->code_buffer, n); @@ -2144,6 +2168,7 @@ stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n) { unsigned int k; if (j->code_bits < n) stbi__grow_buffer_unsafe(j); + if (j->code_bits < n) return 0; // ran out of bits from stream, return 0s intead of continuing k = stbi_lrot(j->code_buffer, n); j->code_buffer = k & ~stbi__bmask[n]; k &= stbi__bmask[n]; @@ -2155,6 +2180,7 @@ stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j) { unsigned int k; if (j->code_bits < 1) stbi__grow_buffer_unsafe(j); + if (j->code_bits < 1) return 0; // ran out of bits from stream, return 0s intead of continuing k = j->code_buffer; j->code_buffer <<= 1; --j->code_bits; @@ -2192,8 +2218,10 @@ static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman memset(data,0,64*sizeof(data[0])); diff = t ? stbi__extend_receive(j, t) : 0; + if (!stbi__addints_valid(j->img_comp[b].dc_pred, diff)) return stbi__err("bad delta","Corrupt JPEG"); dc = j->img_comp[b].dc_pred + diff; j->img_comp[b].dc_pred = dc; + if (!stbi__mul2shorts_valid(dc, dequant[0])) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); data[0] = (short) (dc * dequant[0]); // decode AC components, see JPEG spec @@ -2207,6 +2235,7 @@ static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman if (r) { // fast-AC path k += (r >> 4) & 15; // run s = r & 15; // combined length + if (s > j->code_bits) return stbi__err("bad huffman code", "Combined length longer than code bits available"); j->code_buffer <<= s; j->code_bits -= s; // decode into unzigzag'd location @@ -2246,8 +2275,10 @@ static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__ if (t < 0 || t > 15) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); diff = t ? stbi__extend_receive(j, t) : 0; + if (!stbi__addints_valid(j->img_comp[b].dc_pred, diff)) return stbi__err("bad delta", "Corrupt JPEG"); dc = j->img_comp[b].dc_pred + diff; j->img_comp[b].dc_pred = dc; + if (!stbi__mul2shorts_valid(dc, 1 << j->succ_low)) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); data[0] = (short) (dc * (1 << j->succ_low)); } else { // refinement scan for DC coefficient @@ -2282,6 +2313,7 @@ static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__ if (r) { // fast-AC path k += (r >> 4) & 15; // run s = r & 15; // combined length + if (s > j->code_bits) return stbi__err("bad huffman code", "Combined length longer than code bits available"); j->code_buffer <<= s; j->code_bits -= s; zig = stbi__jpeg_dezigzag[k++]; @@ -3102,6 +3134,7 @@ static int stbi__process_marker(stbi__jpeg *z, int m) sizes[i] = stbi__get8(z->s); n += sizes[i]; } + if(n > 256) return stbi__err("bad DHT header","Corrupt JPEG"); // Loop over i < n would write past end of values! L -= 17; if (tc == 0) { if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0; @@ -3351,6 +3384,28 @@ static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan) return 1; } +static int stbi__skip_jpeg_junk_at_end(stbi__jpeg *j) +{ + // some JPEGs have junk at end, skip over it but if we find what looks + // like a valid marker, resume there + while (!stbi__at_eof(j->s)) { + int x = stbi__get8(j->s); + while (x == 255) { // might be a marker + if (stbi__at_eof(j->s)) return STBI__MARKER_none; + x = stbi__get8(j->s); + if (x != 0x00 && x != 0xff) { + // not a stuffed zero or lead-in to another marker, looks + // like an actual marker, return it + return x; + } + // stuffed zero has x=0 now which ends the loop, meaning we go + // back to regular scan loop. + // repeated 0xff keeps trying to read the next byte of the marker. + } + } + return STBI__MARKER_none; +} + // decode image to YCbCr format static int stbi__decode_jpeg_image(stbi__jpeg *j) { @@ -3367,25 +3422,22 @@ static int stbi__decode_jpeg_image(stbi__jpeg *j) if (!stbi__process_scan_header(j)) return 0; if (!stbi__parse_entropy_coded_data(j)) return 0; if (j->marker == STBI__MARKER_none ) { - // handle 0s at the end of image data from IP Kamera 9060 - while (!stbi__at_eof(j->s)) { - int x = stbi__get8(j->s); - if (x == 255) { - j->marker = stbi__get8(j->s); - break; - } - } + j->marker = stbi__skip_jpeg_junk_at_end(j); // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0 } + m = stbi__get_marker(j); + if (STBI__RESTART(m)) + m = stbi__get_marker(j); } else if (stbi__DNL(m)) { int Ld = stbi__get16be(j->s); stbi__uint32 NL = stbi__get16be(j->s); if (Ld != 4) return stbi__err("bad DNL len", "Corrupt JPEG"); if (NL != j->s->img_y) return stbi__err("bad DNL height", "Corrupt JPEG"); + m = stbi__get_marker(j); } else { - if (!stbi__process_marker(j, m)) return 0; + if (!stbi__process_marker(j, m)) return 1; + m = stbi__get_marker(j); } - m = stbi__get_marker(j); } if (j->progressive) stbi__jpeg_finish(j); @@ -3976,6 +4028,7 @@ static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int re unsigned char* result; stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg)); if (!j) return stbi__errpuc("outofmem", "Out of memory"); + memset(j, 0, sizeof(stbi__jpeg)); STBI_NOTUSED(ri); j->s = s; stbi__setup_jpeg(j); @@ -3989,6 +4042,7 @@ static int stbi__jpeg_test(stbi__context *s) int r; stbi__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg)); if (!j) return stbi__err("outofmem", "Out of memory"); + memset(j, 0, sizeof(stbi__jpeg)); j->s = s; stbi__setup_jpeg(j); r = stbi__decode_jpeg_header(j, STBI__SCAN_type); @@ -4014,6 +4068,7 @@ static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) int result; stbi__jpeg* j = (stbi__jpeg*) (stbi__malloc(sizeof(stbi__jpeg))); if (!j) return stbi__err("outofmem", "Out of memory"); + memset(j, 0, sizeof(stbi__jpeg)); j->s = s; result = stbi__jpeg_info_raw(j, x, y, comp); STBI_FREE(j); @@ -4256,11 +4311,12 @@ static int stbi__parse_huffman_block(stbi__zbuf *a) a->zout = zout; return 1; } + if (z >= 286) return stbi__err("bad huffman code","Corrupt PNG"); // per DEFLATE, length codes 286 and 287 must not appear in compressed data z -= 257; len = stbi__zlength_base[z]; if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]); z = stbi__zhuffman_decode(a, &a->z_distance); - if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); + if (z < 0 || z >= 30) return stbi__err("bad huffman code","Corrupt PNG"); // per DEFLATE, distance codes 30 and 31 must not appear in compressed data dist = stbi__zdist_base[z]; if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]); if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG"); @@ -4955,7 +5011,7 @@ STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert) static STBI_THREAD_LOCAL int stbi__unpremultiply_on_load_local, stbi__unpremultiply_on_load_set; static STBI_THREAD_LOCAL int stbi__de_iphone_flag_local, stbi__de_iphone_flag_set; -STBIDEF void stbi__unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply) +STBIDEF void stbi_set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply) { stbi__unpremultiply_on_load_local = flag_true_if_should_unpremultiply; stbi__unpremultiply_on_load_set = 1; @@ -5064,14 +5120,13 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) if (!pal_img_n) { s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode"); - if (scan == STBI__SCAN_header) return 1; } else { // if paletted, then pal_n is our final components, and // img_n is # components to decompress/filter. s->img_n = 1; if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG"); - // if SCAN_header, have to scan to see if we have a tRNS } + // even with SCAN_header, have to scan to see if we have a tRNS break; } @@ -5103,6 +5158,8 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG"); if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG"); has_trans = 1; + // non-paletted with tRNS = constant alpha. if header-scanning, we can stop now. + if (scan == STBI__SCAN_header) { ++s->img_n; return 1; } if (z->depth == 16) { for (k = 0; k < s->img_n; ++k) tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is } else { @@ -5115,7 +5172,13 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) case STBI__PNG_TYPE('I','D','A','T'): { if (first) return stbi__err("first not IHDR", "Corrupt PNG"); if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG"); - if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; } + if (scan == STBI__SCAN_header) { + // header scan definitely stops at first IDAT + if (pal_img_n) + s->img_n = pal_img_n; + return 1; + } + if (c.length > (1u << 30)) return stbi__err("IDAT size limit", "IDAT section larger than 2^30 bytes"); if ((int)(ioff + c.length) < (int)ioff) return 0; if (ioff + c.length > idata_limit) { stbi__uint32 idata_limit_old = idata_limit; @@ -5498,8 +5561,22 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req psize = (info.offset - info.extra_read - info.hsz) >> 2; } if (psize == 0) { - if (info.offset != s->callback_already_read + (s->img_buffer - s->img_buffer_original)) { - return stbi__errpuc("bad offset", "Corrupt BMP"); + // accept some number of extra bytes after the header, but if the offset points either to before + // the header ends or implies a large amount of extra data, reject the file as malformed + int bytes_read_so_far = s->callback_already_read + (int)(s->img_buffer - s->img_buffer_original); + int header_limit = 1024; // max we actually read is below 256 bytes currently. + int extra_data_limit = 256*4; // what ordinarily goes here is a palette; 256 entries*4 bytes is its max size. + if (bytes_read_so_far <= 0 || bytes_read_so_far > header_limit) { + return stbi__errpuc("bad header", "Corrupt BMP"); + } + // we established that bytes_read_so_far is positive and sensible. + // the first half of this test rejects offsets that are either too small positives, or + // negative, and guarantees that info.offset >= bytes_read_so_far > 0. this in turn + // ensures the number computed in the second half of the test can't overflow. + if (info.offset < bytes_read_so_far || info.offset - bytes_read_so_far > extra_data_limit) { + return stbi__errpuc("bad offset", "Corrupt BMP"); + } else { + stbi__skip(s, info.offset - bytes_read_so_far); } } @@ -7187,12 +7264,12 @@ static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int re // Run value = stbi__get8(s); count -= 128; - if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } + if ((count == 0) || (count > nleft)) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } for (z = 0; z < count; ++z) scanline[i++ * 4 + k] = value; } else { // Dump - if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } + if ((count == 0) || (count > nleft)) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } for (z = 0; z < count; ++z) scanline[i++ * 4 + k] = stbi__get8(s); } @@ -7446,10 +7523,17 @@ static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req out = (stbi_uc *) stbi__malloc_mad4(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0); if (!out) return stbi__errpuc("outofmem", "Out of memory"); - stbi__getn(s, out, s->img_n * s->img_x * s->img_y * (ri->bits_per_channel / 8)); + if (!stbi__getn(s, out, s->img_n * s->img_x * s->img_y * (ri->bits_per_channel / 8))) { + STBI_FREE(out); + return stbi__errpuc("bad PNM", "PNM file truncated"); + } if (req_comp && req_comp != s->img_n) { - out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); + if (ri->bits_per_channel == 16) { + out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, s->img_n, req_comp, s->img_x, s->img_y); + } else { + out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); + } if (out == NULL) return out; // stbi__convert_format frees input on failure } return out; @@ -7486,6 +7570,8 @@ static int stbi__pnm_getinteger(stbi__context *s, char *c) while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) { value = value*10 + (*c - '0'); *c = (char) stbi__get8(s); + if((value > 214748364) || (value == 214748364 && *c > '7')) + return stbi__err("integer parse overflow", "Parsing an integer in the PPM header overflowed a 32-bit int"); } return value; @@ -7516,9 +7602,13 @@ static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp) stbi__pnm_skip_whitespace(s, &c); *x = stbi__pnm_getinteger(s, &c); // read width + if(*x == 0) + return stbi__err("invalid width", "PPM image header had zero or overflowing width"); stbi__pnm_skip_whitespace(s, &c); *y = stbi__pnm_getinteger(s, &c); // read height + if (*y == 0) + return stbi__err("invalid width", "PPM image header had zero or overflowing width"); stbi__pnm_skip_whitespace(s, &c); maxv = stbi__pnm_getinteger(s, &c); // read max value diff --git a/src/external/stb_vorbis.h b/src/external/stb_vorbis.c similarity index 68% rename from src/external/stb_vorbis.h rename to src/external/stb_vorbis.c index 2fcbc4afcd8e..3e5c2504c08f 100644 --- a/src/external/stb_vorbis.h +++ b/src/external/stb_vorbis.c @@ -1,4 +1,4 @@ -// Ogg Vorbis audio decoder - v1.14 - public domain +// Ogg Vorbis audio decoder - v1.22 - public domain // http://nothings.org/stb_vorbis/ // // Original version written by Sean Barrett in 2007. @@ -26,18 +26,29 @@ // Terje Mathisen Niklas Frykholm Andy Hill // Casey Muratori John Bolton Gargaj // Laurent Gomila Marc LeBlanc Ronny Chevalier -// Bernhard Wodo Evan Balster alxprd@github +// Bernhard Wodo Evan Balster github:alxprd // Tom Beaumont Ingo Leitgeb Nicolas Guillemot // Phillip Bennefall Rohit Thiago Goulart -// manxorist@github saga musix github:infatum -// Timur Gagiev BareRose +// github:manxorist Saga Musix github:infatum +// Timur Gagiev Maxwell Koo Peter Waller +// github:audinowho Dougall Johnson David Reid +// github:Clownacy Pedro J. Estebanez Remi Verschelde +// AnthoFoxo github:morlat Gabriel Ravier // // Partial history: +// 1.22 - 2021-07-11 - various small fixes +// 1.21 - 2021-07-02 - fix bug for files with no comments +// 1.20 - 2020-07-11 - several small fixes +// 1.19 - 2020-02-05 - warnings +// 1.18 - 2020-02-02 - fix seek bugs; parse header comments; misc warnings etc. +// 1.17 - 2019-07-08 - fix CVE-2019-13217..CVE-2019-13223 (by ForAllSecure) +// 1.16 - 2019-03-04 - fix warnings +// 1.15 - 2019-02-07 - explicit failure if Ogg Skeleton data is found // 1.14 - 2018-02-11 - delete bogus dealloca usage // 1.13 - 2018-01-29 - fix truncation of last frame (hopefully) // 1.12 - 2017-11-21 - limit residue begin/end to blocksize/2 to avoid large temp allocs in bad/corrupt files -// 1.11 - 2017-07-23 - fix MinGW compilation -// 1.10 - 2017-03-03 - more robust seeking; fix negative stbv_ilog(); clear error in open_memory +// 1.11 - 2017-07-23 - fix MinGW compilation +// 1.10 - 2017-03-03 - more robust seeking; fix negative ilog(); clear error in open_memory // 1.09 - 2016-04-04 - back out 'truncation of last frame' fix from previous version // 1.08 - 2016-04-02 - warnings; setup memory leaks; truncation of last frame // 1.07 - 2015-01-16 - fixes for crashes on invalid files; warning fixes; const @@ -64,28 +75,17 @@ #define STB_VORBIS_INCLUDE_STB_VORBIS_H #if defined(STB_VORBIS_NO_CRT) && !defined(STB_VORBIS_NO_STDIO) -#define STB_VORBIS_NO_STDIO +#define STB_VORBIS_NO_STDIO 1 #endif #ifndef STB_VORBIS_NO_STDIO #include #endif -// NOTE: Added to work with raylib on Android -#if defined(PLATFORM_ANDROID) - #include "utils.h" // Android fopen function map -#endif - #ifdef __cplusplus extern "C" { #endif -#ifdef STB_VORBIS_STATIC -#define STBVDEF static -#else -#define STBVDEF extern -#endif - /////////// THREAD SAFETY // Individual stb_vorbis* handles are not thread-safe; you cannot decode from @@ -101,8 +101,8 @@ extern "C" { // data in the file and how you set the compile flags for speed // vs. size. In my test files the maximal-size usage is ~150KB.) // -// You can modify the wrapper functions in the source (stbv_setup_malloc, -// stbv_setup_temp_malloc, temp_malloc) to change this behavior, or you +// You can modify the wrapper functions in the source (setup_malloc, +// setup_temp_malloc, temp_malloc) to change this behavior, or you // can use a simpler allocation model: you pass in a buffer from // which stb_vorbis will allocate _all_ its memory (including the // temp memory). "open" may fail with a VORBIS_outofmem if you @@ -138,25 +138,36 @@ typedef struct int max_frame_size; } stb_vorbis_info; +typedef struct +{ + char *vendor; + + int comment_list_length; + char **comment_list; +} stb_vorbis_comment; + // get general information about the file -STBVDEF stb_vorbis_info stb_vorbis_get_info(stb_vorbis *f); +extern stb_vorbis_info stb_vorbis_get_info(stb_vorbis *f); + +// get ogg comments +extern stb_vorbis_comment stb_vorbis_get_comment(stb_vorbis *f); // get the last error detected (clears it, too) -STBVDEF int stb_vorbis_get_error(stb_vorbis *f); +extern int stb_vorbis_get_error(stb_vorbis *f); // close an ogg vorbis file and free all memory in use -STBVDEF void stb_vorbis_close(stb_vorbis *f); +extern void stb_vorbis_close(stb_vorbis *f); // this function returns the offset (in samples) from the beginning of the // file that will be returned by the next decode, if it is known, or -1 // otherwise. after a flush_pushdata() call, this may take a while before // it becomes valid again. // NOT WORKING YET after a seek with PULLDATA API -STBVDEF int stb_vorbis_get_sample_offset(stb_vorbis *f); +extern int stb_vorbis_get_sample_offset(stb_vorbis *f); // returns the current seek point within the file, or offset from the beginning // of the memory buffer. In pushdata mode it returns 0. -STBVDEF unsigned int stb_vorbis_get_file_offset(stb_vorbis *f); +extern unsigned int stb_vorbis_get_file_offset(stb_vorbis *f); /////////// PUSHDATA API @@ -169,7 +180,7 @@ STBVDEF unsigned int stb_vorbis_get_file_offset(stb_vorbis *f); // need to give it the same data again PLUS more. Note that the Vorbis // specification does not bound the size of an individual frame. -STBVDEF stb_vorbis *stb_vorbis_open_pushdata( +extern stb_vorbis *stb_vorbis_open_pushdata( const unsigned char * datablock, int datablock_length_in_bytes, int *datablock_memory_consumed_in_bytes, int *error, @@ -183,7 +194,7 @@ STBVDEF stb_vorbis *stb_vorbis_open_pushdata( // if returns NULL and *error is VORBIS_need_more_data, then the input block was // incomplete and you need to pass in a larger block from the start of the file -STBVDEF int stb_vorbis_decode_frame_pushdata( +extern int stb_vorbis_decode_frame_pushdata( stb_vorbis *f, const unsigned char *datablock, int datablock_length_in_bytes, int *channels, // place to write number of float * buffers @@ -212,8 +223,14 @@ STBVDEF int stb_vorbis_decode_frame_pushdata( // channel. In other words, (*output)[0][0] contains the first sample from // the first channel, and (*output)[1][0] contains the first sample from // the second channel. +// +// *output points into stb_vorbis's internal output buffer storage; these +// buffers are owned by stb_vorbis and application code should not free +// them or modify their contents. They are transient and will be overwritten +// once you ask for more data to get decoded, so be sure to grab any data +// you need before then. -STBVDEF void stb_vorbis_flush_pushdata(stb_vorbis *f); +extern void stb_vorbis_flush_pushdata(stb_vorbis *f); // inform stb_vorbis that your next datablock will not be contiguous with // previous ones (e.g. you've seeked in the data); future attempts to decode // frames will cause stb_vorbis to resynchronize (as noted above), and @@ -238,38 +255,38 @@ STBVDEF void stb_vorbis_flush_pushdata(stb_vorbis *f); // just want to go ahead and use pushdata.) #if !defined(STB_VORBIS_NO_STDIO) && !defined(STB_VORBIS_NO_INTEGER_CONVERSION) -STBVDEF int stb_vorbis_decode_filename(const char *filename, int *channels, int *sample_rate, short **output); +extern int stb_vorbis_decode_filename(const char *filename, int *channels, int *sample_rate, short **output); #endif -#ifndef STB_VORBIS_NO_INTEGER_CONVERSION -STBVDEF int stb_vorbis_decode_memory(const unsigned char *mem, int len, int *channels, int *sample_rate, short **output); +#if !defined(STB_VORBIS_NO_INTEGER_CONVERSION) +extern int stb_vorbis_decode_memory(const unsigned char *mem, int len, int *channels, int *sample_rate, short **output); #endif // decode an entire file and output the data interleaved into a malloc()ed // buffer stored in *output. The return value is the number of samples // decoded, or -1 if the file could not be opened or was not an ogg vorbis file. // When you're done with it, just free() the pointer returned in *output. -STBVDEF stb_vorbis * stb_vorbis_open_memory(const unsigned char *data, int len, +extern stb_vorbis * stb_vorbis_open_memory(const unsigned char *data, int len, int *error, const stb_vorbis_alloc *alloc_buffer); // create an ogg vorbis decoder from an ogg vorbis stream in memory (note // this must be the entire stream!). on failure, returns NULL and sets *error #ifndef STB_VORBIS_NO_STDIO -STBVDEF stb_vorbis * stb_vorbis_open_filename(const char *filename, +extern stb_vorbis * stb_vorbis_open_filename(const char *filename, int *error, const stb_vorbis_alloc *alloc_buffer); // create an ogg vorbis decoder from a filename via fopen(). on failure, // returns NULL and sets *error (possibly to VORBIS_file_open_failure). -STBVDEF stb_vorbis * stb_vorbis_open_file(FILE *f, int close_handle_on_close, +extern stb_vorbis * stb_vorbis_open_file(FILE *f, int close_handle_on_close, int *error, const stb_vorbis_alloc *alloc_buffer); // create an ogg vorbis decoder from an open FILE *, looking for a stream at // the _current_ seek point (ftell). on failure, returns NULL and sets *error. // note that stb_vorbis must "own" this stream; if you seek it in between -// calls to stb_vorbis, it will become confused. Morever, if you attempt to +// calls to stb_vorbis, it will become confused. Moreover, if you attempt to // perform stb_vorbis_seek_*() operations on this file, it will assume it // owns the _entire_ rest of the file after the start point. Use the next // function, stb_vorbis_open_file_section(), to limit it. -STBVDEF stb_vorbis * stb_vorbis_open_file_section(FILE *f, int close_handle_on_close, +extern stb_vorbis * stb_vorbis_open_file_section(FILE *f, int close_handle_on_close, int *error, const stb_vorbis_alloc *alloc_buffer, unsigned int len); // create an ogg vorbis decoder from an open FILE *, looking for a stream at // the _current_ seek point (ftell); the stream will be of length 'len' bytes. @@ -278,8 +295,8 @@ STBVDEF stb_vorbis * stb_vorbis_open_file_section(FILE *f, int close_handle_on_c // confused. #endif -STBVDEF int stb_vorbis_seek_frame(stb_vorbis *f, unsigned int sample_number); -STBVDEF int stb_vorbis_seek(stb_vorbis *f, unsigned int sample_number); +extern int stb_vorbis_seek_frame(stb_vorbis *f, unsigned int sample_number); +extern int stb_vorbis_seek(stb_vorbis *f, unsigned int sample_number); // these functions seek in the Vorbis file to (approximately) 'sample_number'. // after calling seek_frame(), the next call to get_frame_*() will include // the specified sample. after calling stb_vorbis_seek(), the next call to @@ -287,14 +304,14 @@ STBVDEF int stb_vorbis_seek(stb_vorbis *f, unsigned int sample_number); // do not need to seek to EXACTLY the target sample when using get_samples_*, // you can also use seek_frame(). -STBVDEF int stb_vorbis_seek_start(stb_vorbis *f); +extern int stb_vorbis_seek_start(stb_vorbis *f); // this function is equivalent to stb_vorbis_seek(f,0) -STBVDEF unsigned int stb_vorbis_stream_length_in_samples(stb_vorbis *f); -STBVDEF float stb_vorbis_stream_length_in_seconds(stb_vorbis *f); +extern unsigned int stb_vorbis_stream_length_in_samples(stb_vorbis *f); +extern float stb_vorbis_stream_length_in_seconds(stb_vorbis *f); // these functions return the total length of the vorbis stream -STBVDEF int stb_vorbis_get_frame_float(stb_vorbis *f, int *channels, float ***output); +extern int stb_vorbis_get_frame_float(stb_vorbis *f, int *channels, float ***output); // decode the next frame and return the number of samples. the number of // channels returned are stored in *channels (which can be NULL--it is always // the same as the number of channels reported by get_info). *output will @@ -305,8 +322,8 @@ STBVDEF int stb_vorbis_get_frame_float(stb_vorbis *f, int *channels, float ***ou // and stb_vorbis_get_samples_*(), since the latter calls the former. #ifndef STB_VORBIS_NO_INTEGER_CONVERSION -STBVDEF int stb_vorbis_get_frame_short_interleaved(stb_vorbis *f, int num_c, short *buffer, int num_shorts); -STBVDEF int stb_vorbis_get_frame_short (stb_vorbis *f, int num_c, short **buffer, int num_samples); +extern int stb_vorbis_get_frame_short_interleaved(stb_vorbis *f, int num_c, short *buffer, int num_shorts); +extern int stb_vorbis_get_frame_short (stb_vorbis *f, int num_c, short **buffer, int num_samples); #endif // decode the next frame and return the number of *samples* per channel. // Note that for interleaved data, you pass in the number of shorts (the @@ -333,16 +350,16 @@ STBVDEF int stb_vorbis_get_frame_short (stb_vorbis *f, int num_c, sho // Note that this is not _good_ surround etc. mixing at all! It's just so // you get something useful. -STBVDEF int stb_vorbis_get_samples_float_interleaved(stb_vorbis *f, int channels, float *buffer, int num_floats); -STBVDEF int stb_vorbis_get_samples_float(stb_vorbis *f, int channels, float **buffer, int num_samples); +extern int stb_vorbis_get_samples_float_interleaved(stb_vorbis *f, int channels, float *buffer, int num_floats); +extern int stb_vorbis_get_samples_float(stb_vorbis *f, int channels, float **buffer, int num_samples); // gets num_samples samples, not necessarily on a frame boundary--this requires // buffering so you have to supply the buffers. DOES NOT APPLY THE COERCION RULES. // Returns the number of samples stored per channel; it may be less than requested // at the end of the file. If there are no more samples in the file, returns 0. #ifndef STB_VORBIS_NO_INTEGER_CONVERSION -STBVDEF int stb_vorbis_get_samples_short_interleaved(stb_vorbis *f, int channels, short *buffer, int num_shorts); -STBVDEF int stb_vorbis_get_samples_short(stb_vorbis *f, int channels, short **buffer, int num_samples); +extern int stb_vorbis_get_samples_short_interleaved(stb_vorbis *f, int channels, short *buffer, int num_shorts); +extern int stb_vorbis_get_samples_short(stb_vorbis *f, int channels, short **buffer, int num_samples); #endif // gets num_samples samples, not necessarily on a frame boundary--this requires // buffering so you have to supply the buffers. Applies the coercion rules above @@ -385,7 +402,8 @@ enum STBVorbisError VORBIS_invalid_first_page, VORBIS_bad_packet_type, VORBIS_cant_find_last_page, - VORBIS_seek_failed + VORBIS_seek_failed, + VORBIS_ogg_skeleton_not_supported }; @@ -399,7 +417,7 @@ enum STBVorbisError // ////////////////////////////////////////////////////////////////////////////// -#ifdef STB_VORBIS_IMPLEMENTATION +#ifndef STB_VORBIS_HEADER_ONLY // global configuration settings (e.g. set these in the project/makefile), // or just set them in this file at the top (although ideally the first few @@ -428,7 +446,7 @@ enum STBVorbisError // STB_VORBIS_NO_FAST_SCALED_FLOAT // does not use a fast float-to-int trick to accelerate float-to-int on // most platforms which requires endianness be defined correctly. -// #define STB_VORBIS_NO_FAST_SCALED_FLOAT +//#define STB_VORBIS_NO_FAST_SCALED_FLOAT // STB_VORBIS_MAX_CHANNELS [number] @@ -570,7 +588,7 @@ enum STBVorbisError #if defined(_MSC_VER) || defined(__MINGW32__) #include #endif - #if defined(__linux__) || defined(__linux) || defined(__EMSCRIPTEN__) || defined(__APPLE__) || defined(__CYGWIN__) + #if defined(__linux__) || defined(__linux) || defined(__sun__) || defined(__EMSCRIPTEN__) || defined(__NEWLIB__) #include #endif #else // STB_VORBIS_NO_CRT @@ -593,7 +611,7 @@ enum STBVorbisError #endif #define __forceinline #ifndef alloca - #define alloca(s) __builtin_alloca(s) + #define alloca __builtin_alloca #endif #elif !defined(_MSC_VER) #if __GNUC__ @@ -614,28 +632,34 @@ enum STBVorbisError #if 0 #include -#define STBV_CHECK(f) _CrtIsValidHeapPointer(f->channel_buffers[1]) +#define CHECK(f) _CrtIsValidHeapPointer(f->channel_buffers[1]) #else -#define STBV_CHECK(f) ((void) 0) +#define CHECK(f) ((void) 0) #endif -#define STBV_MAX_BLOCKSIZE_LOG 13 // from specification -#define STBV_MAX_BLOCKSIZE (1 << STBV_MAX_BLOCKSIZE_LOG) +#define MAX_BLOCKSIZE_LOG 13 // from specification +#define MAX_BLOCKSIZE (1 << MAX_BLOCKSIZE_LOG) -typedef unsigned char stbv_uint8; -typedef signed char stbv_int8; -typedef unsigned short stbv_uint16; -typedef signed short stbv_int16; -typedef unsigned int stbv_uint32; -typedef signed int stbv_int32; +typedef unsigned char uint8; +typedef signed char int8; +typedef unsigned short uint16; +typedef signed short int16; +typedef unsigned int uint32; +typedef signed int int32; #ifndef TRUE #define TRUE 1 #define FALSE 0 #endif -typedef float stbv_codetype; +typedef float codetype; + +#ifdef _MSC_VER +#define STBV_NOTUSED(v) (void)(v) +#else +#define STBV_NOTUSED(v) (void)sizeof(v) +#endif // @NOTE // @@ -650,113 +674,113 @@ typedef float stbv_codetype; // the sizes larger--nothing relies on silently truncating etc., nor the // order of variables. -#define STBV_FAST_HUFFMAN_TABLE_SIZE (1 << STB_VORBIS_FAST_HUFFMAN_LENGTH) -#define STBV_FAST_HUFFMAN_TABLE_MASK (STBV_FAST_HUFFMAN_TABLE_SIZE - 1) +#define FAST_HUFFMAN_TABLE_SIZE (1 << STB_VORBIS_FAST_HUFFMAN_LENGTH) +#define FAST_HUFFMAN_TABLE_MASK (FAST_HUFFMAN_TABLE_SIZE - 1) typedef struct { int dimensions, entries; - stbv_uint8 *codeword_lengths; + uint8 *codeword_lengths; float minimum_value; float delta_value; - stbv_uint8 value_bits; - stbv_uint8 lookup_type; - stbv_uint8 sequence_p; - stbv_uint8 sparse; - stbv_uint32 lookup_values; - stbv_codetype *multiplicands; - stbv_uint32 *codewords; + uint8 value_bits; + uint8 lookup_type; + uint8 sequence_p; + uint8 sparse; + uint32 lookup_values; + codetype *multiplicands; + uint32 *codewords; #ifdef STB_VORBIS_FAST_HUFFMAN_SHORT - stbv_int16 fast_huffman[STBV_FAST_HUFFMAN_TABLE_SIZE]; + int16 fast_huffman[FAST_HUFFMAN_TABLE_SIZE]; #else - stbv_int32 fast_huffman[STBV_FAST_HUFFMAN_TABLE_SIZE]; + int32 fast_huffman[FAST_HUFFMAN_TABLE_SIZE]; #endif - stbv_uint32 *sorted_codewords; + uint32 *sorted_codewords; int *sorted_values; int sorted_entries; -} StbvCodebook; +} Codebook; typedef struct { - stbv_uint8 order; - stbv_uint16 rate; - stbv_uint16 bark_map_size; - stbv_uint8 amplitude_bits; - stbv_uint8 amplitude_offset; - stbv_uint8 number_of_books; - stbv_uint8 book_list[16]; // varies -} StbvFloor0; + uint8 order; + uint16 rate; + uint16 bark_map_size; + uint8 amplitude_bits; + uint8 amplitude_offset; + uint8 number_of_books; + uint8 book_list[16]; // varies +} Floor0; typedef struct { - stbv_uint8 partitions; - stbv_uint8 partition_class_list[32]; // varies - stbv_uint8 class_dimensions[16]; // varies - stbv_uint8 class_subclasses[16]; // varies - stbv_uint8 class_masterbooks[16]; // varies - stbv_int16 subclass_books[16][8]; // varies - stbv_uint16 Xlist[31*8+2]; // varies - stbv_uint8 sorted_order[31*8+2]; - stbv_uint8 stbv_neighbors[31*8+2][2]; - stbv_uint8 floor1_multiplier; - stbv_uint8 rangebits; + uint8 partitions; + uint8 partition_class_list[32]; // varies + uint8 class_dimensions[16]; // varies + uint8 class_subclasses[16]; // varies + uint8 class_masterbooks[16]; // varies + int16 subclass_books[16][8]; // varies + uint16 Xlist[31*8+2]; // varies + uint8 sorted_order[31*8+2]; + uint8 neighbors[31*8+2][2]; + uint8 floor1_multiplier; + uint8 rangebits; int values; -} StbvFloor1; +} Floor1; typedef union { - StbvFloor0 floor0; - StbvFloor1 floor1; -} StbvFloor; + Floor0 floor0; + Floor1 floor1; +} Floor; typedef struct { - stbv_uint32 begin, end; - stbv_uint32 part_size; - stbv_uint8 classifications; - stbv_uint8 classbook; - stbv_uint8 **classdata; - stbv_int16 (*residue_books)[8]; -} StbvResidue; + uint32 begin, end; + uint32 part_size; + uint8 classifications; + uint8 classbook; + uint8 **classdata; + int16 (*residue_books)[8]; +} Residue; typedef struct { - stbv_uint8 magnitude; - stbv_uint8 angle; - stbv_uint8 mux; -} StbvMappingChannel; + uint8 magnitude; + uint8 angle; + uint8 mux; +} MappingChannel; typedef struct { - stbv_uint16 coupling_steps; - StbvMappingChannel *chan; - stbv_uint8 submaps; - stbv_uint8 submap_floor[15]; // varies - stbv_uint8 submap_residue[15]; // varies -} StbvMapping; + uint16 coupling_steps; + MappingChannel *chan; + uint8 submaps; + uint8 submap_floor[15]; // varies + uint8 submap_residue[15]; // varies +} Mapping; typedef struct { - stbv_uint8 blockflag; - stbv_uint8 mapping; - stbv_uint16 windowtype; - stbv_uint16 transformtype; -} StbvMode; + uint8 blockflag; + uint8 mapping; + uint16 windowtype; + uint16 transformtype; +} Mode; typedef struct { - stbv_uint32 goal_crc; // expected crc if match + uint32 goal_crc; // expected crc if match int bytes_left; // bytes left in packet - stbv_uint32 crc_so_far; // running crc + uint32 crc_so_far; // running crc int bytes_done; // bytes processed in _current_ chunk - stbv_uint32 sample_loc; // granule pos encoded in page -} StbvCRCscan; + uint32 sample_loc; // granule pos encoded in page +} CRCscan; typedef struct { - stbv_uint32 page_start, page_end; - stbv_uint32 last_decoded_sample; -} StbvProbedPage; + uint32 page_start, page_end; + uint32 last_decoded_sample; +} ProbedPage; struct stb_vorbis { @@ -768,24 +792,31 @@ struct stb_vorbis unsigned int temp_memory_required; unsigned int setup_temp_memory_required; + char *vendor; + int comment_list_length; + char **comment_list; + // input config #ifndef STB_VORBIS_NO_STDIO FILE *f; - stbv_uint32 f_start; + uint32 f_start; int close_on_free; #endif - stbv_uint8 *stream; - stbv_uint8 *stream_start; - stbv_uint8 *stream_end; + uint8 *stream; + uint8 *stream_start; + uint8 *stream_end; - stbv_uint32 stream_len; + uint32 stream_len; - stbv_uint8 push_mode; + uint8 push_mode; - stbv_uint32 first_audio_page_offset; + // the page to seek to when seeking to start, may be zero + uint32 first_audio_page_offset; - StbvProbedPage p_first, p_last; + // p_first is the page on which the first audio packet ends + // (but not necessarily the page on which it starts) + ProbedPage p_first, p_last; // memory management stb_vorbis_alloc alloc; @@ -802,19 +833,19 @@ struct stb_vorbis int blocksize[2]; int blocksize_0, blocksize_1; int codebook_count; - StbvCodebook *codebooks; + Codebook *codebooks; int floor_count; - stbv_uint16 floor_types[64]; // varies - StbvFloor *floor_config; + uint16 floor_types[64]; // varies + Floor *floor_config; int residue_count; - stbv_uint16 residue_types[64]; // varies - StbvResidue *residue_config; + uint16 residue_types[64]; // varies + Residue *residue_config; int mapping_count; - StbvMapping *mapping; + Mapping *mapping; int mode_count; - StbvMode mode_config[64]; // varies + Mode mode_config[64]; // varies - stbv_uint32 total_samples; + uint32 total_samples; // decode buffer float *channel_buffers[STB_VORBIS_MAX_CHANNELS]; @@ -824,44 +855,44 @@ struct stb_vorbis int previous_length; #ifndef STB_VORBIS_NO_DEFER_FLOOR - stbv_int16 *finalY[STB_VORBIS_MAX_CHANNELS]; + int16 *finalY[STB_VORBIS_MAX_CHANNELS]; #else float *floor_buffers[STB_VORBIS_MAX_CHANNELS]; #endif - stbv_uint32 current_loc; // sample location of next frame to decode + uint32 current_loc; // sample location of next frame to decode int current_loc_valid; // per-blocksize precomputed data - + // twiddle factors float *A[2],*B[2],*C[2]; float *window[2]; - stbv_uint16 *stbv_bit_reverse[2]; + uint16 *bit_reverse[2]; // current page/packet/segment streaming info - stbv_uint32 serial; // stream serial number for verification + uint32 serial; // stream serial number for verification int last_page; int segment_count; - stbv_uint8 segments[255]; - stbv_uint8 page_flag; - stbv_uint8 bytes_in_seg; - stbv_uint8 first_decode; + uint8 segments[255]; + uint8 page_flag; + uint8 bytes_in_seg; + uint8 first_decode; int next_seg; int last_seg; // flag that we're on the last segment int last_seg_which; // what was the segment number of the last seg? - stbv_uint32 acc; + uint32 acc; int valid_bits; int packet_bytes; int end_seg_with_known_loc; - stbv_uint32 known_loc_for_packet; + uint32 known_loc_for_packet; int discard_samples_deferred; - stbv_uint32 samples_output; + uint32 samples_output; // push mode scanning int page_crc_tests; // only in push_mode: number of tests active; -1 if not searching #ifndef STB_VORBIS_NO_PUSHDATA_API - StbvCRCscan scan[STB_VORBIS_PUSHDATA_CRC_COUNT]; + CRCscan scan[STB_VORBIS_PUSHDATA_CRC_COUNT]; #endif // sample-access @@ -870,16 +901,16 @@ struct stb_vorbis }; #if defined(STB_VORBIS_NO_PUSHDATA_API) - #define STBV_IS_PUSH_MODE(f) FALSE + #define IS_PUSH_MODE(f) FALSE #elif defined(STB_VORBIS_NO_PULLDATA_API) - #define STBV_IS_PUSH_MODE(f) TRUE + #define IS_PUSH_MODE(f) TRUE #else - #define STBV_IS_PUSH_MODE(f) ((f)->push_mode) + #define IS_PUSH_MODE(f) ((f)->push_mode) #endif -typedef struct stb_vorbis stbv_vorb; +typedef struct stb_vorbis vorb; -static int stbv_error(stbv_vorb *f, enum STBVorbisError e) +static int error(vorb *f, enum STBVorbisError e) { f->error = e; if (!f->eof && e != VORBIS_need_more_data) { @@ -894,17 +925,17 @@ static int stbv_error(stbv_vorb *f, enum STBVorbisError e) // alloca(); otherwise, provide a temp buffer and it will // allocate out of those. -#define stbv_array_size_required(count,size) (count*(sizeof(void *)+(size))) +#define array_size_required(count,size) (count*(sizeof(void *)+(size))) -#define stbv_temp_alloc(f,size) (f->alloc.alloc_buffer ? stbv_setup_temp_malloc(f,size) : alloca(size)) -#define stbv_temp_free(f,p) 0 -#define stbv_temp_alloc_save(f) ((f)->temp_offset) -#define stbv_temp_alloc_restore(f,p) ((f)->temp_offset = (p)) +#define temp_alloc(f,size) (f->alloc.alloc_buffer ? setup_temp_malloc(f,size) : alloca(size)) +#define temp_free(f,p) (void)0 +#define temp_alloc_save(f) ((f)->temp_offset) +#define temp_alloc_restore(f,p) ((f)->temp_offset = (p)) -#define stbv_temp_block_array(f,count,size) stbv_make_block_array(stbv_temp_alloc(f,stbv_array_size_required(count,size)), count, size) +#define temp_block_array(f,count,size) make_block_array(temp_alloc(f,array_size_required(count,size)), count, size) // given a sufficiently large block of memory, make an array of pointers to subblocks of it -static void *stbv_make_block_array(void *mem, int count, int size) +static void *make_block_array(void *mem, int count, int size) { int i; void ** p = (void **) mem; @@ -916,9 +947,9 @@ static void *stbv_make_block_array(void *mem, int count, int size) return p; } -static void *stbv_setup_malloc(stbv_vorb *f, int sz) +static void *setup_malloc(vorb *f, int sz) { - sz = (sz+3) & ~3; + sz = (sz+7) & ~7; // round up to nearest 8 for alignment of future allocs. f->setup_memory_required += sz; if (f->alloc.alloc_buffer) { void *p = (char *) f->alloc.alloc_buffer + f->setup_offset; @@ -929,15 +960,15 @@ static void *stbv_setup_malloc(stbv_vorb *f, int sz) return sz ? malloc(sz) : NULL; } -static void stbv_setup_free(stbv_vorb *f, void *p) +static void setup_free(vorb *f, void *p) { if (f->alloc.alloc_buffer) return; // do nothing; setup mem is a stack free(p); } -static void *stbv_setup_temp_malloc(stbv_vorb *f, int sz) +static void *setup_temp_malloc(vorb *f, int sz) { - sz = (sz+3) & ~3; + sz = (sz+7) & ~7; // round up to nearest 8 for alignment of future allocs. if (f->alloc.alloc_buffer) { if (f->temp_offset - sz < f->setup_offset) return NULL; f->temp_offset -= sz; @@ -946,37 +977,37 @@ static void *stbv_setup_temp_malloc(stbv_vorb *f, int sz) return malloc(sz); } -static void stbv_setup_temp_free(stbv_vorb *f, void *p, int sz) +static void setup_temp_free(vorb *f, void *p, int sz) { if (f->alloc.alloc_buffer) { - f->temp_offset += (sz+3)&~3; + f->temp_offset += (sz+7)&~7; return; } free(p); } -#define STBV_CRC32_POLY 0x04c11db7 // from spec +#define CRC32_POLY 0x04c11db7 // from spec -static stbv_uint32 stbv_crc_table[256]; -static void stbv_crc32_init(void) +static uint32 crc_table[256]; +static void crc32_init(void) { int i,j; - stbv_uint32 s; + uint32 s; for(i=0; i < 256; i++) { - for (s=(stbv_uint32) i << 24, j=0; j < 8; ++j) - s = (s << 1) ^ (s >= (1U<<31) ? STBV_CRC32_POLY : 0); - stbv_crc_table[i] = s; + for (s=(uint32) i << 24, j=0; j < 8; ++j) + s = (s << 1) ^ (s >= (1U<<31) ? CRC32_POLY : 0); + crc_table[i] = s; } } -static __forceinline stbv_uint32 stbv_crc32_update(stbv_uint32 crc, stbv_uint8 byte) +static __forceinline uint32 crc32_update(uint32 crc, uint8 byte) { - return (crc << 8) ^ stbv_crc_table[byte ^ (crc >> 24)]; + return (crc << 8) ^ crc_table[byte ^ (crc >> 24)]; } // used in setup, and for huffman that doesn't go fast path -static unsigned int stbv_bit_reverse(unsigned int n) +static unsigned int bit_reverse(unsigned int n) { n = ((n & 0xAAAAAAAA) >> 1) | ((n & 0x55555555) << 1); n = ((n & 0xCCCCCCCC) >> 2) | ((n & 0x33333333) << 2); @@ -985,7 +1016,7 @@ static unsigned int stbv_bit_reverse(unsigned int n) return (n >> 16) | (n << 16); } -static float stbv_square(float x) +static float square(float x) { return x*x; } @@ -993,7 +1024,7 @@ static float stbv_square(float x) // this is a weird definition of log2() for which log2(1) = 1, log2(2) = 2, log2(4) = 3 // as required by the specification. fast(?) implementation from stb.h // @OPTIMIZE: called multiple times per-packet with "constants"; move to setup -static int stbv_ilog(stbv_int32 n) +static int ilog(int32 n) { static signed char log2_4[16] = { 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4 }; @@ -1023,14 +1054,14 @@ static int stbv_ilog(stbv_int32 n) // these functions are only called at setup, and only a few times // per file -static float stbv_float32_unpack(stbv_uint32 x) +static float float32_unpack(uint32 x) { // from the specification - stbv_uint32 mantissa = x & 0x1fffff; - stbv_uint32 sign = x & 0x80000000; - stbv_uint32 exp = (x & 0x7fe00000) >> 21; + uint32 mantissa = x & 0x1fffff; + uint32 sign = x & 0x80000000; + uint32 exp = (x & 0x7fe00000) >> 21; double res = sign ? -(double)mantissa : (double)mantissa; - return (float) ldexp((float)res, exp-788); + return (float) ldexp((float)res, (int)exp-788); } @@ -1041,7 +1072,7 @@ static float stbv_float32_unpack(stbv_uint32 x) // vorbis allows a huffman table with non-sorted lengths. This // requires a more sophisticated construction, since symbols in // order do not map to huffman codes "in order". -static void stbv_add_entry(StbvCodebook *c, stbv_uint32 huff_code, int symbol, int count, int len, stbv_uint32 *values) +static void add_entry(Codebook *c, uint32 huff_code, int symbol, int count, int len, uint32 *values) { if (!c->sparse) { c->codewords [symbol] = huff_code; @@ -1052,17 +1083,18 @@ static void stbv_add_entry(StbvCodebook *c, stbv_uint32 huff_code, int symbol, i } } -static int stbv_compute_codewords(StbvCodebook *c, stbv_uint8 *len, int n, stbv_uint32 *values) +static int compute_codewords(Codebook *c, uint8 *len, int n, uint32 *values) { int i,k,m=0; - stbv_uint32 available[32]; + uint32 available[32]; memset(available, 0, sizeof(available)); // find the first entry for (k=0; k < n; ++k) if (len[k] < NO_CODE) break; if (k == n) { assert(c->sorted_entries == 0); return TRUE; } + assert(len[k] < 32); // no error return required, code reading lens checks this // add to the list - stbv_add_entry(c, 0, k, m++, len[k], values); + add_entry(c, 0, k, m++, len[k], values); // add all available leaves for (i=1; i <= len[k]; ++i) available[i] = 1U << (32-i); @@ -1071,9 +1103,10 @@ static int stbv_compute_codewords(StbvCodebook *c, stbv_uint8 *len, int n, stbv_ // could probably be combined (except the initial code is 0, // and I use 0 in available[] to mean 'empty') for (i=k+1; i < n; ++i) { - stbv_uint32 res; + uint32 res; int z = len[i], y; if (z == NO_CODE) continue; + assert(z < 32); // no error return required, code reading lens checks this // find lowest available leaf (should always be earliest, // which is what the specification calls for) // note that this property, and the fact we can never have @@ -1083,12 +1116,10 @@ static int stbv_compute_codewords(StbvCodebook *c, stbv_uint8 *len, int n, stbv_ while (z > 0 && !available[z]) --z; if (z == 0) { return FALSE; } res = available[z]; - assert(z >= 0 && z < 32); available[z] = 0; - stbv_add_entry(c, stbv_bit_reverse(res), i, m++, len[i], values); - // propogate availability up the tree + add_entry(c, bit_reverse(res), i, m++, len[i], values); + // propagate availability up the tree if (z != len[i]) { - assert(len[i] >= 0 && len[i] < 32); for (y=len[i]; y > z; --y) { assert(available[y] == 0); available[y] = res + (1 << (32-y)); @@ -1100,10 +1131,10 @@ static int stbv_compute_codewords(StbvCodebook *c, stbv_uint8 *len, int n, stbv_ // accelerated huffman table allows fast O(1) match of all symbols // of length <= STB_VORBIS_FAST_HUFFMAN_LENGTH -static void stbv_compute_accelerated_huffman(StbvCodebook *c) +static void compute_accelerated_huffman(Codebook *c) { int i, len; - for (i=0; i < STBV_FAST_HUFFMAN_TABLE_SIZE; ++i) + for (i=0; i < FAST_HUFFMAN_TABLE_SIZE; ++i) c->fast_huffman[i] = -1; len = c->sparse ? c->sorted_entries : c->entries; @@ -1112,9 +1143,9 @@ static void stbv_compute_accelerated_huffman(StbvCodebook *c) #endif for (i=0; i < len; ++i) { if (c->codeword_lengths[i] <= STB_VORBIS_FAST_HUFFMAN_LENGTH) { - stbv_uint32 z = c->sparse ? stbv_bit_reverse(c->sorted_codewords[i]) : c->codewords[i]; + uint32 z = c->sparse ? bit_reverse(c->sorted_codewords[i]) : c->codewords[i]; // set table entries for all bit combinations in the higher bits - while (z < STBV_FAST_HUFFMAN_TABLE_SIZE) { + while (z < FAST_HUFFMAN_TABLE_SIZE) { c->fast_huffman[z] = i; z += 1 << c->codeword_lengths[i]; } @@ -1128,14 +1159,14 @@ static void stbv_compute_accelerated_huffman(StbvCodebook *c) #define STBV_CDECL #endif -static int STBV_CDECL stbv_uint32_compare(const void *p, const void *q) +static int STBV_CDECL uint32_compare(const void *p, const void *q) { - stbv_uint32 x = * (stbv_uint32 *) p; - stbv_uint32 y = * (stbv_uint32 *) q; + uint32 x = * (uint32 *) p; + uint32 y = * (uint32 *) q; return x < y ? -1 : x > y; } -static int stbv_include_in_sort(StbvCodebook *c, stbv_uint8 len) +static int include_in_sort(Codebook *c, uint8 len) { if (c->sparse) { assert(len != NO_CODE); return TRUE; } if (len == NO_CODE) return FALSE; @@ -1145,7 +1176,7 @@ static int stbv_include_in_sort(StbvCodebook *c, stbv_uint8 len) // if the fast table above doesn't work, we want to binary // search them... need to reverse the bits -static void stbv_compute_sorted_huffman(StbvCodebook *c, stbv_uint8 *lengths, stbv_uint32 *values) +static void compute_sorted_huffman(Codebook *c, uint8 *lengths, uint32 *values) { int i, len; // build a list of all the entries @@ -1155,15 +1186,15 @@ static void stbv_compute_sorted_huffman(StbvCodebook *c, stbv_uint8 *lengths, st if (!c->sparse) { int k = 0; for (i=0; i < c->entries; ++i) - if (stbv_include_in_sort(c, lengths[i])) - c->sorted_codewords[k++] = stbv_bit_reverse(c->codewords[i]); + if (include_in_sort(c, lengths[i])) + c->sorted_codewords[k++] = bit_reverse(c->codewords[i]); assert(k == c->sorted_entries); } else { for (i=0; i < c->sorted_entries; ++i) - c->sorted_codewords[i] = stbv_bit_reverse(c->codewords[i]); + c->sorted_codewords[i] = bit_reverse(c->codewords[i]); } - qsort(c->sorted_codewords, c->sorted_entries, sizeof(c->sorted_codewords[0]), stbv_uint32_compare); + qsort(c->sorted_codewords, c->sorted_entries, sizeof(c->sorted_codewords[0]), uint32_compare); c->sorted_codewords[c->sorted_entries] = 0xffffffff; len = c->sparse ? c->sorted_entries : c->entries; @@ -1174,8 +1205,8 @@ static void stbv_compute_sorted_huffman(StbvCodebook *c, stbv_uint8 *lengths, st // #1 requires extra storage, #2 is slow, #3 can use binary search! for (i=0; i < len; ++i) { int huff_len = c->sparse ? lengths[values[i]] : lengths[i]; - if (stbv_include_in_sort(c,huff_len)) { - stbv_uint32 code = stbv_bit_reverse(c->codewords[i]); + if (include_in_sort(c,huff_len)) { + uint32 code = bit_reverse(c->codewords[i]); int x=0, n=c->sorted_entries; while (n > 1) { // invariant: sc[x] <= code < sc[x+n] @@ -1199,26 +1230,28 @@ static void stbv_compute_sorted_huffman(StbvCodebook *c, stbv_uint8 *lengths, st } // only run while parsing the header (3 times) -static int stbv_vorbis_validate(stbv_uint8 *data) +static int vorbis_validate(uint8 *data) { - static stbv_uint8 vorbis[6] = { 'v', 'o', 'r', 'b', 'i', 's' }; + static uint8 vorbis[6] = { 'v', 'o', 'r', 'b', 'i', 's' }; return memcmp(data, vorbis, 6) == 0; } // called from setup only, once per code book // (formula implied by specification) -static int stbv_lookup1_values(int entries, int dim) +static int lookup1_values(int entries, int dim) { int r = (int) floor(exp((float) log((float) entries) / dim)); if ((int) floor(pow((float) r+1, dim)) <= entries) // (int) cast for MinGW warning; ++r; // floor() to avoid _ftol() when non-CRT - assert(pow((float) r+1, dim) > entries); - assert((int) floor(pow((float) r, dim)) <= entries); // (int),floor() as above + if (pow((float) r+1, dim) <= entries) + return -1; + if ((int) floor(pow((float) r, dim)) > entries) + return -1; return r; } // called twice per file -static void stbv_compute_twiddle_factors(int n, float *A, float *B, float *C) +static void compute_twiddle_factors(int n, float *A, float *B, float *C) { int n4 = n >> 2, n8 = n >> 3; int k,k2; @@ -1235,39 +1268,39 @@ static void stbv_compute_twiddle_factors(int n, float *A, float *B, float *C) } } -static void stbv_compute_window(int n, float *window) +static void compute_window(int n, float *window) { int n2 = n >> 1, i; for (i=0; i < n2; ++i) - window[i] = (float) sin(0.5 * M_PI * stbv_square((float) sin((i - 0 + 0.5) / n2 * 0.5 * M_PI))); + window[i] = (float) sin(0.5 * M_PI * square((float) sin((i - 0 + 0.5) / n2 * 0.5 * M_PI))); } -static void stbv_compute_bitreverse(int n, stbv_uint16 *rev) +static void compute_bitreverse(int n, uint16 *rev) { - int ld = stbv_ilog(n) - 1; // stbv_ilog is off-by-one from normal definitions + int ld = ilog(n) - 1; // ilog is off-by-one from normal definitions int i, n8 = n >> 3; for (i=0; i < n8; ++i) - rev[i] = (stbv_bit_reverse(i) >> (32-ld+3)) << 2; + rev[i] = (bit_reverse(i) >> (32-ld+3)) << 2; } -static int stbv_init_blocksize(stbv_vorb *f, int b, int n) +static int init_blocksize(vorb *f, int b, int n) { int n2 = n >> 1, n4 = n >> 2, n8 = n >> 3; - f->A[b] = (float *) stbv_setup_malloc(f, sizeof(float) * n2); - f->B[b] = (float *) stbv_setup_malloc(f, sizeof(float) * n2); - f->C[b] = (float *) stbv_setup_malloc(f, sizeof(float) * n4); - if (!f->A[b] || !f->B[b] || !f->C[b]) return stbv_error(f, VORBIS_outofmem); - stbv_compute_twiddle_factors(n, f->A[b], f->B[b], f->C[b]); - f->window[b] = (float *) stbv_setup_malloc(f, sizeof(float) * n2); - if (!f->window[b]) return stbv_error(f, VORBIS_outofmem); - stbv_compute_window(n, f->window[b]); - f->stbv_bit_reverse[b] = (stbv_uint16 *) stbv_setup_malloc(f, sizeof(stbv_uint16) * n8); - if (!f->stbv_bit_reverse[b]) return stbv_error(f, VORBIS_outofmem); - stbv_compute_bitreverse(n, f->stbv_bit_reverse[b]); + f->A[b] = (float *) setup_malloc(f, sizeof(float) * n2); + f->B[b] = (float *) setup_malloc(f, sizeof(float) * n2); + f->C[b] = (float *) setup_malloc(f, sizeof(float) * n4); + if (!f->A[b] || !f->B[b] || !f->C[b]) return error(f, VORBIS_outofmem); + compute_twiddle_factors(n, f->A[b], f->B[b], f->C[b]); + f->window[b] = (float *) setup_malloc(f, sizeof(float) * n2); + if (!f->window[b]) return error(f, VORBIS_outofmem); + compute_window(n, f->window[b]); + f->bit_reverse[b] = (uint16 *) setup_malloc(f, sizeof(uint16) * n8); + if (!f->bit_reverse[b]) return error(f, VORBIS_outofmem); + compute_bitreverse(n, f->bit_reverse[b]); return TRUE; } -static void stbv_neighbors(stbv_uint16 *x, int n, int *plow, int *phigh) +static void neighbors(uint16 *x, int n, int *plow, int *phigh) { int low = -1; int high = 65536; @@ -1281,13 +1314,13 @@ static void stbv_neighbors(stbv_uint16 *x, int n, int *plow, int *phigh) // this has been repurposed so y is now the original index instead of y typedef struct { - stbv_uint16 x,id; -} stbv_floor_ordering; + uint16 x,id; +} stbv__floor_ordering; -static int STBV_CDECL stbv_point_compare(const void *p, const void *q) +static int STBV_CDECL point_compare(const void *p, const void *q) { - stbv_floor_ordering *a = (stbv_floor_ordering *) p; - stbv_floor_ordering *b = (stbv_floor_ordering *) q; + stbv__floor_ordering *a = (stbv__floor_ordering *) p; + stbv__floor_ordering *b = (stbv__floor_ordering *) q; return a->x < b->x ? -1 : a->x > b->x; } @@ -1296,14 +1329,14 @@ static int STBV_CDECL stbv_point_compare(const void *p, const void *q) #if defined(STB_VORBIS_NO_STDIO) - #define STBV_USE_MEMORY(z) TRUE + #define USE_MEMORY(z) TRUE #else - #define STBV_USE_MEMORY(z) ((z)->stream) + #define USE_MEMORY(z) ((z)->stream) #endif -static stbv_uint8 stbv_get8(stbv_vorb *z) +static uint8 get8(vorb *z) { - if (STBV_USE_MEMORY(z)) { + if (USE_MEMORY(z)) { if (z->stream >= z->stream_end) { z->eof = TRUE; return 0; } return *z->stream++; } @@ -1317,26 +1350,26 @@ static stbv_uint8 stbv_get8(stbv_vorb *z) #endif } -static stbv_uint32 stbv_get32(stbv_vorb *f) +static uint32 get32(vorb *f) { - stbv_uint32 x; - x = stbv_get8(f); - x += stbv_get8(f) << 8; - x += stbv_get8(f) << 16; - x += (stbv_uint32) stbv_get8(f) << 24; + uint32 x; + x = get8(f); + x += get8(f) << 8; + x += get8(f) << 16; + x += (uint32) get8(f) << 24; return x; } -static int stbv_getn(stbv_vorb *z, stbv_uint8 *data, int n) +static int getn(vorb *z, uint8 *data, int n) { - if (STBV_USE_MEMORY(z)) { + if (USE_MEMORY(z)) { if (z->stream+n > z->stream_end) { z->eof = 1; return 0; } memcpy(data, z->stream, n); z->stream += n; return 1; } - #ifndef STB_VORBIS_NO_STDIO + #ifndef STB_VORBIS_NO_STDIO if (fread(data, n, 1, z->f) == 1) return 1; else { @@ -1346,9 +1379,9 @@ static int stbv_getn(stbv_vorb *z, stbv_uint8 *data, int n) #endif } -static void stbv_skip(stbv_vorb *z, int n) +static void skip(vorb *z, int n) { - if (STBV_USE_MEMORY(z)) { + if (USE_MEMORY(z)) { z->stream += n; if (z->stream >= z->stream_end) z->eof = 1; return; @@ -1361,13 +1394,13 @@ static void stbv_skip(stbv_vorb *z, int n) #endif } -static int stbv_set_file_offset(stb_vorbis *f, unsigned int loc) +static int set_file_offset(stb_vorbis *f, unsigned int loc) { #ifndef STB_VORBIS_NO_PUSHDATA_API if (f->push_mode) return 0; #endif f->eof = 0; - if (STBV_USE_MEMORY(f)) { + if (USE_MEMORY(f)) { if (f->stream_start + loc >= f->stream_end || f->stream_start + loc < f->stream_start) { f->stream = f->stream_end; f->eof = 1; @@ -1393,44 +1426,47 @@ static int stbv_set_file_offset(stb_vorbis *f, unsigned int loc) } -static stbv_uint8 stbv_ogg_page_header[4] = { 0x4f, 0x67, 0x67, 0x53 }; +static uint8 ogg_page_header[4] = { 0x4f, 0x67, 0x67, 0x53 }; -static int stbv_capture_pattern(stbv_vorb *f) +static int capture_pattern(vorb *f) { - if (0x4f != stbv_get8(f)) return FALSE; - if (0x67 != stbv_get8(f)) return FALSE; - if (0x67 != stbv_get8(f)) return FALSE; - if (0x53 != stbv_get8(f)) return FALSE; + if (0x4f != get8(f)) return FALSE; + if (0x67 != get8(f)) return FALSE; + if (0x67 != get8(f)) return FALSE; + if (0x53 != get8(f)) return FALSE; return TRUE; } -#define STBV_PAGEFLAG_continued_packet 1 -#define STBV_PAGEFLAG_first_page 2 -#define STBV_PAGEFLAG_last_page 4 +#define PAGEFLAG_continued_packet 1 +#define PAGEFLAG_first_page 2 +#define PAGEFLAG_last_page 4 -static int stbv_start_page_no_capturepattern(stbv_vorb *f) +static int start_page_no_capturepattern(vorb *f) { - stbv_uint32 loc0,loc1,n; + uint32 loc0,loc1,n; + if (f->first_decode && !IS_PUSH_MODE(f)) { + f->p_first.page_start = stb_vorbis_get_file_offset(f) - 4; + } // stream structure version - if (0 != stbv_get8(f)) return stbv_error(f, VORBIS_invalid_stream_structure_version); + if (0 != get8(f)) return error(f, VORBIS_invalid_stream_structure_version); // header flag - f->page_flag = stbv_get8(f); + f->page_flag = get8(f); // absolute granule position - loc0 = stbv_get32(f); - loc1 = stbv_get32(f); + loc0 = get32(f); + loc1 = get32(f); // @TODO: validate loc0,loc1 as valid positions? // stream serial number -- vorbis doesn't interleave, so discard - stbv_get32(f); - //if (f->serial != stbv_get32(f)) return stbv_error(f, VORBIS_incorrect_stream_serial_number); + get32(f); + //if (f->serial != get32(f)) return error(f, VORBIS_incorrect_stream_serial_number); // page sequence number - n = stbv_get32(f); + n = get32(f); f->last_page = n; // CRC32 - stbv_get32(f); + get32(f); // page_segments - f->segment_count = stbv_get8(f); - if (!stbv_getn(f, f->segments, f->segment_count)) - return stbv_error(f, VORBIS_unexpected_eof); + f->segment_count = get8(f); + if (!getn(f, f->segments, f->segment_count)) + return error(f, VORBIS_unexpected_eof); // assume we _don't_ know any the sample position of any segments f->end_seg_with_known_loc = -2; if (loc0 != ~0U || loc1 != ~0U) { @@ -1447,32 +1483,29 @@ static int stbv_start_page_no_capturepattern(stbv_vorb *f) } if (f->first_decode) { int i,len; - StbvProbedPage p; len = 0; for (i=0; i < f->segment_count; ++i) len += f->segments[i]; len += 27 + f->segment_count; - p.page_start = f->first_audio_page_offset; - p.page_end = p.page_start + len; - p.last_decoded_sample = loc0; - f->p_first = p; + f->p_first.page_end = f->p_first.page_start + len; + f->p_first.last_decoded_sample = loc0; } f->next_seg = 0; return TRUE; } -static int stbv_start_page(stbv_vorb *f) +static int start_page(vorb *f) { - if (!stbv_capture_pattern(f)) return stbv_error(f, VORBIS_missing_capture_pattern); - return stbv_start_page_no_capturepattern(f); + if (!capture_pattern(f)) return error(f, VORBIS_missing_capture_pattern); + return start_page_no_capturepattern(f); } -static int stbv_start_packet(stbv_vorb *f) +static int start_packet(vorb *f) { while (f->next_seg == -1) { - if (!stbv_start_page(f)) return FALSE; - if (f->page_flag & STBV_PAGEFLAG_continued_packet) - return stbv_error(f, VORBIS_continued_packet_flag_invalid); + if (!start_page(f)) return FALSE; + if (f->page_flag & PAGEFLAG_continued_packet) + return error(f, VORBIS_continued_packet_flag_invalid); } f->last_seg = FALSE; f->valid_bits = 0; @@ -1482,35 +1515,35 @@ static int stbv_start_packet(stbv_vorb *f) return TRUE; } -static int stbv_maybe_start_packet(stbv_vorb *f) +static int maybe_start_packet(vorb *f) { if (f->next_seg == -1) { - int x = stbv_get8(f); + int x = get8(f); if (f->eof) return FALSE; // EOF at page boundary is not an error! - if (0x4f != x ) return stbv_error(f, VORBIS_missing_capture_pattern); - if (0x67 != stbv_get8(f)) return stbv_error(f, VORBIS_missing_capture_pattern); - if (0x67 != stbv_get8(f)) return stbv_error(f, VORBIS_missing_capture_pattern); - if (0x53 != stbv_get8(f)) return stbv_error(f, VORBIS_missing_capture_pattern); - if (!stbv_start_page_no_capturepattern(f)) return FALSE; - if (f->page_flag & STBV_PAGEFLAG_continued_packet) { + if (0x4f != x ) return error(f, VORBIS_missing_capture_pattern); + if (0x67 != get8(f)) return error(f, VORBIS_missing_capture_pattern); + if (0x67 != get8(f)) return error(f, VORBIS_missing_capture_pattern); + if (0x53 != get8(f)) return error(f, VORBIS_missing_capture_pattern); + if (!start_page_no_capturepattern(f)) return FALSE; + if (f->page_flag & PAGEFLAG_continued_packet) { // set up enough state that we can read this packet if we want, // e.g. during recovery f->last_seg = FALSE; f->bytes_in_seg = 0; - return stbv_error(f, VORBIS_continued_packet_flag_invalid); + return error(f, VORBIS_continued_packet_flag_invalid); } } - return stbv_start_packet(f); + return start_packet(f); } -static int stbv_next_segment(stbv_vorb *f) +static int next_segment(vorb *f) { int len; if (f->last_seg) return 0; if (f->next_seg == -1) { - f->last_seg_which = f->segment_count-1; // in case stbv_start_page fails - if (!stbv_start_page(f)) { f->last_seg = 1; return 0; } - if (!(f->page_flag & STBV_PAGEFLAG_continued_packet)) return stbv_error(f, VORBIS_continued_packet_flag_invalid); + f->last_seg_which = f->segment_count-1; // in case start_page fails + if (!start_page(f)) { f->last_seg = 1; return 0; } + if (!(f->page_flag & PAGEFLAG_continued_packet)) return error(f, VORBIS_continued_packet_flag_invalid); } len = f->segments[f->next_seg++]; if (len < 255) { @@ -1524,59 +1557,70 @@ static int stbv_next_segment(stbv_vorb *f) return len; } -#define STBV_EOP (-1) -#define STBV_INVALID_BITS (-1) +#define EOP (-1) +#define INVALID_BITS (-1) -static int stbv_get8_packet_raw(stbv_vorb *f) +static int get8_packet_raw(vorb *f) { if (!f->bytes_in_seg) { // CLANG! - if (f->last_seg) return STBV_EOP; - else if (!stbv_next_segment(f)) return STBV_EOP; + if (f->last_seg) return EOP; + else if (!next_segment(f)) return EOP; } assert(f->bytes_in_seg > 0); --f->bytes_in_seg; ++f->packet_bytes; - return stbv_get8(f); + return get8(f); } -static int stbv_get8_packet(stbv_vorb *f) +static int get8_packet(vorb *f) { - int x = stbv_get8_packet_raw(f); + int x = get8_packet_raw(f); f->valid_bits = 0; return x; } -static void stbv_flush_packet(stbv_vorb *f) +static int get32_packet(vorb *f) { - while (stbv_get8_packet_raw(f) != STBV_EOP); + uint32 x; + x = get8_packet(f); + x += get8_packet(f) << 8; + x += get8_packet(f) << 16; + x += (uint32) get8_packet(f) << 24; + return x; +} + +static void flush_packet(vorb *f) +{ + while (get8_packet_raw(f) != EOP); } // @OPTIMIZE: this is the secondary bit decoder, so it's probably not as important // as the huffman decoder? -static stbv_uint32 stbv_get_bits(stbv_vorb *f, int n) +static uint32 get_bits(vorb *f, int n) { - stbv_uint32 z; + uint32 z; if (f->valid_bits < 0) return 0; if (f->valid_bits < n) { if (n > 24) { // the accumulator technique below would not work correctly in this case - z = stbv_get_bits(f, 24); - z += stbv_get_bits(f, n-24) << 24; + z = get_bits(f, 24); + z += get_bits(f, n-24) << 24; return z; } if (f->valid_bits == 0) f->acc = 0; while (f->valid_bits < n) { - int z = stbv_get8_packet_raw(f); - if (z == STBV_EOP) { - f->valid_bits = STBV_INVALID_BITS; + int z = get8_packet_raw(f); + if (z == EOP) { + f->valid_bits = INVALID_BITS; return 0; } f->acc += z << f->valid_bits; f->valid_bits += 8; } } - if (f->valid_bits < 0) return 0; + + assert(f->valid_bits >= n); z = f->acc & ((1 << n)-1); f->acc >>= n; f->valid_bits -= n; @@ -1587,15 +1631,15 @@ static stbv_uint32 stbv_get_bits(stbv_vorb *f, int n) // expand the buffer to as many bits as possible without reading off end of packet // it might be nice to allow f->valid_bits and f->acc to be stored in registers, // e.g. cache them locally and decode locally -static __forceinline void stbv_prep_huffman(stbv_vorb *f) +static __forceinline void prep_huffman(vorb *f) { if (f->valid_bits <= 24) { if (f->valid_bits == 0) f->acc = 0; do { int z; if (f->last_seg && !f->bytes_in_seg) return; - z = stbv_get8_packet_raw(f); - if (z == STBV_EOP) return; + z = get8_packet_raw(f); + if (z == EOP) return; f->acc += (unsigned) z << f->valid_bits; f->valid_bits += 8; } while (f->valid_bits <= 24); @@ -1604,15 +1648,15 @@ static __forceinline void stbv_prep_huffman(stbv_vorb *f) enum { - STBV_VORBIS_packet_id = 1, - STBV_VORBIS_packet_comment = 3, - STBV_VORBIS_packet_setup = 5 + VORBIS_packet_id = 1, + VORBIS_packet_comment = 3, + VORBIS_packet_setup = 5 }; -static int stbv_codebook_decode_scalar_raw(stbv_vorb *f, StbvCodebook *c) +static int codebook_decode_scalar_raw(vorb *f, Codebook *c) { int i; - stbv_prep_huffman(f); + prep_huffman(f); if (c->codewords == NULL && c->sorted_codewords == NULL) return -1; @@ -1621,7 +1665,7 @@ static int stbv_codebook_decode_scalar_raw(stbv_vorb *f, StbvCodebook *c) // sorted_codewords && c->entries > 8 if (c->entries > 8 ? c->sorted_codewords!=NULL : !c->codewords) { // binary search - stbv_uint32 code = stbv_bit_reverse(f->acc); + uint32 code = bit_reverse(f->acc); int x=0, n=c->sorted_entries, len; while (n > 1) { @@ -1663,17 +1707,17 @@ static int stbv_codebook_decode_scalar_raw(stbv_vorb *f, StbvCodebook *c) } } - stbv_error(f, VORBIS_invalid_stream); + error(f, VORBIS_invalid_stream); f->valid_bits = 0; return -1; } #ifndef STB_VORBIS_NO_INLINE_DECODE -#define STBV_DECODE_RAW(var, f,c) \ +#define DECODE_RAW(var, f,c) \ if (f->valid_bits < STB_VORBIS_FAST_HUFFMAN_LENGTH) \ - stbv_prep_huffman(f); \ - var = f->acc & STBV_FAST_HUFFMAN_TABLE_MASK; \ + prep_huffman(f); \ + var = f->acc & FAST_HUFFMAN_TABLE_MASK; \ var = c->fast_huffman[var]; \ if (var >= 0) { \ int n = c->codeword_lengths[var]; \ @@ -1681,18 +1725,18 @@ static int stbv_codebook_decode_scalar_raw(stbv_vorb *f, StbvCodebook *c) f->valid_bits -= n; \ if (f->valid_bits < 0) { f->valid_bits = 0; var = -1; } \ } else { \ - var = stbv_codebook_decode_scalar_raw(f,c); \ + var = codebook_decode_scalar_raw(f,c); \ } #else -static int stbv_codebook_decode_scalar(stbv_vorb *f, StbvCodebook *c) +static int codebook_decode_scalar(vorb *f, Codebook *c) { int i; if (f->valid_bits < STB_VORBIS_FAST_HUFFMAN_LENGTH) - stbv_prep_huffman(f); + prep_huffman(f); // fast huffman table lookup - i = f->acc & STBV_FAST_HUFFMAN_TABLE_MASK; + i = f->acc & FAST_HUFFMAN_TABLE_MASK; i = c->fast_huffman[i]; if (i >= 0) { f->acc >>= c->codeword_lengths[i]; @@ -1700,21 +1744,21 @@ static int stbv_codebook_decode_scalar(stbv_vorb *f, StbvCodebook *c) if (f->valid_bits < 0) { f->valid_bits = 0; return -1; } return i; } - return stbv_codebook_decode_scalar_raw(f,c); + return codebook_decode_scalar_raw(f,c); } -#define STBV_DECODE_RAW(var,f,c) var = stbv_codebook_decode_scalar(f,c); +#define DECODE_RAW(var,f,c) var = codebook_decode_scalar(f,c); #endif -#define STBV_DECODE(var,f,c) \ - STBV_DECODE_RAW(var,f,c) \ +#define DECODE(var,f,c) \ + DECODE_RAW(var,f,c) \ if (c->sparse) var = c->sorted_values[var]; #ifndef STB_VORBIS_DIVIDES_IN_CODEBOOK - #define DECODE_VQ(var,f,c) STBV_DECODE_RAW(var,f,c) + #define DECODE_VQ(var,f,c) DECODE_RAW(var,f,c) #else - #define DECODE_VQ(var,f,c) STBV_DECODE(var,f,c) + #define DECODE_VQ(var,f,c) DECODE(var,f,c) #endif @@ -1722,45 +1766,45 @@ static int stbv_codebook_decode_scalar(stbv_vorb *f, StbvCodebook *c) -// STBV_CODEBOOK_ELEMENT_FAST is an optimization for the CODEBOOK_FLOATS case +// CODEBOOK_ELEMENT_FAST is an optimization for the CODEBOOK_FLOATS case // where we avoid one addition -#define STBV_CODEBOOK_ELEMENT(c,off) (c->multiplicands[off]) -#define STBV_CODEBOOK_ELEMENT_FAST(c,off) (c->multiplicands[off]) -#define STBV_CODEBOOK_ELEMENT_BASE(c) (0) +#define CODEBOOK_ELEMENT(c,off) (c->multiplicands[off]) +#define CODEBOOK_ELEMENT_FAST(c,off) (c->multiplicands[off]) +#define CODEBOOK_ELEMENT_BASE(c) (0) -static int stbv_codebook_decode_start(stbv_vorb *f, StbvCodebook *c) +static int codebook_decode_start(vorb *f, Codebook *c) { int z = -1; // type 0 is only legal in a scalar context if (c->lookup_type == 0) - stbv_error(f, VORBIS_invalid_stream); + error(f, VORBIS_invalid_stream); else { DECODE_VQ(z,f,c); if (c->sparse) assert(z < c->sorted_entries); - if (z < 0) { // check for STBV_EOP + if (z < 0) { // check for EOP if (!f->bytes_in_seg) if (f->last_seg) return z; - stbv_error(f, VORBIS_invalid_stream); + error(f, VORBIS_invalid_stream); } } return z; } -static int stbv_codebook_decode(stbv_vorb *f, StbvCodebook *c, float *output, int len) +static int codebook_decode(vorb *f, Codebook *c, float *output, int len) { - int i,z = stbv_codebook_decode_start(f,c); + int i,z = codebook_decode_start(f,c); if (z < 0) return FALSE; if (len > c->dimensions) len = c->dimensions; #ifdef STB_VORBIS_DIVIDES_IN_CODEBOOK if (c->lookup_type == 1) { - float last = STBV_CODEBOOK_ELEMENT_BASE(c); + float last = CODEBOOK_ELEMENT_BASE(c); int div = 1; for (i=0; i < len; ++i) { int off = (z / div) % c->lookup_values; - float val = STBV_CODEBOOK_ELEMENT_FAST(c,off) + last; + float val = CODEBOOK_ELEMENT_FAST(c,off) + last; output[i] += val; if (c->sequence_p) last = val + c->minimum_value; div *= c->lookup_values; @@ -1771,26 +1815,26 @@ static int stbv_codebook_decode(stbv_vorb *f, StbvCodebook *c, float *output, in z *= c->dimensions; if (c->sequence_p) { - float last = STBV_CODEBOOK_ELEMENT_BASE(c); + float last = CODEBOOK_ELEMENT_BASE(c); for (i=0; i < len; ++i) { - float val = STBV_CODEBOOK_ELEMENT_FAST(c,z+i) + last; + float val = CODEBOOK_ELEMENT_FAST(c,z+i) + last; output[i] += val; last = val + c->minimum_value; } } else { - float last = STBV_CODEBOOK_ELEMENT_BASE(c); + float last = CODEBOOK_ELEMENT_BASE(c); for (i=0; i < len; ++i) { - output[i] += STBV_CODEBOOK_ELEMENT_FAST(c,z+i) + last; + output[i] += CODEBOOK_ELEMENT_FAST(c,z+i) + last; } } return TRUE; } -static int stbv_codebook_decode_step(stbv_vorb *f, StbvCodebook *c, float *output, int len, int step) +static int codebook_decode_step(vorb *f, Codebook *c, float *output, int len, int step) { - int i,z = stbv_codebook_decode_start(f,c); - float last = STBV_CODEBOOK_ELEMENT_BASE(c); + int i,z = codebook_decode_start(f,c); + float last = CODEBOOK_ELEMENT_BASE(c); if (z < 0) return FALSE; if (len > c->dimensions) len = c->dimensions; @@ -1799,7 +1843,7 @@ static int stbv_codebook_decode_step(stbv_vorb *f, StbvCodebook *c, float *outpu int div = 1; for (i=0; i < len; ++i) { int off = (z / div) % c->lookup_values; - float val = STBV_CODEBOOK_ELEMENT_FAST(c,off) + last; + float val = CODEBOOK_ELEMENT_FAST(c,off) + last; output[i*step] += val; if (c->sequence_p) last = val; div *= c->lookup_values; @@ -1810,7 +1854,7 @@ static int stbv_codebook_decode_step(stbv_vorb *f, StbvCodebook *c, float *outpu z *= c->dimensions; for (i=0; i < len; ++i) { - float val = STBV_CODEBOOK_ELEMENT_FAST(c,z+i) + last; + float val = CODEBOOK_ELEMENT_FAST(c,z+i) + last; output[i*step] += val; if (c->sequence_p) last = val; } @@ -1818,17 +1862,17 @@ static int stbv_codebook_decode_step(stbv_vorb *f, StbvCodebook *c, float *outpu return TRUE; } -static int stbv_codebook_decode_deinterleave_repeat(stbv_vorb *f, StbvCodebook *c, float **outputs, int ch, int *c_inter_p, int *p_inter_p, int len, int total_decode) +static int codebook_decode_deinterleave_repeat(vorb *f, Codebook *c, float **outputs, int ch, int *c_inter_p, int *p_inter_p, int len, int total_decode) { int c_inter = *c_inter_p; int p_inter = *p_inter_p; int i,z, effective = c->dimensions; // type 0 is only legal in a scalar context - if (c->lookup_type == 0) return stbv_error(f, VORBIS_invalid_stream); + if (c->lookup_type == 0) return error(f, VORBIS_invalid_stream); while (total_decode > 0) { - float last = STBV_CODEBOOK_ELEMENT_BASE(c); + float last = CODEBOOK_ELEMENT_BASE(c); DECODE_VQ(z,f,c); #ifndef STB_VORBIS_DIVIDES_IN_CODEBOOK assert(!c->sparse || z < c->sorted_entries); @@ -1836,7 +1880,7 @@ static int stbv_codebook_decode_deinterleave_repeat(stbv_vorb *f, StbvCodebook * if (z < 0) { if (!f->bytes_in_seg) if (f->last_seg) return FALSE; - return stbv_error(f, VORBIS_invalid_stream); + return error(f, VORBIS_invalid_stream); } // if this will take us off the end of the buffers, stop short! @@ -1852,7 +1896,7 @@ static int stbv_codebook_decode_deinterleave_repeat(stbv_vorb *f, StbvCodebook * int div = 1; for (i=0; i < effective; ++i) { int off = (z / div) % c->lookup_values; - float val = STBV_CODEBOOK_ELEMENT_FAST(c,off) + last; + float val = CODEBOOK_ELEMENT_FAST(c,off) + last; if (outputs[c_inter]) outputs[c_inter][p_inter] += val; if (++c_inter == ch) { c_inter = 0; ++p_inter; } @@ -1865,7 +1909,7 @@ static int stbv_codebook_decode_deinterleave_repeat(stbv_vorb *f, StbvCodebook * z *= c->dimensions; if (c->sequence_p) { for (i=0; i < effective; ++i) { - float val = STBV_CODEBOOK_ELEMENT_FAST(c,z+i) + last; + float val = CODEBOOK_ELEMENT_FAST(c,z+i) + last; if (outputs[c_inter]) outputs[c_inter][p_inter] += val; if (++c_inter == ch) { c_inter = 0; ++p_inter; } @@ -1873,7 +1917,7 @@ static int stbv_codebook_decode_deinterleave_repeat(stbv_vorb *f, StbvCodebook * } } else { for (i=0; i < effective; ++i) { - float val = STBV_CODEBOOK_ELEMENT_FAST(c,z+i) + last; + float val = CODEBOOK_ELEMENT_FAST(c,z+i) + last; if (outputs[c_inter]) outputs[c_inter][p_inter] += val; if (++c_inter == ch) { c_inter = 0; ++p_inter; } @@ -1888,7 +1932,7 @@ static int stbv_codebook_decode_deinterleave_repeat(stbv_vorb *f, StbvCodebook * return TRUE; } -static int stbv_predict_point(int x, int x0, int x1, int y0, int y1) +static int predict_point(int x, int x0, int x1, int y0, int y1) { int dy = y1 - y0; int adx = x1 - x0; @@ -1899,71 +1943,71 @@ static int stbv_predict_point(int x, int x0, int x1, int y0, int y1) } // the following table is block-copied from the specification -static float stbv_inverse_db_table[256] = -{ - 1.0649863e-07f, 1.1341951e-07f, 1.2079015e-07f, 1.2863978e-07f, - 1.3699951e-07f, 1.4590251e-07f, 1.5538408e-07f, 1.6548181e-07f, - 1.7623575e-07f, 1.8768855e-07f, 1.9988561e-07f, 2.1287530e-07f, - 2.2670913e-07f, 2.4144197e-07f, 2.5713223e-07f, 2.7384213e-07f, - 2.9163793e-07f, 3.1059021e-07f, 3.3077411e-07f, 3.5226968e-07f, - 3.7516214e-07f, 3.9954229e-07f, 4.2550680e-07f, 4.5315863e-07f, - 4.8260743e-07f, 5.1396998e-07f, 5.4737065e-07f, 5.8294187e-07f, - 6.2082472e-07f, 6.6116941e-07f, 7.0413592e-07f, 7.4989464e-07f, - 7.9862701e-07f, 8.5052630e-07f, 9.0579828e-07f, 9.6466216e-07f, - 1.0273513e-06f, 1.0941144e-06f, 1.1652161e-06f, 1.2409384e-06f, - 1.3215816e-06f, 1.4074654e-06f, 1.4989305e-06f, 1.5963394e-06f, - 1.7000785e-06f, 1.8105592e-06f, 1.9282195e-06f, 2.0535261e-06f, - 2.1869758e-06f, 2.3290978e-06f, 2.4804557e-06f, 2.6416497e-06f, - 2.8133190e-06f, 2.9961443e-06f, 3.1908506e-06f, 3.3982101e-06f, - 3.6190449e-06f, 3.8542308e-06f, 4.1047004e-06f, 4.3714470e-06f, - 4.6555282e-06f, 4.9580707e-06f, 5.2802740e-06f, 5.6234160e-06f, - 5.9888572e-06f, 6.3780469e-06f, 6.7925283e-06f, 7.2339451e-06f, - 7.7040476e-06f, 8.2047000e-06f, 8.7378876e-06f, 9.3057248e-06f, - 9.9104632e-06f, 1.0554501e-05f, 1.1240392e-05f, 1.1970856e-05f, - 1.2748789e-05f, 1.3577278e-05f, 1.4459606e-05f, 1.5399272e-05f, - 1.6400004e-05f, 1.7465768e-05f, 1.8600792e-05f, 1.9809576e-05f, - 2.1096914e-05f, 2.2467911e-05f, 2.3928002e-05f, 2.5482978e-05f, - 2.7139006e-05f, 2.8902651e-05f, 3.0780908e-05f, 3.2781225e-05f, - 3.4911534e-05f, 3.7180282e-05f, 3.9596466e-05f, 4.2169667e-05f, - 4.4910090e-05f, 4.7828601e-05f, 5.0936773e-05f, 5.4246931e-05f, - 5.7772202e-05f, 6.1526565e-05f, 6.5524908e-05f, 6.9783085e-05f, - 7.4317983e-05f, 7.9147585e-05f, 8.4291040e-05f, 8.9768747e-05f, - 9.5602426e-05f, 0.00010181521f, 0.00010843174f, 0.00011547824f, - 0.00012298267f, 0.00013097477f, 0.00013948625f, 0.00014855085f, - 0.00015820453f, 0.00016848555f, 0.00017943469f, 0.00019109536f, - 0.00020351382f, 0.00021673929f, 0.00023082423f, 0.00024582449f, - 0.00026179955f, 0.00027881276f, 0.00029693158f, 0.00031622787f, - 0.00033677814f, 0.00035866388f, 0.00038197188f, 0.00040679456f, - 0.00043323036f, 0.00046138411f, 0.00049136745f, 0.00052329927f, - 0.00055730621f, 0.00059352311f, 0.00063209358f, 0.00067317058f, - 0.00071691700f, 0.00076350630f, 0.00081312324f, 0.00086596457f, - 0.00092223983f, 0.00098217216f, 0.0010459992f, 0.0011139742f, - 0.0011863665f, 0.0012634633f, 0.0013455702f, 0.0014330129f, - 0.0015261382f, 0.0016253153f, 0.0017309374f, 0.0018434235f, - 0.0019632195f, 0.0020908006f, 0.0022266726f, 0.0023713743f, - 0.0025254795f, 0.0026895994f, 0.0028643847f, 0.0030505286f, - 0.0032487691f, 0.0034598925f, 0.0036847358f, 0.0039241906f, - 0.0041792066f, 0.0044507950f, 0.0047400328f, 0.0050480668f, - 0.0053761186f, 0.0057254891f, 0.0060975636f, 0.0064938176f, - 0.0069158225f, 0.0073652516f, 0.0078438871f, 0.0083536271f, - 0.0088964928f, 0.009474637f, 0.010090352f, 0.010746080f, - 0.011444421f, 0.012188144f, 0.012980198f, 0.013823725f, - 0.014722068f, 0.015678791f, 0.016697687f, 0.017782797f, - 0.018938423f, 0.020169149f, 0.021479854f, 0.022875735f, - 0.024362330f, 0.025945531f, 0.027631618f, 0.029427276f, - 0.031339626f, 0.033376252f, 0.035545228f, 0.037855157f, - 0.040315199f, 0.042935108f, 0.045725273f, 0.048696758f, - 0.051861348f, 0.055231591f, 0.058820850f, 0.062643361f, - 0.066714279f, 0.071049749f, 0.075666962f, 0.080584227f, - 0.085821044f, 0.091398179f, 0.097337747f, 0.10366330f, - 0.11039993f, 0.11757434f, 0.12521498f, 0.13335215f, - 0.14201813f, 0.15124727f, 0.16107617f, 0.17154380f, - 0.18269168f, 0.19456402f, 0.20720788f, 0.22067342f, - 0.23501402f, 0.25028656f, 0.26655159f, 0.28387361f, - 0.30232132f, 0.32196786f, 0.34289114f, 0.36517414f, - 0.38890521f, 0.41417847f, 0.44109412f, 0.46975890f, - 0.50028648f, 0.53279791f, 0.56742212f, 0.60429640f, - 0.64356699f, 0.68538959f, 0.72993007f, 0.77736504f, +static float inverse_db_table[256] = +{ + 1.0649863e-07f, 1.1341951e-07f, 1.2079015e-07f, 1.2863978e-07f, + 1.3699951e-07f, 1.4590251e-07f, 1.5538408e-07f, 1.6548181e-07f, + 1.7623575e-07f, 1.8768855e-07f, 1.9988561e-07f, 2.1287530e-07f, + 2.2670913e-07f, 2.4144197e-07f, 2.5713223e-07f, 2.7384213e-07f, + 2.9163793e-07f, 3.1059021e-07f, 3.3077411e-07f, 3.5226968e-07f, + 3.7516214e-07f, 3.9954229e-07f, 4.2550680e-07f, 4.5315863e-07f, + 4.8260743e-07f, 5.1396998e-07f, 5.4737065e-07f, 5.8294187e-07f, + 6.2082472e-07f, 6.6116941e-07f, 7.0413592e-07f, 7.4989464e-07f, + 7.9862701e-07f, 8.5052630e-07f, 9.0579828e-07f, 9.6466216e-07f, + 1.0273513e-06f, 1.0941144e-06f, 1.1652161e-06f, 1.2409384e-06f, + 1.3215816e-06f, 1.4074654e-06f, 1.4989305e-06f, 1.5963394e-06f, + 1.7000785e-06f, 1.8105592e-06f, 1.9282195e-06f, 2.0535261e-06f, + 2.1869758e-06f, 2.3290978e-06f, 2.4804557e-06f, 2.6416497e-06f, + 2.8133190e-06f, 2.9961443e-06f, 3.1908506e-06f, 3.3982101e-06f, + 3.6190449e-06f, 3.8542308e-06f, 4.1047004e-06f, 4.3714470e-06f, + 4.6555282e-06f, 4.9580707e-06f, 5.2802740e-06f, 5.6234160e-06f, + 5.9888572e-06f, 6.3780469e-06f, 6.7925283e-06f, 7.2339451e-06f, + 7.7040476e-06f, 8.2047000e-06f, 8.7378876e-06f, 9.3057248e-06f, + 9.9104632e-06f, 1.0554501e-05f, 1.1240392e-05f, 1.1970856e-05f, + 1.2748789e-05f, 1.3577278e-05f, 1.4459606e-05f, 1.5399272e-05f, + 1.6400004e-05f, 1.7465768e-05f, 1.8600792e-05f, 1.9809576e-05f, + 2.1096914e-05f, 2.2467911e-05f, 2.3928002e-05f, 2.5482978e-05f, + 2.7139006e-05f, 2.8902651e-05f, 3.0780908e-05f, 3.2781225e-05f, + 3.4911534e-05f, 3.7180282e-05f, 3.9596466e-05f, 4.2169667e-05f, + 4.4910090e-05f, 4.7828601e-05f, 5.0936773e-05f, 5.4246931e-05f, + 5.7772202e-05f, 6.1526565e-05f, 6.5524908e-05f, 6.9783085e-05f, + 7.4317983e-05f, 7.9147585e-05f, 8.4291040e-05f, 8.9768747e-05f, + 9.5602426e-05f, 0.00010181521f, 0.00010843174f, 0.00011547824f, + 0.00012298267f, 0.00013097477f, 0.00013948625f, 0.00014855085f, + 0.00015820453f, 0.00016848555f, 0.00017943469f, 0.00019109536f, + 0.00020351382f, 0.00021673929f, 0.00023082423f, 0.00024582449f, + 0.00026179955f, 0.00027881276f, 0.00029693158f, 0.00031622787f, + 0.00033677814f, 0.00035866388f, 0.00038197188f, 0.00040679456f, + 0.00043323036f, 0.00046138411f, 0.00049136745f, 0.00052329927f, + 0.00055730621f, 0.00059352311f, 0.00063209358f, 0.00067317058f, + 0.00071691700f, 0.00076350630f, 0.00081312324f, 0.00086596457f, + 0.00092223983f, 0.00098217216f, 0.0010459992f, 0.0011139742f, + 0.0011863665f, 0.0012634633f, 0.0013455702f, 0.0014330129f, + 0.0015261382f, 0.0016253153f, 0.0017309374f, 0.0018434235f, + 0.0019632195f, 0.0020908006f, 0.0022266726f, 0.0023713743f, + 0.0025254795f, 0.0026895994f, 0.0028643847f, 0.0030505286f, + 0.0032487691f, 0.0034598925f, 0.0036847358f, 0.0039241906f, + 0.0041792066f, 0.0044507950f, 0.0047400328f, 0.0050480668f, + 0.0053761186f, 0.0057254891f, 0.0060975636f, 0.0064938176f, + 0.0069158225f, 0.0073652516f, 0.0078438871f, 0.0083536271f, + 0.0088964928f, 0.009474637f, 0.010090352f, 0.010746080f, + 0.011444421f, 0.012188144f, 0.012980198f, 0.013823725f, + 0.014722068f, 0.015678791f, 0.016697687f, 0.017782797f, + 0.018938423f, 0.020169149f, 0.021479854f, 0.022875735f, + 0.024362330f, 0.025945531f, 0.027631618f, 0.029427276f, + 0.031339626f, 0.033376252f, 0.035545228f, 0.037855157f, + 0.040315199f, 0.042935108f, 0.045725273f, 0.048696758f, + 0.051861348f, 0.055231591f, 0.058820850f, 0.062643361f, + 0.066714279f, 0.071049749f, 0.075666962f, 0.080584227f, + 0.085821044f, 0.091398179f, 0.097337747f, 0.10366330f, + 0.11039993f, 0.11757434f, 0.12521498f, 0.13335215f, + 0.14201813f, 0.15124727f, 0.16107617f, 0.17154380f, + 0.18269168f, 0.19456402f, 0.20720788f, 0.22067342f, + 0.23501402f, 0.25028656f, 0.26655159f, 0.28387361f, + 0.30232132f, 0.32196786f, 0.34289114f, 0.36517414f, + 0.38890521f, 0.41417847f, 0.44109412f, 0.46975890f, + 0.50028648f, 0.53279791f, 0.56742212f, 0.60429640f, + 0.64356699f, 0.68538959f, 0.72993007f, 0.77736504f, 0.82788260f, 0.88168307f, 0.9389798f, 1.0f }; @@ -1976,18 +2020,18 @@ static float stbv_inverse_db_table[256] = // ... also, isn't the whole point of Bresenham's algorithm to NOT // have to divide in the setup? sigh. #ifndef STB_VORBIS_NO_DEFER_FLOOR -#define STBV_LINE_OP(a,b) a *= b +#define LINE_OP(a,b) a *= b #else -#define STBV_LINE_OP(a,b) a = b +#define LINE_OP(a,b) a = b #endif #ifdef STB_VORBIS_DIVIDE_TABLE -#define STBV_DIVTAB_NUMER 32 -#define STBV_DIVTAB_DENOM 64 -stbv_int8 stbv_integer_divide_table[STBV_DIVTAB_NUMER][STBV_DIVTAB_DENOM]; // 2KB +#define DIVTAB_NUMER 32 +#define DIVTAB_DENOM 64 +int8 integer_divide_table[DIVTAB_NUMER][DIVTAB_DENOM]; // 2KB #endif -static __forceinline void stbv_draw_line(float *output, int x0, int y0, int x1, int y1, int n) +static __forceinline void draw_line(float *output, int x0, int y0, int x1, int y1, int n) { int dy = y1 - y0; int adx = x1 - x0; @@ -1998,12 +2042,12 @@ static __forceinline void stbv_draw_line(float *output, int x0, int y0, int x1, int sy; #ifdef STB_VORBIS_DIVIDE_TABLE - if (adx < STBV_DIVTAB_DENOM && ady < STBV_DIVTAB_NUMER) { + if (adx < DIVTAB_DENOM && ady < DIVTAB_NUMER) { if (dy < 0) { - base = -stbv_integer_divide_table[ady][adx]; + base = -integer_divide_table[ady][adx]; sy = base-1; } else { - base = stbv_integer_divide_table[ady][adx]; + base = integer_divide_table[ady][adx]; sy = base+1; } } else { @@ -2023,7 +2067,7 @@ static __forceinline void stbv_draw_line(float *output, int x0, int y0, int x1, ady -= abs(base) * adx; if (x1 > n) x1 = n; if (x < x1) { - STBV_LINE_OP(output[x], stbv_inverse_db_table[y]); + LINE_OP(output[x], inverse_db_table[y&255]); for (++x; x < x1; ++x) { err += ady; if (err >= adx) { @@ -2031,22 +2075,22 @@ static __forceinline void stbv_draw_line(float *output, int x0, int y0, int x1, y += sy; } else y += base; - STBV_LINE_OP(output[x], stbv_inverse_db_table[y]); + LINE_OP(output[x], inverse_db_table[y&255]); } } } -static int stbv_residue_decode(stbv_vorb *f, StbvCodebook *book, float *target, int offset, int n, int rtype) +static int residue_decode(vorb *f, Codebook *book, float *target, int offset, int n, int rtype) { int k; if (rtype == 0) { int step = n / book->dimensions; for (k=0; k < step; ++k) - if (!stbv_codebook_decode_step(f, book, target+offset+k, n-offset-k, step)) + if (!codebook_decode_step(f, book, target+offset+k, n-offset-k, step)) return FALSE; } else { for (k=0; k < n; ) { - if (!stbv_codebook_decode(f, book, target+offset, n-k)) + if (!codebook_decode(f, book, target+offset, n-k)) return FALSE; k += book->dimensions; offset += book->dimensions; @@ -2057,10 +2101,10 @@ static int stbv_residue_decode(stbv_vorb *f, StbvCodebook *book, float *target, // n is 1/2 of the blocksize -- // specification: "Correct per-vector decode length is [n]/2" -static void stbv_decode_residue(stbv_vorb *f, float *residue_buffers[], int ch, int n, int rn, stbv_uint8 *do_not_decode) +static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int rn, uint8 *do_not_decode) { int i,j,pass; - StbvResidue *r = f->residue_config + rn; + Residue *r = f->residue_config + rn; int rtype = f->residue_types[rn]; int c = r->classbook; int classwords = f->codebooks[c].dimensions; @@ -2069,14 +2113,14 @@ static void stbv_decode_residue(stbv_vorb *f, float *residue_buffers[], int ch, unsigned int limit_r_end = (r->end < actual_size ? r->end : actual_size); int n_read = limit_r_end - limit_r_begin; int part_read = n_read / r->part_size; - int temp_alloc_point = stbv_temp_alloc_save(f); + int temp_alloc_point = temp_alloc_save(f); #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE - stbv_uint8 ***part_classdata = (stbv_uint8 ***) stbv_temp_block_array(f,f->channels, part_read * sizeof(**part_classdata)); + uint8 ***part_classdata = (uint8 ***) temp_block_array(f,f->channels, part_read * sizeof(**part_classdata)); #else - int **classifications = (int **) stbv_temp_block_array(f,f->channels, part_read * sizeof(**classifications)); + int **classifications = (int **) temp_block_array(f,f->channels, part_read * sizeof(**classifications)); #endif - STBV_CHECK(f); + CHECK(f); for (i=0; i < ch; ++i) if (!do_not_decode[i]) @@ -2096,10 +2140,10 @@ static void stbv_decode_residue(stbv_vorb *f, float *residue_buffers[], int ch, int z = r->begin + pcount*r->part_size; int c_inter = (z & 1), p_inter = z>>1; if (pass == 0) { - StbvCodebook *c = f->codebooks+r->classbook; + Codebook *c = f->codebooks+r->classbook; int q; - STBV_DECODE(q,f,c); - if (q == STBV_EOP) goto done; + DECODE(q,f,c); + if (q == EOP) goto done; #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE part_classdata[0][class_set] = r->classdata[q]; #else @@ -2118,13 +2162,13 @@ static void stbv_decode_residue(stbv_vorb *f, float *residue_buffers[], int ch, #endif int b = r->residue_books[c][pass]; if (b >= 0) { - StbvCodebook *book = f->codebooks + b; + Codebook *book = f->codebooks + b; #ifdef STB_VORBIS_DIVIDES_IN_CODEBOOK - if (!stbv_codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, r->part_size)) + if (!codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, r->part_size)) goto done; #else // saves 1% - if (!stbv_codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, r->part_size)) + if (!codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, r->part_size)) goto done; #endif } else { @@ -2137,55 +2181,15 @@ static void stbv_decode_residue(stbv_vorb *f, float *residue_buffers[], int ch, ++class_set; #endif } - } else if (ch == 1) { - while (pcount < part_read) { - int z = r->begin + pcount*r->part_size; - int c_inter = 0, p_inter = z; - if (pass == 0) { - StbvCodebook *c = f->codebooks+r->classbook; - int q; - STBV_DECODE(q,f,c); - if (q == STBV_EOP) goto done; - #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE - part_classdata[0][class_set] = r->classdata[q]; - #else - for (i=classwords-1; i >= 0; --i) { - classifications[0][i+pcount] = q % r->classifications; - q /= r->classifications; - } - #endif - } - for (i=0; i < classwords && pcount < part_read; ++i, ++pcount) { - int z = r->begin + pcount*r->part_size; - #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE - int c = part_classdata[0][class_set][i]; - #else - int c = classifications[0][pcount]; - #endif - int b = r->residue_books[c][pass]; - if (b >= 0) { - StbvCodebook *book = f->codebooks + b; - if (!stbv_codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, r->part_size)) - goto done; - } else { - z += r->part_size; - c_inter = 0; - p_inter = z; - } - } - #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE - ++class_set; - #endif - } - } else { + } else if (ch > 2) { while (pcount < part_read) { int z = r->begin + pcount*r->part_size; int c_inter = z % ch, p_inter = z/ch; if (pass == 0) { - StbvCodebook *c = f->codebooks+r->classbook; + Codebook *c = f->codebooks+r->classbook; int q; - STBV_DECODE(q,f,c); - if (q == STBV_EOP) goto done; + DECODE(q,f,c); + if (q == EOP) goto done; #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE part_classdata[0][class_set] = r->classdata[q]; #else @@ -2204,8 +2208,8 @@ static void stbv_decode_residue(stbv_vorb *f, float *residue_buffers[], int ch, #endif int b = r->residue_books[c][pass]; if (b >= 0) { - StbvCodebook *book = f->codebooks + b; - if (!stbv_codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, r->part_size)) + Codebook *book = f->codebooks + b; + if (!codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, r->part_size)) goto done; } else { z += r->part_size; @@ -2221,7 +2225,7 @@ static void stbv_decode_residue(stbv_vorb *f, float *residue_buffers[], int ch, } goto done; } - STBV_CHECK(f); + CHECK(f); for (pass=0; pass < 8; ++pass) { int pcount = 0, class_set=0; @@ -2229,10 +2233,10 @@ static void stbv_decode_residue(stbv_vorb *f, float *residue_buffers[], int ch, if (pass == 0) { for (j=0; j < ch; ++j) { if (!do_not_decode[j]) { - StbvCodebook *c = f->codebooks+r->classbook; + Codebook *c = f->codebooks+r->classbook; int temp; - STBV_DECODE(temp,f,c); - if (temp == STBV_EOP) goto done; + DECODE(temp,f,c); + if (temp == EOP) goto done; #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE part_classdata[j][class_set] = r->classdata[temp]; #else @@ -2257,8 +2261,8 @@ static void stbv_decode_residue(stbv_vorb *f, float *residue_buffers[], int ch, float *target = residue_buffers[j]; int offset = r->begin + pcount * r->part_size; int n = r->part_size; - StbvCodebook *book = f->codebooks + b; - if (!stbv_residue_decode(f, book, target, offset, n, rtype)) + Codebook *book = f->codebooks + b; + if (!residue_decode(f, book, target, offset, n, rtype)) goto done; } } @@ -2270,13 +2274,13 @@ static void stbv_decode_residue(stbv_vorb *f, float *residue_buffers[], int ch, } } done: - STBV_CHECK(f); + CHECK(f); #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE - stbv_temp_free(f,part_classdata); + temp_free(f,part_classdata); #else - stbv_temp_free(f,classifications); + temp_free(f,classifications); #endif - stbv_temp_alloc_restore(f,temp_alloc_point); + temp_alloc_restore(f,temp_alloc_point); } @@ -2305,7 +2309,7 @@ void inverse_mdct_slow(float *buffer, int n) } #elif 0 // same as above, but just barely able to run in real time on modern machines -void inverse_mdct_slow(float *buffer, int n, stbv_vorb *f, int blocktype) +void inverse_mdct_slow(float *buffer, int n, vorb *f, int blocktype) { float mcos[16384]; int i,j; @@ -2343,7 +2347,7 @@ void dct_iv_slow(float *buffer, int n) } } -void inverse_mdct_slow(float *buffer, int n, stbv_vorb *f, int blocktype) +void inverse_mdct_slow(float *buffer, int n, vorb *f, int blocktype) { int i, n4 = n >> 2, n2 = n >> 1, n3_4 = n - n4; float temp[4096]; @@ -2364,11 +2368,11 @@ void inverse_mdct_slow(float *buffer, int n, stbv_vorb *f, int blocktype) #if LIBVORBIS_MDCT // directly call the vorbis MDCT using an interface documented // by Jeff Roberts... useful for performance comparison -typedef struct +typedef struct { int n; int log2n; - + float *trig; int *bitrev; @@ -2381,13 +2385,13 @@ extern void mdct_backward(mdct_lookup *init, float *in, float *out); mdct_lookup M1,M2; -void stbv_inverse_mdct(float *buffer, int n, stbv_vorb *f, int blocktype) +void inverse_mdct(float *buffer, int n, vorb *f, int blocktype) { mdct_lookup *M; if (M1.n == n) M = &M1; else if (M2.n == n) M = &M2; else if (M1.n == 0) { mdct_init(&M1, n); M = &M1; } - else { + else { if (M2.n) __asm int 3; mdct_init(&M2, n); M = &M2; @@ -2401,7 +2405,7 @@ void stbv_inverse_mdct(float *buffer, int n, stbv_vorb *f, int blocktype) // the following were split out into separate functions while optimizing; // they could be pushed back up but eh. __forceinline showed no change; // they're probably already being inlined. -static void stbv_imdct_step3_iter0_loop(int n, float *e, int i_off, int k_off, float *A) +static void imdct_step3_iter0_loop(int n, float *e, int i_off, int k_off, float *A) { float *ee0 = e + i_off; float *ee2 = ee0 + k_off; @@ -2446,7 +2450,7 @@ static void stbv_imdct_step3_iter0_loop(int n, float *e, int i_off, int k_off, f } } -static void stbv_imdct_step3_inner_r_loop(int lim, float *e, int d0, int k_off, float *A, int k1) +static void imdct_step3_inner_r_loop(int lim, float *e, int d0, int k_off, float *A, int k1) { int i; float k00_20, k01_21; @@ -2496,7 +2500,7 @@ static void stbv_imdct_step3_inner_r_loop(int lim, float *e, int d0, int k_off, } } -static void stbv_imdct_step3_inner_s_loop(int n, float *e, int i_off, int k_off, float *A, int a_off, int k0) +static void imdct_step3_inner_s_loop(int n, float *e, int i_off, int k_off, float *A, int a_off, int k0) { int i; float A0 = A[0]; @@ -2547,7 +2551,7 @@ static void stbv_imdct_step3_inner_s_loop(int n, float *e, int i_off, int k_off, } } -static __forceinline void stbv_iter_54(float *z) +static __forceinline void iter_54(float *z) { float k00,k11,k22,k33; float y0,y1,y2,y3; @@ -2579,7 +2583,7 @@ static __forceinline void stbv_iter_54(float *z) z[-7] = k11 + k22; // z1 - z5 - z2 + z6 } -static void stbv_imdct_step3_inner_s_loop_ld654(int n, float *e, int i_off, float *A, int base_n) +static void imdct_step3_inner_s_loop_ld654(int n, float *e, int i_off, float *A, int base_n) { int a_off = base_n >> 3; float A2 = A[0+a_off]; @@ -2588,48 +2592,47 @@ static void stbv_imdct_step3_inner_s_loop_ld654(int n, float *e, int i_off, floa while (z > base) { float k00,k11; - - k00 = z[-0] - z[-8]; - k11 = z[-1] - z[-9]; - z[-0] = z[-0] + z[-8]; - z[-1] = z[-1] + z[-9]; - z[-8] = k00; - z[-9] = k11 ; - - k00 = z[ -2] - z[-10]; - k11 = z[ -3] - z[-11]; - z[ -2] = z[ -2] + z[-10]; - z[ -3] = z[ -3] + z[-11]; - z[-10] = (k00+k11) * A2; - z[-11] = (k11-k00) * A2; - - k00 = z[-12] - z[ -4]; // reverse to avoid a unary negation + float l00,l11; + + k00 = z[-0] - z[ -8]; + k11 = z[-1] - z[ -9]; + l00 = z[-2] - z[-10]; + l11 = z[-3] - z[-11]; + z[ -0] = z[-0] + z[ -8]; + z[ -1] = z[-1] + z[ -9]; + z[ -2] = z[-2] + z[-10]; + z[ -3] = z[-3] + z[-11]; + z[ -8] = k00; + z[ -9] = k11; + z[-10] = (l00+l11) * A2; + z[-11] = (l11-l00) * A2; + + k00 = z[ -4] - z[-12]; k11 = z[ -5] - z[-13]; + l00 = z[ -6] - z[-14]; + l11 = z[ -7] - z[-15]; z[ -4] = z[ -4] + z[-12]; z[ -5] = z[ -5] + z[-13]; - z[-12] = k11; - z[-13] = k00; - - k00 = z[-14] - z[ -6]; // reverse to avoid a unary negation - k11 = z[ -7] - z[-15]; z[ -6] = z[ -6] + z[-14]; z[ -7] = z[ -7] + z[-15]; - z[-14] = (k00+k11) * A2; - z[-15] = (k00-k11) * A2; + z[-12] = k11; + z[-13] = -k00; + z[-14] = (l11-l00) * A2; + z[-15] = (l00+l11) * -A2; - stbv_iter_54(z); - stbv_iter_54(z-8); + iter_54(z); + iter_54(z-8); z -= 16; } } -static void stbv_inverse_mdct(float *buffer, int n, stbv_vorb *f, int blocktype) +static void inverse_mdct(float *buffer, int n, vorb *f, int blocktype) { int n2 = n >> 1, n4 = n >> 2, n8 = n >> 3, l; int ld; // @OPTIMIZE: reduce register pressure by using fewer variables? - int save_point = stbv_temp_alloc_save(f); - float *buf2 = (float *) stbv_temp_alloc(f, n2 * sizeof(*buf2)); + int save_point = temp_alloc_save(f); + float *buf2 = (float *) temp_alloc(f, n2 * sizeof(*buf2)); float *u=NULL,*v=NULL; // twiddle factors float *A = f->A[blocktype]; @@ -2650,7 +2653,7 @@ static void stbv_inverse_mdct(float *buffer, int n, stbv_vorb *f, int blocktype) // once I combined the passes. // so there's a missing 'times 2' here (for adding X to itself). - // this propogates through linearly to the end, where the numbers + // this propagates through linearly to the end, where the numbers // are 1/2 too small, and need to be compensated for. { @@ -2724,7 +2727,7 @@ static void stbv_inverse_mdct(float *buffer, int n, stbv_vorb *f, int blocktype) } // step 3 - ld = stbv_ilog(n) - 1; // stbv_ilog is off-by-one from normal definitions + ld = ilog(n) - 1; // ilog is off-by-one from normal definitions // optimized step 3: @@ -2734,14 +2737,14 @@ static void stbv_inverse_mdct(float *buffer, int n, stbv_vorb *f, int blocktype) // switch between them halfway. // this is iteration 0 of step 3 - stbv_imdct_step3_iter0_loop(n >> 4, u, n2-1-n4*0, -(n >> 3), A); - stbv_imdct_step3_iter0_loop(n >> 4, u, n2-1-n4*1, -(n >> 3), A); + imdct_step3_iter0_loop(n >> 4, u, n2-1-n4*0, -(n >> 3), A); + imdct_step3_iter0_loop(n >> 4, u, n2-1-n4*1, -(n >> 3), A); // this is iteration 1 of step 3 - stbv_imdct_step3_inner_r_loop(n >> 5, u, n2-1 - n8*0, -(n >> 4), A, 16); - stbv_imdct_step3_inner_r_loop(n >> 5, u, n2-1 - n8*1, -(n >> 4), A, 16); - stbv_imdct_step3_inner_r_loop(n >> 5, u, n2-1 - n8*2, -(n >> 4), A, 16); - stbv_imdct_step3_inner_r_loop(n >> 5, u, n2-1 - n8*3, -(n >> 4), A, 16); + imdct_step3_inner_r_loop(n >> 5, u, n2-1 - n8*0, -(n >> 4), A, 16); + imdct_step3_inner_r_loop(n >> 5, u, n2-1 - n8*1, -(n >> 4), A, 16); + imdct_step3_inner_r_loop(n >> 5, u, n2-1 - n8*2, -(n >> 4), A, 16); + imdct_step3_inner_r_loop(n >> 5, u, n2-1 - n8*3, -(n >> 4), A, 16); l=2; for (; l < (ld-3)>>1; ++l) { @@ -2749,7 +2752,7 @@ static void stbv_inverse_mdct(float *buffer, int n, stbv_vorb *f, int blocktype) int lim = 1 << (l+1); int i; for (i=0; i < lim; ++i) - stbv_imdct_step3_inner_r_loop(n >> (l+4), u, n2-1 - k0*i, -k0_2, A, 1 << (l+3)); + imdct_step3_inner_r_loop(n >> (l+4), u, n2-1 - k0*i, -k0_2, A, 1 << (l+3)); } for (; l < ld-6; ++l) { @@ -2760,7 +2763,7 @@ static void stbv_inverse_mdct(float *buffer, int n, stbv_vorb *f, int blocktype) float *A0 = A; i_off = n2-1; for (r=rlim; r > 0; --r) { - stbv_imdct_step3_inner_s_loop(lim, u, i_off, -k0_2, A0, k1, k0); + imdct_step3_inner_s_loop(lim, u, i_off, -k0_2, A0, k1, k0); A0 += k1*4; i_off -= 8; } @@ -2771,14 +2774,14 @@ static void stbv_inverse_mdct(float *buffer, int n, stbv_vorb *f, int blocktype) // the big win comes from getting rid of needless flops // due to the constants on pass 5 & 4 being all 1 and 0; // combining them to be simultaneous to improve cache made little difference - stbv_imdct_step3_inner_s_loop_ld654(n >> 5, u, n2-1, A, n); + imdct_step3_inner_s_loop_ld654(n >> 5, u, n2-1, A, n); // output is u // step 4, 5, and 6 // cannot be in-place because of step 5 { - stbv_uint16 *bitrev = f->stbv_bit_reverse[blocktype]; + uint16 *bitrev = f->bit_reverse[blocktype]; // weirdly, I'd have thought reading sequentially and writing // erratically would have been better than vice-versa, but in // fact that's not what my testing showed. (That is, with @@ -2800,7 +2803,7 @@ static void stbv_inverse_mdct(float *buffer, int n, stbv_vorb *f, int blocktype) d1[0] = u[k4+1]; d0[1] = u[k4+2]; d0[0] = u[k4+3]; - + d0 -= 4; d1 -= 4; bitrev += 2; @@ -2881,7 +2884,7 @@ static void stbv_inverse_mdct(float *buffer, int n, stbv_vorb *f, int blocktype) float p0,p1,p2,p3; p3 = e[6]*B[7] - e[7]*B[6]; - p2 = -e[6]*B[6] - e[7]*B[7]; + p2 = -e[6]*B[6] - e[7]*B[7]; d0[0] = p3; d1[3] = - p3; @@ -2889,7 +2892,7 @@ static void stbv_inverse_mdct(float *buffer, int n, stbv_vorb *f, int blocktype) d3[3] = p2; p1 = e[4]*B[5] - e[5]*B[4]; - p0 = -e[4]*B[4] - e[5]*B[5]; + p0 = -e[4]*B[4] - e[5]*B[5]; d0[1] = p1; d1[2] = - p1; @@ -2897,7 +2900,7 @@ static void stbv_inverse_mdct(float *buffer, int n, stbv_vorb *f, int blocktype) d3[2] = p0; p3 = e[2]*B[3] - e[3]*B[2]; - p2 = -e[2]*B[2] - e[3]*B[3]; + p2 = -e[2]*B[2] - e[3]*B[3]; d0[2] = p3; d1[1] = - p3; @@ -2905,7 +2908,7 @@ static void stbv_inverse_mdct(float *buffer, int n, stbv_vorb *f, int blocktype) d3[1] = p2; p1 = e[0]*B[1] - e[1]*B[0]; - p0 = -e[0]*B[0] - e[1]*B[1]; + p0 = -e[0]*B[0] - e[1]*B[1]; d0[3] = p1; d1[0] = - p1; @@ -2921,8 +2924,8 @@ static void stbv_inverse_mdct(float *buffer, int n, stbv_vorb *f, int blocktype) } } - stbv_temp_free(f,buf2); - stbv_temp_alloc_restore(f,save_point); + temp_free(f,buf2); + temp_alloc_restore(f,save_point); } #if 0 @@ -2973,7 +2976,7 @@ void inverse_mdct_naive(float *buffer, int n) w[k4+1] = (v[n2+1+k4] - v[k4+1])*A[n2-4-k4] + (v[n2+3+k4]-v[k4+3])*A[n2-3-k4]; } // step 3 - ld = stbv_ilog(n) - 1; // stbv_ilog is off-by-one from normal definitions + ld = ilog(n) - 1; // ilog is off-by-one from normal definitions for (l=0; l < ld-3; ++l) { int k0 = n >> (l+2), k1 = 1 << (l+3); int rlim = n >> (l+4), r4, r; @@ -2996,7 +2999,7 @@ void inverse_mdct_naive(float *buffer, int n) // step 4 for (i=0; i < n8; ++i) { - int j = stbv_bit_reverse(i) >> (32-ld+3); + int j = bit_reverse(i) >> (32-ld+3); assert(j < n8); if (i == j) { // paper bug: original code probably swapped in place; if copying, @@ -3053,34 +3056,34 @@ void inverse_mdct_naive(float *buffer, int n) } #endif -static float *stbv_get_window(stbv_vorb *f, int len) +static float *get_window(vorb *f, int len) { len <<= 1; if (len == f->blocksize_0) return f->window[0]; if (len == f->blocksize_1) return f->window[1]; - assert(0); return NULL; } #ifndef STB_VORBIS_NO_DEFER_FLOOR -typedef stbv_int16 STBV_YTYPE; +typedef int16 YTYPE; #else -typedef int STBV_YTYPE; +typedef int YTYPE; #endif -static int stbv_do_floor(stbv_vorb *f, StbvMapping *map, int i, int n, float *target, STBV_YTYPE *finalY, stbv_uint8 *step2_flag) +static int do_floor(vorb *f, Mapping *map, int i, int n, float *target, YTYPE *finalY, uint8 *step2_flag) { int n2 = n >> 1; int s = map->chan[i].mux, floor; floor = map->submap_floor[s]; if (f->floor_types[floor] == 0) { - return stbv_error(f, VORBIS_invalid_stream); + return error(f, VORBIS_invalid_stream); } else { - StbvFloor1 *g = &f->floor_config[floor].floor1; + Floor1 *g = &f->floor_config[floor].floor1; int j,q; int lx = 0, ly = finalY[0] * g->floor1_multiplier; for (q=1; q < g->values; ++q) { j = g->sorted_order[q]; #ifndef STB_VORBIS_NO_DEFER_FLOOR + STBV_NOTUSED(step2_flag); if (finalY[j] >= 0) #else if (step2_flag[j]) @@ -3089,16 +3092,16 @@ static int stbv_do_floor(stbv_vorb *f, StbvMapping *map, int i, int n, float *ta int hy = finalY[j] * g->floor1_multiplier; int hx = g->Xlist[j]; if (lx != hx) - stbv_draw_line(target, lx,ly, hx,hy, n2); - STBV_CHECK(f); + draw_line(target, lx,ly, hx,hy, n2); + CHECK(f); lx = hx, ly = hy; } } if (lx < n2) { - // optimization of: stbv_draw_line(target, lx,ly, n,ly, n2); + // optimization of: draw_line(target, lx,ly, n,ly, n2); for (j=lx; j < n2; ++j) - STBV_LINE_OP(target[j], stbv_inverse_db_table[ly]); - STBV_CHECK(f); + LINE_OP(target[j], inverse_db_table[ly]); + CHECK(f); } } return TRUE; @@ -3118,36 +3121,36 @@ static int stbv_do_floor(stbv_vorb *f, StbvMapping *map, int i, int n, float *ta // has to be the same as frame N+1's left_end-left_start (which they are by // construction) -static int stbv_vorbis_decode_initial(stbv_vorb *f, int *p_left_start, int *p_left_end, int *p_right_start, int *p_right_end, int *mode) +static int vorbis_decode_initial(vorb *f, int *p_left_start, int *p_left_end, int *p_right_start, int *p_right_end, int *mode) { - StbvMode *m; + Mode *m; int i, n, prev, next, window_center; f->channel_buffer_start = f->channel_buffer_end = 0; retry: if (f->eof) return FALSE; - if (!stbv_maybe_start_packet(f)) + if (!maybe_start_packet(f)) return FALSE; // check packet type - if (stbv_get_bits(f,1) != 0) { - if (STBV_IS_PUSH_MODE(f)) - return stbv_error(f,VORBIS_bad_packet_type); - while (STBV_EOP != stbv_get8_packet(f)); + if (get_bits(f,1) != 0) { + if (IS_PUSH_MODE(f)) + return error(f,VORBIS_bad_packet_type); + while (EOP != get8_packet(f)); goto retry; } if (f->alloc.alloc_buffer) assert(f->alloc.alloc_buffer_length_in_bytes == f->temp_offset); - i = stbv_get_bits(f, stbv_ilog(f->mode_count-1)); - if (i == STBV_EOP) return FALSE; + i = get_bits(f, ilog(f->mode_count-1)); + if (i == EOP) return FALSE; if (i >= f->mode_count) return FALSE; *mode = i; m = f->mode_config + i; if (m->blockflag) { n = f->blocksize_1; - prev = stbv_get_bits(f,1); - next = stbv_get_bits(f,1); + prev = get_bits(f,1); + next = get_bits(f,1); } else { prev = next = 0; n = f->blocksize_0; @@ -3174,40 +3177,41 @@ static int stbv_vorbis_decode_initial(stbv_vorb *f, int *p_left_start, int *p_le return TRUE; } -static int stbv_vorbis_decode_packet_rest(stbv_vorb *f, int *len, StbvMode *m, int left_start, int left_end, int right_start, int right_end, int *p_left) +static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start, int left_end, int right_start, int right_end, int *p_left) { - StbvMapping *map; + Mapping *map; int i,j,k,n,n2; int zero_channel[256]; int really_zero_channel[256]; // WINDOWING + STBV_NOTUSED(left_end); n = f->blocksize[m->blockflag]; map = &f->mapping[m->mapping]; // FLOORS n2 = n >> 1; - STBV_CHECK(f); + CHECK(f); for (i=0; i < f->channels; ++i) { int s = map->chan[i].mux, floor; zero_channel[i] = FALSE; floor = map->submap_floor[s]; if (f->floor_types[floor] == 0) { - return stbv_error(f, VORBIS_invalid_stream); + return error(f, VORBIS_invalid_stream); } else { - StbvFloor1 *g = &f->floor_config[floor].floor1; - if (stbv_get_bits(f, 1)) { + Floor1 *g = &f->floor_config[floor].floor1; + if (get_bits(f, 1)) { short *finalY; - stbv_uint8 step2_flag[256]; + uint8 step2_flag[256]; static int range_list[4] = { 256, 128, 86, 64 }; int range = range_list[g->floor1_multiplier-1]; int offset = 2; finalY = f->finalY[i]; - finalY[0] = stbv_get_bits(f, stbv_ilog(range)-1); - finalY[1] = stbv_get_bits(f, stbv_ilog(range)-1); + finalY[0] = get_bits(f, ilog(range)-1); + finalY[1] = get_bits(f, ilog(range)-1); for (j=0; j < g->partitions; ++j) { int pclass = g->partition_class_list[j]; int cdim = g->class_dimensions[pclass]; @@ -3215,29 +3219,29 @@ static int stbv_vorbis_decode_packet_rest(stbv_vorb *f, int *len, StbvMode *m, i int csub = (1 << cbits)-1; int cval = 0; if (cbits) { - StbvCodebook *c = f->codebooks + g->class_masterbooks[pclass]; - STBV_DECODE(cval,f,c); + Codebook *c = f->codebooks + g->class_masterbooks[pclass]; + DECODE(cval,f,c); } for (k=0; k < cdim; ++k) { int book = g->subclass_books[pclass][cval & csub]; cval = cval >> cbits; if (book >= 0) { int temp; - StbvCodebook *c = f->codebooks + book; - STBV_DECODE(temp,f,c); + Codebook *c = f->codebooks + book; + DECODE(temp,f,c); finalY[offset++] = temp; } else finalY[offset++] = 0; } } - if (f->valid_bits == STBV_INVALID_BITS) goto error; // behavior according to spec + if (f->valid_bits == INVALID_BITS) goto error; // behavior according to spec step2_flag[0] = step2_flag[1] = 1; for (j=2; j < g->values; ++j) { int low, high, pred, highroom, lowroom, room, val; - low = g->stbv_neighbors[j][0]; - high = g->stbv_neighbors[j][1]; - //stbv_neighbors(g->Xlist, j, &low, &high); - pred = stbv_predict_point(g->Xlist[j], g->Xlist[low], g->Xlist[high], finalY[low], finalY[high]); + low = g->neighbors[j][0]; + high = g->neighbors[j][1]; + //neighbors(g->Xlist, j, &low, &high); + pred = predict_point(g->Xlist[j], g->Xlist[low], g->Xlist[high], finalY[low], finalY[high]); val = finalY[j]; highroom = range - pred; lowroom = pred; @@ -3265,7 +3269,7 @@ static int stbv_vorbis_decode_packet_rest(stbv_vorb *f, int *len, StbvMode *m, i } #ifdef STB_VORBIS_NO_DEFER_FLOOR - stbv_do_floor(f, map, i, n, f->floor_buffers[i], finalY, step2_flag); + do_floor(f, map, i, n, f->floor_buffers[i], finalY, step2_flag); #else // defer final floor computation until _after_ residue for (j=0; j < g->values; ++j) { @@ -3282,7 +3286,7 @@ static int stbv_vorbis_decode_packet_rest(stbv_vorb *f, int *len, StbvMode *m, i // at this point we've decoded the floor into buffer } } - STBV_CHECK(f); + CHECK(f); // at this point we've decoded all floors if (f->alloc.alloc_buffer) @@ -3295,12 +3299,12 @@ static int stbv_vorbis_decode_packet_rest(stbv_vorb *f, int *len, StbvMode *m, i zero_channel[map->chan[i].magnitude] = zero_channel[map->chan[i].angle] = FALSE; } - STBV_CHECK(f); -// RESIDUE STBV_DECODE + CHECK(f); +// RESIDUE DECODE for (i=0; i < map->submaps; ++i) { float *residue_buffers[STB_VORBIS_MAX_CHANNELS]; int r; - stbv_uint8 do_not_decode[256]; + uint8 do_not_decode[256]; int ch = 0; for (j=0; j < f->channels; ++j) { if (map->chan[j].mux == i) { @@ -3315,12 +3319,12 @@ static int stbv_vorbis_decode_packet_rest(stbv_vorb *f, int *len, StbvMode *m, i } } r = map->submap_residue[i]; - stbv_decode_residue(f, residue_buffers, ch, n2, r, do_not_decode); + decode_residue(f, residue_buffers, ch, n2, r, do_not_decode); } if (f->alloc.alloc_buffer) assert(f->alloc.alloc_buffer_length_in_bytes == f->temp_offset); - STBV_CHECK(f); + CHECK(f); // INVERSE COUPLING for (i = map->coupling_steps-1; i >= 0; --i) { @@ -3343,7 +3347,7 @@ static int stbv_vorbis_decode_packet_rest(stbv_vorb *f, int *len, StbvMode *m, i a[j] = a2; } } - STBV_CHECK(f); + CHECK(f); // finish decoding the floors #ifndef STB_VORBIS_NO_DEFER_FLOOR @@ -3351,7 +3355,7 @@ static int stbv_vorbis_decode_packet_rest(stbv_vorb *f, int *len, StbvMode *m, i if (really_zero_channel[i]) { memset(f->channel_buffers[i], 0, sizeof(*f->channel_buffers[i]) * n2); } else { - stbv_do_floor(f, map, i, n, f->channel_buffers[i], f->finalY[i], NULL); + do_floor(f, map, i, n, f->channel_buffers[i], f->finalY[i], NULL); } } #else @@ -3366,21 +3370,21 @@ static int stbv_vorbis_decode_packet_rest(stbv_vorb *f, int *len, StbvMode *m, i #endif // INVERSE MDCT - STBV_CHECK(f); + CHECK(f); for (i=0; i < f->channels; ++i) - stbv_inverse_mdct(f->channel_buffers[i], n, f, m->blockflag); - STBV_CHECK(f); + inverse_mdct(f->channel_buffers[i], n, f, m->blockflag); + CHECK(f); // this shouldn't be necessary, unless we exited on an error // and want to flush to get to the next packet - stbv_flush_packet(f); + flush_packet(f); if (f->first_decode) { // assume we start so first non-discarded sample is sample 0 // this isn't to spec, but spec would require us to read ahead // and decode the size of all current frames--could be done, // but presumably it's not a commonly used feature - f->current_loc = -n2; // start of first frame is positioned for discard + f->current_loc = 0u - n2; // start of first frame is positioned for discard (NB this is an intentional unsigned overflow/wrap-around) // we might have to discard samples "from" the next frame too, // if we're lapping a large block then a small at the start? f->discard_samples_deferred = n - right_end; @@ -3408,8 +3412,8 @@ static int stbv_vorbis_decode_packet_rest(stbv_vorb *f, int *len, StbvMode *m, i // check if we have ogg information about the sample # for this packet if (f->last_seg_which == f->end_seg_with_known_loc) { // if we have a valid current loc, and this is final: - if (f->current_loc_valid && (f->page_flag & STBV_PAGEFLAG_last_page)) { - stbv_uint32 current_end = f->known_loc_for_packet; + if (f->current_loc_valid && (f->page_flag & PAGEFLAG_last_page)) { + uint32 current_end = f->known_loc_for_packet; // then let's infer the size of the (probably) short final frame if (current_end < f->current_loc + (right_end-left_start)) { if (current_end < f->current_loc) { @@ -3437,19 +3441,19 @@ static int stbv_vorbis_decode_packet_rest(stbv_vorb *f, int *len, StbvMode *m, i if (f->alloc.alloc_buffer) assert(f->alloc.alloc_buffer_length_in_bytes == f->temp_offset); *len = right_end; // ignore samples after the window goes to 0 - STBV_CHECK(f); + CHECK(f); return TRUE; } -static int stbv_vorbis_decode_packet(stbv_vorb *f, int *len, int *p_left, int *p_right) +static int vorbis_decode_packet(vorb *f, int *len, int *p_left, int *p_right) { int mode, left_end, right_end; - if (!stbv_vorbis_decode_initial(f, p_left, &left_end, p_right, &right_end, &mode)) return 0; - return stbv_vorbis_decode_packet_rest(f, len, f->mode_config + mode, *p_left, left_end, *p_right, right_end, p_left); + if (!vorbis_decode_initial(f, p_left, &left_end, p_right, &right_end, &mode)) return 0; + return vorbis_decode_packet_rest(f, len, f->mode_config + mode, *p_left, left_end, *p_right, right_end, p_left); } -static int stbv_vorbis_finish_frame(stb_vorbis *f, int len, int left, int right) +static int vorbis_finish_frame(stb_vorbis *f, int len, int left, int right) { int prev,i,j; // we use right&left (the start of the right- and left-window sin()-regions) @@ -3463,7 +3467,8 @@ static int stbv_vorbis_finish_frame(stb_vorbis *f, int len, int left, int right) // mixin from previous window if (f->previous_length) { int i,j, n = f->previous_length; - float *w = stbv_get_window(f, n); + float *w = get_window(f, n); + if (w == NULL) return 0; for (i=0; i < f->channels; ++i) { for (j=0; j < n; ++j) f->channel_buffers[i][left+j] = @@ -3501,28 +3506,28 @@ static int stbv_vorbis_finish_frame(stb_vorbis *f, int len, int left, int right) return right - left; } -static int stbv_vorbis_pump_first_frame(stb_vorbis *f) +static int vorbis_pump_first_frame(stb_vorbis *f) { int len, right, left, res; - res = stbv_vorbis_decode_packet(f, &len, &left, &right); + res = vorbis_decode_packet(f, &len, &left, &right); if (res) - stbv_vorbis_finish_frame(f, len, left, right); + vorbis_finish_frame(f, len, left, right); return res; } #ifndef STB_VORBIS_NO_PUSHDATA_API -static int stbv_is_whole_packet_present(stb_vorbis *f, int end_page) +static int is_whole_packet_present(stb_vorbis *f) { // make sure that we have the packet available before continuing... // this requires a full ogg parse, but we know we can fetch from f->stream // instead of coding this out explicitly, we could save the current read state, - // read the next packet with stbv_get8() until end-of-packet, check f->eof, then + // read the next packet with get8() until end-of-packet, check f->eof, then // reset the state? but that would be slower, esp. since we'd have over 256 bytes // of state to restore (primarily the page segment table) int s = f->next_seg, first = TRUE; - stbv_uint8 *p = f->stream; + uint8 *p = f->stream; if (s != -1) { // if we're not starting the packet with a 'continue on next page' flag for (; s < f->segment_count; ++s) { @@ -3531,112 +3536,166 @@ static int stbv_is_whole_packet_present(stb_vorbis *f, int end_page) break; } // either this continues, or it ends it... - if (end_page) - if (s < f->segment_count-1) return stbv_error(f, VORBIS_invalid_stream); if (s == f->segment_count) s = -1; // set 'crosses page' flag - if (p > f->stream_end) return stbv_error(f, VORBIS_need_more_data); + if (p > f->stream_end) return error(f, VORBIS_need_more_data); first = FALSE; } for (; s == -1;) { - stbv_uint8 *q; + uint8 *q; int n; // check that we have the page header ready - if (p + 26 >= f->stream_end) return stbv_error(f, VORBIS_need_more_data); + if (p + 26 >= f->stream_end) return error(f, VORBIS_need_more_data); // validate the page - if (memcmp(p, stbv_ogg_page_header, 4)) return stbv_error(f, VORBIS_invalid_stream); - if (p[4] != 0) return stbv_error(f, VORBIS_invalid_stream); + if (memcmp(p, ogg_page_header, 4)) return error(f, VORBIS_invalid_stream); + if (p[4] != 0) return error(f, VORBIS_invalid_stream); if (first) { // the first segment must NOT have 'continued_packet', later ones MUST if (f->previous_length) - if ((p[5] & STBV_PAGEFLAG_continued_packet)) return stbv_error(f, VORBIS_invalid_stream); + if ((p[5] & PAGEFLAG_continued_packet)) return error(f, VORBIS_invalid_stream); // if no previous length, we're resynching, so we can come in on a continued-packet, // which we'll just drop } else { - if (!(p[5] & STBV_PAGEFLAG_continued_packet)) return stbv_error(f, VORBIS_invalid_stream); + if (!(p[5] & PAGEFLAG_continued_packet)) return error(f, VORBIS_invalid_stream); } n = p[26]; // segment counts q = p+27; // q points to segment table p = q + n; // advance past header // make sure we've read the segment table - if (p > f->stream_end) return stbv_error(f, VORBIS_need_more_data); + if (p > f->stream_end) return error(f, VORBIS_need_more_data); for (s=0; s < n; ++s) { p += q[s]; if (q[s] < 255) break; } - if (end_page) - if (s < n-1) return stbv_error(f, VORBIS_invalid_stream); if (s == n) s = -1; // set 'crosses page' flag - if (p > f->stream_end) return stbv_error(f, VORBIS_need_more_data); + if (p > f->stream_end) return error(f, VORBIS_need_more_data); first = FALSE; } return TRUE; } #endif // !STB_VORBIS_NO_PUSHDATA_API -static int stbv_start_decoder(stbv_vorb *f) +static int start_decoder(vorb *f) { - stbv_uint8 header[6], x,y; + uint8 header[6], x,y; int len,i,j,k, max_submaps = 0; int longest_floorlist=0; // first page, first packet + f->first_decode = TRUE; - if (!stbv_start_page(f)) return FALSE; + if (!start_page(f)) return FALSE; // validate page flag - if (!(f->page_flag & STBV_PAGEFLAG_first_page)) return stbv_error(f, VORBIS_invalid_first_page); - if (f->page_flag & STBV_PAGEFLAG_last_page) return stbv_error(f, VORBIS_invalid_first_page); - if (f->page_flag & STBV_PAGEFLAG_continued_packet) return stbv_error(f, VORBIS_invalid_first_page); + if (!(f->page_flag & PAGEFLAG_first_page)) return error(f, VORBIS_invalid_first_page); + if (f->page_flag & PAGEFLAG_last_page) return error(f, VORBIS_invalid_first_page); + if (f->page_flag & PAGEFLAG_continued_packet) return error(f, VORBIS_invalid_first_page); // check for expected packet length - if (f->segment_count != 1) return stbv_error(f, VORBIS_invalid_first_page); - if (f->segments[0] != 30) return stbv_error(f, VORBIS_invalid_first_page); + if (f->segment_count != 1) return error(f, VORBIS_invalid_first_page); + if (f->segments[0] != 30) { + // check for the Ogg skeleton fishead identifying header to refine our error + if (f->segments[0] == 64 && + getn(f, header, 6) && + header[0] == 'f' && + header[1] == 'i' && + header[2] == 's' && + header[3] == 'h' && + header[4] == 'e' && + header[5] == 'a' && + get8(f) == 'd' && + get8(f) == '\0') return error(f, VORBIS_ogg_skeleton_not_supported); + else + return error(f, VORBIS_invalid_first_page); + } + // read packet // check packet header - if (stbv_get8(f) != STBV_VORBIS_packet_id) return stbv_error(f, VORBIS_invalid_first_page); - if (!stbv_getn(f, header, 6)) return stbv_error(f, VORBIS_unexpected_eof); - if (!stbv_vorbis_validate(header)) return stbv_error(f, VORBIS_invalid_first_page); + if (get8(f) != VORBIS_packet_id) return error(f, VORBIS_invalid_first_page); + if (!getn(f, header, 6)) return error(f, VORBIS_unexpected_eof); + if (!vorbis_validate(header)) return error(f, VORBIS_invalid_first_page); // vorbis_version - if (stbv_get32(f) != 0) return stbv_error(f, VORBIS_invalid_first_page); - f->channels = stbv_get8(f); if (!f->channels) return stbv_error(f, VORBIS_invalid_first_page); - if (f->channels > STB_VORBIS_MAX_CHANNELS) return stbv_error(f, VORBIS_too_many_channels); - f->sample_rate = stbv_get32(f); if (!f->sample_rate) return stbv_error(f, VORBIS_invalid_first_page); - stbv_get32(f); // bitrate_maximum - stbv_get32(f); // bitrate_nominal - stbv_get32(f); // bitrate_minimum - x = stbv_get8(f); + if (get32(f) != 0) return error(f, VORBIS_invalid_first_page); + f->channels = get8(f); if (!f->channels) return error(f, VORBIS_invalid_first_page); + if (f->channels > STB_VORBIS_MAX_CHANNELS) return error(f, VORBIS_too_many_channels); + f->sample_rate = get32(f); if (!f->sample_rate) return error(f, VORBIS_invalid_first_page); + get32(f); // bitrate_maximum + get32(f); // bitrate_nominal + get32(f); // bitrate_minimum + x = get8(f); { int log0,log1; log0 = x & 15; log1 = x >> 4; f->blocksize_0 = 1 << log0; f->blocksize_1 = 1 << log1; - if (log0 < 6 || log0 > 13) return stbv_error(f, VORBIS_invalid_setup); - if (log1 < 6 || log1 > 13) return stbv_error(f, VORBIS_invalid_setup); - if (log0 > log1) return stbv_error(f, VORBIS_invalid_setup); + if (log0 < 6 || log0 > 13) return error(f, VORBIS_invalid_setup); + if (log1 < 6 || log1 > 13) return error(f, VORBIS_invalid_setup); + if (log0 > log1) return error(f, VORBIS_invalid_setup); } // framing_flag - x = stbv_get8(f); - if (!(x & 1)) return stbv_error(f, VORBIS_invalid_first_page); + x = get8(f); + if (!(x & 1)) return error(f, VORBIS_invalid_first_page); // second packet! - if (!stbv_start_page(f)) return FALSE; + if (!start_page(f)) return FALSE; + + if (!start_packet(f)) return FALSE; + + if (!next_segment(f)) return FALSE; + + if (get8_packet(f) != VORBIS_packet_comment) return error(f, VORBIS_invalid_setup); + for (i=0; i < 6; ++i) header[i] = get8_packet(f); + if (!vorbis_validate(header)) return error(f, VORBIS_invalid_setup); + //file vendor + len = get32_packet(f); + f->vendor = (char*)setup_malloc(f, sizeof(char) * (len+1)); + if (f->vendor == NULL) return error(f, VORBIS_outofmem); + for(i=0; i < len; ++i) { + f->vendor[i] = get8_packet(f); + } + f->vendor[len] = (char)'\0'; + //user comments + f->comment_list_length = get32_packet(f); + f->comment_list = NULL; + if (f->comment_list_length > 0) + { + f->comment_list = (char**) setup_malloc(f, sizeof(char*) * (f->comment_list_length)); + if (f->comment_list == NULL) return error(f, VORBIS_outofmem); + } + + for(i=0; i < f->comment_list_length; ++i) { + len = get32_packet(f); + f->comment_list[i] = (char*)setup_malloc(f, sizeof(char) * (len+1)); + if (f->comment_list[i] == NULL) return error(f, VORBIS_outofmem); + + for(j=0; j < len; ++j) { + f->comment_list[i][j] = get8_packet(f); + } + f->comment_list[i][len] = (char)'\0'; + } + + // framing_flag + x = get8_packet(f); + if (!(x & 1)) return error(f, VORBIS_invalid_setup); + + + skip(f, f->bytes_in_seg); + f->bytes_in_seg = 0; - if (!stbv_start_packet(f)) return FALSE; do { - len = stbv_next_segment(f); - stbv_skip(f, len); + len = next_segment(f); + skip(f, len); f->bytes_in_seg = 0; } while (len); // third packet! - if (!stbv_start_packet(f)) return FALSE; + if (!start_packet(f)) return FALSE; #ifndef STB_VORBIS_NO_PUSHDATA_API - if (STBV_IS_PUSH_MODE(f)) { - if (!stbv_is_whole_packet_present(f, TRUE)) { + if (IS_PUSH_MODE(f)) { + if (!is_whole_packet_present(f)) { // convert error in ogg header to write type if (f->error == VORBIS_invalid_stream) f->error = VORBIS_invalid_setup; @@ -3645,64 +3704,65 @@ static int stbv_start_decoder(stbv_vorb *f) } #endif - stbv_crc32_init(); // always init it, to avoid multithread race conditions + crc32_init(); // always init it, to avoid multithread race conditions - if (stbv_get8_packet(f) != STBV_VORBIS_packet_setup) return stbv_error(f, VORBIS_invalid_setup); - for (i=0; i < 6; ++i) header[i] = stbv_get8_packet(f); - if (!stbv_vorbis_validate(header)) return stbv_error(f, VORBIS_invalid_setup); + if (get8_packet(f) != VORBIS_packet_setup) return error(f, VORBIS_invalid_setup); + for (i=0; i < 6; ++i) header[i] = get8_packet(f); + if (!vorbis_validate(header)) return error(f, VORBIS_invalid_setup); // codebooks - f->codebook_count = stbv_get_bits(f,8) + 1; - f->codebooks = (StbvCodebook *) stbv_setup_malloc(f, sizeof(*f->codebooks) * f->codebook_count); - if (f->codebooks == NULL) return stbv_error(f, VORBIS_outofmem); + f->codebook_count = get_bits(f,8) + 1; + f->codebooks = (Codebook *) setup_malloc(f, sizeof(*f->codebooks) * f->codebook_count); + if (f->codebooks == NULL) return error(f, VORBIS_outofmem); memset(f->codebooks, 0, sizeof(*f->codebooks) * f->codebook_count); for (i=0; i < f->codebook_count; ++i) { - stbv_uint32 *values; + uint32 *values; int ordered, sorted_count; int total=0; - stbv_uint8 *lengths; - StbvCodebook *c = f->codebooks+i; - STBV_CHECK(f); - x = stbv_get_bits(f, 8); if (x != 0x42) return stbv_error(f, VORBIS_invalid_setup); - x = stbv_get_bits(f, 8); if (x != 0x43) return stbv_error(f, VORBIS_invalid_setup); - x = stbv_get_bits(f, 8); if (x != 0x56) return stbv_error(f, VORBIS_invalid_setup); - x = stbv_get_bits(f, 8); - c->dimensions = (stbv_get_bits(f, 8)<<8) + x; - x = stbv_get_bits(f, 8); - y = stbv_get_bits(f, 8); - c->entries = (stbv_get_bits(f, 8)<<16) + (y<<8) + x; - ordered = stbv_get_bits(f,1); - c->sparse = ordered ? 0 : stbv_get_bits(f,1); - - if (c->dimensions == 0 && c->entries != 0) return stbv_error(f, VORBIS_invalid_setup); + uint8 *lengths; + Codebook *c = f->codebooks+i; + CHECK(f); + x = get_bits(f, 8); if (x != 0x42) return error(f, VORBIS_invalid_setup); + x = get_bits(f, 8); if (x != 0x43) return error(f, VORBIS_invalid_setup); + x = get_bits(f, 8); if (x != 0x56) return error(f, VORBIS_invalid_setup); + x = get_bits(f, 8); + c->dimensions = (get_bits(f, 8)<<8) + x; + x = get_bits(f, 8); + y = get_bits(f, 8); + c->entries = (get_bits(f, 8)<<16) + (y<<8) + x; + ordered = get_bits(f,1); + c->sparse = ordered ? 0 : get_bits(f,1); + + if (c->dimensions == 0 && c->entries != 0) return error(f, VORBIS_invalid_setup); if (c->sparse) - lengths = (stbv_uint8 *) stbv_setup_temp_malloc(f, c->entries); + lengths = (uint8 *) setup_temp_malloc(f, c->entries); else - lengths = c->codeword_lengths = (stbv_uint8 *) stbv_setup_malloc(f, c->entries); + lengths = c->codeword_lengths = (uint8 *) setup_malloc(f, c->entries); - if (!lengths) return stbv_error(f, VORBIS_outofmem); + if (!lengths) return error(f, VORBIS_outofmem); if (ordered) { int current_entry = 0; - int current_length = stbv_get_bits(f,5) + 1; + int current_length = get_bits(f,5) + 1; while (current_entry < c->entries) { int limit = c->entries - current_entry; - int n = stbv_get_bits(f, stbv_ilog(limit)); - if (current_entry + n > (int) c->entries) { return stbv_error(f, VORBIS_invalid_setup); } + int n = get_bits(f, ilog(limit)); + if (current_length >= 32) return error(f, VORBIS_invalid_setup); + if (current_entry + n > (int) c->entries) { return error(f, VORBIS_invalid_setup); } memset(lengths + current_entry, current_length, n); current_entry += n; ++current_length; } } else { for (j=0; j < c->entries; ++j) { - int present = c->sparse ? stbv_get_bits(f,1) : 1; + int present = c->sparse ? get_bits(f,1) : 1; if (present) { - lengths[j] = stbv_get_bits(f, 5) + 1; + lengths[j] = get_bits(f, 5) + 1; ++total; if (lengths[j] == 32) - return stbv_error(f, VORBIS_invalid_setup); + return error(f, VORBIS_invalid_setup); } else { lengths[j] = NO_CODE; } @@ -3714,10 +3774,10 @@ static int stbv_start_decoder(stbv_vorb *f) if (c->entries > (int) f->setup_temp_memory_required) f->setup_temp_memory_required = c->entries; - c->codeword_lengths = (stbv_uint8 *) stbv_setup_malloc(f, c->entries); - if (c->codeword_lengths == NULL) return stbv_error(f, VORBIS_outofmem); + c->codeword_lengths = (uint8 *) setup_malloc(f, c->entries); + if (c->codeword_lengths == NULL) return error(f, VORBIS_outofmem); memcpy(c->codeword_lengths, lengths, c->entries); - stbv_setup_temp_free(f, lengths, c->entries); // note this is only safe if there have been no intervening temp mallocs! + setup_temp_free(f, lengths, c->entries); // note this is only safe if there have been no intervening temp mallocs! lengths = c->codeword_lengths; c->sparse = 0; } @@ -3737,72 +3797,74 @@ static int stbv_start_decoder(stbv_vorb *f) c->sorted_entries = sorted_count; values = NULL; - STBV_CHECK(f); + CHECK(f); if (!c->sparse) { - c->codewords = (stbv_uint32 *) stbv_setup_malloc(f, sizeof(c->codewords[0]) * c->entries); - if (!c->codewords) return stbv_error(f, VORBIS_outofmem); + c->codewords = (uint32 *) setup_malloc(f, sizeof(c->codewords[0]) * c->entries); + if (!c->codewords) return error(f, VORBIS_outofmem); } else { unsigned int size; if (c->sorted_entries) { - c->codeword_lengths = (stbv_uint8 *) stbv_setup_malloc(f, c->sorted_entries); - if (!c->codeword_lengths) return stbv_error(f, VORBIS_outofmem); - c->codewords = (stbv_uint32 *) stbv_setup_temp_malloc(f, sizeof(*c->codewords) * c->sorted_entries); - if (!c->codewords) return stbv_error(f, VORBIS_outofmem); - values = (stbv_uint32 *) stbv_setup_temp_malloc(f, sizeof(*values) * c->sorted_entries); - if (!values) return stbv_error(f, VORBIS_outofmem); + c->codeword_lengths = (uint8 *) setup_malloc(f, c->sorted_entries); + if (!c->codeword_lengths) return error(f, VORBIS_outofmem); + c->codewords = (uint32 *) setup_temp_malloc(f, sizeof(*c->codewords) * c->sorted_entries); + if (!c->codewords) return error(f, VORBIS_outofmem); + values = (uint32 *) setup_temp_malloc(f, sizeof(*values) * c->sorted_entries); + if (!values) return error(f, VORBIS_outofmem); } size = c->entries + (sizeof(*c->codewords) + sizeof(*values)) * c->sorted_entries; if (size > f->setup_temp_memory_required) f->setup_temp_memory_required = size; } - if (!stbv_compute_codewords(c, lengths, c->entries, values)) { - if (c->sparse) stbv_setup_temp_free(f, values, 0); - return stbv_error(f, VORBIS_invalid_setup); + if (!compute_codewords(c, lengths, c->entries, values)) { + if (c->sparse) setup_temp_free(f, values, 0); + return error(f, VORBIS_invalid_setup); } if (c->sorted_entries) { // allocate an extra slot for sentinels - c->sorted_codewords = (stbv_uint32 *) stbv_setup_malloc(f, sizeof(*c->sorted_codewords) * (c->sorted_entries+1)); - if (c->sorted_codewords == NULL) return stbv_error(f, VORBIS_outofmem); + c->sorted_codewords = (uint32 *) setup_malloc(f, sizeof(*c->sorted_codewords) * (c->sorted_entries+1)); + if (c->sorted_codewords == NULL) return error(f, VORBIS_outofmem); // allocate an extra slot at the front so that c->sorted_values[-1] is defined // so that we can catch that case without an extra if - c->sorted_values = ( int *) stbv_setup_malloc(f, sizeof(*c->sorted_values ) * (c->sorted_entries+1)); - if (c->sorted_values == NULL) return stbv_error(f, VORBIS_outofmem); + c->sorted_values = ( int *) setup_malloc(f, sizeof(*c->sorted_values ) * (c->sorted_entries+1)); + if (c->sorted_values == NULL) return error(f, VORBIS_outofmem); ++c->sorted_values; c->sorted_values[-1] = -1; - stbv_compute_sorted_huffman(c, lengths, values); + compute_sorted_huffman(c, lengths, values); } if (c->sparse) { - stbv_setup_temp_free(f, values, sizeof(*values)*c->sorted_entries); - stbv_setup_temp_free(f, c->codewords, sizeof(*c->codewords)*c->sorted_entries); - stbv_setup_temp_free(f, lengths, c->entries); + setup_temp_free(f, values, sizeof(*values)*c->sorted_entries); + setup_temp_free(f, c->codewords, sizeof(*c->codewords)*c->sorted_entries); + setup_temp_free(f, lengths, c->entries); c->codewords = NULL; } - stbv_compute_accelerated_huffman(c); + compute_accelerated_huffman(c); - STBV_CHECK(f); - c->lookup_type = stbv_get_bits(f, 4); - if (c->lookup_type > 2) return stbv_error(f, VORBIS_invalid_setup); + CHECK(f); + c->lookup_type = get_bits(f, 4); + if (c->lookup_type > 2) return error(f, VORBIS_invalid_setup); if (c->lookup_type > 0) { - stbv_uint16 *mults; - c->minimum_value = stbv_float32_unpack(stbv_get_bits(f, 32)); - c->delta_value = stbv_float32_unpack(stbv_get_bits(f, 32)); - c->value_bits = stbv_get_bits(f, 4)+1; - c->sequence_p = stbv_get_bits(f,1); + uint16 *mults; + c->minimum_value = float32_unpack(get_bits(f, 32)); + c->delta_value = float32_unpack(get_bits(f, 32)); + c->value_bits = get_bits(f, 4)+1; + c->sequence_p = get_bits(f,1); if (c->lookup_type == 1) { - c->lookup_values = stbv_lookup1_values(c->entries, c->dimensions); + int values = lookup1_values(c->entries, c->dimensions); + if (values < 0) return error(f, VORBIS_invalid_setup); + c->lookup_values = (uint32) values; } else { c->lookup_values = c->entries * c->dimensions; } - if (c->lookup_values == 0) return stbv_error(f, VORBIS_invalid_setup); - mults = (stbv_uint16 *) stbv_setup_temp_malloc(f, sizeof(mults[0]) * c->lookup_values); - if (mults == NULL) return stbv_error(f, VORBIS_outofmem); + if (c->lookup_values == 0) return error(f, VORBIS_invalid_setup); + mults = (uint16 *) setup_temp_malloc(f, sizeof(mults[0]) * c->lookup_values); + if (mults == NULL) return error(f, VORBIS_outofmem); for (j=0; j < (int) c->lookup_values; ++j) { - int q = stbv_get_bits(f, c->value_bits); - if (q == STBV_EOP) { stbv_setup_temp_free(f,mults,sizeof(mults[0])*c->lookup_values); return stbv_error(f, VORBIS_invalid_setup); } + int q = get_bits(f, c->value_bits); + if (q == EOP) { setup_temp_free(f,mults,sizeof(mults[0])*c->lookup_values); return error(f, VORBIS_invalid_setup); } mults[j] = q; } @@ -3812,26 +3874,25 @@ static int stbv_start_decoder(stbv_vorb *f) float last=0; // pre-expand the lookup1-style multiplicands, to avoid a divide in the inner loop if (sparse) { - if (c->sorted_entries == 0) goto stbv_skip; - c->multiplicands = (stbv_codetype *) stbv_setup_malloc(f, sizeof(c->multiplicands[0]) * c->sorted_entries * c->dimensions); + if (c->sorted_entries == 0) goto skip; + c->multiplicands = (codetype *) setup_malloc(f, sizeof(c->multiplicands[0]) * c->sorted_entries * c->dimensions); } else - c->multiplicands = (stbv_codetype *) stbv_setup_malloc(f, sizeof(c->multiplicands[0]) * c->entries * c->dimensions); - if (c->multiplicands == NULL) { stbv_setup_temp_free(f,mults,sizeof(mults[0])*c->lookup_values); return stbv_error(f, VORBIS_outofmem); } + c->multiplicands = (codetype *) setup_malloc(f, sizeof(c->multiplicands[0]) * c->entries * c->dimensions); + if (c->multiplicands == NULL) { setup_temp_free(f,mults,sizeof(mults[0])*c->lookup_values); return error(f, VORBIS_outofmem); } len = sparse ? c->sorted_entries : c->entries; for (j=0; j < len; ++j) { unsigned int z = sparse ? c->sorted_values[j] : j; unsigned int div=1; for (k=0; k < c->dimensions; ++k) { int off = (z / div) % c->lookup_values; - float val = mults[off]; - val = mults[off]*c->delta_value + c->minimum_value + last; + float val = mults[off]*c->delta_value + c->minimum_value + last; c->multiplicands[j*c->dimensions + k] = val; if (c->sequence_p) last = val; if (k+1 < c->dimensions) { if (div > UINT_MAX / (unsigned int) c->lookup_values) { - stbv_setup_temp_free(f, mults,sizeof(mults[0])*c->lookup_values); - return stbv_error(f, VORBIS_invalid_setup); + setup_temp_free(f, mults,sizeof(mults[0])*c->lookup_values); + return error(f, VORBIS_invalid_setup); } div *= c->lookup_values; } @@ -3843,9 +3904,9 @@ static int stbv_start_decoder(stbv_vorb *f) #endif { float last=0; - STBV_CHECK(f); - c->multiplicands = (stbv_codetype *) stbv_setup_malloc(f, sizeof(c->multiplicands[0]) * c->lookup_values); - if (c->multiplicands == NULL) { stbv_setup_temp_free(f, mults,sizeof(mults[0])*c->lookup_values); return stbv_error(f, VORBIS_outofmem); } + CHECK(f); + c->multiplicands = (codetype *) setup_malloc(f, sizeof(c->multiplicands[0]) * c->lookup_values); + if (c->multiplicands == NULL) { setup_temp_free(f, mults,sizeof(mults[0])*c->lookup_values); return error(f, VORBIS_outofmem); } for (j=0; j < (int) c->lookup_values; ++j) { float val = mults[j] * c->delta_value + c->minimum_value + last; c->multiplicands[j] = val; @@ -3854,72 +3915,72 @@ static int stbv_start_decoder(stbv_vorb *f) } } #ifndef STB_VORBIS_DIVIDES_IN_CODEBOOK - stbv_skip:; + skip:; #endif - stbv_setup_temp_free(f, mults, sizeof(mults[0])*c->lookup_values); + setup_temp_free(f, mults, sizeof(mults[0])*c->lookup_values); - STBV_CHECK(f); + CHECK(f); } - STBV_CHECK(f); + CHECK(f); } // time domain transfers (notused) - x = stbv_get_bits(f, 6) + 1; + x = get_bits(f, 6) + 1; for (i=0; i < x; ++i) { - stbv_uint32 z = stbv_get_bits(f, 16); - if (z != 0) return stbv_error(f, VORBIS_invalid_setup); + uint32 z = get_bits(f, 16); + if (z != 0) return error(f, VORBIS_invalid_setup); } // Floors - f->floor_count = stbv_get_bits(f, 6)+1; - f->floor_config = (StbvFloor *) stbv_setup_malloc(f, f->floor_count * sizeof(*f->floor_config)); - if (f->floor_config == NULL) return stbv_error(f, VORBIS_outofmem); + f->floor_count = get_bits(f, 6)+1; + f->floor_config = (Floor *) setup_malloc(f, f->floor_count * sizeof(*f->floor_config)); + if (f->floor_config == NULL) return error(f, VORBIS_outofmem); for (i=0; i < f->floor_count; ++i) { - f->floor_types[i] = stbv_get_bits(f, 16); - if (f->floor_types[i] > 1) return stbv_error(f, VORBIS_invalid_setup); + f->floor_types[i] = get_bits(f, 16); + if (f->floor_types[i] > 1) return error(f, VORBIS_invalid_setup); if (f->floor_types[i] == 0) { - StbvFloor0 *g = &f->floor_config[i].floor0; - g->order = stbv_get_bits(f,8); - g->rate = stbv_get_bits(f,16); - g->bark_map_size = stbv_get_bits(f,16); - g->amplitude_bits = stbv_get_bits(f,6); - g->amplitude_offset = stbv_get_bits(f,8); - g->number_of_books = stbv_get_bits(f,4) + 1; + Floor0 *g = &f->floor_config[i].floor0; + g->order = get_bits(f,8); + g->rate = get_bits(f,16); + g->bark_map_size = get_bits(f,16); + g->amplitude_bits = get_bits(f,6); + g->amplitude_offset = get_bits(f,8); + g->number_of_books = get_bits(f,4) + 1; for (j=0; j < g->number_of_books; ++j) - g->book_list[j] = stbv_get_bits(f,8); - return stbv_error(f, VORBIS_feature_not_supported); + g->book_list[j] = get_bits(f,8); + return error(f, VORBIS_feature_not_supported); } else { - stbv_floor_ordering p[31*8+2]; - StbvFloor1 *g = &f->floor_config[i].floor1; - int max_class = -1; - g->partitions = stbv_get_bits(f, 5); + stbv__floor_ordering p[31*8+2]; + Floor1 *g = &f->floor_config[i].floor1; + int max_class = -1; + g->partitions = get_bits(f, 5); for (j=0; j < g->partitions; ++j) { - g->partition_class_list[j] = stbv_get_bits(f, 4); + g->partition_class_list[j] = get_bits(f, 4); if (g->partition_class_list[j] > max_class) max_class = g->partition_class_list[j]; } for (j=0; j <= max_class; ++j) { - g->class_dimensions[j] = stbv_get_bits(f, 3)+1; - g->class_subclasses[j] = stbv_get_bits(f, 2); + g->class_dimensions[j] = get_bits(f, 3)+1; + g->class_subclasses[j] = get_bits(f, 2); if (g->class_subclasses[j]) { - g->class_masterbooks[j] = stbv_get_bits(f, 8); - if (g->class_masterbooks[j] >= f->codebook_count) return stbv_error(f, VORBIS_invalid_setup); + g->class_masterbooks[j] = get_bits(f, 8); + if (g->class_masterbooks[j] >= f->codebook_count) return error(f, VORBIS_invalid_setup); } for (k=0; k < 1 << g->class_subclasses[j]; ++k) { - g->subclass_books[j][k] = stbv_get_bits(f,8)-1; - if (g->subclass_books[j][k] >= f->codebook_count) return stbv_error(f, VORBIS_invalid_setup); + g->subclass_books[j][k] = (int16)get_bits(f,8)-1; + if (g->subclass_books[j][k] >= f->codebook_count) return error(f, VORBIS_invalid_setup); } } - g->floor1_multiplier = stbv_get_bits(f,2)+1; - g->rangebits = stbv_get_bits(f,4); + g->floor1_multiplier = get_bits(f,2)+1; + g->rangebits = get_bits(f,4); g->Xlist[0] = 0; g->Xlist[1] = 1 << g->rangebits; g->values = 2; for (j=0; j < g->partitions; ++j) { int c = g->partition_class_list[j]; for (k=0; k < g->class_dimensions[c]; ++k) { - g->Xlist[g->values] = stbv_get_bits(f, g->rangebits); + g->Xlist[g->values] = get_bits(f, g->rangebits); ++g->values; } } @@ -3928,15 +3989,18 @@ static int stbv_start_decoder(stbv_vorb *f) p[j].x = g->Xlist[j]; p[j].id = j; } - qsort(p, g->values, sizeof(p[0]), stbv_point_compare); + qsort(p, g->values, sizeof(p[0]), point_compare); + for (j=0; j < g->values-1; ++j) + if (p[j].x == p[j+1].x) + return error(f, VORBIS_invalid_setup); for (j=0; j < g->values; ++j) - g->sorted_order[j] = (stbv_uint8) p[j].id; - // precompute the stbv_neighbors + g->sorted_order[j] = (uint8) p[j].id; + // precompute the neighbors for (j=2; j < g->values; ++j) { - int low,hi; - stbv_neighbors(g->Xlist, j, &low,&hi); - g->stbv_neighbors[j][0] = low; - g->stbv_neighbors[j][1] = hi; + int low = 0,hi = 0; + neighbors(g->Xlist, j, &low,&hi); + g->neighbors[j][0] = low; + g->neighbors[j][1] = hi; } if (g->values > longest_floorlist) @@ -3944,37 +4008,37 @@ static int stbv_start_decoder(stbv_vorb *f) } } - // StbvResidue - f->residue_count = stbv_get_bits(f, 6)+1; - f->residue_config = (StbvResidue *) stbv_setup_malloc(f, f->residue_count * sizeof(f->residue_config[0])); - if (f->residue_config == NULL) return stbv_error(f, VORBIS_outofmem); + // Residue + f->residue_count = get_bits(f, 6)+1; + f->residue_config = (Residue *) setup_malloc(f, f->residue_count * sizeof(f->residue_config[0])); + if (f->residue_config == NULL) return error(f, VORBIS_outofmem); memset(f->residue_config, 0, f->residue_count * sizeof(f->residue_config[0])); for (i=0; i < f->residue_count; ++i) { - stbv_uint8 residue_cascade[64]; - StbvResidue *r = f->residue_config+i; - f->residue_types[i] = stbv_get_bits(f, 16); - if (f->residue_types[i] > 2) return stbv_error(f, VORBIS_invalid_setup); - r->begin = stbv_get_bits(f, 24); - r->end = stbv_get_bits(f, 24); - if (r->end < r->begin) return stbv_error(f, VORBIS_invalid_setup); - r->part_size = stbv_get_bits(f,24)+1; - r->classifications = stbv_get_bits(f,6)+1; - r->classbook = stbv_get_bits(f,8); - if (r->classbook >= f->codebook_count) return stbv_error(f, VORBIS_invalid_setup); + uint8 residue_cascade[64]; + Residue *r = f->residue_config+i; + f->residue_types[i] = get_bits(f, 16); + if (f->residue_types[i] > 2) return error(f, VORBIS_invalid_setup); + r->begin = get_bits(f, 24); + r->end = get_bits(f, 24); + if (r->end < r->begin) return error(f, VORBIS_invalid_setup); + r->part_size = get_bits(f,24)+1; + r->classifications = get_bits(f,6)+1; + r->classbook = get_bits(f,8); + if (r->classbook >= f->codebook_count) return error(f, VORBIS_invalid_setup); for (j=0; j < r->classifications; ++j) { - stbv_uint8 high_bits=0; - stbv_uint8 low_bits=stbv_get_bits(f,3); - if (stbv_get_bits(f,1)) - high_bits = stbv_get_bits(f,5); + uint8 high_bits=0; + uint8 low_bits=get_bits(f,3); + if (get_bits(f,1)) + high_bits = get_bits(f,5); residue_cascade[j] = high_bits*8 + low_bits; } - r->residue_books = (short (*)[8]) stbv_setup_malloc(f, sizeof(r->residue_books[0]) * r->classifications); - if (r->residue_books == NULL) return stbv_error(f, VORBIS_outofmem); + r->residue_books = (short (*)[8]) setup_malloc(f, sizeof(r->residue_books[0]) * r->classifications); + if (r->residue_books == NULL) return error(f, VORBIS_outofmem); for (j=0; j < r->classifications; ++j) { for (k=0; k < 8; ++k) { if (residue_cascade[j] & (1 << k)) { - r->residue_books[j][k] = stbv_get_bits(f, 8); - if (r->residue_books[j][k] >= f->codebook_count) return stbv_error(f, VORBIS_invalid_setup); + r->residue_books[j][k] = get_bits(f, 8); + if (r->residue_books[j][k] >= f->codebook_count) return error(f, VORBIS_invalid_setup); } else { r->residue_books[j][k] = -1; } @@ -3982,14 +4046,14 @@ static int stbv_start_decoder(stbv_vorb *f) } // precompute the classifications[] array to avoid inner-loop mod/divide // call it 'classdata' since we already have r->classifications - r->classdata = (stbv_uint8 **) stbv_setup_malloc(f, sizeof(*r->classdata) * f->codebooks[r->classbook].entries); - if (!r->classdata) return stbv_error(f, VORBIS_outofmem); + r->classdata = (uint8 **) setup_malloc(f, sizeof(*r->classdata) * f->codebooks[r->classbook].entries); + if (!r->classdata) return error(f, VORBIS_outofmem); memset(r->classdata, 0, sizeof(*r->classdata) * f->codebooks[r->classbook].entries); for (j=0; j < f->codebooks[r->classbook].entries; ++j) { int classwords = f->codebooks[r->classbook].dimensions; int temp = j; - r->classdata[j] = (stbv_uint8 *) stbv_setup_malloc(f, sizeof(r->classdata[j][0]) * classwords); - if (r->classdata[j] == NULL) return stbv_error(f, VORBIS_outofmem); + r->classdata[j] = (uint8 *) setup_malloc(f, sizeof(r->classdata[j][0]) * classwords); + if (r->classdata[j] == NULL) return error(f, VORBIS_outofmem); for (k=classwords-1; k >= 0; --k) { r->classdata[j][k] = temp % r->classifications; temp /= r->classifications; @@ -3997,40 +4061,41 @@ static int stbv_start_decoder(stbv_vorb *f) } } - f->mapping_count = stbv_get_bits(f,6)+1; - f->mapping = (StbvMapping *) stbv_setup_malloc(f, f->mapping_count * sizeof(*f->mapping)); - if (f->mapping == NULL) return stbv_error(f, VORBIS_outofmem); + f->mapping_count = get_bits(f,6)+1; + f->mapping = (Mapping *) setup_malloc(f, f->mapping_count * sizeof(*f->mapping)); + if (f->mapping == NULL) return error(f, VORBIS_outofmem); memset(f->mapping, 0, f->mapping_count * sizeof(*f->mapping)); for (i=0; i < f->mapping_count; ++i) { - StbvMapping *m = f->mapping + i; - int mapping_type = stbv_get_bits(f,16); - if (mapping_type != 0) return stbv_error(f, VORBIS_invalid_setup); - m->chan = (StbvMappingChannel *) stbv_setup_malloc(f, f->channels * sizeof(*m->chan)); - if (m->chan == NULL) return stbv_error(f, VORBIS_outofmem); - if (stbv_get_bits(f,1)) - m->submaps = stbv_get_bits(f,4)+1; + Mapping *m = f->mapping + i; + int mapping_type = get_bits(f,16); + if (mapping_type != 0) return error(f, VORBIS_invalid_setup); + m->chan = (MappingChannel *) setup_malloc(f, f->channels * sizeof(*m->chan)); + if (m->chan == NULL) return error(f, VORBIS_outofmem); + if (get_bits(f,1)) + m->submaps = get_bits(f,4)+1; else m->submaps = 1; if (m->submaps > max_submaps) max_submaps = m->submaps; - if (stbv_get_bits(f,1)) { - m->coupling_steps = stbv_get_bits(f,8)+1; + if (get_bits(f,1)) { + m->coupling_steps = get_bits(f,8)+1; + if (m->coupling_steps > f->channels) return error(f, VORBIS_invalid_setup); for (k=0; k < m->coupling_steps; ++k) { - m->chan[k].magnitude = stbv_get_bits(f, stbv_ilog(f->channels-1)); - m->chan[k].angle = stbv_get_bits(f, stbv_ilog(f->channels-1)); - if (m->chan[k].magnitude >= f->channels) return stbv_error(f, VORBIS_invalid_setup); - if (m->chan[k].angle >= f->channels) return stbv_error(f, VORBIS_invalid_setup); - if (m->chan[k].magnitude == m->chan[k].angle) return stbv_error(f, VORBIS_invalid_setup); + m->chan[k].magnitude = get_bits(f, ilog(f->channels-1)); + m->chan[k].angle = get_bits(f, ilog(f->channels-1)); + if (m->chan[k].magnitude >= f->channels) return error(f, VORBIS_invalid_setup); + if (m->chan[k].angle >= f->channels) return error(f, VORBIS_invalid_setup); + if (m->chan[k].magnitude == m->chan[k].angle) return error(f, VORBIS_invalid_setup); } } else m->coupling_steps = 0; // reserved field - if (stbv_get_bits(f,2)) return stbv_error(f, VORBIS_invalid_setup); + if (get_bits(f,2)) return error(f, VORBIS_invalid_setup); if (m->submaps > 1) { for (j=0; j < f->channels; ++j) { - m->chan[j].mux = stbv_get_bits(f, 4); - if (m->chan[j].mux >= m->submaps) return stbv_error(f, VORBIS_invalid_setup); + m->chan[j].mux = get_bits(f, 4); + if (m->chan[j].mux >= m->submaps) return error(f, VORBIS_invalid_setup); } } else // @SPECIFICATION: this case is missing from the spec @@ -4038,64 +4103,64 @@ static int stbv_start_decoder(stbv_vorb *f) m->chan[j].mux = 0; for (j=0; j < m->submaps; ++j) { - stbv_get_bits(f,8); // discard - m->submap_floor[j] = stbv_get_bits(f,8); - m->submap_residue[j] = stbv_get_bits(f,8); - if (m->submap_floor[j] >= f->floor_count) return stbv_error(f, VORBIS_invalid_setup); - if (m->submap_residue[j] >= f->residue_count) return stbv_error(f, VORBIS_invalid_setup); + get_bits(f,8); // discard + m->submap_floor[j] = get_bits(f,8); + m->submap_residue[j] = get_bits(f,8); + if (m->submap_floor[j] >= f->floor_count) return error(f, VORBIS_invalid_setup); + if (m->submap_residue[j] >= f->residue_count) return error(f, VORBIS_invalid_setup); } } // Modes - f->mode_count = stbv_get_bits(f, 6)+1; + f->mode_count = get_bits(f, 6)+1; for (i=0; i < f->mode_count; ++i) { - StbvMode *m = f->mode_config+i; - m->blockflag = stbv_get_bits(f,1); - m->windowtype = stbv_get_bits(f,16); - m->transformtype = stbv_get_bits(f,16); - m->mapping = stbv_get_bits(f,8); - if (m->windowtype != 0) return stbv_error(f, VORBIS_invalid_setup); - if (m->transformtype != 0) return stbv_error(f, VORBIS_invalid_setup); - if (m->mapping >= f->mapping_count) return stbv_error(f, VORBIS_invalid_setup); + Mode *m = f->mode_config+i; + m->blockflag = get_bits(f,1); + m->windowtype = get_bits(f,16); + m->transformtype = get_bits(f,16); + m->mapping = get_bits(f,8); + if (m->windowtype != 0) return error(f, VORBIS_invalid_setup); + if (m->transformtype != 0) return error(f, VORBIS_invalid_setup); + if (m->mapping >= f->mapping_count) return error(f, VORBIS_invalid_setup); } - stbv_flush_packet(f); + flush_packet(f); f->previous_length = 0; for (i=0; i < f->channels; ++i) { - f->channel_buffers[i] = (float *) stbv_setup_malloc(f, sizeof(float) * f->blocksize_1); - f->previous_window[i] = (float *) stbv_setup_malloc(f, sizeof(float) * f->blocksize_1/2); - f->finalY[i] = (stbv_int16 *) stbv_setup_malloc(f, sizeof(stbv_int16) * longest_floorlist); - if (f->channel_buffers[i] == NULL || f->previous_window[i] == NULL || f->finalY[i] == NULL) return stbv_error(f, VORBIS_outofmem); + f->channel_buffers[i] = (float *) setup_malloc(f, sizeof(float) * f->blocksize_1); + f->previous_window[i] = (float *) setup_malloc(f, sizeof(float) * f->blocksize_1/2); + f->finalY[i] = (int16 *) setup_malloc(f, sizeof(int16) * longest_floorlist); + if (f->channel_buffers[i] == NULL || f->previous_window[i] == NULL || f->finalY[i] == NULL) return error(f, VORBIS_outofmem); memset(f->channel_buffers[i], 0, sizeof(float) * f->blocksize_1); #ifdef STB_VORBIS_NO_DEFER_FLOOR - f->floor_buffers[i] = (float *) stbv_setup_malloc(f, sizeof(float) * f->blocksize_1/2); - if (f->floor_buffers[i] == NULL) return stbv_error(f, VORBIS_outofmem); + f->floor_buffers[i] = (float *) setup_malloc(f, sizeof(float) * f->blocksize_1/2); + if (f->floor_buffers[i] == NULL) return error(f, VORBIS_outofmem); #endif } - if (!stbv_init_blocksize(f, 0, f->blocksize_0)) return FALSE; - if (!stbv_init_blocksize(f, 1, f->blocksize_1)) return FALSE; + if (!init_blocksize(f, 0, f->blocksize_0)) return FALSE; + if (!init_blocksize(f, 1, f->blocksize_1)) return FALSE; f->blocksize[0] = f->blocksize_0; f->blocksize[1] = f->blocksize_1; #ifdef STB_VORBIS_DIVIDE_TABLE - if (stbv_integer_divide_table[1][1]==0) - for (i=0; i < STBV_DIVTAB_NUMER; ++i) - for (j=1; j < STBV_DIVTAB_DENOM; ++j) - stbv_integer_divide_table[i][j] = i / j; + if (integer_divide_table[1][1]==0) + for (i=0; i < DIVTAB_NUMER; ++i) + for (j=1; j < DIVTAB_DENOM; ++j) + integer_divide_table[i][j] = i / j; #endif // compute how much temporary memory is needed // 1. { - stbv_uint32 imdct_mem = (f->blocksize_1 * sizeof(float) >> 1); - stbv_uint32 classify_mem; + uint32 imdct_mem = (f->blocksize_1 * sizeof(float) >> 1); + uint32 classify_mem; int i,max_part_read=0; for (i=0; i < f->residue_count; ++i) { - StbvResidue *r = f->residue_config + i; + Residue *r = f->residue_config + i; unsigned int actual_size = f->blocksize_1 / 2; unsigned int limit_r_begin = r->begin < actual_size ? r->begin : actual_size; unsigned int limit_r_end = r->end < actual_size ? r->end : actual_size; @@ -4105,7 +4170,7 @@ static int stbv_start_decoder(stbv_vorb *f) max_part_read = part_read; } #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE - classify_mem = f->channels * (sizeof(void*) + max_part_read * sizeof(stbv_uint8 *)); + classify_mem = f->channels * (sizeof(void*) + max_part_read * sizeof(uint8 *)); #else classify_mem = f->channels * (sizeof(void*) + max_part_read * sizeof(int *)); #endif @@ -4117,89 +4182,105 @@ static int stbv_start_decoder(stbv_vorb *f) f->temp_memory_required = imdct_mem; } - f->first_decode = TRUE; if (f->alloc.alloc_buffer) { assert(f->temp_offset == f->alloc.alloc_buffer_length_in_bytes); // check if there's enough temp memory so we don't error later if (f->setup_offset + sizeof(*f) + f->temp_memory_required > (unsigned) f->temp_offset) - return stbv_error(f, VORBIS_outofmem); + return error(f, VORBIS_outofmem); } - f->first_audio_page_offset = stb_vorbis_get_file_offset(f); + // @TODO: stb_vorbis_seek_start expects first_audio_page_offset to point to a page + // without PAGEFLAG_continued_packet, so this either points to the first page, or + // the page after the end of the headers. It might be cleaner to point to a page + // in the middle of the headers, when that's the page where the first audio packet + // starts, but we'd have to also correctly skip the end of any continued packet in + // stb_vorbis_seek_start. + if (f->next_seg == -1) { + f->first_audio_page_offset = stb_vorbis_get_file_offset(f); + } else { + f->first_audio_page_offset = 0; + } return TRUE; } -static void stbv_vorbis_deinit(stb_vorbis *p) +static void vorbis_deinit(stb_vorbis *p) { int i,j; + + setup_free(p, p->vendor); + for (i=0; i < p->comment_list_length; ++i) { + setup_free(p, p->comment_list[i]); + } + setup_free(p, p->comment_list); + if (p->residue_config) { for (i=0; i < p->residue_count; ++i) { - StbvResidue *r = p->residue_config+i; + Residue *r = p->residue_config+i; if (r->classdata) { for (j=0; j < p->codebooks[r->classbook].entries; ++j) - stbv_setup_free(p, r->classdata[j]); - stbv_setup_free(p, r->classdata); + setup_free(p, r->classdata[j]); + setup_free(p, r->classdata); } - stbv_setup_free(p, r->residue_books); + setup_free(p, r->residue_books); } } if (p->codebooks) { - STBV_CHECK(p); + CHECK(p); for (i=0; i < p->codebook_count; ++i) { - StbvCodebook *c = p->codebooks + i; - stbv_setup_free(p, c->codeword_lengths); - stbv_setup_free(p, c->multiplicands); - stbv_setup_free(p, c->codewords); - stbv_setup_free(p, c->sorted_codewords); + Codebook *c = p->codebooks + i; + setup_free(p, c->codeword_lengths); + setup_free(p, c->multiplicands); + setup_free(p, c->codewords); + setup_free(p, c->sorted_codewords); // c->sorted_values[-1] is the first entry in the array - stbv_setup_free(p, c->sorted_values ? c->sorted_values-1 : NULL); + setup_free(p, c->sorted_values ? c->sorted_values-1 : NULL); } - stbv_setup_free(p, p->codebooks); + setup_free(p, p->codebooks); } - stbv_setup_free(p, p->floor_config); - stbv_setup_free(p, p->residue_config); + setup_free(p, p->floor_config); + setup_free(p, p->residue_config); if (p->mapping) { for (i=0; i < p->mapping_count; ++i) - stbv_setup_free(p, p->mapping[i].chan); - stbv_setup_free(p, p->mapping); + setup_free(p, p->mapping[i].chan); + setup_free(p, p->mapping); } - STBV_CHECK(p); + CHECK(p); for (i=0; i < p->channels && i < STB_VORBIS_MAX_CHANNELS; ++i) { - stbv_setup_free(p, p->channel_buffers[i]); - stbv_setup_free(p, p->previous_window[i]); + setup_free(p, p->channel_buffers[i]); + setup_free(p, p->previous_window[i]); #ifdef STB_VORBIS_NO_DEFER_FLOOR - stbv_setup_free(p, p->floor_buffers[i]); + setup_free(p, p->floor_buffers[i]); #endif - stbv_setup_free(p, p->finalY[i]); + setup_free(p, p->finalY[i]); } for (i=0; i < 2; ++i) { - stbv_setup_free(p, p->A[i]); - stbv_setup_free(p, p->B[i]); - stbv_setup_free(p, p->C[i]); - stbv_setup_free(p, p->window[i]); - stbv_setup_free(p, p->stbv_bit_reverse[i]); + setup_free(p, p->A[i]); + setup_free(p, p->B[i]); + setup_free(p, p->C[i]); + setup_free(p, p->window[i]); + setup_free(p, p->bit_reverse[i]); } #ifndef STB_VORBIS_NO_STDIO if (p->close_on_free) fclose(p->f); #endif } -STBVDEF void stb_vorbis_close(stb_vorbis *p) +void stb_vorbis_close(stb_vorbis *p) { if (p == NULL) return; - stbv_vorbis_deinit(p); - stbv_setup_free(p,p); + vorbis_deinit(p); + setup_free(p,p); } -static void stbv_vorbis_init(stb_vorbis *p, const stb_vorbis_alloc *z) +static void vorbis_init(stb_vorbis *p, const stb_vorbis_alloc *z) { memset(p, 0, sizeof(*p)); // NULL out all malloc'd pointers to start if (z) { p->alloc = *z; - p->alloc.alloc_buffer_length_in_bytes = (p->alloc.alloc_buffer_length_in_bytes+3) & ~3; + p->alloc.alloc_buffer_length_in_bytes &= ~7; p->temp_offset = p->alloc.alloc_buffer_length_in_bytes; } p->eof = 0; @@ -4213,7 +4294,7 @@ static void stbv_vorbis_init(stb_vorbis *p, const stb_vorbis_alloc *z) #endif } -STBVDEF int stb_vorbis_get_sample_offset(stb_vorbis *f) +int stb_vorbis_get_sample_offset(stb_vorbis *f) { if (f->current_loc_valid) return f->current_loc; @@ -4221,7 +4302,7 @@ STBVDEF int stb_vorbis_get_sample_offset(stb_vorbis *f) return -1; } -STBVDEF stb_vorbis_info stb_vorbis_get_info(stb_vorbis *f) +stb_vorbis_info stb_vorbis_get_info(stb_vorbis *f) { stb_vorbis_info d; d.channels = f->channels; @@ -4233,22 +4314,31 @@ STBVDEF stb_vorbis_info stb_vorbis_get_info(stb_vorbis *f) return d; } -STBVDEF int stb_vorbis_get_error(stb_vorbis *f) +stb_vorbis_comment stb_vorbis_get_comment(stb_vorbis *f) +{ + stb_vorbis_comment d; + d.vendor = f->vendor; + d.comment_list_length = f->comment_list_length; + d.comment_list = f->comment_list; + return d; +} + +int stb_vorbis_get_error(stb_vorbis *f) { int e = f->error; f->error = VORBIS__no_error; return e; } -static stb_vorbis * stbv_vorbis_alloc(stb_vorbis *f) +static stb_vorbis * vorbis_alloc(stb_vorbis *f) { - stb_vorbis *p = (stb_vorbis *) stbv_setup_malloc(f, sizeof(*p)); + stb_vorbis *p = (stb_vorbis *) setup_malloc(f, sizeof(*p)); return p; } #ifndef STB_VORBIS_NO_PUSHDATA_API -STBVDEF void stb_vorbis_flush_pushdata(stb_vorbis *f) +void stb_vorbis_flush_pushdata(stb_vorbis *f) { f->previous_length = 0; f->page_crc_tests = 0; @@ -4260,7 +4350,7 @@ STBVDEF void stb_vorbis_flush_pushdata(stb_vorbis *f) f->channel_buffer_end = 0; } -static int stbv_vorbis_search_for_page_pushdata(stbv_vorb *f, stbv_uint8 *data, int data_len) +static int vorbis_search_for_page_pushdata(vorb *f, uint8 *data, int data_len) { int i,n; for (i=0; i < f->page_crc_tests; ++i) @@ -4274,9 +4364,9 @@ static int stbv_vorbis_search_for_page_pushdata(stbv_vorb *f, stbv_uint8 *data, // one that straddles a boundary for (i=0; i < data_len; ++i) { if (data[i] == 0x4f) { - if (0==memcmp(data+i, stbv_ogg_page_header, 4)) { + if (0==memcmp(data+i, ogg_page_header, 4)) { int j,len; - stbv_uint32 crc; + uint32 crc; // make sure we have the whole page header if (i+26 >= data_len || i+27+data[i+26] >= data_len) { // only read up to this page start, so hopefully we'll @@ -4291,10 +4381,10 @@ static int stbv_vorbis_search_for_page_pushdata(stbv_vorb *f, stbv_uint8 *data, // scan everything up to the embedded crc (which we must 0) crc = 0; for (j=0; j < 22; ++j) - crc = stbv_crc32_update(crc, data[i+j]); + crc = crc32_update(crc, data[i+j]); // now process 4 0-bytes for ( ; j < 26; ++j) - crc = stbv_crc32_update(crc, 0); + crc = crc32_update(crc, 0); // len is the total number of bytes we need to scan n = f->page_crc_tests++; f->scan[n].bytes_left = len-j; @@ -4316,7 +4406,7 @@ static int stbv_vorbis_search_for_page_pushdata(stbv_vorb *f, stbv_uint8 *data, } for (i=0; i < f->page_crc_tests;) { - stbv_uint32 crc; + uint32 crc; int j; int n = f->scan[i].bytes_done; int m = f->scan[i].bytes_left; @@ -4324,7 +4414,7 @@ static int stbv_vorbis_search_for_page_pushdata(stbv_vorb *f, stbv_uint8 *data, // m is the bytes to scan in the current chunk crc = f->scan[i].crc_so_far; for (j=0; j < m; ++j) - crc = stbv_crc32_update(crc, data[n+j]); + crc = crc32_update(crc, data[n+j]); f->scan[i].bytes_left -= m; f->scan[i].crc_so_far = crc; if (f->scan[i].bytes_left == 0) { @@ -4351,9 +4441,9 @@ static int stbv_vorbis_search_for_page_pushdata(stbv_vorb *f, stbv_uint8 *data, } // return value: number of bytes we used -STBVDEF int stb_vorbis_decode_frame_pushdata( +int stb_vorbis_decode_frame_pushdata( stb_vorbis *f, // the file we're decoding - const stbv_uint8 *data, int data_len, // the memory available for decoding + const uint8 *data, int data_len, // the memory available for decoding int *channels, // place to write number of float * buffers float ***output, // place to write float ** array of float * buffers int *samples // place to write number of output samples @@ -4362,30 +4452,30 @@ STBVDEF int stb_vorbis_decode_frame_pushdata( int i; int len,right,left; - if (!STBV_IS_PUSH_MODE(f)) return stbv_error(f, VORBIS_invalid_api_mixing); + if (!IS_PUSH_MODE(f)) return error(f, VORBIS_invalid_api_mixing); if (f->page_crc_tests >= 0) { *samples = 0; - return stbv_vorbis_search_for_page_pushdata(f, (stbv_uint8 *) data, data_len); + return vorbis_search_for_page_pushdata(f, (uint8 *) data, data_len); } - f->stream = (stbv_uint8 *) data; - f->stream_end = (stbv_uint8 *) data + data_len; + f->stream = (uint8 *) data; + f->stream_end = (uint8 *) data + data_len; f->error = VORBIS__no_error; // check that we have the entire packet in memory - if (!stbv_is_whole_packet_present(f, FALSE)) { + if (!is_whole_packet_present(f)) { *samples = 0; return 0; } - if (!stbv_vorbis_decode_packet(f, &len, &left, &right)) { + if (!vorbis_decode_packet(f, &len, &left, &right)) { // save the actual error we encountered enum STBVorbisError error = f->error; if (error == VORBIS_bad_packet_type) { // flush and resynch f->error = VORBIS__no_error; - while (stbv_get8_packet(f) != STBV_EOP) + while (get8_packet(f) != EOP) if (f->eof) break; *samples = 0; return (int) (f->stream - data); @@ -4395,7 +4485,7 @@ STBVDEF int stb_vorbis_decode_frame_pushdata( // we may be resynching, in which case it's ok to hit one // of these; just discard the packet f->error = VORBIS__no_error; - while (stbv_get8_packet(f) != STBV_EOP) + while (get8_packet(f) != EOP) if (f->eof) break; *samples = 0; return (int) (f->stream - data); @@ -4411,7 +4501,7 @@ STBVDEF int stb_vorbis_decode_frame_pushdata( } // success! - len = stbv_vorbis_finish_frame(f, len, left, right); + len = vorbis_finish_frame(f, len, left, right); for (i=0; i < f->channels; ++i) f->outputs[i] = f->channel_buffers[i] + left; @@ -4421,42 +4511,43 @@ STBVDEF int stb_vorbis_decode_frame_pushdata( return (int) (f->stream - data); } -STBVDEF stb_vorbis *stb_vorbis_open_pushdata( +stb_vorbis *stb_vorbis_open_pushdata( const unsigned char *data, int data_len, // the memory available for decoding int *data_used, // only defined if result is not NULL int *error, const stb_vorbis_alloc *alloc) { stb_vorbis *f, p; - stbv_vorbis_init(&p, alloc); - p.stream = (stbv_uint8 *) data; - p.stream_end = (stbv_uint8 *) data + data_len; + vorbis_init(&p, alloc); + p.stream = (uint8 *) data; + p.stream_end = (uint8 *) data + data_len; p.push_mode = TRUE; - if (!stbv_start_decoder(&p)) { + if (!start_decoder(&p)) { if (p.eof) *error = VORBIS_need_more_data; else *error = p.error; + vorbis_deinit(&p); return NULL; } - f = stbv_vorbis_alloc(&p); + f = vorbis_alloc(&p); if (f) { *f = p; *data_used = (int) (f->stream - data); *error = 0; return f; } else { - stbv_vorbis_deinit(&p); + vorbis_deinit(&p); return NULL; } } #endif // STB_VORBIS_NO_PUSHDATA_API -STBVDEF unsigned int stb_vorbis_get_file_offset(stb_vorbis *f) +unsigned int stb_vorbis_get_file_offset(stb_vorbis *f) { #ifndef STB_VORBIS_NO_PUSHDATA_API if (f->push_mode) return 0; #endif - if (STBV_USE_MEMORY(f)) return (unsigned int) (f->stream - f->stream_start); + if (USE_MEMORY(f)) return (unsigned int) (f->stream - f->stream_start); #ifndef STB_VORBIS_NO_STDIO return (unsigned int) (ftell(f->f) - f->f_start); #endif @@ -4467,12 +4558,12 @@ STBVDEF unsigned int stb_vorbis_get_file_offset(stb_vorbis *f) // DATA-PULLING API // -static stbv_uint32 stbv_vorbis_find_page(stb_vorbis *f, stbv_uint32 *end, stbv_uint32 *last) +static uint32 vorbis_find_page(stb_vorbis *f, uint32 *end, uint32 *last) { for(;;) { int n; if (f->eof) return 0; - n = stbv_get8(f); + n = get8(f); if (n == 0x4f) { // page header candidate unsigned int retry_loc = stb_vorbis_get_file_offset(f); int i; @@ -4481,33 +4572,33 @@ static stbv_uint32 stbv_vorbis_find_page(stb_vorbis *f, stbv_uint32 *end, stbv_u return 0; // check the rest of the header for (i=1; i < 4; ++i) - if (stbv_get8(f) != stbv_ogg_page_header[i]) + if (get8(f) != ogg_page_header[i]) break; if (f->eof) return 0; if (i == 4) { - stbv_uint8 header[27]; - stbv_uint32 i, crc, goal, len; + uint8 header[27]; + uint32 i, crc, goal, len; for (i=0; i < 4; ++i) - header[i] = stbv_ogg_page_header[i]; + header[i] = ogg_page_header[i]; for (; i < 27; ++i) - header[i] = stbv_get8(f); + header[i] = get8(f); if (f->eof) return 0; if (header[4] != 0) goto invalid; - goal = header[22] + (header[23] << 8) + (header[24]<<16) + (header[25]<<24); + goal = header[22] + (header[23] << 8) + (header[24]<<16) + ((uint32)header[25]<<24); for (i=22; i < 26; ++i) header[i] = 0; crc = 0; for (i=0; i < 27; ++i) - crc = stbv_crc32_update(crc, header[i]); + crc = crc32_update(crc, header[i]); len = 0; for (i=0; i < header[26]; ++i) { - int s = stbv_get8(f); - crc = stbv_crc32_update(crc, s); + int s = get8(f); + crc = crc32_update(crc, s); len += s; } if (len && f->eof) return 0; for (i=0; i < len; ++i) - crc = stbv_crc32_update(crc, stbv_get8(f)); + crc = crc32_update(crc, get8(f)); // finished parsing probable page if (crc == goal) { // we could now check that it's either got the last @@ -4526,19 +4617,19 @@ static stbv_uint32 stbv_vorbis_find_page(stb_vorbis *f, stbv_uint32 *end, stbv_u else *last = 0; } - stbv_set_file_offset(f, retry_loc-1); + set_file_offset(f, retry_loc-1); return 1; } } invalid: // not a valid page, so rewind and look for next one - stbv_set_file_offset(f, retry_loc); + set_file_offset(f, retry_loc); } } } -#define STBV_SAMPLE_unknown 0xffffffff +#define SAMPLE_unknown 0xffffffff // seeking is implemented with a binary search, which narrows down the range to // 64K, before using a linear search (because finding the synchronization @@ -4549,19 +4640,19 @@ static stbv_uint32 stbv_vorbis_find_page(stb_vorbis *f, stbv_uint32 *end, stbv_u // to try to bound either side of the binary search sensibly, while still // working in O(log n) time if they fail. -static int stbv_get_seek_page_info(stb_vorbis *f, StbvProbedPage *z) +static int get_seek_page_info(stb_vorbis *f, ProbedPage *z) { - stbv_uint8 header[27], lacing[255]; + uint8 header[27], lacing[255]; int i,len; // record where the page starts z->page_start = stb_vorbis_get_file_offset(f); // parse the header - stbv_getn(f, header, 27); + getn(f, header, 27); if (header[0] != 'O' || header[1] != 'g' || header[2] != 'g' || header[3] != 'S') return 0; - stbv_getn(f, lacing, header[26]); + getn(f, lacing, header[26]); // determine the length of the payload len = 0; @@ -4575,13 +4666,13 @@ static int stbv_get_seek_page_info(stb_vorbis *f, StbvProbedPage *z) z->last_decoded_sample = header[6] + (header[7] << 8) + (header[8] << 16) + (header[9] << 24); // restore file state to where we were - stbv_set_file_offset(f, z->page_start); + set_file_offset(f, z->page_start); return 1; } -// rarely used function to seek back to the preceeding page while finding the +// rarely used function to seek back to the preceding page while finding the // start of a packet -static int stbv_go_to_page_before(stb_vorbis *f, unsigned int limit_offset) +static int go_to_page_before(stb_vorbis *f, unsigned int limit_offset) { unsigned int previous_safe, end; @@ -4591,12 +4682,12 @@ static int stbv_go_to_page_before(stb_vorbis *f, unsigned int limit_offset) else previous_safe = f->first_audio_page_offset; - stbv_set_file_offset(f, previous_safe); + set_file_offset(f, previous_safe); - while (stbv_vorbis_find_page(f, &end, NULL)) { + while (vorbis_find_page(f, &end, NULL)) { if (end >= limit_offset && stb_vorbis_get_file_offset(f) < limit_offset) return 1; - stbv_set_file_offset(f, end); + set_file_offset(f, end); } return 0; @@ -4606,42 +4697,45 @@ static int stbv_go_to_page_before(stb_vorbis *f, unsigned int limit_offset) // the function succeeds, current_loc_valid will be true and current_loc will // be less than or equal to the provided sample number (the closer the // better). -static int stbv_seek_to_sample_coarse(stb_vorbis *f, stbv_uint32 sample_number) +static int seek_to_sample_coarse(stb_vorbis *f, uint32 sample_number) { - StbvProbedPage left, right, mid; + ProbedPage left, right, mid; int i, start_seg_with_known_loc, end_pos, page_start; - stbv_uint32 delta, stream_length, padding; - double offset, bytes_per_sample; + uint32 delta, stream_length, padding, last_sample_limit; + double offset = 0.0, bytes_per_sample = 0.0; int probe = 0; // find the last page and validate the target sample stream_length = stb_vorbis_stream_length_in_samples(f); - if (stream_length == 0) return stbv_error(f, VORBIS_seek_without_length); - if (sample_number > stream_length) return stbv_error(f, VORBIS_seek_invalid); + if (stream_length == 0) return error(f, VORBIS_seek_without_length); + if (sample_number > stream_length) return error(f, VORBIS_seek_invalid); // this is the maximum difference between the window-center (which is the // actual granule position value), and the right-start (which the spec // indicates should be the granule position (give or take one)). padding = ((f->blocksize_1 - f->blocksize_0) >> 2); if (sample_number < padding) - sample_number = 0; + last_sample_limit = 0; else - sample_number -= padding; + last_sample_limit = sample_number - padding; left = f->p_first; while (left.last_decoded_sample == ~0U) { // (untested) the first page does not have a 'last_decoded_sample' - stbv_set_file_offset(f, left.page_end); - if (!stbv_get_seek_page_info(f, &left)) goto error; + set_file_offset(f, left.page_end); + if (!get_seek_page_info(f, &left)) goto error; } right = f->p_last; assert(right.last_decoded_sample != ~0U); // starting from the start is handled differently - if (sample_number <= left.last_decoded_sample) { - if (stb_vorbis_seek_start(f)) + if (last_sample_limit <= left.last_decoded_sample) { + if (stb_vorbis_seek_start(f)) { + if (f->current_loc > sample_number) + return error(f, VORBIS_seek_failed); return 1; + } return 0; } @@ -4651,17 +4745,17 @@ static int stbv_seek_to_sample_coarse(stb_vorbis *f, stbv_uint32 sample_number) delta = right.page_start - left.page_end; if (delta <= 65536) { // there's only 64K left to search - handle it linearly - stbv_set_file_offset(f, left.page_end); + set_file_offset(f, left.page_end); } else { if (probe < 2) { if (probe == 0) { // first probe (interpolate) double data_bytes = right.page_end - left.page_start; bytes_per_sample = data_bytes / right.last_decoded_sample; - offset = left.page_start + bytes_per_sample * (sample_number - left.last_decoded_sample); + offset = left.page_start + bytes_per_sample * (last_sample_limit - left.last_decoded_sample); } else { // second probe (try to bound the other side) - double error = ((double) sample_number - mid.last_decoded_sample) * bytes_per_sample; + double error = ((double) last_sample_limit - mid.last_decoded_sample) * bytes_per_sample; if (error >= 0 && error < 8000) error = 8000; if (error < 0 && error > -8000) error = -8000; offset += error * 2; @@ -4673,41 +4767,43 @@ static int stbv_seek_to_sample_coarse(stb_vorbis *f, stbv_uint32 sample_number) if (offset > right.page_start - 65536) offset = right.page_start - 65536; - stbv_set_file_offset(f, (unsigned int) offset); + set_file_offset(f, (unsigned int) offset); } else { // binary search for large ranges (offset by 32K to ensure // we don't hit the right page) - stbv_set_file_offset(f, left.page_end + (delta / 2) - 32768); + set_file_offset(f, left.page_end + (delta / 2) - 32768); } - if (!stbv_vorbis_find_page(f, NULL, NULL)) goto error; + if (!vorbis_find_page(f, NULL, NULL)) goto error; } for (;;) { - if (!stbv_get_seek_page_info(f, &mid)) goto error; + if (!get_seek_page_info(f, &mid)) goto error; if (mid.last_decoded_sample != ~0U) break; // (untested) no frames end on this page - stbv_set_file_offset(f, mid.page_end); + set_file_offset(f, mid.page_end); assert(mid.page_start < right.page_start); } // if we've just found the last page again then we're in a tricky file, - // and we're close enough. - if (mid.page_start == right.page_start) - break; - - if (sample_number < mid.last_decoded_sample) - right = mid; - else - left = mid; + // and we're close enough (if it wasn't an interpolation probe). + if (mid.page_start == right.page_start) { + if (probe >= 2 || delta <= 65536) + break; + } else { + if (last_sample_limit < mid.last_decoded_sample) + right = mid; + else + left = mid; + } ++probe; } // seek back to start of the last packet page_start = left.page_start; - stbv_set_file_offset(f, page_start); - if (!stbv_start_page(f)) return stbv_error(f, VORBIS_seek_failed); + set_file_offset(f, page_start); + if (!start_page(f)) return error(f, VORBIS_seek_failed); end_pos = f->end_seg_with_known_loc; assert(end_pos >= 0); @@ -4718,15 +4814,15 @@ static int stbv_seek_to_sample_coarse(stb_vorbis *f, stbv_uint32 sample_number) start_seg_with_known_loc = i; - if (start_seg_with_known_loc > 0 || !(f->page_flag & STBV_PAGEFLAG_continued_packet)) + if (start_seg_with_known_loc > 0 || !(f->page_flag & PAGEFLAG_continued_packet)) break; // (untested) the final packet begins on an earlier page - if (!stbv_go_to_page_before(f, page_start)) + if (!go_to_page_before(f, page_start)) goto error; page_start = stb_vorbis_get_file_offset(f); - if (!stbv_start_page(f)) goto error; + if (!start_page(f)) goto error; end_pos = f->segment_count - 1; } @@ -4740,38 +4836,38 @@ static int stbv_seek_to_sample_coarse(stb_vorbis *f, stbv_uint32 sample_number) f->next_seg = start_seg_with_known_loc; for (i = 0; i < start_seg_with_known_loc; i++) - stbv_skip(f, f->segments[i]); + skip(f, f->segments[i]); // start decoding (optimizable - this frame is generally discarded) - if (!stbv_vorbis_pump_first_frame(f)) + if (!vorbis_pump_first_frame(f)) return 0; if (f->current_loc > sample_number) - return stbv_error(f, VORBIS_seek_failed); + return error(f, VORBIS_seek_failed); return 1; error: // try to restore the file to a valid state stb_vorbis_seek_start(f); - return stbv_error(f, VORBIS_seek_failed); + return error(f, VORBIS_seek_failed); } -// the same as stbv_vorbis_decode_initial, but without advancing -static int stbv_peek_decode_initial(stbv_vorb *f, int *p_left_start, int *p_left_end, int *p_right_start, int *p_right_end, int *mode) +// the same as vorbis_decode_initial, but without advancing +static int peek_decode_initial(vorb *f, int *p_left_start, int *p_left_end, int *p_right_start, int *p_right_end, int *mode) { int bits_read, bytes_read; - if (!stbv_vorbis_decode_initial(f, p_left_start, p_left_end, p_right_start, p_right_end, mode)) + if (!vorbis_decode_initial(f, p_left_start, p_left_end, p_right_start, p_right_end, mode)) return 0; // either 1 or 2 bytes were read, figure out which so we can rewind - bits_read = 1 + stbv_ilog(f->mode_count-1); + bits_read = 1 + ilog(f->mode_count-1); if (f->mode_config[*mode].blockflag) bits_read += 2; bytes_read = (bits_read + 7) / 8; f->bytes_in_seg += bytes_read; f->packet_bytes -= bytes_read; - stbv_skip(f, -bytes_read); + skip(f, -bytes_read); if (f->next_seg == -1) f->next_seg = f->segment_count - 1; else @@ -4781,14 +4877,14 @@ static int stbv_peek_decode_initial(stbv_vorb *f, int *p_left_start, int *p_left return 1; } -STBVDEF int stb_vorbis_seek_frame(stb_vorbis *f, unsigned int sample_number) +int stb_vorbis_seek_frame(stb_vorbis *f, unsigned int sample_number) { - stbv_uint32 max_frame_samples; + uint32 max_frame_samples; - if (STBV_IS_PUSH_MODE(f)) return stbv_error(f, VORBIS_invalid_api_mixing); + if (IS_PUSH_MODE(f)) return error(f, VORBIS_invalid_api_mixing); // fast page-level search - if (!stbv_seek_to_sample_coarse(f, sample_number)) + if (!seek_to_sample_coarse(f, sample_number)) return 0; assert(f->current_loc_valid); @@ -4798,36 +4894,36 @@ STBVDEF int stb_vorbis_seek_frame(stb_vorbis *f, unsigned int sample_number) max_frame_samples = (f->blocksize_1*3 - f->blocksize_0) >> 2; while (f->current_loc < sample_number) { int left_start, left_end, right_start, right_end, mode, frame_samples; - if (!stbv_peek_decode_initial(f, &left_start, &left_end, &right_start, &right_end, &mode)) - return stbv_error(f, VORBIS_seek_failed); + if (!peek_decode_initial(f, &left_start, &left_end, &right_start, &right_end, &mode)) + return error(f, VORBIS_seek_failed); // calculate the number of samples returned by the next frame frame_samples = right_start - left_start; if (f->current_loc + frame_samples > sample_number) { return 1; // the next frame will contain the sample } else if (f->current_loc + frame_samples + max_frame_samples > sample_number) { // there's a chance the frame after this could contain the sample - stbv_vorbis_pump_first_frame(f); + vorbis_pump_first_frame(f); } else { // this frame is too early to be relevant f->current_loc += frame_samples; f->previous_length = 0; - stbv_maybe_start_packet(f); - stbv_flush_packet(f); + maybe_start_packet(f); + flush_packet(f); } } - // the next frame will start with the sample - assert(f->current_loc == sample_number); + // the next frame should start with the sample + if (f->current_loc != sample_number) return error(f, VORBIS_seek_failed); return 1; } -STBVDEF int stb_vorbis_seek(stb_vorbis *f, unsigned int sample_number) +int stb_vorbis_seek(stb_vorbis *f, unsigned int sample_number) { if (!stb_vorbis_seek_frame(f, sample_number)) return 0; if (sample_number != f->current_loc) { int n; - stbv_uint32 frame_start = f->current_loc; + uint32 frame_start = f->current_loc; stb_vorbis_get_frame_float(f, &n, NULL); assert(sample_number > frame_start); assert(f->channel_buffer_start + (int) (sample_number-frame_start) <= f->channel_buffer_end); @@ -4837,25 +4933,25 @@ STBVDEF int stb_vorbis_seek(stb_vorbis *f, unsigned int sample_number) return 1; } -STBVDEF int stb_vorbis_seek_start(stb_vorbis *f) +int stb_vorbis_seek_start(stb_vorbis *f) { - if (STBV_IS_PUSH_MODE(f)) { return stbv_error(f, VORBIS_invalid_api_mixing); } - stbv_set_file_offset(f, f->first_audio_page_offset); + if (IS_PUSH_MODE(f)) { return error(f, VORBIS_invalid_api_mixing); } + set_file_offset(f, f->first_audio_page_offset); f->previous_length = 0; f->first_decode = TRUE; f->next_seg = -1; - return stbv_vorbis_pump_first_frame(f); + return vorbis_pump_first_frame(f); } -STBVDEF unsigned int stb_vorbis_stream_length_in_samples(stb_vorbis *f) +unsigned int stb_vorbis_stream_length_in_samples(stb_vorbis *f) { unsigned int restore_offset, previous_safe; unsigned int end, last_page_loc; - if (STBV_IS_PUSH_MODE(f)) return stbv_error(f, VORBIS_invalid_api_mixing); + if (IS_PUSH_MODE(f)) return error(f, VORBIS_invalid_api_mixing); if (!f->total_samples) { unsigned int last; - stbv_uint32 lo,hi; + uint32 lo,hi; char header[6]; // first, store the current decode position so we can restore it @@ -4868,11 +4964,11 @@ STBVDEF unsigned int stb_vorbis_stream_length_in_samples(stb_vorbis *f) else previous_safe = f->first_audio_page_offset; - stbv_set_file_offset(f, previous_safe); + set_file_offset(f, previous_safe); // previous_safe is now our candidate 'earliest known place that seeking // to will lead to the final page' - if (!stbv_vorbis_find_page(f, &end, &last)) { + if (!vorbis_find_page(f, &end, &last)) { // if we can't find a page, we're hosed! f->error = VORBIS_cant_find_last_page; f->total_samples = 0xffffffff; @@ -4886,26 +4982,26 @@ STBVDEF unsigned int stb_vorbis_stream_length_in_samples(stb_vorbis *f) // this allows us to stop short of a 'file_section' end without // explicitly checking the length of the section while (!last) { - stbv_set_file_offset(f, end); - if (!stbv_vorbis_find_page(f, &end, &last)) { + set_file_offset(f, end); + if (!vorbis_find_page(f, &end, &last)) { // the last page we found didn't have the 'last page' flag // set. whoops! break; } - previous_safe = last_page_loc+1; + //previous_safe = last_page_loc+1; // NOTE: not used after this point, but note for debugging last_page_loc = stb_vorbis_get_file_offset(f); } - stbv_set_file_offset(f, last_page_loc); + set_file_offset(f, last_page_loc); // parse the header - stbv_getn(f, (unsigned char *)header, 6); + getn(f, (unsigned char *)header, 6); // extract the absolute granule position - lo = stbv_get32(f); - hi = stbv_get32(f); + lo = get32(f); + hi = get32(f); if (lo == 0xffffffff && hi == 0xffffffff) { f->error = VORBIS_cant_find_last_page; - f->total_samples = STBV_SAMPLE_unknown; + f->total_samples = SAMPLE_unknown; goto done; } if (hi) @@ -4917,29 +5013,29 @@ STBVDEF unsigned int stb_vorbis_stream_length_in_samples(stb_vorbis *f) f->p_last.last_decoded_sample = lo; done: - stbv_set_file_offset(f, restore_offset); + set_file_offset(f, restore_offset); } - return f->total_samples == STBV_SAMPLE_unknown ? 0 : f->total_samples; + return f->total_samples == SAMPLE_unknown ? 0 : f->total_samples; } -STBVDEF float stb_vorbis_stream_length_in_seconds(stb_vorbis *f) +float stb_vorbis_stream_length_in_seconds(stb_vorbis *f) { return stb_vorbis_stream_length_in_samples(f) / (float) f->sample_rate; } -STBVDEF int stb_vorbis_get_frame_float(stb_vorbis *f, int *channels, float ***output) +int stb_vorbis_get_frame_float(stb_vorbis *f, int *channels, float ***output) { int len, right,left,i; - if (STBV_IS_PUSH_MODE(f)) return stbv_error(f, VORBIS_invalid_api_mixing); + if (IS_PUSH_MODE(f)) return error(f, VORBIS_invalid_api_mixing); - if (!stbv_vorbis_decode_packet(f, &len, &left, &right)) { + if (!vorbis_decode_packet(f, &len, &left, &right)) { f->channel_buffer_start = f->channel_buffer_end = 0; return 0; } - len = stbv_vorbis_finish_frame(f, len, left, right); + len = vorbis_finish_frame(f, len, left, right); for (i=0; i < f->channels; ++i) f->outputs[i] = f->channel_buffers[i] + left; @@ -4953,28 +5049,28 @@ STBVDEF int stb_vorbis_get_frame_float(stb_vorbis *f, int *channels, float ***ou #ifndef STB_VORBIS_NO_STDIO -STBVDEF stb_vorbis * stb_vorbis_open_file_section(FILE *file, int close_on_free, int *error, const stb_vorbis_alloc *alloc, unsigned int length) +stb_vorbis * stb_vorbis_open_file_section(FILE *file, int close_on_free, int *error, const stb_vorbis_alloc *alloc, unsigned int length) { stb_vorbis *f, p; - stbv_vorbis_init(&p, alloc); + vorbis_init(&p, alloc); p.f = file; - p.f_start = (stbv_uint32) ftell(file); + p.f_start = (uint32) ftell(file); p.stream_len = length; p.close_on_free = close_on_free; - if (stbv_start_decoder(&p)) { - f = stbv_vorbis_alloc(&p); + if (start_decoder(&p)) { + f = vorbis_alloc(&p); if (f) { *f = p; - stbv_vorbis_pump_first_frame(f); + vorbis_pump_first_frame(f); return f; } } if (error) *error = p.error; - stbv_vorbis_deinit(&p); + vorbis_deinit(&p); return NULL; } -STBVDEF stb_vorbis * stb_vorbis_open_file(FILE *file, int close_on_free, int *error, const stb_vorbis_alloc *alloc) +stb_vorbis * stb_vorbis_open_file(FILE *file, int close_on_free, int *error, const stb_vorbis_alloc *alloc) { unsigned int len, start; start = (unsigned int) ftell(file); @@ -4984,58 +5080,67 @@ STBVDEF stb_vorbis * stb_vorbis_open_file(FILE *file, int close_on_free, int *er return stb_vorbis_open_file_section(file, close_on_free, error, alloc, len); } -STBVDEF stb_vorbis * stb_vorbis_open_filename(const char *filename, int *error, const stb_vorbis_alloc *alloc) +stb_vorbis * stb_vorbis_open_filename(const char *filename, int *error, const stb_vorbis_alloc *alloc) { - FILE *f = fopen(filename, "rb"); - if (f) + FILE *f; +#if defined(_WIN32) && defined(__STDC_WANT_SECURE_LIB__) + if (0 != fopen_s(&f, filename, "rb")) + f = NULL; +#else + f = fopen(filename, "rb"); +#endif + if (f) return stb_vorbis_open_file(f, TRUE, error, alloc); if (error) *error = VORBIS_file_open_failure; return NULL; } #endif // STB_VORBIS_NO_STDIO -STBVDEF stb_vorbis * stb_vorbis_open_memory(const unsigned char *data, int len, int *error, const stb_vorbis_alloc *alloc) +stb_vorbis * stb_vorbis_open_memory(const unsigned char *data, int len, int *error, const stb_vorbis_alloc *alloc) { stb_vorbis *f, p; - if (data == NULL) return NULL; - stbv_vorbis_init(&p, alloc); - p.stream = (stbv_uint8 *) data; - p.stream_end = (stbv_uint8 *) data + len; - p.stream_start = (stbv_uint8 *) p.stream; + if (!data) { + if (error) *error = VORBIS_unexpected_eof; + return NULL; + } + vorbis_init(&p, alloc); + p.stream = (uint8 *) data; + p.stream_end = (uint8 *) data + len; + p.stream_start = (uint8 *) p.stream; p.stream_len = len; p.push_mode = FALSE; - if (stbv_start_decoder(&p)) { - f = stbv_vorbis_alloc(&p); + if (start_decoder(&p)) { + f = vorbis_alloc(&p); if (f) { *f = p; - stbv_vorbis_pump_first_frame(f); + vorbis_pump_first_frame(f); if (error) *error = VORBIS__no_error; return f; } } if (error) *error = p.error; - stbv_vorbis_deinit(&p); + vorbis_deinit(&p); return NULL; } #ifndef STB_VORBIS_NO_INTEGER_CONVERSION -#define STBV_PLAYBACK_MONO 1 -#define STBV_PLAYBACK_LEFT 2 -#define STBV_PLAYBACK_RIGHT 4 +#define PLAYBACK_MONO 1 +#define PLAYBACK_LEFT 2 +#define PLAYBACK_RIGHT 4 -#define STBV_L (STBV_PLAYBACK_LEFT | STBV_PLAYBACK_MONO) -#define STBV_C (STBV_PLAYBACK_LEFT | STBV_PLAYBACK_RIGHT | STBV_PLAYBACK_MONO) -#define STBV_R (STBV_PLAYBACK_RIGHT | STBV_PLAYBACK_MONO) +#define L (PLAYBACK_LEFT | PLAYBACK_MONO) +#define C (PLAYBACK_LEFT | PLAYBACK_RIGHT | PLAYBACK_MONO) +#define R (PLAYBACK_RIGHT | PLAYBACK_MONO) -static stbv_int8 stbv_channel_position[7][6] = +static int8 channel_position[7][6] = { { 0 }, - { STBV_C }, - { STBV_L, STBV_R }, - { STBV_L, STBV_C, STBV_R }, - { STBV_L, STBV_R, STBV_L, STBV_R }, - { STBV_L, STBV_C, STBV_R, STBV_L, STBV_R }, - { STBV_L, STBV_C, STBV_R, STBV_L, STBV_R, STBV_C }, + { C }, + { L, R }, + { L, C, R }, + { L, R, L, R }, + { L, C, R, L, R }, + { L, C, R, L, R, C }, }; @@ -5043,139 +5148,141 @@ static stbv_int8 stbv_channel_position[7][6] = typedef union { float f; int i; - } stbv_float_conv; + } float_conv; typedef char stb_vorbis_float_size_test[sizeof(float)==4 && sizeof(int) == 4]; - #define STBV_FASTDEF(x) stbv_float_conv x + #define FASTDEF(x) float_conv x // add (1<<23) to convert to int, then divide by 2^SHIFT, then add 0.5/2^SHIFT to round - #define STBV_MAGIC(SHIFT) (1.5f * (1 << (23-SHIFT)) + 0.5f/(1 << SHIFT)) - #define STBV_ADDEND(SHIFT) (((150-SHIFT) << 23) + (1 << 22)) - #define STBV_FAST_SCALED_FLOAT_TO_INT(temp,x,s) (temp.f = (x) + STBV_MAGIC(s), temp.i - STBV_ADDEND(s)) - #define stbv_check_endianness() + #define MAGIC(SHIFT) (1.5f * (1 << (23-SHIFT)) + 0.5f/(1 << SHIFT)) + #define ADDEND(SHIFT) (((150-SHIFT) << 23) + (1 << 22)) + #define FAST_SCALED_FLOAT_TO_INT(temp,x,s) (temp.f = (x) + MAGIC(s), temp.i - ADDEND(s)) + #define check_endianness() #else - #define STBV_FAST_SCALED_FLOAT_TO_INT(temp,x,s) ((int) ((x) * (1 << (s)))) - #define stbv_check_endianness() - #define STBV_FASTDEF(x) + #define FAST_SCALED_FLOAT_TO_INT(temp,x,s) ((int) ((x) * (1 << (s)))) + #define check_endianness() + #define FASTDEF(x) #endif -static void stbv_copy_samples(short *dest, float *src, int len) +static void copy_samples(short *dest, float *src, int len) { int i; - stbv_check_endianness(); + check_endianness(); for (i=0; i < len; ++i) { - STBV_FASTDEF(temp); - int v = STBV_FAST_SCALED_FLOAT_TO_INT(temp, src[i],15); + FASTDEF(temp); + int v = FAST_SCALED_FLOAT_TO_INT(temp, src[i],15); if ((unsigned int) (v + 32768) > 65535) v = v < 0 ? -32768 : 32767; dest[i] = v; } } -static void stbv_compute_samples(int mask, short *output, int num_c, float **data, int d_offset, int len) +static void compute_samples(int mask, short *output, int num_c, float **data, int d_offset, int len) { - #define BUFFER_SIZE 32 - float buffer[BUFFER_SIZE]; - int i,j,o,n = BUFFER_SIZE; - stbv_check_endianness(); - for (o = 0; o < len; o += BUFFER_SIZE) { + #define STB_BUFFER_SIZE 32 + float buffer[STB_BUFFER_SIZE]; + int i,j,o,n = STB_BUFFER_SIZE; + check_endianness(); + for (o = 0; o < len; o += STB_BUFFER_SIZE) { memset(buffer, 0, sizeof(buffer)); if (o + n > len) n = len - o; for (j=0; j < num_c; ++j) { - if (stbv_channel_position[num_c][j] & mask) { + if (channel_position[num_c][j] & mask) { for (i=0; i < n; ++i) buffer[i] += data[j][d_offset+o+i]; } } for (i=0; i < n; ++i) { - STBV_FASTDEF(temp); - int v = STBV_FAST_SCALED_FLOAT_TO_INT(temp,buffer[i],15); + FASTDEF(temp); + int v = FAST_SCALED_FLOAT_TO_INT(temp,buffer[i],15); if ((unsigned int) (v + 32768) > 65535) v = v < 0 ? -32768 : 32767; output[o+i] = v; } } + #undef STB_BUFFER_SIZE } -static void stbv_compute_stereo_samples(short *output, int num_c, float **data, int d_offset, int len) +static void compute_stereo_samples(short *output, int num_c, float **data, int d_offset, int len) { - #define BUFFER_SIZE 32 - float buffer[BUFFER_SIZE]; - int i,j,o,n = BUFFER_SIZE >> 1; + #define STB_BUFFER_SIZE 32 + float buffer[STB_BUFFER_SIZE]; + int i,j,o,n = STB_BUFFER_SIZE >> 1; // o is the offset in the source data - stbv_check_endianness(); - for (o = 0; o < len; o += BUFFER_SIZE >> 1) { + check_endianness(); + for (o = 0; o < len; o += STB_BUFFER_SIZE >> 1) { // o2 is the offset in the output data int o2 = o << 1; memset(buffer, 0, sizeof(buffer)); if (o + n > len) n = len - o; for (j=0; j < num_c; ++j) { - int m = stbv_channel_position[num_c][j] & (STBV_PLAYBACK_LEFT | STBV_PLAYBACK_RIGHT); - if (m == (STBV_PLAYBACK_LEFT | STBV_PLAYBACK_RIGHT)) { + int m = channel_position[num_c][j] & (PLAYBACK_LEFT | PLAYBACK_RIGHT); + if (m == (PLAYBACK_LEFT | PLAYBACK_RIGHT)) { for (i=0; i < n; ++i) { buffer[i*2+0] += data[j][d_offset+o+i]; buffer[i*2+1] += data[j][d_offset+o+i]; } - } else if (m == STBV_PLAYBACK_LEFT) { + } else if (m == PLAYBACK_LEFT) { for (i=0; i < n; ++i) { buffer[i*2+0] += data[j][d_offset+o+i]; } - } else if (m == STBV_PLAYBACK_RIGHT) { + } else if (m == PLAYBACK_RIGHT) { for (i=0; i < n; ++i) { buffer[i*2+1] += data[j][d_offset+o+i]; } } } for (i=0; i < (n<<1); ++i) { - STBV_FASTDEF(temp); - int v = STBV_FAST_SCALED_FLOAT_TO_INT(temp,buffer[i],15); + FASTDEF(temp); + int v = FAST_SCALED_FLOAT_TO_INT(temp,buffer[i],15); if ((unsigned int) (v + 32768) > 65535) v = v < 0 ? -32768 : 32767; output[o2+i] = v; } } + #undef STB_BUFFER_SIZE } -static void stbv_convert_samples_short(int buf_c, short **buffer, int b_offset, int data_c, float **data, int d_offset, int samples) +static void convert_samples_short(int buf_c, short **buffer, int b_offset, int data_c, float **data, int d_offset, int samples) { int i; if (buf_c != data_c && buf_c <= 2 && data_c <= 6) { - static int channel_selector[3][2] = { {0}, {STBV_PLAYBACK_MONO}, {STBV_PLAYBACK_LEFT, STBV_PLAYBACK_RIGHT} }; + static int channel_selector[3][2] = { {0}, {PLAYBACK_MONO}, {PLAYBACK_LEFT, PLAYBACK_RIGHT} }; for (i=0; i < buf_c; ++i) - stbv_compute_samples(channel_selector[buf_c][i], buffer[i]+b_offset, data_c, data, d_offset, samples); + compute_samples(channel_selector[buf_c][i], buffer[i]+b_offset, data_c, data, d_offset, samples); } else { int limit = buf_c < data_c ? buf_c : data_c; for (i=0; i < limit; ++i) - stbv_copy_samples(buffer[i]+b_offset, data[i]+d_offset, samples); + copy_samples(buffer[i]+b_offset, data[i]+d_offset, samples); for ( ; i < buf_c; ++i) memset(buffer[i]+b_offset, 0, sizeof(short) * samples); } } -STBVDEF int stb_vorbis_get_frame_short(stb_vorbis *f, int num_c, short **buffer, int num_samples) +int stb_vorbis_get_frame_short(stb_vorbis *f, int num_c, short **buffer, int num_samples) { - float **output; + float **output = NULL; int len = stb_vorbis_get_frame_float(f, NULL, &output); if (len > num_samples) len = num_samples; if (len) - stbv_convert_samples_short(num_c, buffer, 0, f->channels, output, 0, len); + convert_samples_short(num_c, buffer, 0, f->channels, output, 0, len); return len; } -static void stbv_convert_channels_short_interleaved(int buf_c, short *buffer, int data_c, float **data, int d_offset, int len) +static void convert_channels_short_interleaved(int buf_c, short *buffer, int data_c, float **data, int d_offset, int len) { int i; - stbv_check_endianness(); + check_endianness(); if (buf_c != data_c && buf_c <= 2 && data_c <= 6) { assert(buf_c == 2); for (i=0; i < buf_c; ++i) - stbv_compute_stereo_samples(buffer, data_c, data, d_offset, len); + compute_stereo_samples(buffer, data_c, data, d_offset, len); } else { int limit = buf_c < data_c ? buf_c : data_c; int j; for (j=0; j < len; ++j) { for (i=0; i < limit; ++i) { - STBV_FASTDEF(temp); + FASTDEF(temp); float f = data[i][d_offset+j]; - int v = STBV_FAST_SCALED_FLOAT_TO_INT(temp, f,15);//data[i][d_offset+j],15); + int v = FAST_SCALED_FLOAT_TO_INT(temp, f,15);//data[i][d_offset+j],15); if ((unsigned int) (v + 32768) > 65535) v = v < 0 ? -32768 : 32767; *buffer++ = v; @@ -5186,7 +5293,7 @@ static void stbv_convert_channels_short_interleaved(int buf_c, short *buffer, in } } -STBVDEF int stb_vorbis_get_frame_short_interleaved(stb_vorbis *f, int num_c, short *buffer, int num_shorts) +int stb_vorbis_get_frame_short_interleaved(stb_vorbis *f, int num_c, short *buffer, int num_shorts) { float **output; int len; @@ -5194,23 +5301,21 @@ STBVDEF int stb_vorbis_get_frame_short_interleaved(stb_vorbis *f, int num_c, sho len = stb_vorbis_get_frame_float(f, NULL, &output); if (len) { if (len*num_c > num_shorts) len = num_shorts / num_c; - stbv_convert_channels_short_interleaved(num_c, buffer, f->channels, output, 0, len); + convert_channels_short_interleaved(num_c, buffer, f->channels, output, 0, len); } return len; } -STBVDEF int stb_vorbis_get_samples_short_interleaved(stb_vorbis *f, int channels, short *buffer, int num_shorts) +int stb_vorbis_get_samples_short_interleaved(stb_vorbis *f, int channels, short *buffer, int num_shorts) { float **outputs; int len = num_shorts / channels; int n=0; - int z = f->channels; - if (z > channels) z = channels; while (n < len) { int k = f->channel_buffer_end - f->channel_buffer_start; if (n+k >= len) k = len - n; if (k) - stbv_convert_channels_short_interleaved(channels, buffer, f->channels, f->channel_buffers, f->channel_buffer_start, k); + convert_channels_short_interleaved(channels, buffer, f->channels, f->channel_buffers, f->channel_buffer_start, k); buffer += k*channels; n += k; f->channel_buffer_start += k; @@ -5220,17 +5325,15 @@ STBVDEF int stb_vorbis_get_samples_short_interleaved(stb_vorbis *f, int channels return n; } -STBVDEF int stb_vorbis_get_samples_short(stb_vorbis *f, int channels, short **buffer, int len) +int stb_vorbis_get_samples_short(stb_vorbis *f, int channels, short **buffer, int len) { float **outputs; int n=0; - int z = f->channels; - if (z > channels) z = channels; while (n < len) { int k = f->channel_buffer_end - f->channel_buffer_start; if (n+k >= len) k = len - n; if (k) - stbv_convert_samples_short(channels, buffer, n, f->channels, f->channel_buffers, f->channel_buffer_start, k); + convert_samples_short(channels, buffer, n, f->channels, f->channel_buffers, f->channel_buffer_start, k); n += k; f->channel_buffer_start += k; if (n == len) break; @@ -5240,7 +5343,7 @@ STBVDEF int stb_vorbis_get_samples_short(stb_vorbis *f, int channels, short **bu } #ifndef STB_VORBIS_NO_STDIO -STBVDEF int stb_vorbis_decode_filename(const char *filename, int *channels, int *sample_rate, short **output) +int stb_vorbis_decode_filename(const char *filename, int *channels, int *sample_rate, short **output) { int data_len, offset, total, limit, error; short *data; @@ -5280,7 +5383,7 @@ STBVDEF int stb_vorbis_decode_filename(const char *filename, int *channels, int } #endif // NO_STDIO -STBVDEF int stb_vorbis_decode_memory(const stbv_uint8 *mem, int len, int *channels, int *sample_rate, short **output) +int stb_vorbis_decode_memory(const uint8 *mem, int len, int *channels, int *sample_rate, short **output) { int data_len, offset, total, limit, error; short *data; @@ -5320,7 +5423,7 @@ STBVDEF int stb_vorbis_decode_memory(const stbv_uint8 *mem, int len, int *channe } #endif // STB_VORBIS_NO_INTEGER_CONVERSION -STBVDEF int stb_vorbis_get_samples_float_interleaved(stb_vorbis *f, int channels, float *buffer, int num_floats) +int stb_vorbis_get_samples_float_interleaved(stb_vorbis *f, int channels, float *buffer, int num_floats) { float **outputs; int len = num_floats / channels; @@ -5347,7 +5450,7 @@ STBVDEF int stb_vorbis_get_samples_float_interleaved(stb_vorbis *f, int channels return n; } -STBVDEF int stb_vorbis_get_samples_float(stb_vorbis *f, int channels, float **buffer, int num_samples) +int stb_vorbis_get_samples_float(stb_vorbis *f, int channels, float **buffer, int num_samples) { float **outputs; int n=0; @@ -5375,14 +5478,20 @@ STBVDEF int stb_vorbis_get_samples_float(stb_vorbis *f, int channels, float **bu #endif // STB_VORBIS_NO_PULLDATA_API /* Version history + 1.17 - 2019-07-08 - fix CVE-2019-13217, -13218, -13219, -13220, -13221, -13222, -13223 + found with Mayhem by ForAllSecure + 1.16 - 2019-03-04 - fix warnings + 1.15 - 2019-02-07 - explicit failure if Ogg Skeleton data is found + 1.14 - 2018-02-11 - delete bogus dealloca usage + 1.13 - 2018-01-29 - fix truncation of last frame (hopefully) 1.12 - 2017-11-21 - limit residue begin/end to blocksize/2 to avoid large temp allocs in bad/corrupt files - 1.11 - 2017-07-23 - fix MinGW compilation - 1.10 - 2017-03-03 - more robust seeking; fix negative stbv_ilog(); clear error in open_memory + 1.11 - 2017-07-23 - fix MinGW compilation + 1.10 - 2017-03-03 - more robust seeking; fix negative ilog(); clear error in open_memory 1.09 - 2016-04-04 - back out 'avoid discarding last frame' fix from previous version 1.08 - 2016-04-02 - fixed multiple warnings; fix setup memory leaks; avoid discarding last frame of audio data 1.07 - 2015-01-16 - fixed some warnings, fix mingw, const-correct API - some more crash fixes when out of memory or with corrupt files + some more crash fixes when out of memory or with corrupt files 1.06 - 2015-08-31 - full, correct support for seeking API (Dougall Johnson) some crash fixes when out of memory or with corrupt files 1.05 - 2015-04-19 - don't define __forceinline if it's redundant @@ -5429,7 +5538,7 @@ STBVDEF int stb_vorbis_get_samples_float(stb_vorbis *f, int channels, float **bu 0.90 - first public release */ -#endif // STB_VORBIS_IMPLEMENTATION +#endif // STB_VORBIS_HEADER_ONLY /* @@ -5438,38 +5547,38 @@ This software is available under 2 licenses -- choose whichever you prefer. ------------------------------------------------------------------------------ ALTERNATIVE A - MIT License Copyright (c) 2017 Sean Barrett -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 +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 +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 +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. ------------------------------------------------------------------------------ ALTERNATIVE B - Public Domain (www.unlicense.org) This is free and unencumbered software released into the public domain. -Anyone is free to copy, modify, publish, use, compile, sell, or distribute this -software, either in source code form or as a compiled binary, for any purpose, +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means. -In jurisdictions that recognize copyright laws, the author or authors of this -software dedicate any and all copyright interest in the software to the public -domain. We make this dedication for the benefit of the public at large and to -the detriment of our heirs and successors. We intend this dedication to be an -overt act of relinquishment in perpetuity of all present and future rights to +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law. -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 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 +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 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. ------------------------------------------------------------------------------ */ diff --git a/src/raudio.c b/src/raudio.c index 46d8223d9d1e..591d6f69f43d 100644 --- a/src/raudio.c +++ b/src/raudio.c @@ -198,8 +198,7 @@ typedef struct tagBITMAPINFOHEADER { #if defined(SUPPORT_FILEFORMAT_OGG) // TODO: Remap stb_vorbis malloc()/free() calls to RL_MALLOC/RL_FREE - #define STB_VORBIS_IMPLEMENTATION - #include "external/stb_vorbis.h" // OGG loading functions + #include "external/stb_vorbis.c" // OGG loading functions #endif #if defined(SUPPORT_FILEFORMAT_XM) From 212f331583c8847162d5950183bed9c551fbf552 Mon Sep 17 00:00:00 2001 From: Antonis Geralis <43617260+planetis-m@users.noreply.github.com> Date: Wed, 1 Feb 2023 16:13:25 +0200 Subject: [PATCH 076/192] Update core_input_gamepad.c (#2903) --- examples/core/core_input_gamepad.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/core/core_input_gamepad.c b/examples/core/core_input_gamepad.c index 411472b34058..cd0c867d7b15 100644 --- a/examples/core/core_input_gamepad.c +++ b/examples/core/core_input_gamepad.c @@ -174,7 +174,7 @@ int main(void) DrawText(TextFormat("AXIS %i: %.02f", i, GetGamepadAxisMovement(0, i)), 20, 70 + 20*i, 10, DARKGRAY); } - if (GetGamepadButtonPressed() != -1) DrawText(TextFormat("DETECTED BUTTON: %i", GetGamepadButtonPressed()), 10, 430, 10, RED); + if (GetGamepadButtonPressed() != GAMEPAD_BUTTON_UNKNOWN) DrawText(TextFormat("DETECTED BUTTON: %i", GetGamepadButtonPressed()), 10, 430, 10, RED); else DrawText("DETECTED BUTTON: NONE", 10, 430, 10, GRAY); } else From b9e49cdca6a6b8fb65f3cc7679911c7fff41cf57 Mon Sep 17 00:00:00 2001 From: Ian McFarlane <70479099+the-argus@users.noreply.github.com> Date: Fri, 3 Feb 2023 13:52:15 +0000 Subject: [PATCH 077/192] rcamera: move y clamp to before 3d projection (#2905) --- src/rcamera.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/rcamera.h b/src/rcamera.h index 1b77e19a96ff..70221b34747f 100644 --- a/src/rcamera.h +++ b/src/rcamera.h @@ -405,6 +405,9 @@ void UpdateCamera(Camera *camera) } break; case CAMERA_FIRST_PERSON: // Camera moves as in a first-person game, controls are configurable { + // NOTE: On CAMERA_FIRST_PERSON player Y-movement is limited to player 'eyes position' + camera->position.y = CAMERA.playerEyesPosition; + camera->position.x += (sinf(CAMERA.angle.x)*direction[MOVE_BACK] - sinf(CAMERA.angle.x)*direction[MOVE_FRONT] - cosf(CAMERA.angle.x)*direction[MOVE_LEFT] + @@ -479,10 +482,6 @@ void UpdateCamera(Camera *camera) camera->target.y = camera->position.y - matTransform.m13; camera->target.z = camera->position.z - matTransform.m14; - // Camera position update - // NOTE: On CAMERA_FIRST_PERSON player Y-movement is limited to player 'eyes position' - camera->position.y = CAMERA.playerEyesPosition; - // Camera swinging (y-movement), only when walking (some key pressed) for (int i = 0; i < 6; i++) if (direction[i]) { swingCounter += GetFrameTime(); break; } camera->position.y -= sinf(2*PI*CAMERA_FIRST_PERSON_STEP_FREQUENCY*swingCounter)*CAMERA_FIRST_PERSON_SWINGING_DELTA; From 7914332c40ee811ad08a90e4eb7d40c2d1e81f4e Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 3 Feb 2023 14:54:28 +0100 Subject: [PATCH 078/192] Update qoi.h --- src/external/qoi.h | 48 +++++++++++++--------------------------------- 1 file changed, 13 insertions(+), 35 deletions(-) diff --git a/src/external/qoi.h b/src/external/qoi.h index 988f9edcb4fe..6734ac46e74d 100644 --- a/src/external/qoi.h +++ b/src/external/qoi.h @@ -1,30 +1,10 @@ /* -QOI - The "Quite OK Image" format for fast, lossless image compression - -Dominic Szablewski - https://phoboslab.org - +Copyright (c) 2021, Dominic Szablewski - https://phoboslab.org +SPDX-License-Identifier: MIT --- LICENSE: The MIT License(MIT) - -Copyright(c) 2021 Dominic Szablewski - -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. +QOI - The "Quite OK Image" format for fast, lossless image compression -- About @@ -424,13 +404,12 @@ void *qoi_encode(const void *data, const qoi_desc *desc, int *out_len) { channels = desc->channels; for (px_pos = 0; px_pos < px_len; px_pos += channels) { + px.rgba.r = pixels[px_pos + 0]; + px.rgba.g = pixels[px_pos + 1]; + px.rgba.b = pixels[px_pos + 2]; + if (channels == 4) { - px = *(qoi_rgba_t *)(pixels + px_pos); - } - else { - px.rgba.r = pixels[px_pos + 0]; - px.rgba.g = pixels[px_pos + 1]; - px.rgba.b = pixels[px_pos + 2]; + px.rgba.a = pixels[px_pos + 3]; } if (px.v == px_prev.v) { @@ -598,13 +577,12 @@ void *qoi_decode(const void *data, int size, qoi_desc *desc, int channels) { index[QOI_COLOR_HASH(px) % 64] = px; } + pixels[px_pos + 0] = px.rgba.r; + pixels[px_pos + 1] = px.rgba.g; + pixels[px_pos + 2] = px.rgba.b; + if (channels == 4) { - *(qoi_rgba_t*)(pixels + px_pos) = px; - } - else { - pixels[px_pos + 0] = px.rgba.r; - pixels[px_pos + 1] = px.rgba.g; - pixels[px_pos + 2] = px.rgba.b; + pixels[px_pos + 3] = px.rgba.a; } } From 43e45cbb810b58a5c78e3d6fe708260043083b91 Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 4 Feb 2023 20:19:51 +0100 Subject: [PATCH 079/192] Replace TABS by 4 spaces --- src/rmodels.c | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/rmodels.c b/src/rmodels.c index b5d8578f6ea6..3c9384d2db97 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -1875,34 +1875,34 @@ bool ExportMesh(Mesh mesh, const char *fileName) // Process obj materials static void ProcessMaterialsOBJ(Material *rayMaterials, tinyobj_material_t *materials, int materialCount) { - // Init model materials - for (int m = 0; m < materialCount; m++) - { - // Init material to default - // NOTE: Uses default shader, which only supports MATERIAL_MAP_DIFFUSE - rayMaterials[m] = LoadMaterialDefault(); + // Init model materials + for (int m = 0; m < materialCount; m++) + { + // Init material to default + // NOTE: Uses default shader, which only supports MATERIAL_MAP_DIFFUSE + rayMaterials[m] = LoadMaterialDefault(); - // Get default texture, in case no texture is defined - // NOTE: rlgl default texture is a 1x1 pixel UNCOMPRESSED_R8G8B8A8 - rayMaterials[m].maps[MATERIAL_MAP_DIFFUSE].texture = (Texture2D){ rlGetTextureIdDefault(), 1, 1, 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 }; + // Get default texture, in case no texture is defined + // NOTE: rlgl default texture is a 1x1 pixel UNCOMPRESSED_R8G8B8A8 + rayMaterials[m].maps[MATERIAL_MAP_DIFFUSE].texture = (Texture2D){ rlGetTextureIdDefault(), 1, 1, 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 }; - if (materials[m].diffuse_texname != NULL) rayMaterials[m].maps[MATERIAL_MAP_DIFFUSE].texture = LoadTexture(materials[m].diffuse_texname); //char *diffuse_texname; // map_Kd + if (materials[m].diffuse_texname != NULL) rayMaterials[m].maps[MATERIAL_MAP_DIFFUSE].texture = LoadTexture(materials[m].diffuse_texname); //char *diffuse_texname; // map_Kd - rayMaterials[m].maps[MATERIAL_MAP_DIFFUSE].color = (Color){ (unsigned char)(materials[m].diffuse[0]*255.0f), (unsigned char)(materials[m].diffuse[1]*255.0f), (unsigned char)(materials[m].diffuse[2] * 255.0f), 255 }; //float diffuse[3]; - rayMaterials[m].maps[MATERIAL_MAP_DIFFUSE].value = 0.0f; + rayMaterials[m].maps[MATERIAL_MAP_DIFFUSE].color = (Color){ (unsigned char)(materials[m].diffuse[0]*255.0f), (unsigned char)(materials[m].diffuse[1]*255.0f), (unsigned char)(materials[m].diffuse[2] * 255.0f), 255 }; //float diffuse[3]; + rayMaterials[m].maps[MATERIAL_MAP_DIFFUSE].value = 0.0f; - if (materials[m].specular_texname != NULL) rayMaterials[m].maps[MATERIAL_MAP_SPECULAR].texture = LoadTexture(materials[m].specular_texname); //char *specular_texname; // map_Ks - rayMaterials[m].maps[MATERIAL_MAP_SPECULAR].color = (Color){ (unsigned char)(materials[m].specular[0]*255.0f), (unsigned char)(materials[m].specular[1]*255.0f), (unsigned char)(materials[m].specular[2] * 255.0f), 255 }; //float specular[3]; - rayMaterials[m].maps[MATERIAL_MAP_SPECULAR].value = 0.0f; + if (materials[m].specular_texname != NULL) rayMaterials[m].maps[MATERIAL_MAP_SPECULAR].texture = LoadTexture(materials[m].specular_texname); //char *specular_texname; // map_Ks + rayMaterials[m].maps[MATERIAL_MAP_SPECULAR].color = (Color){ (unsigned char)(materials[m].specular[0]*255.0f), (unsigned char)(materials[m].specular[1]*255.0f), (unsigned char)(materials[m].specular[2] * 255.0f), 255 }; //float specular[3]; + rayMaterials[m].maps[MATERIAL_MAP_SPECULAR].value = 0.0f; - if (materials[m].bump_texname != NULL) rayMaterials[m].maps[MATERIAL_MAP_NORMAL].texture = LoadTexture(materials[m].bump_texname); //char *bump_texname; // map_bump, bump - rayMaterials[m].maps[MATERIAL_MAP_NORMAL].color = WHITE; - rayMaterials[m].maps[MATERIAL_MAP_NORMAL].value = materials[m].shininess; + if (materials[m].bump_texname != NULL) rayMaterials[m].maps[MATERIAL_MAP_NORMAL].texture = LoadTexture(materials[m].bump_texname); //char *bump_texname; // map_bump, bump + rayMaterials[m].maps[MATERIAL_MAP_NORMAL].color = WHITE; + rayMaterials[m].maps[MATERIAL_MAP_NORMAL].value = materials[m].shininess; - rayMaterials[m].maps[MATERIAL_MAP_EMISSION].color = (Color){ (unsigned char)(materials[m].emission[0]*255.0f), (unsigned char)(materials[m].emission[1]*255.0f), (unsigned char)(materials[m].emission[2] * 255.0f), 255 }; //float emission[3]; + rayMaterials[m].maps[MATERIAL_MAP_EMISSION].color = (Color){ (unsigned char)(materials[m].emission[0]*255.0f), (unsigned char)(materials[m].emission[1]*255.0f), (unsigned char)(materials[m].emission[2] * 255.0f), 255 }; //float emission[3]; - if (materials[m].displacement_texname != NULL) rayMaterials[m].maps[MATERIAL_MAP_HEIGHT].texture = LoadTexture(materials[m].displacement_texname); //char *displacement_texname; // disp - } + if (materials[m].displacement_texname != NULL) rayMaterials[m].maps[MATERIAL_MAP_HEIGHT].texture = LoadTexture(materials[m].displacement_texname); //char *displacement_texname; // disp + } } #endif @@ -4041,7 +4041,7 @@ static Model LoadOBJ(const char *fileName) } // Init model materials - ProcessMaterialsOBJ(model.materials, materials, materialCount); + ProcessMaterialsOBJ(model.materials, materials, materialCount); tinyobj_attrib_free(&attrib); tinyobj_shapes_free(meshes, meshCount); From 901c4553d2b9c23337f10083f6726cdd71927cf5 Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 4 Feb 2023 20:20:21 +0100 Subject: [PATCH 080/192] ADDED: QOA audio format support -WIP- --- src/config.h | 5 +- src/external/qoa.h | 658 +++++++++++++++++++++++++++++++++++++++++++++ src/raudio.c | 306 +++++++++++++-------- 3 files changed, 861 insertions(+), 108 deletions(-) create mode 100644 src/external/qoa.h diff --git a/src/config.h b/src/config.h index f67ea3cb02c8..be24c01904ce 100644 --- a/src/config.h +++ b/src/config.h @@ -211,10 +211,11 @@ // Desired audio fileformats to be supported for loading #define SUPPORT_FILEFORMAT_WAV 1 #define SUPPORT_FILEFORMAT_OGG 1 -#define SUPPORT_FILEFORMAT_XM 1 -#define SUPPORT_FILEFORMAT_MOD 1 #define SUPPORT_FILEFORMAT_MP3 1 +//#define SUPPORT_FILEFORMAT_QOA 1 //#define SUPPORT_FILEFORMAT_FLAC 1 +#define SUPPORT_FILEFORMAT_XM 1 +#define SUPPORT_FILEFORMAT_MOD 1 // raudio: Configuration values //------------------------------------------------------------------------------------ diff --git a/src/external/qoa.h b/src/external/qoa.h new file mode 100644 index 000000000000..aae575512081 --- /dev/null +++ b/src/external/qoa.h @@ -0,0 +1,658 @@ +/* + +Copyright (c) 2023, Dominic Szablewski - https://phoboslab.org +SPDX-License-Identifier: MIT + +QOA - The "Quite OK Audio" format for fast, lossy audio compression + + +-- Data Format + +A QOA file has an 8 byte file header, followed by a number of frames. Each frame +consists of an 8 byte frame header, the current 8 byte en-/decoder state per +channel and 256 slices per channel. Each slice is 8 bytes wide and encodes 20 +samples of audio data. + +Note that the last frame of a file may contain less than 256 slices per channel. +The last slice (per channel) in the last frame may contain less 20 samples, but +the slice will still be 8 bytes wide, with the unused samples zeroed out. + +The samplerate and number of channels is only stated in the frame headers, but +not in the file header. A decoder may peek into the first frame of the file to +find these values. + +In a valid QOA file all frames have the same number of channels and the same +samplerate. These restriction may be releaxed for streaming. This remains to +be decided. + +All values in a QOA file are BIG ENDIAN. Luckily, EVERYTHING in a QOA file, +including the headers, is 64 bit aligned, so it's possible to read files with +just a read_u64() that does the byte swapping if neccessary. + +In pseudocode, the file layout is as follows: + +struct { + struct { + char magic[4]; // magic bytes 'qoaf' + uint32_t samples; // number of samples per channel in this file + } file_header; // = 64 bits + + struct { + struct { + uint8_t num_channels; // number of channels + uint24_t samplerate; // samplerate in hz + uint16_t fsamples; // sample count per channel in this frame + uint16_t fsize; // frame size (including the frame header) + } frame_header; // = 64 bits + + struct { + int16_t history[4]; // = 64 bits + int16_t weights[4]; // = 64 bits + } lms_state[num_channels]; + + qoa_slice_t slices[256][num_channels]; // = 64 bits each + } frames[samples * channels / qoa_max_framesize()]; +} qoa_file; + +Wheras the 64bit qoa_slice_t is defined as follows: + +.- QOA_SLICE -- 64 bits, 20 samples --------------------------/ /------------. +| Byte[0] | Byte[1] | Byte[2] \ \ Byte[7] | +| 7 6 5 4 3 2 1 0 | 7 6 5 4 3 2 1 0 | 7 6 5 / / 2 1 0 | +|------------+--------+--------+--------+---------+---------+-\ \--+---------| +| sf_index | r00 | r01 | r02 | r03 | r04 | / / | r19 | +`-------------------------------------------------------------\ \------------` + +`sf_index` defines the scalefactor to use for this slice as an index into the +qoa_scalefactor_tab[16] + +`r00`--`r19` are the residuals for the individiual samples, divided by the +scalefactor and quantized by the qoa_quant_tab[]. + +In the decoder, a prediction of the next sample is computed by multiplying the +state (the last four output samples) with the predictor. The residual from the +slice is then dequantized using the qoa_dequant_tab[] and added to the +prediction. The result is clamped to int16 to form the final output sample. + +*/ + + + +/* ----------------------------------------------------------------------------- + Header - Public functions */ + +#ifndef QOA_H +#define QOA_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define QOA_MIN_FILESIZE 16 +#define QOA_MAX_CHANNELS 8 + +#define QOA_SLICE_LEN 20 +#define QOA_SLICES_PER_FRAME 256 +#define QOA_FRAME_LEN (QOA_SLICES_PER_FRAME * QOA_SLICE_LEN) +#define QOA_LMS_LEN 4 +#define QOA_MAGIC 0x716f6166 /* 'qoaf' */ + +#define QOA_FRAME_SIZE(channels, slices) \ + (8 + QOA_LMS_LEN * 4 * channels + 8 * slices * channels) + +typedef struct { + int history[QOA_LMS_LEN]; + int weights[QOA_LMS_LEN]; +} qoa_lms_t; + +typedef struct { + unsigned int channels; + unsigned int samplerate; + unsigned int samples; + qoa_lms_t lms[QOA_MAX_CHANNELS]; + #ifdef QOA_RECORD_TOTAL_ERROR + double error; + #endif +} qoa_desc; + +unsigned int qoa_encode_header(qoa_desc *qoa, unsigned char *bytes); +unsigned int qoa_encode_frame(const short *sample_data, qoa_desc *qoa, unsigned int frame_len, unsigned char *bytes); +void *qoa_encode(const short *sample_data, qoa_desc *qoa, unsigned int *out_len); + +unsigned int qoa_max_frame_size(qoa_desc *qoa); +unsigned int qoa_decode_header(const unsigned char *bytes, int size, qoa_desc *qoa); +unsigned int qoa_decode_frame(const unsigned char *bytes, unsigned int size, qoa_desc *qoa, short *sample_data, unsigned int *frame_len); +short *qoa_decode(const unsigned char *bytes, int size, qoa_desc *file); + +#ifndef QOA_NO_STDIO + +int qoa_write(const char *filename, const short *sample_data, qoa_desc *qoa); +void *qoa_read(const char *filename, qoa_desc *qoa); + +#endif /* QOA_NO_STDIO */ + + +#ifdef __cplusplus +} +#endif +#endif /* QOA_H */ + + +/* ----------------------------------------------------------------------------- + Implementation */ + +#ifdef QOA_IMPLEMENTATION +#include + +#ifndef QOA_MALLOC + #define QOA_MALLOC(sz) malloc(sz) + #define QOA_FREE(p) free(p) +#endif + +typedef unsigned long long qoa_uint64_t; + + +/* The quant_tab provides an index into the dequant_tab for residuals in the +range of -8 .. 8. It maps this range to just 3bits and becommes less accurate at +the higher end. Note that the residual zero is identical to the lowest positive +value. This is mostly fine, since the qoa_div() function always rounds away +from zero. */ + +static int qoa_quant_tab[17] = { + 7, 7, 7, 5, 5, 3, 3, 1, /* -8..-1 */ + 0, /* 0 */ + 0, 2, 2, 4, 4, 6, 6, 6 /* 1.. 8 */ +}; + + +/* We have 16 different scalefactors. Like the quantized residuals these become +less accurate at the higher end. In theory, the highest scalefactor that we +would need to encode the highest 16bit residual is (2**16)/8 = 8192. However we +rely on the LMS filter to predict samples accurately enough that a maximum +residual of one quarter of the 16 bit range is high sufficent. I.e. with the +scalefactor 2048 times the quant range of 8 we can encode residuals up to 2**14. + +The scalefactor values are computed as: +scalefactor_tab[s] <- round(pow(s + 1, 2.75)) */ + +static int qoa_scalefactor_tab[16] = { + 1, 7, 21, 45, 84, 138, 211, 304, 421, 562, 731, 928, 1157, 1419, 1715, 2048 +}; + + +/* The reciprocal_tab maps each of the 16 scalefactors to their rounded +reciprocals 1/scalefactor. This allows us to calculate the scaled residuals in +the encoder with just one multiplication instead of an expensive division. We +do this in .16 fixed point with integers, instead of floats. + +The reciprocal_tab is computed as: +reciprocal_tab[s] <- ((1<<16) + scalefactor_tab[s] - 1) / scalefactor_tab[s] */ + +static int qoa_reciprocal_tab[16] = { + 65536, 9363, 3121, 1457, 781, 475, 311, 216, 156, 117, 90, 71, 57, 47, 39, 32 +}; + + +/* The dequant_tab maps each of the scalefactors and quantized residuals to +their unscaled & dequantized version. + +Since qoa_div rounds away from the zero, the smallest entries are mapped to 3/4 +instead of 1. The dequant_tab assumes the following dequantized values for each +of the quant_tab indices and is computed as: +float dqt[8] = {0.75, -0.75, 2.5, -2.5, 4.5, -4.5, 7, -7}; +dequant_tab[s][q] <- round(scalefactor_tab[s] * dqt[q]) */ + +static int qoa_dequant_tab[16][8] = { + { 1, -1, 3, -3, 5, -5, 7, -7}, + { 5, -5, 18, -18, 32, -32, 49, -49}, + { 16, -16, 53, -53, 95, -95, 147, -147}, + { 34, -34, 113, -113, 203, -203, 315, -315}, + { 63, -63, 210, -210, 378, -378, 588, -588}, + { 104, -104, 345, -345, 621, -621, 966, -966}, + { 158, -158, 528, -528, 950, -950, 1477, -1477}, + { 228, -228, 760, -760, 1368, -1368, 2128, -2128}, + { 316, -316, 1053, -1053, 1895, -1895, 2947, -2947}, + { 422, -422, 1405, -1405, 2529, -2529, 3934, -3934}, + { 548, -548, 1828, -1828, 3290, -3290, 5117, -5117}, + { 696, -696, 2320, -2320, 4176, -4176, 6496, -6496}, + { 868, -868, 2893, -2893, 5207, -5207, 8099, -8099}, + {1064, -1064, 3548, -3548, 6386, -6386, 9933, -9933}, + {1286, -1286, 4288, -4288, 7718, -7718, 12005, -12005}, + {1536, -1536, 5120, -5120, 9216, -9216, 14336, -14336}, +}; + + +/* The Least Mean Squares Filter is the heart of QOA. It predicts the next +sample based on the previous 4 reconstructed samples. It does so by continuously +adjusting 4 weights based on the residual of the previous prediction. + +The next sample is predicted as the sum of (weight[i] * history[i]). + +The adjustment of the weights is done with a "Sign-Sign-LMS" that adds or +subtracts the residual to each weight, based on the corresponding sample from +the history. This, suprisingly, is sufficent to get worthwhile predictions. + +This is all done with fixed point integers. Hence the right-shifts when updating +the weights and calculating the prediction. */ + +static int qoa_lms_predict(qoa_lms_t *lms) { + int prediction = 0; + for (int i = 0; i < QOA_LMS_LEN; i++) { + prediction += lms->weights[i] * lms->history[i]; + } + return prediction >> 13; +} + +static void qoa_lms_update(qoa_lms_t *lms, int sample, int residual) { + int delta = residual >> 4; + for (int i = 0; i < QOA_LMS_LEN; i++) { + lms->weights[i] += lms->history[i] < 0 ? -delta : delta; + } + + for (int i = 0; i < QOA_LMS_LEN-1; i++) { + lms->history[i] = lms->history[i+1]; + } + lms->history[QOA_LMS_LEN-1] = sample; +} + + +/* qoa_div() implements a rounding division, but avoids rounding to zero for +small numbers. E.g. 0.1 will be rounded to 1. Note that 0 itself still +returns as 0, which is handled in the qoa_quant_tab[]. +qoa_div() takes an index into the .16 fixed point qoa_reciprocal_tab as an +argument, so it can do the division with a cheaper integer multiplication. */ + +static inline int qoa_div(int v, int scalefactor) { + int reciprocal = qoa_reciprocal_tab[scalefactor]; + int n = (v * reciprocal + (1 << 15)) >> 16; + n = n + ((v > 0) - (v < 0)) - ((n > 0) - (n < 0)); /* round away from 0 */ + return n; +} + +static inline int qoa_clamp(int v, int min, int max) { + return (v < min) ? min : (v > max) ? max : v; +} + +static inline qoa_uint64_t qoa_read_u64(const unsigned char *bytes, unsigned int *p) { + qoa_uint64_t v = + (qoa_uint64_t)bytes[(*p)+0] << 56 | (qoa_uint64_t)bytes[(*p)+1] << 48 | + (qoa_uint64_t)bytes[(*p)+2] << 40 | (qoa_uint64_t)bytes[(*p)+3] << 32 | + (qoa_uint64_t)bytes[(*p)+4] << 24 | (qoa_uint64_t)bytes[(*p)+5] << 16 | + (qoa_uint64_t)bytes[(*p)+6] << 8 | (qoa_uint64_t)bytes[(*p)+7]; + *p += 8; + return v; +} + +static inline void qoa_write_u64(qoa_uint64_t v, unsigned char *bytes, unsigned int *p) { + bytes[(*p)++] = (v >> 56) & 0xff; + bytes[(*p)++] = (v >> 48) & 0xff; + bytes[(*p)++] = (v >> 40) & 0xff; + bytes[(*p)++] = (v >> 32) & 0xff; + bytes[(*p)++] = (v >> 24) & 0xff; + bytes[(*p)++] = (v >> 16) & 0xff; + bytes[(*p)++] = (v >> 8) & 0xff; + bytes[(*p)++] = (v >> 0) & 0xff; +} + + +/* ----------------------------------------------------------------------------- + Encoder */ + +unsigned int qoa_encode_header(qoa_desc *qoa, unsigned char *bytes) { + unsigned int p = 0; + qoa_write_u64(((qoa_uint64_t)QOA_MAGIC << 32) | qoa->samples, bytes, &p); + return p; +} + +unsigned int qoa_encode_frame(const short *sample_data, qoa_desc *qoa, unsigned int frame_len, unsigned char *bytes) { + unsigned int channels = qoa->channels; + + unsigned int p = 0; + unsigned int slices = (frame_len + QOA_SLICE_LEN - 1) / QOA_SLICE_LEN; + unsigned int frame_size = QOA_FRAME_SIZE(channels, slices); + + /* Write the frame header */ + qoa_write_u64(( + (qoa_uint64_t)qoa->channels << 56 | + (qoa_uint64_t)qoa->samplerate << 32 | + (qoa_uint64_t)frame_len << 16 | + (qoa_uint64_t)frame_size + ), bytes, &p); + + /* Write the current LMS state */ + for (int c = 0; c < channels; c++) { + qoa_uint64_t weights = 0; + qoa_uint64_t history = 0; + for (int i = 0; i < QOA_LMS_LEN; i++) { + history = (history << 16) | (qoa->lms[c].history[i] & 0xffff); + weights = (weights << 16) | (qoa->lms[c].weights[i] & 0xffff); + } + qoa_write_u64(history, bytes, &p); + qoa_write_u64(weights, bytes, &p); + } + + /* We encode all samples with the channels interleaved on a slice level. + E.g. for stereo: (ch-0, slice 0), (ch 1, slice 0), (ch 0, slice 1), ...*/ + for (int sample_index = 0; sample_index < frame_len; sample_index += QOA_SLICE_LEN) { + + for (int c = 0; c < channels; c++) { + int slice_len = qoa_clamp(QOA_SLICE_LEN, 0, frame_len - sample_index); + int slice_start = sample_index * channels + c; + int slice_end = (sample_index + slice_len) * channels + c; + + /* Brute for search for the best scalefactor. Just go through all + 16 scalefactors, encode all samples for the current slice and + meassure the total squared error. */ + qoa_uint64_t best_error = -1; + qoa_uint64_t best_slice; + qoa_lms_t best_lms; + + for (int scalefactor = 0; scalefactor < 16; scalefactor++) { + + /* We have to reset the LMS state to the last known good one + before trying each scalefactor, as each pass updates the LMS + state when encoding. */ + qoa_lms_t lms = qoa->lms[c]; + qoa_uint64_t slice = scalefactor; + qoa_uint64_t current_error = 0; + + for (int si = slice_start; si < slice_end; si += channels) { + int sample = sample_data[si]; + int predicted = qoa_lms_predict(&lms); + + int residual = sample - predicted; + int scaled = qoa_div(residual, scalefactor); + int clamped = qoa_clamp(scaled, -8, 8); + int quantized = qoa_quant_tab[clamped + 8]; + int dequantized = qoa_dequant_tab[scalefactor][quantized]; + int reconstructed = qoa_clamp(predicted + dequantized, -32768, 32767); + + int error = (sample - reconstructed); + current_error += error * error; + if (current_error > best_error) { + break; + } + + qoa_lms_update(&lms, reconstructed, dequantized); + slice = (slice << 3) | quantized; + } + + if (current_error < best_error) { + best_error = current_error; + best_slice = slice; + best_lms = lms; + } + } + + qoa->lms[c] = best_lms; + #ifdef QOA_RECORD_TOTAL_ERROR + qoa->error += best_error; + #endif + + /* If this slice was shorter than QOA_SLICE_LEN, we have to left- + shift all encoded data, to ensure the rightmost bits are the empty + ones. This should only happen in the last frame of a file as all + slices are completely filled otherwise. */ + best_slice <<= (QOA_SLICE_LEN - slice_len) * 3; + qoa_write_u64(best_slice, bytes, &p); + } + } + + return p; +} + +void *qoa_encode(const short *sample_data, qoa_desc *qoa, unsigned int *out_len) { + if ( + qoa->samples == 0 || + qoa->samplerate == 0 || qoa->samplerate > 0xffffff || + qoa->channels == 0 || qoa->channels > QOA_MAX_CHANNELS + ) { + return NULL; + } + + /* Calculate the encoded size and allocate */ + unsigned int num_frames = (qoa->samples + QOA_FRAME_LEN-1) / QOA_FRAME_LEN; + unsigned int num_slices = (qoa->samples + QOA_SLICE_LEN-1) / QOA_SLICE_LEN; + unsigned int encoded_size = 8 + /* 8 byte file header */ + num_frames * 8 + /* 8 byte frame headers */ + 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); + + for (int c = 0; c < qoa->channels; c++) { + /* Set the initial LMS weights to {0, 0, -1, 2}. This helps with the + prediction of the first few ms of a file. */ + qoa->lms[c].weights[0] = 0; + qoa->lms[c].weights[1] = 0; + qoa->lms[c].weights[2] = -(1<<13); + qoa->lms[c].weights[3] = (1<<14); + + /* Explicitly set the history samples to 0, as we might have some + garbage in there. */ + for (int i = 0; i < QOA_LMS_LEN; i++) { + qoa->lms[c].history[i] = 0; + } + } + + + /* Encode the header and go through all frames */ + unsigned int p = qoa_encode_header(qoa, bytes); + #ifdef QOA_RECORD_TOTAL_ERROR + qoa->error = 0; + #endif + + int frame_len = QOA_FRAME_LEN; + for (int sample_index = 0; sample_index < qoa->samples; sample_index += frame_len) { + frame_len = qoa_clamp(QOA_FRAME_LEN, 0, qoa->samples - sample_index); + const short *frame_samples = sample_data + sample_index * qoa->channels; + unsigned int frame_size = qoa_encode_frame(frame_samples, qoa, frame_len, bytes + p); + p += frame_size; + } + + *out_len = p; + return bytes; +} + + + +/* ----------------------------------------------------------------------------- + Decoder */ + +unsigned int qoa_max_frame_size(qoa_desc *qoa) { + return QOA_FRAME_SIZE(qoa->channels, QOA_SLICES_PER_FRAME); +} + +unsigned int qoa_decode_header(const unsigned char *bytes, int size, qoa_desc *qoa) { + unsigned int p = 0; + if (size < QOA_MIN_FILESIZE) { + return 0; + } + + + /* Read the file header, verify the magic number ('qoaf') and read the + total number of samples. */ + qoa_uint64_t file_header = qoa_read_u64(bytes, &p); + + if ((file_header >> 32) != QOA_MAGIC) { + return 0; + } + + qoa->samples = file_header & 0xffffffff; + if (!qoa->samples) { + return 0; + } + + /* Peek into the first frame header to get the number of channels and + the samplerate. */ + qoa_uint64_t frame_header = qoa_read_u64(bytes, &p); + qoa->channels = (frame_header >> 56) & 0x0000ff; + qoa->samplerate = (frame_header >> 32) & 0xffffff; + + if (qoa->channels == 0 || qoa->samples == 0 || qoa->samplerate == 0) { + return 0; + } + + return 8; +} + +unsigned int qoa_decode_frame(const unsigned char *bytes, unsigned int size, qoa_desc *qoa, short *sample_data, unsigned int *frame_len) { + unsigned int p = 0; + *frame_len = 0; + + if (size < 8 + QOA_LMS_LEN * 4 * qoa->channels) { + return 0; + } + + /* Read and verify the frame header */ + qoa_uint64_t frame_header = qoa_read_u64(bytes, &p); + int channels = (frame_header >> 56) & 0x0000ff; + int samplerate = (frame_header >> 32) & 0xffffff; + int samples = (frame_header >> 16) & 0x00ffff; + int frame_size = (frame_header ) & 0x00ffff; + + int data_size = frame_size - 8 - QOA_LMS_LEN * 4 * channels; + int num_slices = data_size / 8; + int max_total_samples = num_slices * QOA_SLICE_LEN; + + if ( + channels != qoa->channels || + samplerate != qoa->samplerate || + frame_size > size || + samples * channels > max_total_samples + ) { + return 0; + } + + + /* Read the LMS state: 4 x 2 bytes history, 4 x 2 bytes weights per channel */ + for (int c = 0; c < channels; c++) { + qoa_uint64_t history = qoa_read_u64(bytes, &p); + qoa_uint64_t weights = qoa_read_u64(bytes, &p); + for (int i = 0; i < QOA_LMS_LEN; i++) { + qoa->lms[c].history[i] = ((signed short)(history >> 48)); + history <<= 16; + qoa->lms[c].weights[i] = ((signed short)(weights >> 48)); + weights <<= 16; + } + } + + + /* Decode all slices for all channels in this frame */ + for (int sample_index = 0; sample_index < samples; sample_index += QOA_SLICE_LEN) { + for (int c = 0; c < channels; c++) { + qoa_uint64_t slice = qoa_read_u64(bytes, &p); + + int scalefactor = (slice >> 60) & 0xf; + int slice_start = sample_index * channels + c; + int slice_end = qoa_clamp(sample_index + QOA_SLICE_LEN, 0, samples) * channels + c; + + for (int si = slice_start; si < slice_end; si += channels) { + int predicted = qoa_lms_predict(&qoa->lms[c]); + int quantized = (slice >> 57) & 0x7; + int dequantized = qoa_dequant_tab[scalefactor][quantized]; + int reconstructed = qoa_clamp(predicted + dequantized, -32768, 32767); + + sample_data[si] = reconstructed; + slice <<= 3; + + qoa_lms_update(&qoa->lms[c], reconstructed, dequantized); + } + } + } + + *frame_len = samples; + return p; +} + +short *qoa_decode(const unsigned char *bytes, int size, qoa_desc *qoa) { + unsigned int p = qoa_decode_header(bytes, size, qoa); + if (!p) { + return NULL; + } + + /* 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)); + + unsigned int sample_index = 0; + unsigned int frame_len; + unsigned int frame_size; + + /* Decode all frames */ + do { + short *sample_ptr = sample_data + sample_index * qoa->channels; + frame_size = qoa_decode_frame(bytes + p, size - p, qoa, sample_ptr, &frame_len); + + p += frame_size; + sample_index += frame_len; + } while (frame_size && sample_index < qoa->samples); + + qoa->samples = sample_index; + return sample_data; +} + + + +/* ----------------------------------------------------------------------------- + File read/write convenience functions */ + +#ifndef QOA_NO_STDIO +#include + +int qoa_write(const char *filename, const short *sample_data, qoa_desc *qoa) { + FILE *f = fopen(filename, "wb"); + unsigned int size; + void *encoded; + + if (!f) { + return 0; + } + + encoded = qoa_encode(sample_data, qoa, &size); + if (!encoded) { + fclose(f); + return 0; + } + + fwrite(encoded, 1, size, f); + fclose(f); + + QOA_FREE(encoded); + return size; +} + +void *qoa_read(const char *filename, qoa_desc *qoa) { + FILE *f = fopen(filename, "rb"); + int size, bytes_read; + void *data; + short *sample_data; + + if (!f) { + return NULL; + } + + fseek(f, 0, SEEK_END); + size = ftell(f); + if (size <= 0) { + fclose(f); + return NULL; + } + fseek(f, 0, SEEK_SET); + + data = QOA_MALLOC(size); + if (!data) { + fclose(f); + return NULL; + } + + bytes_read = fread(data, 1, size, f); + fclose(f); + + sample_data = qoa_decode(data, bytes_read, qoa); + QOA_FREE(data); + return sample_data; +} + +#endif /* QOA_NO_STDIO */ +#endif /* QOA_IMPLEMENTATION */ diff --git a/src/raudio.c b/src/raudio.c index 591d6f69f43d..90de7fe9ec72 100644 --- a/src/raudio.c +++ b/src/raudio.c @@ -21,10 +21,11 @@ * * #define SUPPORT_FILEFORMAT_WAV * #define SUPPORT_FILEFORMAT_OGG +* #define SUPPORT_FILEFORMAT_MP3 +* #define SUPPORT_FILEFORMAT_QOA +* #define SUPPORT_FILEFORMAT_FLAC * #define SUPPORT_FILEFORMAT_XM * #define SUPPORT_FILEFORMAT_MOD -* #define SUPPORT_FILEFORMAT_FLAC -* #define SUPPORT_FILEFORMAT_MP3 * Selected desired fileformats to be supported for loading. Some of those formats are * supported by default, to remove support, just comment unrequired #define in this module * @@ -196,37 +197,6 @@ typedef struct tagBITMAPINFOHEADER { #endif #endif -#if defined(SUPPORT_FILEFORMAT_OGG) - // TODO: Remap stb_vorbis malloc()/free() calls to RL_MALLOC/RL_FREE - #include "external/stb_vorbis.c" // OGG loading functions -#endif - -#if defined(SUPPORT_FILEFORMAT_XM) - #define JARXM_MALLOC RL_MALLOC - #define JARXM_FREE RL_FREE - -#if defined(_MSC_VER ) // jar xm has warnings on windows, so disable them just for this file -#pragma warning( push ) -#pragma warning( disable : 4244) -#endif - - #define JAR_XM_IMPLEMENTATION - #include "external/jar_xm.h" // XM loading functions - -#if defined(_MSC_VER ) -#pragma warning( pop ) -#endif - -#endif - -#if defined(SUPPORT_FILEFORMAT_MOD) - #define JARMOD_MALLOC RL_MALLOC - #define JARMOD_FREE RL_FREE - - #define JAR_MOD_IMPLEMENTATION - #include "external/jar_mod.h" // MOD loading functions -#endif - #if defined(SUPPORT_FILEFORMAT_WAV) #define DRWAV_MALLOC RL_MALLOC #define DRWAV_REALLOC RL_REALLOC @@ -236,6 +206,11 @@ typedef struct tagBITMAPINFOHEADER { #include "external/dr_wav.h" // WAV loading functions #endif +#if defined(SUPPORT_FILEFORMAT_OGG) + // TODO: Remap stb_vorbis malloc()/free() calls to RL_MALLOC/RL_FREE + #include "external/stb_vorbis.c" // OGG loading functions +#endif + #if defined(SUPPORT_FILEFORMAT_MP3) #define DRMP3_MALLOC RL_MALLOC #define DRMP3_REALLOC RL_REALLOC @@ -245,6 +220,14 @@ typedef struct tagBITMAPINFOHEADER { #include "external/dr_mp3.h" // MP3 loading functions #endif +#if defined(SUPPORT_FILEFORMAT_QOA) + #define QOA_MALLOC RL_MALLOC + #define QOA_FREE RL_FREE + + #define QOA_IMPLEMENTATION + #include "external/qoa.h" // QOA loading and saving functions +#endif + #if defined(SUPPORT_FILEFORMAT_FLAC) #define DRFLAC_MALLOC RL_MALLOC #define DRFLAC_REALLOC RL_REALLOC @@ -255,6 +238,31 @@ typedef struct tagBITMAPINFOHEADER { #include "external/dr_flac.h" // FLAC loading functions #endif +#if defined(SUPPORT_FILEFORMAT_XM) + #define JARXM_MALLOC RL_MALLOC + #define JARXM_FREE RL_FREE + + #if defined(_MSC_VER ) // jar_xm has warnings on windows, so disable them just for this file + #pragma warning( push ) + #pragma warning( disable : 4244) + #endif + + #define JAR_XM_IMPLEMENTATION + #include "external/jar_xm.h" // XM loading functions + + #if defined(_MSC_VER ) + #pragma warning( pop ) + #endif +#endif + +#if defined(SUPPORT_FILEFORMAT_MOD) + #define JARMOD_MALLOC RL_MALLOC + #define JARMOD_FREE RL_FREE + + #define JAR_MOD_IMPLEMENTATION + #include "external/jar_mod.h" // MOD loading functions +#endif + //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- @@ -285,6 +293,7 @@ typedef enum { MUSIC_AUDIO_OGG, // OGG audio context MUSIC_AUDIO_FLAC, // FLAC audio context MUSIC_AUDIO_MP3, // MP3 audio context + MUSIC_AUDIO_QOA, // QOA audio context MUSIC_MODULE_XM, // XM module audio context MUSIC_MODULE_MOD // MOD module audio context } MusicContextType; @@ -795,19 +804,6 @@ Wave LoadWaveFromMemory(const char *fileType, const unsigned char *fileData, int else TRACELOG(LOG_WARNING, "WAVE: Failed to load OGG data"); } #endif -#if defined(SUPPORT_FILEFORMAT_FLAC) - else if (strcmp(fileType, ".flac") == 0) - { - unsigned long long int totalFrameCount = 0; - - // NOTE: We are forcing conversion to 16bit sample size on reading - wave.data = drflac_open_memory_and_read_pcm_frames_s16(fileData, dataSize, &wave.channels, &wave.sampleRate, &totalFrameCount, NULL); - wave.sampleSize = 16; - - if (wave.data != NULL) wave.frameCount = (unsigned int)totalFrameCount; - else TRACELOG(LOG_WARNING, "WAVE: Failed to load FLAC data"); - } -#endif #if defined(SUPPORT_FILEFORMAT_MP3) else if (strcmp(fileType, ".mp3") == 0) { @@ -827,6 +823,38 @@ Wave LoadWaveFromMemory(const char *fileType, const unsigned char *fileData, int else TRACELOG(LOG_WARNING, "WAVE: Failed to load MP3 data"); } +#endif +#if defined(SUPPORT_FILEFORMAT_QOA) + else if (strcmp(fileType, ".qoa") == 0) + { + qoa_desc qoa = { 0 }; + + // NOTE: Returned sample data is always 16 bit? + wave.data = qoa_decode(fileData, dataSize, &qoa); + wave.sampleSize = 16; + + if (wave.data != NULL) + { + wave.channels = qoa.channels; + wave.sampleRate = qoa.samplerate; + wave.frameCount = qoa.samples; + } + else TRACELOG(LOG_WARNING, "WAVE: Failed to load QOA data"); + + } +#endif +#if defined(SUPPORT_FILEFORMAT_FLAC) + else if (strcmp(fileType, ".flac") == 0) + { + unsigned long long int totalFrameCount = 0; + + // NOTE: We are forcing conversion to 16bit sample size on reading + wave.data = drflac_open_memory_and_read_pcm_frames_s16(fileData, dataSize, &wave.channels, &wave.sampleRate, &totalFrameCount, NULL); + wave.sampleSize = 16; + + if (wave.data != NULL) wave.frameCount = (unsigned int)totalFrameCount; + else TRACELOG(LOG_WARNING, "WAVE: Failed to load FLAC data"); + } #endif else TRACELOG(LOG_WARNING, "WAVE: Data format not supported"); @@ -1316,23 +1344,6 @@ Music LoadMusicStream(const char *fileName) } } #endif -#if defined(SUPPORT_FILEFORMAT_FLAC) - else if (IsFileExtension(fileName, ".flac")) - { - music.ctxType = MUSIC_AUDIO_FLAC; - music.ctxData = drflac_open_file(fileName, NULL); - - if (music.ctxData != NULL) - { - drflac *ctxFlac = (drflac *)music.ctxData; - - music.stream = LoadAudioStream(ctxFlac->sampleRate, ctxFlac->bitsPerSample, ctxFlac->channels); - music.frameCount = (unsigned int)ctxFlac->totalPCMFrameCount; - music.looping = true; // Looping enabled by default - musicLoaded = true; - } - } -#endif #if defined(SUPPORT_FILEFORMAT_MP3) else if (IsFileExtension(fileName, ".mp3")) { @@ -1351,6 +1362,45 @@ Music LoadMusicStream(const char *fileName) } } #endif +#if defined(SUPPORT_FILEFORMAT_QOA) + else if (IsFileExtension(fileName, ".qoa")) + { + qoa_desc *ctxQoa = RL_CALLOC(1, sizeof(qoa_desc)); + + // TODO: QOA stream support: Init context from file + + music.ctxType = MUSIC_AUDIO_QOA; + music.ctxData = ctxQoa; + + if (result > 0) + { + music.stream = LoadAudioStream(ctxQoa->samplerate, 16, ctxQoa->channels); + + // TODO: Read next frame(s) from QOA stream + //music.frameCount = qoa_decode_frame(const unsigned char *bytes, unsigned int size, ctxQoa, short *sample_data, unsigned int *frame_len); + + music.looping = true; // Looping enabled by default + musicLoaded = true; + } + } +#endif +#if defined(SUPPORT_FILEFORMAT_FLAC) + else if (IsFileExtension(fileName, ".flac")) + { + music.ctxType = MUSIC_AUDIO_FLAC; + music.ctxData = drflac_open_file(fileName, NULL); + + if (music.ctxData != NULL) + { + drflac *ctxFlac = (drflac *)music.ctxData; + + music.stream = LoadAudioStream(ctxFlac->sampleRate, ctxFlac->bitsPerSample, ctxFlac->channels); + music.frameCount = (unsigned int)ctxFlac->totalPCMFrameCount; + music.looping = true; // Looping enabled by default + musicLoaded = true; + } + } +#endif #if defined(SUPPORT_FILEFORMAT_XM) else if (IsFileExtension(fileName, ".xm")) { @@ -1408,12 +1458,15 @@ Music LoadMusicStream(const char *fileName) #if defined(SUPPORT_FILEFORMAT_OGG) else if (music.ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close((stb_vorbis *)music.ctxData); #endif - #if defined(SUPPORT_FILEFORMAT_FLAC) - else if (music.ctxType == MUSIC_AUDIO_FLAC) drflac_free((drflac *)music.ctxData, NULL); - #endif #if defined(SUPPORT_FILEFORMAT_MP3) else if (music.ctxType == MUSIC_AUDIO_MP3) { drmp3_uninit((drmp3 *)music.ctxData); RL_FREE(music.ctxData); } #endif + #if defined(SUPPORT_FILEFORMAT_QOA) + else if (music.ctxType == MUSIC_AUDIO_QOA) { /*TODO: Release QOA context data*/ RL_FREE(music.ctxData); } + #endif + #if defined(SUPPORT_FILEFORMAT_FLAC) + else if (music.ctxType == MUSIC_AUDIO_FLAC) drflac_free((drflac *)music.ctxData, NULL); + #endif #if defined(SUPPORT_FILEFORMAT_XM) else if (music.ctxType == MUSIC_MODULE_XM) jar_xm_free_context((jar_xm_context_t *)music.ctxData); #endif @@ -1467,18 +1520,23 @@ Music LoadMusicStreamFromMemory(const char *fileType, const unsigned char *data, } } #endif -#if defined(SUPPORT_FILEFORMAT_FLAC) - else if (strcmp(fileType, ".flac") == 0) +#if defined(SUPPORT_FILEFORMAT_OGG) + else if (strcmp(fileType, ".ogg") == 0) { - music.ctxType = MUSIC_AUDIO_FLAC; - music.ctxData = drflac_open_memory((const void*)data, dataSize, NULL); + // Open ogg audio stream + music.ctxType = MUSIC_AUDIO_OGG; + //music.ctxData = stb_vorbis_open_filename(fileName, NULL, NULL); + music.ctxData = stb_vorbis_open_memory((const unsigned char *)data, dataSize, NULL, NULL); if (music.ctxData != NULL) { - drflac *ctxFlac = (drflac *)music.ctxData; + stb_vorbis_info info = stb_vorbis_get_info((stb_vorbis *)music.ctxData); // Get Ogg file info - music.stream = LoadAudioStream(ctxFlac->sampleRate, ctxFlac->bitsPerSample, ctxFlac->channels); - music.frameCount = (unsigned int)ctxFlac->totalPCMFrameCount; + // OGG bit rate defaults to 16 bit, it's enough for compressed format + music.stream = LoadAudioStream(info.sample_rate, 16, info.channels); + + // WARNING: It seems this function returns length in frames, not samples, so we multiply by channels + music.frameCount = (unsigned int)stb_vorbis_stream_length_in_samples((stb_vorbis *)music.ctxData); music.looping = true; // Looping enabled by default musicLoaded = true; } @@ -1502,23 +1560,40 @@ Music LoadMusicStreamFromMemory(const char *fileType, const unsigned char *data, } } #endif -#if defined(SUPPORT_FILEFORMAT_OGG) - else if (strcmp(fileType, ".ogg") == 0) +#if defined(SUPPORT_FILEFORMAT_QOA) + else if (strcmp(fileType, ".qoa") == 0) { - // Open ogg audio stream - music.ctxType = MUSIC_AUDIO_OGG; - //music.ctxData = stb_vorbis_open_filename(fileName, NULL, NULL); - music.ctxData = stb_vorbis_open_memory((const unsigned char *)data, dataSize, NULL, NULL); + qoa_desc *ctxQoa = RL_CALLOC(1, sizeof(qoa_desc)); + + // TODO: Init QOA context data + + music.ctxType = MUSIC_AUDIO_QOA; + music.ctxData = ctxQoa; - if (music.ctxData != NULL) + if (success) { - stb_vorbis_info info = stb_vorbis_get_info((stb_vorbis *)music.ctxData); // Get Ogg file info + music.stream = LoadAudioStream(ctxQoa->samplerate, 16, ctxQoa->channels); + + // TODO: Read next frame(s) from QOA stream + //music.frameCount = qoa_decode_frame(const unsigned char *bytes, unsigned int size, ctxQoa, short *sample_data, unsigned int *frame_len); + + music.looping = true; // Looping enabled by default + musicLoaded = true; + } + } +#endif +#if defined(SUPPORT_FILEFORMAT_FLAC) + else if (strcmp(fileType, ".flac") == 0) + { + music.ctxType = MUSIC_AUDIO_FLAC; + music.ctxData = drflac_open_memory((const void*)data, dataSize, NULL); - // OGG bit rate defaults to 16 bit, it's enough for compressed format - music.stream = LoadAudioStream(info.sample_rate, 16, info.channels); + if (music.ctxData != NULL) + { + drflac *ctxFlac = (drflac *)music.ctxData; - // WARNING: It seems this function returns length in frames, not samples, so we multiply by channels - music.frameCount = (unsigned int)stb_vorbis_stream_length_in_samples((stb_vorbis *)music.ctxData); + music.stream = LoadAudioStream(ctxFlac->sampleRate, ctxFlac->bitsPerSample, ctxFlac->channels); + music.frameCount = (unsigned int)ctxFlac->totalPCMFrameCount; music.looping = true; // Looping enabled by default musicLoaded = true; } @@ -1593,14 +1668,17 @@ Music LoadMusicStreamFromMemory(const char *fileType, const unsigned char *data, #if defined(SUPPORT_FILEFORMAT_WAV) else if (music.ctxType == MUSIC_AUDIO_WAV) drwav_uninit((drwav *)music.ctxData); #endif - #if defined(SUPPORT_FILEFORMAT_FLAC) - else if (music.ctxType == MUSIC_AUDIO_FLAC) drflac_free((drflac *)music.ctxData, NULL); + #if defined(SUPPORT_FILEFORMAT_OGG) + else if (music.ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close((stb_vorbis *)music.ctxData); #endif #if defined(SUPPORT_FILEFORMAT_MP3) else if (music.ctxType == MUSIC_AUDIO_MP3) { drmp3_uninit((drmp3 *)music.ctxData); RL_FREE(music.ctxData); } #endif - #if defined(SUPPORT_FILEFORMAT_OGG) - else if (music.ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close((stb_vorbis *)music.ctxData); + #if defined(SUPPORT_FILEFORMAT_QOA) + else if (music.ctxType == MUSIC_AUDIO_QOA) { /*TODO: Release QOA context*/ RL_FREE(music.ctxData); } + #endif + #if defined(SUPPORT_FILEFORMAT_FLAC) + else if (music.ctxType == MUSIC_AUDIO_FLAC) drflac_free((drflac *)music.ctxData, NULL); #endif #if defined(SUPPORT_FILEFORMAT_XM) else if (music.ctxType == MUSIC_MODULE_XM) jar_xm_free_context((jar_xm_context_t *)music.ctxData); @@ -1645,12 +1723,15 @@ void UnloadMusicStream(Music music) #if defined(SUPPORT_FILEFORMAT_OGG) else if (music.ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close((stb_vorbis *)music.ctxData); #endif -#if defined(SUPPORT_FILEFORMAT_FLAC) - else if (music.ctxType == MUSIC_AUDIO_FLAC) drflac_free((drflac *)music.ctxData, NULL); -#endif #if defined(SUPPORT_FILEFORMAT_MP3) else if (music.ctxType == MUSIC_AUDIO_MP3) { drmp3_uninit((drmp3 *)music.ctxData); RL_FREE(music.ctxData); } #endif +#if defined(SUPPORT_FILEFORMAT_QOA) + else if (music.ctxType == MUSIC_AUDIO_QOA) { /*TODO: Release QOA context*/ RL_FREE(music.ctxData); } +#endif +#if defined(SUPPORT_FILEFORMAT_FLAC) + else if (music.ctxType == MUSIC_AUDIO_FLAC) drflac_free((drflac *)music.ctxData, NULL); +#endif #if defined(SUPPORT_FILEFORMAT_XM) else if (music.ctxType == MUSIC_MODULE_XM) jar_xm_free_context((jar_xm_context_t *)music.ctxData); #endif @@ -1700,12 +1781,15 @@ void StopMusicStream(Music music) #if defined(SUPPORT_FILEFORMAT_OGG) case MUSIC_AUDIO_OGG: stb_vorbis_seek_start((stb_vorbis *)music.ctxData); break; #endif -#if defined(SUPPORT_FILEFORMAT_FLAC) - case MUSIC_AUDIO_FLAC: drflac__seek_to_first_frame((drflac *)music.ctxData); break; -#endif #if defined(SUPPORT_FILEFORMAT_MP3) case MUSIC_AUDIO_MP3: drmp3_seek_to_start_of_stream((drmp3 *)music.ctxData); break; #endif +#if defined(SUPPORT_FILEFORMAT_QOA) + case MUSIC_AUDIO_QOA: /*TODO: Restart QOA context to beginning*/ break; +#endif +#if defined(SUPPORT_FILEFORMAT_FLAC) + case MUSIC_AUDIO_FLAC: drflac__seek_to_first_frame((drflac *)music.ctxData); break; +#endif #if defined(SUPPORT_FILEFORMAT_XM) case MUSIC_MODULE_XM: jar_xm_reset((jar_xm_context_t *)music.ctxData); break; #endif @@ -1732,11 +1816,14 @@ void SeekMusicStream(Music music, float position) #if defined(SUPPORT_FILEFORMAT_OGG) case MUSIC_AUDIO_OGG: stb_vorbis_seek_frame((stb_vorbis *)music.ctxData, positionInFrames); break; #endif -#if defined(SUPPORT_FILEFORMAT_FLAC) - case MUSIC_AUDIO_FLAC: drflac_seek_to_pcm_frame((drflac *)music.ctxData, positionInFrames); break; -#endif #if defined(SUPPORT_FILEFORMAT_MP3) case MUSIC_AUDIO_MP3: drmp3_seek_to_pcm_frame((drmp3 *)music.ctxData, positionInFrames); break; +#endif +#if defined(SUPPORT_FILEFORMAT_QOA) + case MUSIC_AUDIO_QOA: /*TODO: Seek to specific QOA frame*/ break; +#endif +#if defined(SUPPORT_FILEFORMAT_FLAC) + case MUSIC_AUDIO_FLAC: drflac_seek_to_pcm_frame((drflac *)music.ctxData, positionInFrames); break; #endif default: break; } @@ -1754,6 +1841,7 @@ void UpdateMusicStream(Music music) // On first call of this function we lazily pre-allocated a temp buffer to read audio files/memory data in int frameSize = music.stream.channels*music.stream.sampleSize/8; unsigned int pcmSize = subBufferSizeInFrames*frameSize; + if (AUDIO.System.pcmBufferSize < pcmSize) { RL_FREE(AUDIO.System.pcmBuffer); @@ -1815,29 +1903,35 @@ void UpdateMusicStream(Music music) } } break; #endif - #if defined(SUPPORT_FILEFORMAT_FLAC) - case MUSIC_AUDIO_FLAC: + #if defined(SUPPORT_FILEFORMAT_MP3) + case MUSIC_AUDIO_MP3: { while (true) { - int frameCountRed = drflac_read_pcm_frames_s16((drflac *)music.ctxData, frameCountStillNeeded, (short *)((char *)AUDIO.System.pcmBuffer + frameCountRedTotal*frameSize)); + int frameCountRed = (int)drmp3_read_pcm_frames_f32((drmp3 *)music.ctxData, frameCountStillNeeded, (float *)((char *)AUDIO.System.pcmBuffer + frameCountRedTotal*frameSize)); frameCountRedTotal += frameCountRed; frameCountStillNeeded -= frameCountRed; if (frameCountStillNeeded == 0) break; - else drflac__seek_to_first_frame((drflac *)music.ctxData); + else drmp3_seek_to_start_of_stream((drmp3 *)music.ctxData); } } break; #endif - #if defined(SUPPORT_FILEFORMAT_MP3) - case MUSIC_AUDIO_MP3: + #if defined(SUPPORT_FILEFORMAT_QOA) + case MUSIC_AUDIO_QOA: + { + // TODO: Read QOA required framecount to fill buffer to keep music playing + } break; + #endif + #if defined(SUPPORT_FILEFORMAT_FLAC) + case MUSIC_AUDIO_FLAC: { while (true) { - int frameCountRed = (int)drmp3_read_pcm_frames_f32((drmp3 *)music.ctxData, frameCountStillNeeded, (float *)((char *)AUDIO.System.pcmBuffer + frameCountRedTotal*frameSize)); + int frameCountRed = drflac_read_pcm_frames_s16((drflac *)music.ctxData, frameCountStillNeeded, (short *)((char *)AUDIO.System.pcmBuffer + frameCountRedTotal*frameSize)); frameCountRedTotal += frameCountRed; frameCountStillNeeded -= frameCountRed; if (frameCountStillNeeded == 0) break; - else drmp3_seek_to_start_of_stream((drmp3 *)music.ctxData); + else drflac__seek_to_first_frame((drflac *)music.ctxData); } } break; #endif From 589892af07e8ee7392f9ab7b8c9bb0f8263c4e48 Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 4 Feb 2023 20:27:47 +0100 Subject: [PATCH 081/192] Support QOA audio format on `ExportWave()` -WIP- --- src/raudio.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/raudio.c b/src/raudio.c index 90de7fe9ec72..c66a99c19d62 100644 --- a/src/raudio.c +++ b/src/raudio.c @@ -985,6 +985,18 @@ bool ExportWave(Wave wave, const char *fileName) drwav_free(fileData, NULL); } +#endif +#if defined(SUPPORT_FILEFORMAT_QOA) + else if (IsFileExtension(fileName, ".qoa")) + { + qoa_desc qoa = { 0 }; + qoa.channels = wave.channels; + qoa.samplerate = wave.sampleRate; + qoa.samples = wave.frameCount; + + // TODO: Review wave.data format required for export + success = qoa_write(fileName, wave.data, &qoa); + } #endif else if (IsFileExtension(fileName, ".raw")) { From 8c50da167de3854c4be2f0690a3e801e7723f980 Mon Sep 17 00:00:00 2001 From: HKrogstie Date: Sun, 5 Feb 2023 11:04:30 +0100 Subject: [PATCH 082/192] fix DrawMesh using SHADER_LOC_COLOR_SPECULAR as a material map (#2908) (#2909) --- src/rmodels.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/rmodels.c b/src/rmodels.c index 3c9384d2db97..3976b92e52a0 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -1373,10 +1373,10 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform) if (material.shader.locs[SHADER_LOC_COLOR_SPECULAR] != -1) { float values[4] = { - (float)material.maps[SHADER_LOC_COLOR_SPECULAR].color.r/255.0f, - (float)material.maps[SHADER_LOC_COLOR_SPECULAR].color.g/255.0f, - (float)material.maps[SHADER_LOC_COLOR_SPECULAR].color.b/255.0f, - (float)material.maps[SHADER_LOC_COLOR_SPECULAR].color.a/255.0f + (float)material.maps[MATERIAL_MAP_SPECULAR].color.r/255.0f, + (float)material.maps[MATERIAL_MAP_SPECULAR].color.g/255.0f, + (float)material.maps[MATERIAL_MAP_SPECULAR].color.b/255.0f, + (float)material.maps[MATERIAL_MAP_SPECULAR].color.a/255.0f }; rlSetUniform(material.shader.locs[SHADER_LOC_COLOR_SPECULAR], values, SHADER_UNIFORM_VEC4, 1); From 60d0ab418a3011fe5df663ac4be37ee53bcc5393 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 5 Feb 2023 11:44:12 +0100 Subject: [PATCH 083/192] some typos review --- src/raymath.h | 4 ++-- src/rcore.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/raymath.h b/src/raymath.h index 96c241843a6e..86134d090d74 100644 --- a/src/raymath.h +++ b/src/raymath.h @@ -912,7 +912,7 @@ RMAPI Vector3 Vector3Unproject(Vector3 source, Matrix projection, Matrix view) { Vector3 result = { 0 }; - // Calculate unproject matrix (multiply view matrix by projection matrix) and invert it + // Calculate unprojected matrix (multiply view matrix by projection matrix) and invert it Matrix matViewProj = { // MatrixMultiply(view, projection); view.m0*projection.m0 + view.m1*projection.m4 + view.m2*projection.m8 + view.m3*projection.m12, view.m0*projection.m1 + view.m1*projection.m5 + view.m2*projection.m9 + view.m3*projection.m13, @@ -975,7 +975,7 @@ RMAPI Vector3 Vector3Unproject(Vector3 source, Matrix projection, Matrix view) // Create quaternion from source point Quaternion quat = { source.x, source.y, source.z, 1.0f }; - // Multiply quat point by unproject matrix + // Multiply quat point by unprojecte matrix Quaternion qtransformed = { // QuaternionTransform(quat, matViewProjInv) matViewProjInv.m0*quat.x + matViewProjInv.m4*quat.y + matViewProjInv.m8*quat.z + matViewProjInv.m12*quat.w, matViewProjInv.m1*quat.x + matViewProjInv.m5*quat.y + matViewProjInv.m9*quat.z + matViewProjInv.m13*quat.w, diff --git a/src/rcore.c b/src/rcore.c index f2f0cbbe0b97..ee88727d534a 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -3032,7 +3032,7 @@ const char *GetDirectoryPath(const char *filePath) if (filePath[1] != ':' && filePath[0] != '\\' && filePath[0] != '/') { // For security, we set starting path to current directory, - // obtained path will be concated to this + // obtained path will be concatenated to this dirPath[0] = '.'; dirPath[1] = '/'; } From ff70a04bf5e2aea84fe9d71cede790e1a031f810 Mon Sep 17 00:00:00 2001 From: star-tek-mb Date: Sun, 5 Feb 2023 17:03:03 +0500 Subject: [PATCH 084/192] update zig build to latest master (#2910) also, adds package manager support --- build.zig | 18 ++++++++++++++++++ examples/build.zig | 34 ++++++++++++++++++---------------- src/build.zig | 15 +++++++++++---- 3 files changed, 47 insertions(+), 20 deletions(-) create mode 100644 build.zig diff --git a/build.zig b/build.zig new file mode 100644 index 000000000000..9959d8e0c099 --- /dev/null +++ b/build.zig @@ -0,0 +1,18 @@ +const std = @import("std"); +const raylib = @import("src/build.zig"); + +pub fn build(b: *std.Build) void { + // Standard target options allows the person running `zig build` to choose + // what target to build for. Here we do not override the defaults, which + // means any target is allowed, and the default is native. Other options + // for restricting supported target set are available. + const target = b.standardTargetOptions(.{}); + // Standard optimization options allow the person running `zig build` to select + // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not + // set a preferred release mode, allowing the user to decide how to optimize. + const optimize = b.standardOptimizeOption(.{}); + + const lib = raylib.addRaylib(b, target, optimize); + lib.installHeader("src/raylib.h", "raylib.h"); + lib.install(); +} \ No newline at end of file diff --git a/examples/build.zig b/examples/build.zig index eb040fd2ffcd..c0479910f4a2 100644 --- a/examples/build.zig +++ b/examples/build.zig @@ -1,15 +1,11 @@ const std = @import("std"); const builtin = @import("builtin"); -fn add_module(comptime module: []const u8, b: *std.build.Builder, target: std.zig.CrossTarget) !*std.build.Step { +fn add_module(comptime module: []const u8, b: *std.build.Builder, target: std.zig.CrossTarget, optimize: std.builtin.OptimizeMode) !*std.build.Step { if (target.getOsTag() == .emscripten) { @panic("Emscripten building via Zig unsupported"); } - // Standard release options allow the person running `zig build` to select - // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. - const mode = b.standardReleaseOptions(); - const all = b.step(module, "All " ++ module ++ " examples"); const dir = try std.fs.cwd().openIterableDir(module, .{}); var iter = dir.iterate(); @@ -22,10 +18,12 @@ fn add_module(comptime module: []const u8, b: *std.build.Builder, target: std.zi // zig's mingw headers do not include pthread.h if (std.mem.eql(u8, "core_loading_thread", name) and target.getOsTag() == .windows) continue; - const exe = b.addExecutable(name, null); + const exe = b.addExecutable(.{ + .name = name, + .target = target, + .optimize = optimize, + }); exe.addCSourceFile(path, &[_][]const u8{}); - exe.setTarget(target); - exe.setBuildMode(mode); exe.linkLibC(); exe.addObjectFile(switch (target.getOsTag()) { .windows => "../src/raylib.lib", @@ -89,15 +87,19 @@ pub fn build(b: *std.build.Builder) !void { // means any target is allowed, and the default is native. Other options // for restricting supported target set are available. const target = b.standardTargetOptions(.{}); + // Standard optimization options allow the person running `zig build` to select + // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not + // set a preferred release mode, allowing the user to decide how to optimize. + const optimize = b.standardOptimizeOption(.{}); const all = b.getInstallStep(); - all.dependOn(try add_module("audio", b, target)); - all.dependOn(try add_module("core", b, target)); - all.dependOn(try add_module("models", b, target)); - all.dependOn(try add_module("others", b, target)); - all.dependOn(try add_module("shaders", b, target)); - all.dependOn(try add_module("shapes", b, target)); - all.dependOn(try add_module("text", b, target)); - all.dependOn(try add_module("textures", b, target)); + all.dependOn(try add_module("audio", b, target, optimize)); + all.dependOn(try add_module("core", b, target, optimize)); + all.dependOn(try add_module("models", b, target, optimize)); + all.dependOn(try add_module("others", b, target, optimize)); + all.dependOn(try add_module("shaders", b, target, optimize)); + all.dependOn(try add_module("shapes", b, target, optimize)); + all.dependOn(try add_module("text", b, target, optimize)); + all.dependOn(try add_module("textures", b, target, optimize)); } diff --git a/src/build.zig b/src/build.zig index 919db3e9fbcf..adf7fdc9dcf7 100644 --- a/src/build.zig +++ b/src/build.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn addRaylib(b: *std.build.Builder, target: std.zig.CrossTarget) *std.build.LibExeObjStep { +pub fn addRaylib(b: *std.build.Builder, target: std.zig.CrossTarget, optimize: std.builtin.OptimizeMode) *std.build.LibExeObjStep { const raylib_flags = &[_][]const u8{ "-std=gnu99", "-D_GNU_SOURCE", @@ -8,8 +8,11 @@ pub fn addRaylib(b: *std.build.Builder, target: std.zig.CrossTarget) *std.build. "-fno-sanitize=undefined", // https://github.com/raysan5/raylib/issues/1891 }; - const raylib = b.addStaticLibrary("raylib", null); - raylib.setTarget(target); + const raylib = b.addStaticLibrary(.{ + .name = "raylib", + .target = target, + .optimize = optimize, + }); raylib.linkLibC(); raylib.addIncludePath(srcdir ++ "/external/glfw/include"); @@ -106,8 +109,12 @@ pub fn build(b: *std.build.Builder) void { // means any target is allowed, and the default is native. Other options // for restricting supported target set are available. const target = b.standardTargetOptions(.{}); + // Standard optimization options allow the person running `zig build` to select + // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not + // set a preferred release mode, allowing the user to decide how to optimize. + const optimize = b.standardOptimizeOption(.{}); - const lib = addRaylib(b, target); + const lib = addRaylib(b, target, optimize); lib.setOutputDir(srcdir); lib.install(); } From c91190fc6e9355f58c15a0a17990ca9b450aaf5d Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 5 Feb 2023 16:28:04 +0100 Subject: [PATCH 085/192] Review QOA sound loading -WIP- --- src/raudio.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/raudio.c b/src/raudio.c index c66a99c19d62..524aaef43e56 100644 --- a/src/raudio.c +++ b/src/raudio.c @@ -829,18 +829,26 @@ Wave LoadWaveFromMemory(const char *fileType, const unsigned char *fileData, int { qoa_desc qoa = { 0 }; - // NOTE: Returned sample data is always 16 bit? - wave.data = qoa_decode(fileData, dataSize, &qoa); - wave.sampleSize = 16; - - if (wave.data != NULL) + unsigned int result = qoa_decode_header(fileData, dataSize, &qoa); + + if (result > 0) { - wave.channels = qoa.channels; - wave.sampleRate = qoa.samplerate; + + // Calculate the total audio frame count wave.frameCount = qoa.samples; + + // NOTE: Returned sample data is always 16 bit + wave.data = qoa_decode(fileData, dataSize, &qoa); + wave.sampleSize = 16; + + if (wave.data != NULL) + { + wave.channels = qoa.channels; + wave.sampleRate = qoa.samplerate; + } + else TRACELOG(LOG_WARNING, "WAVE: Failed to load QOA data"); } else TRACELOG(LOG_WARNING, "WAVE: Failed to load QOA data"); - } #endif #if defined(SUPPORT_FILEFORMAT_FLAC) @@ -1380,6 +1388,7 @@ Music LoadMusicStream(const char *fileName) qoa_desc *ctxQoa = RL_CALLOC(1, sizeof(qoa_desc)); // TODO: QOA stream support: Init context from file + int result = 0; music.ctxType = MUSIC_AUDIO_QOA; music.ctxData = ctxQoa; @@ -1578,11 +1587,12 @@ Music LoadMusicStreamFromMemory(const char *fileType, const unsigned char *data, qoa_desc *ctxQoa = RL_CALLOC(1, sizeof(qoa_desc)); // TODO: Init QOA context data + int result = 0; music.ctxType = MUSIC_AUDIO_QOA; music.ctxData = ctxQoa; - if (success) + if (result > 0) { music.stream = LoadAudioStream(ctxQoa->samplerate, 16, ctxQoa->channels); From 1fea26647214308774c4630d10883f42d608fa9d Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 5 Feb 2023 16:30:23 +0100 Subject: [PATCH 086/192] Clean trailing spaces --- src/raudio.c | 42 ++++------ src/raymath.h | 6 +- src/rcore.c | 16 ++-- src/rglfw.c | 10 +-- src/rlgl.h | 46 +++++------ src/rmodels.c | 214 ++++++++++++++++++++++++------------------------ src/rshapes.c | 8 +- src/rtext.c | 10 +-- src/rtextures.c | 16 ++-- 9 files changed, 179 insertions(+), 189 deletions(-) diff --git a/src/raudio.c b/src/raudio.c index 524aaef43e56..04ae35c5a996 100644 --- a/src/raudio.c +++ b/src/raudio.c @@ -528,7 +528,7 @@ void CloseAudioDevice(void) RL_FREE(AUDIO.System.pcmBuffer); AUDIO.System.pcmBuffer = NULL; AUDIO.System.pcmBufferSize = 0; - + TRACELOG(LOG_INFO, "AUDIO: Device closed successfully"); } else TRACELOG(LOG_WARNING, "AUDIO: Device could not be closed, not currently initialized"); @@ -829,26 +829,18 @@ Wave LoadWaveFromMemory(const char *fileType, const unsigned char *fileData, int { qoa_desc qoa = { 0 }; - unsigned int result = qoa_decode_header(fileData, dataSize, &qoa); + // NOTE: Returned sample data is always 16 bit? + wave.data = qoa_decode(fileData, dataSize, &qoa); + wave.sampleSize = 16; - if (result > 0) + if (wave.data != NULL) { - - // Calculate the total audio frame count + wave.channels = qoa.channels; + wave.sampleRate = qoa.samplerate; wave.frameCount = qoa.samples; - - // NOTE: Returned sample data is always 16 bit - wave.data = qoa_decode(fileData, dataSize, &qoa); - wave.sampleSize = 16; - - if (wave.data != NULL) - { - wave.channels = qoa.channels; - wave.sampleRate = qoa.samplerate; - } - else TRACELOG(LOG_WARNING, "WAVE: Failed to load QOA data"); } else TRACELOG(LOG_WARNING, "WAVE: Failed to load QOA data"); + } #endif #if defined(SUPPORT_FILEFORMAT_FLAC) @@ -1001,7 +993,7 @@ bool ExportWave(Wave wave, const char *fileName) qoa.channels = wave.channels; qoa.samplerate = wave.sampleRate; qoa.samples = wave.frameCount; - + // TODO: Review wave.data format required for export success = qoa_write(fileName, wave.data, &qoa); } @@ -1388,7 +1380,6 @@ Music LoadMusicStream(const char *fileName) qoa_desc *ctxQoa = RL_CALLOC(1, sizeof(qoa_desc)); // TODO: QOA stream support: Init context from file - int result = 0; music.ctxType = MUSIC_AUDIO_QOA; music.ctxData = ctxQoa; @@ -1399,7 +1390,7 @@ Music LoadMusicStream(const char *fileName) // TODO: Read next frame(s) from QOA stream //music.frameCount = qoa_decode_frame(const unsigned char *bytes, unsigned int size, ctxQoa, short *sample_data, unsigned int *frame_len); - + music.looping = true; // Looping enabled by default musicLoaded = true; } @@ -1585,20 +1576,19 @@ Music LoadMusicStreamFromMemory(const char *fileType, const unsigned char *data, else if (strcmp(fileType, ".qoa") == 0) { qoa_desc *ctxQoa = RL_CALLOC(1, sizeof(qoa_desc)); - + // TODO: Init QOA context data - int result = 0; - + music.ctxType = MUSIC_AUDIO_QOA; music.ctxData = ctxQoa; - if (result > 0) + if (success) { music.stream = LoadAudioStream(ctxQoa->samplerate, 16, ctxQoa->channels); - + // TODO: Read next frame(s) from QOA stream //music.frameCount = qoa_decode_frame(const unsigned char *bytes, unsigned int size, ctxQoa, short *sample_data, unsigned int *frame_len); - + music.looping = true; // Looping enabled by default musicLoaded = true; } @@ -1863,7 +1853,7 @@ void UpdateMusicStream(Music music) // On first call of this function we lazily pre-allocated a temp buffer to read audio files/memory data in int frameSize = music.stream.channels*music.stream.sampleSize/8; unsigned int pcmSize = subBufferSizeInFrames*frameSize; - + if (AUDIO.System.pcmBufferSize < pcmSize) { RL_FREE(AUDIO.System.pcmBuffer); diff --git a/src/raymath.h b/src/raymath.h index 86134d090d74..422a42eeeef0 100644 --- a/src/raymath.h +++ b/src/raymath.h @@ -311,7 +311,7 @@ RMAPI float Vector2DistanceSqr(Vector2 v1, Vector2 v2) RMAPI float Vector2Angle(Vector2 v1, Vector2 v2) { float result = atan2f(v2.y - v1.y, v2.x - v1.x); - + return result; } @@ -321,14 +321,14 @@ RMAPI float Vector2Angle(Vector2 v1, Vector2 v2) RMAPI float Vector2LineAngle(Vector2 start, Vector2 end) { float result = 0.0f; - + float dot = start.x*end.x + start.y*end.y; // Dot product float dotClamp = (dot < -1.0f)? -1.0f : dot; // Clamp if (dotClamp > 1.0f) dotClamp = 1.0f; result = acosf(dotClamp); - + // Alternative implementation, more costly //float v1Length = sqrtf((start.x*start.x) + (start.y*start.y)); //float v2Length = sqrtf((end.x*end.x) + (end.y*end.y)); diff --git a/src/rcore.c b/src/rcore.c index ee88727d534a..98800a790d4e 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -1955,10 +1955,10 @@ const char *GetClipboardText(void) .then(text => { document.getElementById('clipboard').innerText = text; console.log('Pasted content: ', text); }) \ .catch(err => { console.error('Failed to read clipboard contents: ', err); });" ); - + // The main issue is getting that data, one approach could be using ASYNCIFY and wait // for the data but it requires adding Asyncify emscripten library on compilation - + // Another approach could be just copy the data in a HTML text field and try to retrieve it // later on if available... and clean it for future accesses @@ -2478,7 +2478,7 @@ Shader LoadShaderFromMemory(const char *vsCode, const char *fsCode) // vertex texcoord2 location = 5 // NOTE: If any location is not found, loc point becomes -1 - + shader.locs = (int *)RL_CALLOC(RL_MAX_SHADER_LOCATIONS, sizeof(int)); // All locations reseted to -1 (no location) @@ -2521,7 +2521,7 @@ void UnloadShader(Shader shader) if (shader.id != rlGetShaderIdDefault()) { rlUnloadShaderProgram(shader.id); - + // NOTE: If shader loading failed, it should be 0 RL_FREE(shader.locs); } @@ -2846,7 +2846,7 @@ void TakeScreenshot(const char *fileName) // Get a random value between min and max (both included) // WARNING: Ranges higher than RAND_MAX will return invalid results -// More specifically, if (max - min) > INT_MAX there will be an overflow, +// More specifically, if (max - min) > INT_MAX there will be an overflow, // and otherwise if (max - min) > RAND_MAX the random value will incorrectly never exceed a certain threshold int GetRandomValue(int min, int max) { @@ -2856,7 +2856,7 @@ int GetRandomValue(int min, int max) max = min; min = tmp; } - + if ((unsigned int)(max - min) > (unsigned int)RAND_MAX) { TRACELOG(LOG_WARNING, "Invalid GetRandomValue() arguments, range should not be higher than %i", RAND_MAX); @@ -5756,7 +5756,7 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event) CORE.Input.Gamepad.ready[0] = true; GamepadButton button = AndroidTranslateGamepadButton(keycode); - + if (button == GAMEPAD_BUTTON_UNKNOWN) return 1; if (AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_DOWN) @@ -5764,7 +5764,7 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event) CORE.Input.Gamepad.currentButtonState[0][button] = 1; } else CORE.Input.Gamepad.currentButtonState[0][button] = 0; // Key up - + return 1; // Handled gamepad button } diff --git a/src/rglfw.c b/src/rglfw.c index 940257ab1993..794e0d2e44e2 100644 --- a/src/rglfw.c +++ b/src/rglfw.c @@ -75,7 +75,7 @@ #include "external/glfw/src/win32_time.c" #include "external/glfw/src/win32_thread.c" #include "external/glfw/src/wgl_context.c" - + #include "external/glfw/src/egl_context.c" #include "external/glfw/src/osmesa_context.c" #endif @@ -87,10 +87,10 @@ #include "external/glfw/src/posix_poll.c" #include "external/glfw/src/linux_joystick.c" #include "external/glfw/src/xkb_unicode.c" - + #include "external/glfw/src/egl_context.c" #include "external/glfw/src/osmesa_context.c" - + #if defined(_GLFW_WAYLAND) #include "external/glfw/src/wl_init.c" #include "external/glfw/src/wl_monitor.c" @@ -110,7 +110,7 @@ #include "external/glfw/src/posix_time.c" #include "external/glfw/src/null_joystick.c" #include "external/glfw/src/xkb_unicode.c" - + #include "external/glfw/src/x11_init.c" #include "external/glfw/src/x11_monitor.c" #include "external/glfw/src/x11_window.c" @@ -129,7 +129,7 @@ #include "external/glfw/src/cocoa_window.m" #include "external/glfw/src/cocoa_time.c" #include "external/glfw/src/nsgl_context.m" - + #include "external/glfw/src/egl_context.c" #include "external/glfw/src/osmesa_context.c" #endif diff --git a/src/rlgl.h b/src/rlgl.h index 2b982a9a1fb7..ebd0f4de6482 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -281,33 +281,33 @@ // GL blending factors #define RL_ZERO 0 // GL_ZERO -#define RL_ONE 1 // GL_ONE -#define RL_SRC_COLOR 0x0300 // GL_SRC_COLOR -#define RL_ONE_MINUS_SRC_COLOR 0x0301 // GL_ONE_MINUS_SRC_COLOR -#define RL_SRC_ALPHA 0x0302 // GL_SRC_ALPHA -#define RL_ONE_MINUS_SRC_ALPHA 0x0303 // GL_ONE_MINUS_SRC_ALPHA -#define RL_DST_ALPHA 0x0304 // GL_DST_ALPHA -#define RL_ONE_MINUS_DST_ALPHA 0x0305 // GL_ONE_MINUS_DST_ALPHA -#define RL_DST_COLOR 0x0306 // GL_DST_COLOR -#define RL_ONE_MINUS_DST_COLOR 0x0307 // GL_ONE_MINUS_DST_COLOR -#define RL_SRC_ALPHA_SATURATE 0x0308 // GL_SRC_ALPHA_SATURATE -#define RL_CONSTANT_COLOR 0x8001 // GL_CONSTANT_COLOR +#define RL_ONE 1 // GL_ONE +#define RL_SRC_COLOR 0x0300 // GL_SRC_COLOR +#define RL_ONE_MINUS_SRC_COLOR 0x0301 // GL_ONE_MINUS_SRC_COLOR +#define RL_SRC_ALPHA 0x0302 // GL_SRC_ALPHA +#define RL_ONE_MINUS_SRC_ALPHA 0x0303 // GL_ONE_MINUS_SRC_ALPHA +#define RL_DST_ALPHA 0x0304 // GL_DST_ALPHA +#define RL_ONE_MINUS_DST_ALPHA 0x0305 // GL_ONE_MINUS_DST_ALPHA +#define RL_DST_COLOR 0x0306 // GL_DST_COLOR +#define RL_ONE_MINUS_DST_COLOR 0x0307 // GL_ONE_MINUS_DST_COLOR +#define RL_SRC_ALPHA_SATURATE 0x0308 // GL_SRC_ALPHA_SATURATE +#define RL_CONSTANT_COLOR 0x8001 // GL_CONSTANT_COLOR #define RL_ONE_MINUS_CONSTANT_COLOR 0x8002 // GL_ONE_MINUS_CONSTANT_COLOR -#define RL_CONSTANT_ALPHA 0x8003 // GL_CONSTANT_ALPHA +#define RL_CONSTANT_ALPHA 0x8003 // GL_CONSTANT_ALPHA #define RL_ONE_MINUS_CONSTANT_ALPHA 0x8004 // GL_ONE_MINUS_CONSTANT_ALPHA // GL blending functions/equations -#define RL_FUNC_ADD 0x8006 // GL_FUNC_ADD -#define RL_FUNC_SUBTRACT 0x800A // GL_FUNC_SUBTRACT +#define RL_FUNC_ADD 0x8006 // GL_FUNC_ADD +#define RL_FUNC_SUBTRACT 0x800A // GL_FUNC_SUBTRACT #define RL_FUNC_REVERSE_SUBTRACT 0x800B // GL_FUNC_REVERSE_SUBTRACT -#define RL_BLEND_EQUATION 0x8009 // GL_BLEND_EQUATION +#define RL_BLEND_EQUATION 0x8009 // GL_BLEND_EQUATION #define RL_BLEND_EQUATION_RGB 0x8009 // GL_BLEND_EQUATION_RGB // (Same as BLEND_EQUATION) -#define RL_BLEND_EQUATION_ALPHA 0x883D // GL_BLEND_EQUATION_ALPHA -#define RL_BLEND_DST_RGB 0x80C8 // GL_BLEND_DST_RGB -#define RL_BLEND_SRC_RGB 0x80C9 // GL_BLEND_SRC_RGB -#define RL_BLEND_DST_ALPHA 0x80CA // GL_BLEND_DST_ALPHA -#define RL_BLEND_SRC_ALPHA 0x80CB // GL_BLEND_SRC_ALPHA -#define RL_BLEND_COLOR 0x8005 // GL_BLEND_COLOR +#define RL_BLEND_EQUATION_ALPHA 0x883D // GL_BLEND_EQUATION_ALPHA +#define RL_BLEND_DST_RGB 0x80C8 // GL_BLEND_DST_RGB +#define RL_BLEND_SRC_RGB 0x80C9 // GL_BLEND_SRC_RGB +#define RL_BLEND_DST_ALPHA 0x80CA // GL_BLEND_DST_ALPHA +#define RL_BLEND_SRC_ALPHA 0x80CB // GL_BLEND_SRC_ALPHA +#define RL_BLEND_COLOR 0x8005 // GL_BLEND_COLOR //---------------------------------------------------------------------------------- @@ -790,7 +790,7 @@ RLAPI void rlLoadDrawQuad(void); // Load and draw a quad #if defined(GRAPHICS_API_OPENGL_ES2) // NOTE: OpenGL ES 2.0 can be enabled on PLATFORM_DESKTOP, - // in that case, functions are loaded from a custom glad for OpenGL ES 2.0 + // in that case, functions are loaded from a custom glad for OpenGL ES 2.0 #if defined(PLATFORM_DESKTOP) #define GLAD_GLES2_IMPLEMENTATION #include "external/glad_gles2.h" @@ -3042,7 +3042,7 @@ unsigned int rlLoadTextureDepth(int width, int height, bool useRenderBuffer) #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) // In case depth textures not supported, we force renderbuffer usage if (!RLGL.ExtSupported.texDepth) useRenderBuffer = true; - + // NOTE: We let the implementation to choose the best bit-depth // Possible formats: GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT32 and GL_DEPTH_COMPONENT32F unsigned int glInternalFormat = GL_DEPTH_COMPONENT; diff --git a/src/rmodels.c b/src/rmodels.c index 3976b92e52a0..4a8261795daf 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -112,7 +112,7 @@ #include "external/par_shapes.h" // Shapes 3d parametric generation #if defined(_MSC_VER ) // disable MSVC warning suppression for par shapes -#pragma warning( pop ) +#pragma warning( pop ) #endif #endif @@ -692,7 +692,7 @@ void DrawCapsule(Vector3 startPos, Vector3 endPos, float radius, int slices, int if (slices < 3) slices = 3; Vector3 direction = { endPos.x - startPos.x, endPos.y - startPos.y, endPos.z - startPos.z }; - + // draw a sphere if start and end points are the same bool sphereCase = (direction.x == 0) && (direction.y == 0) && (direction.z == 0); if (sphereCase) direction = (Vector3){0.0f, 1.0f, 0.0f}; @@ -704,7 +704,7 @@ void DrawCapsule(Vector3 startPos, Vector3 endPos, float radius, int slices, int Vector3 capCenter = endPos; float baseSliceAngle = (2.0f*PI)/slices; - float baseRingAngle = PI * 0.5f / rings; + float baseRingAngle = PI * 0.5f / rings; rlBegin(RL_TRIANGLES); rlColor4ub(color.r, color.g, color.b, color.a); @@ -714,7 +714,7 @@ void DrawCapsule(Vector3 startPos, Vector3 endPos, float radius, int slices, int { for (int i = 0; i < rings; i++) { - for (int j = 0; j < slices; j++) + for (int j = 0; j < slices; j++) { // we build up the rings from capCenter in the direction of the 'direction' vector we computed earlier @@ -725,32 +725,32 @@ void DrawCapsule(Vector3 startPos, Vector3 endPos, float radius, int slices, int // compute the four vertices float ringSin1 = sinf(baseSliceAngle*(j + 0))*cosf(baseRingAngle * ( i + 0 )); float ringCos1 = cosf(baseSliceAngle*(j + 0))*cosf(baseRingAngle * ( i + 0 )); - Vector3 w1 = (Vector3){ + Vector3 w1 = (Vector3){ capCenter.x + (sinf(baseRingAngle * ( i + 0 ))*b0.x + ringSin1*b1.x + ringCos1*b2.x) * radius, - capCenter.y + (sinf(baseRingAngle * ( i + 0 ))*b0.y + ringSin1*b1.y + ringCos1*b2.y) * radius, + capCenter.y + (sinf(baseRingAngle * ( i + 0 ))*b0.y + ringSin1*b1.y + ringCos1*b2.y) * radius, capCenter.z + (sinf(baseRingAngle * ( i + 0 ))*b0.z + ringSin1*b1.z + ringCos1*b2.z) * radius }; float ringSin2 = sinf(baseSliceAngle*(j + 1))*cosf(baseRingAngle * ( i + 0 )); float ringCos2 = cosf(baseSliceAngle*(j + 1))*cosf(baseRingAngle * ( i + 0 )); - Vector3 w2 = (Vector3){ - capCenter.x + (sinf(baseRingAngle * ( i + 0 ))*b0.x + ringSin2*b1.x + ringCos2*b2.x) * radius, - capCenter.y + (sinf(baseRingAngle * ( i + 0 ))*b0.y + ringSin2*b1.y + ringCos2*b2.y) * radius, - capCenter.z + (sinf(baseRingAngle * ( i + 0 ))*b0.z + ringSin2*b1.z + ringCos2*b2.z) * radius + Vector3 w2 = (Vector3){ + capCenter.x + (sinf(baseRingAngle * ( i + 0 ))*b0.x + ringSin2*b1.x + ringCos2*b2.x) * radius, + capCenter.y + (sinf(baseRingAngle * ( i + 0 ))*b0.y + ringSin2*b1.y + ringCos2*b2.y) * radius, + capCenter.z + (sinf(baseRingAngle * ( i + 0 ))*b0.z + ringSin2*b1.z + ringCos2*b2.z) * radius }; float ringSin3 = sinf(baseSliceAngle*(j + 0))*cosf(baseRingAngle * ( i + 1 )); float ringCos3 = cosf(baseSliceAngle*(j + 0))*cosf(baseRingAngle * ( i + 1 )); - Vector3 w3 = (Vector3){ - capCenter.x + (sinf(baseRingAngle * ( i + 1 ))*b0.x + ringSin3*b1.x + ringCos3*b2.x) * radius, - capCenter.y + (sinf(baseRingAngle * ( i + 1 ))*b0.y + ringSin3*b1.y + ringCos3*b2.y) * radius, - capCenter.z + (sinf(baseRingAngle * ( i + 1 ))*b0.z + ringSin3*b1.z + ringCos3*b2.z) * radius + Vector3 w3 = (Vector3){ + capCenter.x + (sinf(baseRingAngle * ( i + 1 ))*b0.x + ringSin3*b1.x + ringCos3*b2.x) * radius, + capCenter.y + (sinf(baseRingAngle * ( i + 1 ))*b0.y + ringSin3*b1.y + ringCos3*b2.y) * radius, + capCenter.z + (sinf(baseRingAngle * ( i + 1 ))*b0.z + ringSin3*b1.z + ringCos3*b2.z) * radius }; float ringSin4 = sinf(baseSliceAngle*(j + 1))*cosf(baseRingAngle * ( i + 1 )); float ringCos4 = cosf(baseSliceAngle*(j + 1))*cosf(baseRingAngle * ( i + 1 )); - Vector3 w4 = (Vector3){ - capCenter.x + (sinf(baseRingAngle * ( i + 1 ))*b0.x + ringSin4*b1.x + ringCos4*b2.x) * radius, - capCenter.y + (sinf(baseRingAngle * ( i + 1 ))*b0.y + ringSin4*b1.y + ringCos4*b2.y) * radius, - capCenter.z + (sinf(baseRingAngle * ( i + 1 ))*b0.z + ringSin4*b1.z + ringCos4*b2.z) * radius + Vector3 w4 = (Vector3){ + capCenter.x + (sinf(baseRingAngle * ( i + 1 ))*b0.x + ringSin4*b1.x + ringCos4*b2.x) * radius, + capCenter.y + (sinf(baseRingAngle * ( i + 1 ))*b0.y + ringSin4*b1.y + ringCos4*b2.y) * radius, + capCenter.z + (sinf(baseRingAngle * ( i + 1 ))*b0.z + ringSin4*b1.z + ringCos4*b2.z) * radius }; // make sure cap triangle normals are facing outwards @@ -759,10 +759,10 @@ void DrawCapsule(Vector3 startPos, Vector3 endPos, float radius, int slices, int rlVertex3f(w1.x, w1.y, w1.z); rlVertex3f(w2.x, w2.y, w2.z); rlVertex3f(w3.x, w3.y, w3.z); - - rlVertex3f(w2.x, w2.y, w2.z); - rlVertex3f(w4.x, w4.y, w4.z); - rlVertex3f(w3.x, w3.y, w3.z); + + rlVertex3f(w2.x, w2.y, w2.z); + rlVertex3f(w4.x, w4.y, w4.z); + rlVertex3f(w3.x, w3.y, w3.z); } else { @@ -770,9 +770,9 @@ void DrawCapsule(Vector3 startPos, Vector3 endPos, float radius, int slices, int rlVertex3f(w3.x, w3.y, w3.z); rlVertex3f(w2.x, w2.y, w2.z); - rlVertex3f(w2.x, w2.y, w2.z); - rlVertex3f(w3.x, w3.y, w3.z); - rlVertex3f(w4.x, w4.y, w4.z); + rlVertex3f(w2.x, w2.y, w2.z); + rlVertex3f(w3.x, w3.y, w3.z); + rlVertex3f(w4.x, w4.y, w4.z); } } } @@ -782,37 +782,37 @@ void DrawCapsule(Vector3 startPos, Vector3 endPos, float radius, int slices, int // render middle if (!sphereCase) { - for (int j = 0; j < slices; j++) + for (int j = 0; j < slices; j++) { // compute the four vertices float ringSin1 = sinf(baseSliceAngle*(j + 0))*radius; float ringCos1 = cosf(baseSliceAngle*(j + 0))*radius; - Vector3 w1 = { + Vector3 w1 = { startPos.x + ringSin1*b1.x + ringCos1*b2.x, - startPos.y + ringSin1*b1.y + ringCos1*b2.y, - startPos.z + ringSin1*b1.z + ringCos1*b2.z + startPos.y + ringSin1*b1.y + ringCos1*b2.y, + startPos.z + ringSin1*b1.z + ringCos1*b2.z }; float ringSin2 = sinf(baseSliceAngle*(j + 1))*radius; float ringCos2 = cosf(baseSliceAngle*(j + 1))*radius; - Vector3 w2 = { - startPos.x + ringSin2*b1.x + ringCos2*b2.x, - startPos.y + ringSin2*b1.y + ringCos2*b2.y, - startPos.z + ringSin2*b1.z + ringCos2*b2.z + Vector3 w2 = { + startPos.x + ringSin2*b1.x + ringCos2*b2.x, + startPos.y + ringSin2*b1.y + ringCos2*b2.y, + startPos.z + ringSin2*b1.z + ringCos2*b2.z }; float ringSin3 = sinf(baseSliceAngle*(j + 0))*radius; float ringCos3 = cosf(baseSliceAngle*(j + 0))*radius; - Vector3 w3 = { - endPos.x + ringSin3*b1.x + ringCos3*b2.x, - endPos.y + ringSin3*b1.y + ringCos3*b2.y, - endPos.z + ringSin3*b1.z + ringCos3*b2.z + Vector3 w3 = { + endPos.x + ringSin3*b1.x + ringCos3*b2.x, + endPos.y + ringSin3*b1.y + ringCos3*b2.y, + endPos.z + ringSin3*b1.z + ringCos3*b2.z }; float ringSin4 = sinf(baseSliceAngle*(j + 1))*radius; float ringCos4 = cosf(baseSliceAngle*(j + 1))*radius; - Vector3 w4 = { - endPos.x + ringSin4*b1.x + ringCos4*b2.x, - endPos.y + ringSin4*b1.y + ringCos4*b2.y, - endPos.z + ringSin4*b1.z + ringCos4*b2.z + Vector3 w4 = { + endPos.x + ringSin4*b1.x + ringCos4*b2.x, + endPos.y + ringSin4*b1.y + ringCos4*b2.y, + endPos.z + ringSin4*b1.z + ringCos4*b2.z }; // w2 x.-----------x startPos rlVertex3f(w1.x, w1.y, w1.z); // | |\'. T0 / @@ -847,7 +847,7 @@ void DrawCapsuleWires(Vector3 startPos, Vector3 endPos, float radius, int slices Vector3 capCenter = endPos; float baseSliceAngle = (2.0f*PI)/slices; - float baseRingAngle = PI * 0.5f / rings; + float baseRingAngle = PI * 0.5f / rings; rlBegin(RL_LINES); rlColor4ub(color.r, color.g, color.b, color.a); @@ -857,7 +857,7 @@ void DrawCapsuleWires(Vector3 startPos, Vector3 endPos, float radius, int slices { for (int i = 0; i < rings; i++) { - for (int j = 0; j < slices; j++) + for (int j = 0; j < slices; j++) { // we build up the rings from capCenter in the direction of the 'direction' vector we computed earlier @@ -868,32 +868,32 @@ void DrawCapsuleWires(Vector3 startPos, Vector3 endPos, float radius, int slices // compute the four vertices float ringSin1 = sinf(baseSliceAngle*(j + 0))*cosf(baseRingAngle * ( i + 0 )); float ringCos1 = cosf(baseSliceAngle*(j + 0))*cosf(baseRingAngle * ( i + 0 )); - Vector3 w1 = (Vector3){ + Vector3 w1 = (Vector3){ capCenter.x + (sinf(baseRingAngle * ( i + 0 ))*b0.x + ringSin1*b1.x + ringCos1*b2.x) * radius, - capCenter.y + (sinf(baseRingAngle * ( i + 0 ))*b0.y + ringSin1*b1.y + ringCos1*b2.y) * radius, + capCenter.y + (sinf(baseRingAngle * ( i + 0 ))*b0.y + ringSin1*b1.y + ringCos1*b2.y) * radius, capCenter.z + (sinf(baseRingAngle * ( i + 0 ))*b0.z + ringSin1*b1.z + ringCos1*b2.z) * radius }; float ringSin2 = sinf(baseSliceAngle*(j + 1))*cosf(baseRingAngle * ( i + 0 )); float ringCos2 = cosf(baseSliceAngle*(j + 1))*cosf(baseRingAngle * ( i + 0 )); - Vector3 w2 = (Vector3){ - capCenter.x + (sinf(baseRingAngle * ( i + 0 ))*b0.x + ringSin2*b1.x + ringCos2*b2.x) * radius, - capCenter.y + (sinf(baseRingAngle * ( i + 0 ))*b0.y + ringSin2*b1.y + ringCos2*b2.y) * radius, - capCenter.z + (sinf(baseRingAngle * ( i + 0 ))*b0.z + ringSin2*b1.z + ringCos2*b2.z) * radius + Vector3 w2 = (Vector3){ + capCenter.x + (sinf(baseRingAngle * ( i + 0 ))*b0.x + ringSin2*b1.x + ringCos2*b2.x) * radius, + capCenter.y + (sinf(baseRingAngle * ( i + 0 ))*b0.y + ringSin2*b1.y + ringCos2*b2.y) * radius, + capCenter.z + (sinf(baseRingAngle * ( i + 0 ))*b0.z + ringSin2*b1.z + ringCos2*b2.z) * radius }; float ringSin3 = sinf(baseSliceAngle*(j + 0))*cosf(baseRingAngle * ( i + 1 )); float ringCos3 = cosf(baseSliceAngle*(j + 0))*cosf(baseRingAngle * ( i + 1 )); - Vector3 w3 = (Vector3){ - capCenter.x + (sinf(baseRingAngle * ( i + 1 ))*b0.x + ringSin3*b1.x + ringCos3*b2.x) * radius, - capCenter.y + (sinf(baseRingAngle * ( i + 1 ))*b0.y + ringSin3*b1.y + ringCos3*b2.y) * radius, - capCenter.z + (sinf(baseRingAngle * ( i + 1 ))*b0.z + ringSin3*b1.z + ringCos3*b2.z) * radius + Vector3 w3 = (Vector3){ + capCenter.x + (sinf(baseRingAngle * ( i + 1 ))*b0.x + ringSin3*b1.x + ringCos3*b2.x) * radius, + capCenter.y + (sinf(baseRingAngle * ( i + 1 ))*b0.y + ringSin3*b1.y + ringCos3*b2.y) * radius, + capCenter.z + (sinf(baseRingAngle * ( i + 1 ))*b0.z + ringSin3*b1.z + ringCos3*b2.z) * radius }; float ringSin4 = sinf(baseSliceAngle*(j + 1))*cosf(baseRingAngle * ( i + 1 )); float ringCos4 = cosf(baseSliceAngle*(j + 1))*cosf(baseRingAngle * ( i + 1 )); - Vector3 w4 = (Vector3){ - capCenter.x + (sinf(baseRingAngle * ( i + 1 ))*b0.x + ringSin4*b1.x + ringCos4*b2.x) * radius, - capCenter.y + (sinf(baseRingAngle * ( i + 1 ))*b0.y + ringSin4*b1.y + ringCos4*b2.y) * radius, - capCenter.z + (sinf(baseRingAngle * ( i + 1 ))*b0.z + ringSin4*b1.z + ringCos4*b2.z) * radius + Vector3 w4 = (Vector3){ + capCenter.x + (sinf(baseRingAngle * ( i + 1 ))*b0.x + ringSin4*b1.x + ringCos4*b2.x) * radius, + capCenter.y + (sinf(baseRingAngle * ( i + 1 ))*b0.y + ringSin4*b1.y + ringCos4*b2.y) * radius, + capCenter.z + (sinf(baseRingAngle * ( i + 1 ))*b0.z + ringSin4*b1.z + ringCos4*b2.z) * radius }; rlVertex3f(w1.x, w1.y, w1.z); @@ -904,12 +904,12 @@ void DrawCapsuleWires(Vector3 startPos, Vector3 endPos, float radius, int slices rlVertex3f(w1.x, w1.y, w1.z); rlVertex3f(w3.x, w3.y, w3.z); - - rlVertex3f(w2.x, w2.y, w2.z); - rlVertex3f(w4.x, w4.y, w4.z); + + rlVertex3f(w2.x, w2.y, w2.z); + rlVertex3f(w4.x, w4.y, w4.z); rlVertex3f(w3.x, w3.y, w3.z); - rlVertex3f(w4.x, w4.y, w4.z); + rlVertex3f(w4.x, w4.y, w4.z); } } capCenter = startPos; @@ -918,46 +918,46 @@ void DrawCapsuleWires(Vector3 startPos, Vector3 endPos, float radius, int slices // render middle if (!sphereCase) { - for (int j = 0; j < slices; j++) + for (int j = 0; j < slices; j++) { // compute the four vertices float ringSin1 = sinf(baseSliceAngle*(j + 0))*radius; float ringCos1 = cosf(baseSliceAngle*(j + 0))*radius; - Vector3 w1 = { + Vector3 w1 = { startPos.x + ringSin1*b1.x + ringCos1*b2.x, - startPos.y + ringSin1*b1.y + ringCos1*b2.y, - startPos.z + ringSin1*b1.z + ringCos1*b2.z + startPos.y + ringSin1*b1.y + ringCos1*b2.y, + startPos.z + ringSin1*b1.z + ringCos1*b2.z }; float ringSin2 = sinf(baseSliceAngle*(j + 1))*radius; float ringCos2 = cosf(baseSliceAngle*(j + 1))*radius; - Vector3 w2 = { - startPos.x + ringSin2*b1.x + ringCos2*b2.x, - startPos.y + ringSin2*b1.y + ringCos2*b2.y, - startPos.z + ringSin2*b1.z + ringCos2*b2.z + Vector3 w2 = { + startPos.x + ringSin2*b1.x + ringCos2*b2.x, + startPos.y + ringSin2*b1.y + ringCos2*b2.y, + startPos.z + ringSin2*b1.z + ringCos2*b2.z }; float ringSin3 = sinf(baseSliceAngle*(j + 0))*radius; float ringCos3 = cosf(baseSliceAngle*(j + 0))*radius; - Vector3 w3 = { - endPos.x + ringSin3*b1.x + ringCos3*b2.x, - endPos.y + ringSin3*b1.y + ringCos3*b2.y, - endPos.z + ringSin3*b1.z + ringCos3*b2.z + Vector3 w3 = { + endPos.x + ringSin3*b1.x + ringCos3*b2.x, + endPos.y + ringSin3*b1.y + ringCos3*b2.y, + endPos.z + ringSin3*b1.z + ringCos3*b2.z }; float ringSin4 = sinf(baseSliceAngle*(j + 1))*radius; float ringCos4 = cosf(baseSliceAngle*(j + 1))*radius; - Vector3 w4 = { - endPos.x + ringSin4*b1.x + ringCos4*b2.x, - endPos.y + ringSin4*b1.y + ringCos4*b2.y, - endPos.z + ringSin4*b1.z + ringCos4*b2.z + Vector3 w4 = { + endPos.x + ringSin4*b1.x + ringCos4*b2.x, + endPos.y + ringSin4*b1.y + ringCos4*b2.y, + endPos.z + ringSin4*b1.z + ringCos4*b2.z }; - rlVertex3f(w1.x, w1.y, w1.z); + rlVertex3f(w1.x, w1.y, w1.z); rlVertex3f(w3.x, w3.y, w3.z); - rlVertex3f(w2.x, w2.y, w2.z); - rlVertex3f(w4.x, w4.y, w4.z); + rlVertex3f(w2.x, w2.y, w2.z); + rlVertex3f(w4.x, w4.y, w4.z); - rlVertex3f(w2.x, w2.y, w2.z); + rlVertex3f(w2.x, w2.y, w2.z); rlVertex3f(w3.x, w3.y, w3.z); } } @@ -1373,10 +1373,10 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform) if (material.shader.locs[SHADER_LOC_COLOR_SPECULAR] != -1) { float values[4] = { - (float)material.maps[MATERIAL_MAP_SPECULAR].color.r/255.0f, - (float)material.maps[MATERIAL_MAP_SPECULAR].color.g/255.0f, - (float)material.maps[MATERIAL_MAP_SPECULAR].color.b/255.0f, - (float)material.maps[MATERIAL_MAP_SPECULAR].color.a/255.0f + (float)material.maps[SHADER_LOC_COLOR_SPECULAR].color.r/255.0f, + (float)material.maps[SHADER_LOC_COLOR_SPECULAR].color.g/255.0f, + (float)material.maps[SHADER_LOC_COLOR_SPECULAR].color.b/255.0f, + (float)material.maps[SHADER_LOC_COLOR_SPECULAR].color.a/255.0f }; rlSetUniform(material.shader.locs[SHADER_LOC_COLOR_SPECULAR], values, SHADER_UNIFORM_VEC4, 1); @@ -2024,7 +2024,7 @@ void UpdateModelAnimation(Model model, ModelAnimation anim, int frame) for (int m = 0; m < model.meshCount; m++) { Mesh mesh = model.meshes[m]; - + if (mesh.boneIds == NULL || mesh.boneWeights == NULL) { TRACELOG(LOG_WARNING, "MODEL: UpdateModelAnimation(): Mesh %i has no connection to bones", m); @@ -2065,7 +2065,7 @@ void UpdateModelAnimation(Model model, ModelAnimation anim, int frame) for (int j = 0; j < 4; j++, boneCounter++) { boneWeight = mesh.boneWeights[boneCounter]; - + // Early stop when no transformation will be applied if (boneWeight == 0.0f) continue; @@ -4748,7 +4748,7 @@ static BoneInfo *LoadBoneInfoGLTF(cgltf_skin skin, int *boneCount) // Find parent bone index unsigned int parentIndex = -1; - + for (unsigned int j = 0; j < skin.joints_count; j++) { if (skin.joints[j] == node.parent) @@ -5238,12 +5238,12 @@ static bool GetPoseAtTimeGLTF(cgltf_accessor *input, cgltf_accessor *output, flo float tstart = 0.0f; float tend = 0.0f; int keyframe = 0; // Defaults to first pose - + for (int i = 0; i < input->count - 1; i++) { cgltf_bool r1 = cgltf_accessor_read_float(input, i, &tstart, 1); if (!r1) return false; - + cgltf_bool r2 = cgltf_accessor_read_float(input, i + 1, &tend, 1); if (!r2) return false; @@ -5278,11 +5278,11 @@ static bool GetPoseAtTimeGLTF(cgltf_accessor *input, cgltf_accessor *output, flo cgltf_accessor_read_float(output, keyframe+1, tmp, 4); Vector4 v2 = {tmp[0], tmp[1], tmp[2], tmp[3]}; Vector4 *r = data; - + // Only v4 is for rotations, so we know it's a quat *r = QuaternionSlerp(v1, v2, t); } - + return true; } @@ -5295,12 +5295,12 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, unsigned in unsigned char *fileData = LoadFileData(fileName, &dataSize); ModelAnimation *animations = NULL; - + // glTF data loading cgltf_options options = { 0 }; cgltf_data *data = NULL; cgltf_result result = cgltf_parse(&options, fileData, dataSize, &data); - + if (result != cgltf_result_success) { TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load glTF data", fileName); @@ -5318,7 +5318,7 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, unsigned in cgltf_skin skin = data->skins[0]; *animCount = (int)data->animations_count; animations = RL_MALLOC(data->animations_count*sizeof(ModelAnimation)); - + for (unsigned int i = 0; i < data->animations_count; i++) { animations[i].bones = LoadBoneInfoGLTF(skin, &animations[i].boneCount); @@ -5333,12 +5333,12 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, unsigned in struct Channels *boneChannels = RL_CALLOC(animations[i].boneCount, sizeof(struct Channels)); float animDuration = 0.0f; - + for (unsigned int j = 0; j < animData.channels_count; j++) { cgltf_animation_channel channel = animData.channels[j]; int boneIndex = -1; - + for (unsigned int k = 0; k < skin.joints_count; k++) { if (animData.channels[j].target_node == skin.joints[k]) @@ -5372,12 +5372,12 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, unsigned in { TRACELOG(LOG_WARNING, "MODEL: [%s] Unsupported target_path on channel %d's sampler for animation %d. Skipping.", fileName, j, i); } - } + } else TRACELOG(LOG_WARNING, "MODEL: [%s] Only linear interpolation curves are supported for GLTF animation.", fileName); float t = 0.0f; cgltf_bool r = cgltf_accessor_read_float(channel.sampler->input, channel.sampler->input->count - 1, &t, 1); - + if (!r) { TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load input time", fileName); @@ -5394,13 +5394,13 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, unsigned in { animations[i].framePoses[j] = RL_MALLOC(animations[i].boneCount*sizeof(Transform)); float time = ((float) j*GLTF_ANIMDELAY)/1000.0f; - + for (int k = 0; k < animations[i].boneCount; k++) { Vector3 translation = {0, 0, 0}; Quaternion rotation = {0, 0, 0, 1}; Vector3 scale = {1, 1, 1}; - + if (boneChannels[k].translate) { if (!GetPoseAtTimeGLTF(boneChannels[k].translate->sampler->input, boneChannels[k].translate->sampler->output, time, &translation)) @@ -5438,7 +5438,7 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, unsigned in TRACELOG(LOG_INFO, "MODEL: [%s] Loaded animation: %s (%d frames, %fs)", fileName, animData.name, animations[i].frameCount, animDuration); RL_FREE(boneChannels); } - } + } else TRACELOG(LOG_ERROR, "MODEL: [%s] expected exactly one skin to load animation data from, but found %i", fileName, data->skins_count); cgltf_free(data); @@ -5632,7 +5632,7 @@ static Model LoadM3D(const char *fileName) model.meshes[k].vertices = (float *)RL_CALLOC(model.meshes[k].vertexCount*3, sizeof(float)); model.meshes[k].texcoords = (float *)RL_CALLOC(model.meshes[k].vertexCount*2, sizeof(float)); model.meshes[k].normals = (float *)RL_CALLOC(model.meshes[k].vertexCount*3, sizeof(float)); - + // If color map is provided, we allocate storage for vertex colors if (m3d->cmap != NULL) model.meshes[k].colors = RL_CALLOC(model.meshes[k].vertexCount*4, sizeof(unsigned char)); @@ -5643,7 +5643,7 @@ static Model LoadM3D(const char *fileName) model.meshes[k].animVertices = (float *)RL_CALLOC(model.meshes[k].vertexCount*3, sizeof(float)); model.meshes[k].animNormals = (float *)RL_CALLOC(model.meshes[k].vertexCount*3, sizeof(float)); } - + model.meshMaterial[k] = mi + 1; l = 0; } @@ -5658,7 +5658,7 @@ static Model LoadM3D(const char *fileName) model.meshes[k].vertices[l*9 + 6] = m3d->vertex[m3d->face[i].vertex[2]].x*m3d->scale; model.meshes[k].vertices[l*9 + 7] = m3d->vertex[m3d->face[i].vertex[2]].y*m3d->scale; model.meshes[k].vertices[l*9 + 8] = m3d->vertex[m3d->face[i].vertex[2]].z*m3d->scale; - + // without vertex color (full transparency), we use the default color if (model.meshes[k].colors != NULL) { @@ -5809,7 +5809,7 @@ static Model LoadM3D(const char *fileName) model.bindPose[i].rotation.y = m3d->vertex[m3d->bone[i].ori].y; model.bindPose[i].rotation.z = m3d->vertex[m3d->bone[i].ori].z; model.bindPose[i].rotation.w = m3d->vertex[m3d->bone[i].ori].w; - + // TODO: if the orientation quaternion not normalized, then that's encoding scaling model.bindPose[i].rotation = QuaternionNormalize(model.bindPose[i].rotation); model.bindPose[i].scale.x = model.bindPose[i].scale.y = model.bindPose[i].scale.z = 1.0f; @@ -5918,7 +5918,7 @@ static ModelAnimation *LoadModelAnimationsM3D(const char *fileName, unsigned int animations[a].framePoses[i] = RL_MALLOC((m3d->numbone + 1)*sizeof(Transform)); m3db_t *pose = m3d_pose(m3d, a, i*M3D_ANIMDELAY); - + if (pose != NULL) { for (j = 0; j < (int)m3d->numbone; j++) diff --git a/src/rshapes.c b/src/rshapes.c index 86e014e2ad42..4c50724599d8 100644 --- a/src/rshapes.c +++ b/src/rshapes.c @@ -300,7 +300,7 @@ void DrawLineBezierCubic(Vector2 startPos, Vector2 endPos, Vector2 startControlP float dy = current.y-previous.y; float dx = current.x-previous.x; float size = 0.5f*thick/sqrtf(dx*dx+dy*dy); - + if (i==1) { points[0].x = previous.x+dy*size; @@ -1639,19 +1639,19 @@ bool CheckCollisionPointTriangle(Vector2 point, Vector2 p1, Vector2 p2, Vector2 bool CheckCollisionPointPoly(Vector2 point, Vector2 *points, int pointCount) { bool collision = false; - + if (pointCount > 2) { for (int i = 0; i < pointCount - 1; i++) { Vector2 vc = points[i]; Vector2 vn = points[i + 1]; - + if ((((vc.y >= point.y) && (vn.y < point.y)) || ((vc.y < point.y) && (vn.y >= point.y))) && (point.x < ((vn.x - vc.x)*(point.y - vc.y)/(vn.y - vc.y) + vc.x))) collision = !collision; } } - + return collision; } diff --git a/src/rtext.c b/src/rtext.c index 9908b44dfc70..52fc615df29f 100644 --- a/src/rtext.c +++ b/src/rtext.c @@ -1869,7 +1869,7 @@ int GetCodepointNext(const char *text, int *codepointSize) const char *ptr = text; int codepoint = 0x3f; // Codepoint (defaults to '?') *codepointSize = 0; - + // Get current codepoint and bytes processed if (0xf0 == (0xf8 & ptr[0])) { @@ -1882,20 +1882,20 @@ int GetCodepointNext(const char *text, int *codepointSize) // 3 byte UTF-8 codepoint */ 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 codepoint = ((0x1f & ptr[0]) << 6) | (0x3f & ptr[1]); *codepointSize = 2; - } + } else { // 1 byte UTF-8 codepoint codepoint = ptr[0]; *codepointSize = 1; } - + return codepoint; } @@ -1910,7 +1910,7 @@ int GetCodepointPrevious(const char *text, int *codepointSize) // Move to previous codepoint do ptr--; while (((0x80 & ptr[0]) != 0) && ((0xc0 & ptr[0]) == 0x80)); - + codepoint = GetCodepointNext(ptr, &cpSize); if (codepoint != 0) *codepointSize = cpSize; diff --git a/src/rtextures.c b/src/rtextures.c index 89a91b0519a4..c3744f640f0b 100644 --- a/src/rtextures.c +++ b/src/rtextures.c @@ -923,7 +923,7 @@ Image GenImageCellular(int width, int height, int tileSize) Image GenImageText(int width, int height, const char *text) { Image image = { 0 }; - + int textLength = TextLength(text); int imageViewSize = width*height; @@ -1551,7 +1551,7 @@ void ImageBlurGaussian(Image *image, int blurSize) { float avgAlpha = 0.0f; int convolutionSize = blurSize+1; - for (int i = 0; i < blurSize+1; i++) + for (int i = 0; i < blurSize+1; i++) { avgR += pixelsCopy1[row*image->width + i].x; avgG += pixelsCopy1[row*image->width + i].y; @@ -1600,7 +1600,7 @@ void ImageBlurGaussian(Image *image, int blurSize) { float avgAlpha = 0.0f; int convolutionSize = blurSize+1; - for (int i = 0; i < blurSize+1; i++) + for (int i = 0; i < blurSize+1; i++) { avgR += pixelsCopy2[i*image->width + col].x; avgG += pixelsCopy2[i*image->width + col].y; @@ -2931,7 +2931,7 @@ void ImageDrawCircle(Image* dst, int centerX, int centerY, int radius, Color col { y--; decesionParameter = decesionParameter + 4*(x - y) + 10; - } + } else decesionParameter = decesionParameter + 4*x + 6; } } @@ -3998,10 +3998,10 @@ Color ColorTint(Color color, Color tint) Color ColorBrightness(Color color, float factor) { Color result = color; - + if (factor > 1.0f) factor = 1.0f; else if (factor < -1.0f) factor = -1.0f; - + float red = (float)color.r; float green = (float)color.g; float blue = (float)color.b; @@ -4019,7 +4019,7 @@ Color ColorBrightness(Color color, float factor) green = (255 - green)*factor + green; blue = (255 - blue)*factor + blue; } - + result.r = (unsigned char)red; result.g = (unsigned char)green; result.b = (unsigned char)blue; @@ -4032,7 +4032,7 @@ Color ColorBrightness(Color color, float factor) Color ColorContrast(Color color, float contrast) { Color result = color; - + if (contrast < -1.0f) contrast = -1.0f; else if (contrast > 1.0f) contrast = 1.0f; From 04ab76b88927981844aedcdeaebd8f1866a32406 Mon Sep 17 00:00:00 2001 From: star-tek-mb Date: Mon, 6 Feb 2023 14:28:24 +0500 Subject: [PATCH 087/192] zig build: do not use deprecated functions (#2913) --- examples/build.zig | 4 ++-- src/build.zig | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/build.zig b/examples/build.zig index c0479910f4a2..65586f12fec6 100644 --- a/examples/build.zig +++ b/examples/build.zig @@ -1,7 +1,7 @@ const std = @import("std"); const builtin = @import("builtin"); -fn add_module(comptime module: []const u8, b: *std.build.Builder, target: std.zig.CrossTarget, optimize: std.builtin.OptimizeMode) !*std.build.Step { +fn add_module(comptime module: []const u8, b: *std.Build, target: std.zig.CrossTarget, optimize: std.builtin.OptimizeMode) !*std.Build.Step { if (target.getOsTag() == .emscripten) { @panic("Emscripten building via Zig unsupported"); } @@ -81,7 +81,7 @@ fn add_module(comptime module: []const u8, b: *std.build.Builder, target: std.zi return all; } -pub fn build(b: *std.build.Builder) !void { +pub fn build(b: *std.Build) !void { // Standard target options allows the person running `zig build` to choose // what target to build for. Here we do not override the defaults, which // means any target is allowed, and the default is native. Other options diff --git a/src/build.zig b/src/build.zig index adf7fdc9dcf7..84684fef83bc 100644 --- a/src/build.zig +++ b/src/build.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn addRaylib(b: *std.build.Builder, target: std.zig.CrossTarget, optimize: std.builtin.OptimizeMode) *std.build.LibExeObjStep { +pub fn addRaylib(b: *std.Build, target: std.zig.CrossTarget, optimize: std.builtin.OptimizeMode) *std.Build.CompileStep { const raylib_flags = &[_][]const u8{ "-std=gnu99", "-D_GNU_SOURCE", @@ -103,7 +103,7 @@ pub fn addRaylib(b: *std.build.Builder, target: std.zig.CrossTarget, optimize: s return raylib; } -pub fn build(b: *std.build.Builder) void { +pub fn build(b: *std.Build) void { // Standard target options allows the person running `zig build` to choose // what target to build for. Here we do not override the defaults, which // means any target is allowed, and the default is native. Other options From e187b693eaa4873a0d44d6578f44c269fd751315 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 6 Feb 2023 11:02:46 +0100 Subject: [PATCH 088/192] Update raudio.c --- src/raudio.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/raudio.c b/src/raudio.c index 04ae35c5a996..4705ca58298f 100644 --- a/src/raudio.c +++ b/src/raudio.c @@ -1380,6 +1380,7 @@ Music LoadMusicStream(const char *fileName) qoa_desc *ctxQoa = RL_CALLOC(1, sizeof(qoa_desc)); // TODO: QOA stream support: Init context from file + int result = 0; music.ctxType = MUSIC_AUDIO_QOA; music.ctxData = ctxQoa; @@ -1578,11 +1579,12 @@ Music LoadMusicStreamFromMemory(const char *fileType, const unsigned char *data, qoa_desc *ctxQoa = RL_CALLOC(1, sizeof(qoa_desc)); // TODO: Init QOA context data + int result = 0; music.ctxType = MUSIC_AUDIO_QOA; music.ctxData = ctxQoa; - if (success) + if (result > 0) { music.stream = LoadAudioStream(ctxQoa->samplerate, 16, ctxQoa->channels); From f784961b9ce8f516c60b11d73444803db363ca0d Mon Sep 17 00:00:00 2001 From: Nikolas Date: Tue, 7 Feb 2023 22:18:14 +0100 Subject: [PATCH 089/192] Enable GetWindowHandle() on macOS (#2915) --- src/rcore.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/rcore.c b/src/rcore.c index 98800a790d4e..7af6551672e6 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -242,6 +242,7 @@ #include // Required for: usleep() //#define GLFW_EXPOSE_NATIVE_COCOA // WARNING: Fails due to type redefinition + void *glfwGetCocoaWindow(GLFWwindow* handle); #include "GLFW/glfw3native.h" // Required for: glfwGetCocoaWindow() #endif @@ -1677,7 +1678,7 @@ void *GetWindowHandle(void) #endif #if defined(__APPLE__) // NOTE: Returned handle is: (objc_object *) - return NULL; // TODO: return (void *)glfwGetCocoaWindow(window); + return (void *)glfwGetCocoaWindow(CORE.Window.handle); #endif return NULL; From 5c6a756014fa27e6ec534e6bafa4cf4e1fac890c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sasquatch=20=E3=83=BD=28=C2=B4=E3=83=BC=60=20=29=E2=94=8C?= <74960320+foreignsasquatch@users.noreply.github.com> Date: Wed, 8 Feb 2023 18:15:34 +0530 Subject: [PATCH 090/192] Update raylib-hx bindings to 4.2 in BINDINGS.md (#2916) --- BINDINGS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BINDINGS.md b/BINDINGS.md index 1bc2c57acd01..f703296a7895 100644 --- a/BINDINGS.md +++ b/BINDINGS.md @@ -27,7 +27,7 @@ Some people ported raylib to other languages in form of bindings or wrappers to | raylib-guile | auto | [Guile](https://www.gnu.org/software/guile/) | Zlib | https://github.com/petelliott/raylib-guile | | gforth-raylib | 3.5 | [Gforth](https://gforth.org/) | MIT | https://github.com/ArnautDaniel/gforth-raylib | | h-raylib | 4.5-dev | [Haskell](https://haskell.org/) | Apache-2.0 | https://github.com/Anut-py/h-raylib | -| raylib-hx | 4.0 | [Haxe](https://haxe.org/) | Zlib | https://github.com/foreignsasquatch/raylib-hx | +| raylib-hx | **4.2** | [Haxe](https://haxe.org/) | Zlib | https://github.com/foreignsasquatch/raylib-hx | | hb-raylib | 3.5 | [Harbour](https://harbour.github.io) | MIT | https://github.com/MarcosLeonardoMendezGerencir/hb-raylib | | jaylib | **4.2** | [Java](https://en.wikipedia.org/wiki/Java_(programming_language)) | GPLv3+CE | https://github.com/electronstudio/jaylib/ | | raylib-j | **4.0** | [Java](https://en.wikipedia.org/wiki/Java_(programming_language)) | Zlib | https://github.com/CreedVI/Raylib-J | From 6ae21d6581e6030dbb218a932d3ae280e26481ff Mon Sep 17 00:00:00 2001 From: "Julio C. Galindo" <54072664+stickM4N@users.noreply.github.com> Date: Thu, 9 Feb 2023 07:17:47 -0500 Subject: [PATCH 091/192] Fixed some grammar mistakes and typos. (#2914) * Fixed some grammar mistakes. * Fixed some typos. --- src/config.h | 18 ++++++++-------- src/minshell.html | 2 +- src/raudio.c | 20 +++++++++--------- src/raylib.h | 16 +++++++-------- src/rcamera.h | 2 +- src/rcore.c | 52 +++++++++++++++++++++++------------------------ src/rgestures.h | 10 ++++----- src/rlgl.h | 2 +- src/rmodels.c | 36 ++++++++++++++++---------------- src/rshapes.c | 6 +++--- src/rtext.c | 22 ++++++++++---------- src/rtextures.c | 26 ++++++++++++------------ src/shell.html | 2 +- src/utils.c | 8 ++++---- 14 files changed, 111 insertions(+), 111 deletions(-) diff --git a/src/config.h b/src/config.h index be24c01904ce..48f66aba4a54 100644 --- a/src/config.h +++ b/src/config.h @@ -50,7 +50,7 @@ // Setting a higher resolution can improve the accuracy of time-out intervals in wait functions. // However, it can also reduce overall system performance, because the thread scheduler switches tasks more often. #define SUPPORT_WINMM_HIGHRES_TIMER 1 -// Use busy wait loop for timing sync, if not defined, a high-resolution timer is setup and used +// Use busy wait loop for timing sync, if not defined, a high-resolution timer is set up and used //#define SUPPORT_BUSY_WAIT_LOOP 1 // Use a partial-busy wait loop, in this case frame sleeps for most of the time, but then runs a busy loop at the end for accuracy #define SUPPORT_PARTIALBUSY_WAIT_LOOP @@ -65,7 +65,7 @@ // Support automatic generated events, loading and recording of those events when required //#define SUPPORT_EVENTS_AUTOMATION 1 // Support custom frame control, only for advance users -// By default EndDrawing() does this job: draws everything + SwapScreenBuffer() + manage frame timming + PollInputEvents() +// By default EndDrawing() does this job: draws everything + SwapScreenBuffer() + manage frame timing + PollInputEvents() // Enabling this flag allows manual control of the frame processes, use at your own risk //#define SUPPORT_CUSTOM_FRAME_CONTROL 1 @@ -110,12 +110,12 @@ // Default shader vertex attribute names to set location points // NOTE: When a new shader is loaded, the following locations are tried to be set for convenience -#define RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION "vertexPosition" // Binded by default to shader location: 0 -#define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD "vertexTexCoord" // Binded by default to shader location: 1 -#define RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL "vertexNormal" // Binded by default to shader location: 2 -#define RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR "vertexColor" // Binded by default to shader location: 3 -#define RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT "vertexTangent" // Binded by default to shader location: 4 -#define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 "vertexTexCoord2" // Binded by default to shader location: 5 +#define RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION "vertexPosition" // Bound by default to shader location: 0 +#define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD "vertexTexCoord" // Bound by default to shader location: 1 +#define RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL "vertexNormal" // Bound by default to shader location: 2 +#define RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR "vertexColor" // Bound by default to shader location: 3 +#define RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT "vertexTangent" // Bound by default to shader location: 4 +#define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 "vertexTexCoord2" // Bound by default to shader location: 5 #define RL_DEFAULT_SHADER_UNIFORM_NAME_MVP "mvp" // model-view-projection matrix #define RL_DEFAULT_SHADER_UNIFORM_NAME_VIEW "matView" // view matrix @@ -139,7 +139,7 @@ //------------------------------------------------------------------------------------ // Module: rtextures - Configuration Flags //------------------------------------------------------------------------------------ -// Selecte desired fileformats to be supported for image data loading +// Select the desired fileformats to be supported for image data loading #define SUPPORT_FILEFORMAT_PNG 1 //#define SUPPORT_FILEFORMAT_BMP 1 //#define SUPPORT_FILEFORMAT_TGA 1 diff --git a/src/minshell.html b/src/minshell.html index 4f0d6ade0871..2aa75578fa35 100644 --- a/src/minshell.html +++ b/src/minshell.html @@ -1,5 +1,5 @@ - + diff --git a/src/raudio.c b/src/raudio.c index 4705ca58298f..443fb924ea54 100644 --- a/src/raudio.c +++ b/src/raudio.c @@ -314,7 +314,7 @@ typedef enum { #endif // NOTE: Different logic is used when feeding data to the playback device -// depending on whether or not data is streamed (Music vs Sound) +// depending on whether data is streamed (Music vs Sound) typedef enum { AUDIO_BUFFER_USAGE_STATIC = 0, AUDIO_BUFFER_USAGE_STREAM @@ -474,7 +474,7 @@ void InitAudioDevice(void) return; } - // Mixing happens on a seperate thread which means we need to synchronize. I'm using a mutex here to make things simple, but may + // Mixing happens on a separate thread which means we need to synchronize. I'm using a mutex here to make things simple, but may // want to look at something a bit smarter later on to keep everything real-time, if that's necessary. if (ma_mutex_init(&AUDIO.System.lock) != MA_SUCCESS) { @@ -1089,7 +1089,7 @@ void PlaySoundMulti(Sound sound) unsigned int oldAge = 0; int oldIndex = -1; - // find the first non playing pool entry + // find the first non-playing pool entry for (int i = 0; i < MAX_AUDIO_BUFFER_POOL_CHANNELS; i++) { if (AUDIO.MultiChannel.channels[i] > oldAge) @@ -1105,7 +1105,7 @@ void PlaySoundMulti(Sound sound) } } - // If no none playing pool members can be index choose the oldest + // If no none playing pool members can be indexed choose the oldest if (index == -1) { TRACELOG(LOG_WARNING, "SOUND: Buffer pool is already full, count: %i", AUDIO.MultiChannel.poolCounter); @@ -1113,7 +1113,7 @@ void PlaySoundMulti(Sound sound) if (oldIndex == -1) { // Shouldn't be able to get here... but just in case something odd happens! - TRACELOG(LOG_WARNING, "SOUND: Buffer pool could not determine oldest buffer not playing sound"); + TRACELOG(LOG_WARNING, "SOUND: Buffer pool could not determine the oldest buffer not playing sound"); return; } @@ -2107,8 +2107,8 @@ void UnloadAudioStream(AudioStream stream) } // Update audio stream buffers with data -// NOTE 1: Only updates one buffer of the stream source: unqueue -> update -> queue -// NOTE 2: To unqueue a buffer it needs to be processed: IsAudioStreamProcessed() +// NOTE 1: Only updates one buffer of the stream source: dequeue -> update -> queue +// NOTE 2: To dequeue a buffer it needs to be processed: IsAudioStreamProcessed() void UpdateAudioStream(AudioStream stream, const void *data, int frameCount) { if (stream.buffer != NULL) @@ -2305,7 +2305,7 @@ static ma_uint32 ReadAudioBufferFramesInInternalFormat(AudioBuffer *audioBuffer, if (currentSubBufferIndex > 1) return 0; - // Another thread can update the processed state of buffers so + // Another thread can update the processed state of buffers, so // we just take a copy here to try and avoid potential synchronization problems bool isSubBufferProcessed[2] = { 0 }; isSubBufferProcessed[0] = audioBuffer->isSubBufferProcessed[0]; @@ -2319,7 +2319,7 @@ static ma_uint32 ReadAudioBufferFramesInInternalFormat(AudioBuffer *audioBuffer, { // We break from this loop differently depending on the buffer's usage // - For static buffers, we simply fill as much data as we can - // - For streaming buffers we only fill the halves of the buffer that are processed + // - For streaming buffers we only fill half of the buffer that are processed // Unprocessed halves must keep their audio data in-tact if (audioBuffer->usage == AUDIO_BUFFER_USAGE_STATIC) { @@ -2376,7 +2376,7 @@ static ma_uint32 ReadAudioBufferFramesInInternalFormat(AudioBuffer *audioBuffer, // For static buffers we can fill the remaining frames with silence for safety, but we don't want // to report those frames as "read". The reason for this is that the caller uses the return value - // to know whether or not a non-looping sound has finished playback. + // to know whether a non-looping sound has finished playback. if (audioBuffer->usage != AUDIO_BUFFER_USAGE_STATIC) framesRead += totalFramesRemaining; } diff --git a/src/raylib.h b/src/raylib.h index e0b7a31598dd..e31a514a6738 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -216,7 +216,7 @@ typedef struct Vector4 { // Quaternion, 4 components (Vector4 alias) typedef Vector4 Quaternion; -// Matrix, 4x4 components, column major, OpenGL style, right handed +// Matrix, 4x4 components, column major, OpenGL style, right-handed typedef struct Matrix { float m0, m4, m8, m12; // Matrix first row (4 components) float m1, m5, m9, m13; // Matrix second row (4 components) @@ -413,8 +413,8 @@ typedef struct Ray { // RayCollision, ray hit information typedef struct RayCollision { bool hit; // Did the ray hit something? - float distance; // Distance to nearest hit - Vector3 point; // Point of nearest hit + float distance; // Distance to the nearest hit + Vector3 point; // Point of the nearest hit Vector3 normal; // Surface normal of hit } RayCollision; @@ -681,7 +681,7 @@ typedef enum { MOUSE_CURSOR_RESIZE_NS = 6, // Vertical resize/move arrow shape MOUSE_CURSOR_RESIZE_NWSE = 7, // Top-left to bottom-right diagonal resize/move arrow shape MOUSE_CURSOR_RESIZE_NESW = 8, // The top-right to bottom-left diagonal resize/move arrow shape - MOUSE_CURSOR_RESIZE_ALL = 9, // The omni-directional resize/move cursor shape + MOUSE_CURSOR_RESIZE_ALL = 9, // The omnidirectional resize/move cursor shape MOUSE_CURSOR_NOT_ALLOWED = 10 // The operation-not-allowed shape } MouseCursor; @@ -839,10 +839,10 @@ typedef enum { typedef enum { CUBEMAP_LAYOUT_AUTO_DETECT = 0, // Automatically detect layout type CUBEMAP_LAYOUT_LINE_VERTICAL, // Layout is defined by a vertical line with faces - CUBEMAP_LAYOUT_LINE_HORIZONTAL, // Layout is defined by an horizontal line with faces + CUBEMAP_LAYOUT_LINE_HORIZONTAL, // Layout is defined by a horizontal line with faces CUBEMAP_LAYOUT_CROSS_THREE_BY_FOUR, // Layout is defined by a 3x4 cross with cubemap faces CUBEMAP_LAYOUT_CROSS_FOUR_BY_THREE, // Layout is defined by a 4x3 cross with cubemap faces - CUBEMAP_LAYOUT_PANORAMA // Layout is defined by a panorama image (equirectangular map) + CUBEMAP_LAYOUT_PANORAMA // Layout is defined by a panorama image (equirrectangular map) } CubemapLayout; // Font type, defines generation method @@ -903,7 +903,7 @@ typedef enum { } NPatchLayout; // Callbacks to hook some internal functions -// WARNING: This callbacks are intended for advance users +// WARNING: These callbacks are intended for advance users typedef void (*TraceLogCallback)(int logLevel, const char *text, va_list args); // Logging: Redirect trace log messages typedef unsigned char *(*LoadFileDataCallback)(const char *fileName, unsigned int *bytesRead); // FileIO: Load binary data typedef bool (*SaveFileDataCallback)(const char *fileName, void *data, unsigned int bytesToWrite); // FileIO: Save binary data @@ -1228,7 +1228,7 @@ RLAPI Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2); //------------------------------------------------------------------------------------ // Image loading functions -// NOTE: This functions do not require GPU access +// NOTE: These functions do not require GPU access RLAPI Image LoadImage(const char *fileName); // Load image from file into CPU memory (RAM) RLAPI Image LoadImageRaw(const char *fileName, int width, int height, int format, int headerSize); // Load image from RAW file data RLAPI Image LoadImageAnim(const char *fileName, int *frames); // Load image sequence from file (frames appended to image.data) diff --git a/src/rcamera.h b/src/rcamera.h index 70221b34747f..0caad666da86 100644 --- a/src/rcamera.h +++ b/src/rcamera.h @@ -150,7 +150,7 @@ void SetCameraMoveControls(int keyFront, int keyBack, #endif // Camera mouse movement sensitivity -#define CAMERA_MOUSE_MOVE_SENSITIVITY 0.5f // TODO: it should be independant of framerate +#define CAMERA_MOUSE_MOVE_SENSITIVITY 0.5f // TODO: it should be independent of framerate #define CAMERA_MOUSE_SCROLL_SENSITIVITY 1.5f // FREE_CAMERA diff --git a/src/rcore.c b/src/rcore.c index 7af6551672e6..83a70632eee4 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -865,7 +865,7 @@ void InitWindow(int width, int height, const char *title) LoadFontDefault(); #if defined(SUPPORT_MODULE_RSHAPES) Rectangle rec = GetFontDefault().recs[95]; - // NOTE: We setup a 1px padding on char rectangle to avoid pixel bleeding on MSAA filtering + // NOTE: We set up a 1px padding on char rectangle to avoid pixel bleeding on MSAA filtering SetShapesTexture(GetFontDefault().texture, (Rectangle){ rec.x + 1, rec.y + 1, rec.width - 2, rec.height - 2 }); // WARNING: Module required: rshapes #endif #else @@ -1318,7 +1318,7 @@ void MaximizeWindow(void) void MinimizeWindow(void) { #if defined(PLATFORM_DESKTOP) - // NOTE: Following function launches callback that sets appropiate flag! + // NOTE: Following function launches callback that sets appropriate flag! glfwIconifyWindow(CORE.Window.handle); #endif } @@ -1417,13 +1417,13 @@ void SetWindowState(unsigned int flags) // State change: FLAG_WINDOW_TRANSPARENT if (((CORE.Window.flags & FLAG_WINDOW_TRANSPARENT) != (flags & FLAG_WINDOW_TRANSPARENT)) && ((flags & FLAG_WINDOW_TRANSPARENT) > 0)) { - TRACELOG(LOG_WARNING, "WINDOW: Framebuffer transparency can only by configured before window initialization"); + TRACELOG(LOG_WARNING, "WINDOW: Framebuffer transparency can only be configured before window initialization"); } // State change: FLAG_WINDOW_HIGHDPI if (((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) != (flags & FLAG_WINDOW_HIGHDPI)) && ((flags & FLAG_WINDOW_HIGHDPI) > 0)) { - TRACELOG(LOG_WARNING, "WINDOW: High DPI can only by configured before window initialization"); + TRACELOG(LOG_WARNING, "WINDOW: High DPI can only be configured before window initialization"); } // State change: FLAG_WINDOW_MOUSE_PASSTHROUGH @@ -1436,13 +1436,13 @@ void SetWindowState(unsigned int flags) // State change: FLAG_MSAA_4X_HINT if (((CORE.Window.flags & FLAG_MSAA_4X_HINT) != (flags & FLAG_MSAA_4X_HINT)) && ((flags & FLAG_MSAA_4X_HINT) > 0)) { - TRACELOG(LOG_WARNING, "WINDOW: MSAA can only by configured before window initialization"); + TRACELOG(LOG_WARNING, "WINDOW: MSAA can only be configured before window initialization"); } // 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 by configured before window initialization"); + TRACELOG(LOG_WARNING, "RPI: Interlaced mode can only be configured before window initialization"); } #endif } @@ -1525,13 +1525,13 @@ void ClearWindowState(unsigned int flags) // State change: FLAG_WINDOW_TRANSPARENT if (((CORE.Window.flags & FLAG_WINDOW_TRANSPARENT) > 0) && ((flags & FLAG_WINDOW_TRANSPARENT) > 0)) { - TRACELOG(LOG_WARNING, "WINDOW: Framebuffer transparency can only by configured before window initialization"); + TRACELOG(LOG_WARNING, "WINDOW: Framebuffer transparency can only be configured before window initialization"); } // State change: FLAG_WINDOW_HIGHDPI if (((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0) && ((flags & FLAG_WINDOW_HIGHDPI) > 0)) { - TRACELOG(LOG_WARNING, "WINDOW: High DPI can only by configured before window initialization"); + TRACELOG(LOG_WARNING, "WINDOW: High DPI can only be configured before window initialization"); } // State change: FLAG_WINDOW_MOUSE_PASSTHROUGH @@ -1544,13 +1544,13 @@ void ClearWindowState(unsigned int flags) // State change: FLAG_MSAA_4X_HINT if (((CORE.Window.flags & FLAG_MSAA_4X_HINT) > 0) && ((flags & FLAG_MSAA_4X_HINT) > 0)) { - TRACELOG(LOG_WARNING, "WINDOW: MSAA can only by configured before window initialization"); + TRACELOG(LOG_WARNING, "WINDOW: MSAA can only be configured before window initialization"); } // State change: FLAG_INTERLACED_HINT if (((CORE.Window.flags & FLAG_INTERLACED_HINT) > 0) && ((flags & FLAG_INTERLACED_HINT) > 0)) { - TRACELOG(LOG_WARNING, "RPI: Interlaced mode can only by configured before window initialization"); + TRACELOG(LOG_WARNING, "RPI: Interlaced mode can only be configured before window initialization"); } #endif } @@ -2482,10 +2482,10 @@ Shader LoadShaderFromMemory(const char *vsCode, const char *fsCode) shader.locs = (int *)RL_CALLOC(RL_MAX_SHADER_LOCATIONS, sizeof(int)); - // All locations reseted to -1 (no location) + // All locations reset to -1 (no location) for (int i = 0; i < RL_MAX_SHADER_LOCATIONS; i++) shader.locs[i] = -1; - // Get handles to GLSL input attibute locations + // Get handles to GLSL input attribute locations shader.locs[SHADER_LOC_VERTEX_POSITION] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION); shader.locs[SHADER_LOC_VERTEX_TEXCOORD01] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD); shader.locs[SHADER_LOC_VERTEX_TEXCOORD02] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2); @@ -2553,7 +2553,7 @@ void SetShaderValueV(Shader shader, int locIndex, const void *value, int uniform { rlEnableShader(shader.id); rlSetUniform(locIndex, value, uniformType, count); - //rlDisableShader(); // Avoid reseting current shader program, in case other uniforms are set + //rlDisableShader(); // Avoid resetting current shader program, in case other uniforms are set } } @@ -2618,7 +2618,7 @@ Ray GetMouseRay(Vector2 mouse, Camera camera) Vector3 farPoint = Vector3Unproject((Vector3){ deviceCoords.x, deviceCoords.y, 1.0f }, matProj, matView); // Unproject the mouse cursor in the near plane. - // We need this as the source position because orthographic projects, compared to perspect doesn't have a + // We need this as the source position because orthographic projects, compared to perspective doesn't have a // convergence point, meaning that the "eye" of the camera is more like a plane than a point. Vector3 cameraPlanePointerPos = Vector3Unproject((Vector3){ deviceCoords.x, deviceCoords.y, -1.0f }, matProj, matView); @@ -2808,7 +2808,7 @@ double GetTime(void) // Setup window configuration flags (view FLAGS) // NOTE: This function is expected to be called before window creation, -// because it setups some flags for the window creation process. +// because it sets up some flags for the window creation process. // To configure window states after creation, just use SetWindowState() void SetConfigFlags(unsigned int flags) { @@ -3929,7 +3929,7 @@ static bool InitGraphicsDevice(int width, int height) CORE.Window.screenScale = MatrixIdentity(); // No draw scaling required by default // NOTE: Framebuffer (render area - CORE.Window.render.width, CORE.Window.render.height) could include black bars... - // ...in top-down or left-right to match display aspect ratio (no weird scalings) + // ...in top-down or left-right to match display aspect ratio (no weird scaling) #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) glfwSetErrorCallback(ErrorCallback); @@ -4100,8 +4100,8 @@ static bool InitGraphicsDevice(int width, int height) // remember center for switchinging from fullscreen to window if ((CORE.Window.screen.height == CORE.Window.display.height) && (CORE.Window.screen.width == CORE.Window.display.width)) { - // If screen width/height equal to the dislpay, we can't calclulate the window pos for toggling fullscreened/windowed. - // Toggling fullscreened/windowed with pos(0, 0) can cause problems in some platforms, such as X11. + // If screen width/height equal to the display, we can't calculate the window pos for toggling full-screened/windowed. + // Toggling full-screened/windowed with pos(0, 0) can cause problems in some platforms, such as X11. CORE.Window.position.x = CORE.Window.display.width/4; CORE.Window.position.y = CORE.Window.display.height/4; } @@ -4138,7 +4138,7 @@ static bool InitGraphicsDevice(int width, int height) // framebuffer is rendered correctly but once displayed on a 16:9 monitor, it gets stretched // by the sides to fit all monitor space... - // Try to setup the most appropiate fullscreen framebuffer for the requested screenWidth/screenHeight + // Try to setup the most appropriate fullscreen framebuffer for the requested screenWidth/screenHeight // It considers device display resolution mode and setups a framebuffer with black bars if required (render size/offset) // Modified global variables: CORE.Window.screen.width/CORE.Window.screen.height - CORE.Window.render.width/CORE.Window.render.height - CORE.Window.renderOffset.x/CORE.Window.renderOffset.y - CORE.Window.screenScale // TODO: It is a quite cumbersome solution to display size vs requested size, it should be reviewed or removed... @@ -4205,7 +4205,7 @@ static bool InitGraphicsDevice(int width, int height) // NOTE: V-Sync can be enabled by graphic driver configuration if (CORE.Window.flags & FLAG_VSYNC_HINT) { - // WARNING: It seems to hits a critical render path in Intel HD Graphics + // WARNING: It seems to hit a critical render path in Intel HD Graphics glfwSwapInterval(1); TRACELOG(LOG_INFO, "DISPLAY: Trying to enable VSYNC"); } @@ -4216,12 +4216,12 @@ static bool InitGraphicsDevice(int width, int height) #if defined(PLATFORM_DESKTOP) if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0) { - // NOTE: On APPLE platforms system should manage window/input scaling and also framebuffer scaling + // NOTE: On APPLE platforms system should manage window/input scaling and also framebuffer scaling. // Framebuffer scaling should be activated with: glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER, GLFW_TRUE); #if !defined(__APPLE__) glfwGetFramebufferSize(CORE.Window.handle, &fbWidth, &fbHeight); - // Screen scaling matrix is required in case desired screen area is different than display area + // Screen scaling matrix is required in case desired screen area is different from display area CORE.Window.screenScale = MatrixScale((float)fbWidth/CORE.Window.screen.width, (float)fbHeight/CORE.Window.screen.height, 1.0f); // Mouse input scaling for the new screen size @@ -4819,7 +4819,7 @@ static void InitTimer(void) // NOTE: Sleep() granularity could be around 10 ms, it means, Sleep() could // take longer than expected... for that reason we use the busy wait loop // Ref: http://stackoverflow.com/questions/43057578/c-programming-win32-games-sleep-taking-longer-than-expected -// Ref: http://www.geisswerks.com/ryan/FAQS/timing.html --> All about timming on Win32! +// Ref: http://www.geisswerks.com/ryan/FAQS/timing.html --> All about timing on Win32! void WaitTime(double seconds) { #if defined(SUPPORT_BUSY_WAIT_LOOP) || defined(SUPPORT_PARTIALBUSY_WAIT_LOOP) @@ -5414,7 +5414,7 @@ static void CharCallback(GLFWwindow *window, unsigned int key) //TRACELOG(LOG_DEBUG, "Char Callback: KEY:%i(%c)", key, key); // NOTE: Registers any key down considering OS keyboard layout but - // do not detects action events, those should be managed by user... + // does not detect action events, those should be managed by user... // Ref: https://github.com/glfw/glfw/issues/668#issuecomment-166794907 // Ref: https://www.glfw.org/docs/latest/input_guide.html#input_char @@ -5457,7 +5457,7 @@ static void MouseButtonCallback(GLFWwindow *window, int button, int action, int gestureEvent.position[0].x /= (float)GetScreenWidth(); gestureEvent.position[0].y /= (float)GetScreenHeight(); - // Gesture data is sent to gestures system for processing + // Gesture data is sent to gestures-system for processing ProcessGestureEvent(gestureEvent); #endif } @@ -5488,7 +5488,7 @@ static void MouseCursorPosCallback(GLFWwindow *window, double x, double y) gestureEvent.position[0].x /= (float)GetScreenWidth(); gestureEvent.position[0].y /= (float)GetScreenHeight(); - // Gesture data is sent to gestures system for processing + // Gesture data is sent to gestures-system for processing ProcessGestureEvent(gestureEvent); #endif } diff --git a/src/rgestures.h b/src/rgestures.h index b63ac9678d80..a7440fb9856b 100644 --- a/src/rgestures.h +++ b/src/rgestures.h @@ -249,7 +249,7 @@ static double rgGetCurrentTime(void); // Module Functions Definition //---------------------------------------------------------------------------------- -// Enable only desired getures to be detected +// Enable only desired gestures to be detected void SetGesturesEnabled(unsigned int flags) { GESTURES.enabledFlags = flags; @@ -300,7 +300,7 @@ void ProcessGestureEvent(GestureEvent event) { if (GESTURES.current == GESTURE_DRAG) GESTURES.Touch.upPosition = event.position[0]; - // NOTE: GESTURES.Drag.intensity dependend on the resolution of the screen + // NOTE: GESTURES.Drag.intensity dependent on the resolution of the screen GESTURES.Drag.distance = rgVector2Distance(GESTURES.Touch.downPositionA, GESTURES.Touch.upPosition); GESTURES.Drag.intensity = GESTURES.Drag.distance/(float)((rgGetCurrentTime() - GESTURES.Swipe.timeDuration)); @@ -472,7 +472,7 @@ Vector2 GetGestureDragVector(void) } // Get drag angle -// NOTE: Angle in degrees, horizontal-right is 0, counterclock-wise +// NOTE: Angle in degrees, horizontal-right is 0, counterclockwise float GetGestureDragAngle(void) { // NOTE: drag angle is calculated on one touch points TOUCH_ACTION_UP @@ -488,8 +488,8 @@ Vector2 GetGesturePinchVector(void) return GESTURES.Pinch.vector; } -// Get angle beween two pinch points -// NOTE: Angle in degrees, horizontal-right is 0, counterclock-wise +// Get angle between two pinch points +// NOTE: Angle in degrees, horizontal-right is 0, counterclockwise float GetGesturePinchAngle(void) { // NOTE: pinch angle is calculated on two touch points TOUCH_ACTION_MOVE diff --git a/src/rlgl.h b/src/rlgl.h index ebd0f4de6482..f7d73edaf11b 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -502,7 +502,7 @@ typedef enum { } rlShaderAttributeDataType; // Framebuffer attachment type -// NOTE: By default up to 8 color channels defined but it can be more +// NOTE: By default up to 8 color channels defined, but it can be more typedef enum { RL_ATTACHMENT_COLOR_CHANNEL0 = 0, // Framebuffer attachment type: color 0 RL_ATTACHMENT_COLOR_CHANNEL1, // Framebuffer attachment type: color 1 diff --git a/src/rmodels.c b/src/rmodels.c index 4a8261795daf..893c031ef5e5 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -1125,7 +1125,7 @@ void UnloadModel(Model model) // Unload materials maps // NOTE: As the user could be sharing shaders and textures between models, - // we don't unload the material but just free it's maps, + // we don't unload the material but just free its maps, // the user is responsible for freeing models shaders and textures for (int i = 0; i < model.materialCount; i++) RL_FREE(model.materials[i].maps); @@ -1146,7 +1146,7 @@ void UnloadModelKeepMeshes(Model model) { // Unload materials maps // NOTE: As the user could be sharing shaders and textures between models, - // we don't unload the material but just free it's maps, + // we don't unload the material but just free its maps, // the user is responsible for freeing models shaders and textures for (int i = 0; i < model.materialCount; i++) RL_FREE(model.materials[i].maps); @@ -1230,7 +1230,7 @@ void UploadMesh(Mesh *mesh, bool dynamic) rlEnableVertexAttribute(1); // 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 + // is part of current state, and it is maintained even if a different program object is used if (mesh->normals != NULL) { @@ -1383,7 +1383,7 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform) } // Get a copy of current matrices to work with, - // just in case stereo render is required and we need to modify them + // just in case stereo render is required, and we need to modify them // NOTE: At this point the modelview matrix just contains the view matrix (camera) // That's because BeginMode3D() sets it and there is no model-drawing function // that modifies it, all use rlPushMatrix() and rlPopMatrix() @@ -1396,7 +1396,7 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform) if (material.shader.locs[SHADER_LOC_MATRIX_VIEW] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_VIEW], matView); if (material.shader.locs[SHADER_LOC_MATRIX_PROJECTION] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_PROJECTION], matProjection); - // Model transformation matrix is send to shader uniform location: SHADER_LOC_MATRIX_MODEL + // Model transformation matrix is sent to shader uniform location: SHADER_LOC_MATRIX_MODEL if (material.shader.locs[SHADER_LOC_MATRIX_MODEL] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_MODEL], transform); // Accumulate several model transformations: @@ -1517,7 +1517,7 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform) else rlDrawVertexArray(0, mesh.vertexCount); } - // Unbind all binded texture maps + // Unbind all bound texture maps for (int i = 0; i < MAX_MATERIAL_MAPS; i++) { if (material.maps[i].texture.id > 0) @@ -1587,7 +1587,7 @@ void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, i } // Get a copy of current matrices to work with, - // just in case stereo render is required and we need to modify them + // just in case stereo render is required, and we need to modify them // NOTE: At this point the modelview matrix just contains the view matrix (camera) // That's because BeginMode3D() sets it and there is no model-drawing function // that modifies it, all use rlPushMatrix() and rlPopMatrix() @@ -1738,7 +1738,7 @@ void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, i else rlDrawVertexArrayInstanced(0, mesh.vertexCount, instances); } - // Unbind all binded texture maps + // Unbind all bound texture maps for (int i = 0; i < MAX_MATERIAL_MAPS; i++) { if (material.maps[i].texture.id > 0) @@ -2559,7 +2559,7 @@ Mesh GenMeshSphere(float radius, int rings, int slices) return mesh; } -// Generate hemi-sphere mesh (half sphere, no bottom cap) +// Generate hemisphere mesh (half sphere, no bottom cap) Mesh GenMeshHemiSphere(float radius, int rings, int slices) { Mesh mesh = { 0 }; @@ -3242,7 +3242,7 @@ Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize) } } - // Move data from mapVertices temp arays to vertices float array + // Move data from mapVertices temp arrays to vertices float array mesh.vertexCount = vCounter; mesh.triangleCount = vCounter/3; @@ -3742,7 +3742,7 @@ RayCollision GetRayCollisionBox(Ray ray, BoundingBox box) // NOTE: We use an additional .01 to fix numerical errors collision.normal = Vector3Scale(collision.normal, 2.01f); collision.normal = Vector3Divide(collision.normal, Vector3Subtract(box.max, box.min)); - // The relevant elemets of the vector are now slightly larger than 1.0f (or smaller than -1.0f) + // The relevant elements of the vector are now slightly larger than 1.0f (or smaller than -1.0f) // and the others are somewhere between -1.0 and 1.0 casting to int is exactly our wanted normal! collision.normal.x = (float)((int)collision.normal.x); collision.normal.y = (float)((int)collision.normal.y); @@ -3842,7 +3842,7 @@ RayCollision GetRayCollisionTriangle(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3 // Calculate u parameter and test bound u = Vector3DotProduct(tv, p)*invDet; - // The intersection lies outside of the triangle + // The intersection lies outside the triangle if ((u < 0.0f) || (u > 1.0f)) return collision; // Prepare to test v parameter @@ -3851,7 +3851,7 @@ RayCollision GetRayCollisionTriangle(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3 // Calculate V parameter and test bound v = Vector3DotProduct(ray.direction, q)*invDet; - // The intersection lies outside of the triangle + // The intersection lies outside the triangle if ((v < 0.0f) || ((u + v) > 1.0f)) return collision; t = Vector3DotProduct(edge2, q)*invDet; @@ -4671,7 +4671,7 @@ static Image LoadImageFromCgltfImage(cgltf_image *cgltfImage, const char *texPat { Image image = { 0 }; - if (cgltfImage->uri != NULL) // Check if image data is provided as a uri (base64 or path) + if (cgltfImage->uri != NULL) // Check if image data is provided as an uri (base64 or path) { if ((strlen(cgltfImage->uri) > 5) && (cgltfImage->uri[0] == 'd') && @@ -4959,7 +4959,7 @@ static Model LoadGLTF(const char *fileName) for (unsigned int j = 0; j < data->meshes[i].primitives[p].attributes_count; j++) { - // Check the different attributes for every pimitive + // Check the different attributes for every primitive if (data->meshes[i].primitives[p].attributes[j].type == cgltf_attribute_type_position) // POSITION { cgltf_accessor *attribute = data->meshes[i].primitives[p].attributes[j].data; @@ -5110,7 +5110,7 @@ static Model LoadGLTF(const char *fileName) { // The primitive actually keeps the pointer to the corresponding material, // raylib instead assigns to the mesh the by its index, as loaded in model.materials array - // To get the index, we check if material pointers match and we assign the corresponding index, + // To get the index, we check if material pointers match, and we assign the corresponding index, // skipping index 0, the default material if (&data->materials[m] == data->meshes[i].primitives[p].material) { @@ -5613,7 +5613,7 @@ static Model LoadM3D(const char *fileName) // Materials are grouped together if (mi != m3d->face[i].materialid) { - // there should be only one material switch per material kind, but be bulletproof for unoptimal model files + // there should be only one material switch per material kind, but be bulletproof for non-optimal model files if (k + 1 >= model.meshCount) { model.meshCount++; @@ -5838,7 +5838,7 @@ static Model LoadM3D(const char *fileName) } // Load bone-pose default mesh into animation vertices. These will be updated when UpdateModelAnimation gets - // called, but not before, however DrawMesh uses these if they exists (so not good if they are left empty). + // called, but not before, however DrawMesh uses these if they exist (so not good if they are left empty). if (m3d->numbone && m3d->numskin) { for(i = 0; i < model.meshCount; i++) diff --git a/src/rshapes.c b/src/rshapes.c index 4c50724599d8..f7ee8f5cdd7c 100644 --- a/src/rshapes.c +++ b/src/rshapes.c @@ -978,7 +978,7 @@ void DrawRectangleRounded(Rectangle rec, float roundness, int segments, Color co rlSetTexture(texShapes.id); rlBegin(RL_QUADS); - // Draw all of the 4 corners: [1] Upper Left Corner, [3] Upper Right Corner, [5] Lower Right Corner, [7] Lower Left Corner + // Draw all the 4 corners: [1] Upper Left Corner, [3] Upper Right Corner, [5] Lower Right Corner, [7] Lower Left Corner for (int k = 0; k < 4; ++k) // Hope the compiler is smart enough to unroll this loop { float angle = angles[k]; @@ -1207,7 +1207,7 @@ void DrawRectangleRoundedLines(Rectangle rec, float roundness, int segments, flo rlBegin(RL_QUADS); - // Draw all of the 4 corners first: Upper Left Corner, Upper Right Corner, Lower Right Corner, Lower Left Corner + // Draw all the 4 corners first: Upper Left Corner, Upper Right Corner, Lower Right Corner, Lower Left Corner for (int k = 0; k < 4; ++k) // Hope the compiler is smart enough to unroll this loop { float angle = angles[k]; @@ -1342,7 +1342,7 @@ void DrawRectangleRoundedLines(Rectangle rec, float roundness, int segments, flo // Use LINES to draw the outline rlBegin(RL_LINES); - // Draw all of the 4 corners first: Upper Left Corner, Upper Right Corner, Lower Right Corner, Lower Left Corner + // Draw all the 4 corners first: Upper Left Corner, Upper Right Corner, Lower Right Corner, Lower Left Corner for (int k = 0; k < 4; ++k) // Hope the compiler is smart enough to unroll this loop { float angle = angles[k]; diff --git a/src/rtext.c b/src/rtext.c index 52fc615df29f..3e838f85cc56 100644 --- a/src/rtext.c +++ b/src/rtext.c @@ -65,7 +65,7 @@ #include // Required for: vsprintf() #include // Required for: strcmp(), strstr(), strcpy(), strncpy() [Used in TextReplace()], sscanf() [Used in LoadBMFont()] #include // Required for: va_list, va_start(), vsprintf(), va_end() [Used in TextFormat()] -#include // Requried for: toupper(), tolower() [Used in TextToUpper(), TextToLower()] +#include // Required for: toupper(), tolower() [Used in TextToUpper(), TextToLower()] #if defined(SUPPORT_FILEFORMAT_TTF) #define STB_RECT_PACK_IMPLEMENTATION @@ -336,7 +336,7 @@ Font LoadFont(const char *fileName) } else { - SetTextureFilter(font.texture, TEXTURE_FILTER_POINT); // By default we set point filter (best performance) + SetTextureFilter(font.texture, TEXTURE_FILTER_POINT); // By default, we set point filter (the best performance) TRACELOG(LOG_INFO, "FONT: Data loaded successfully (%i pixel size | %i glyphs)", FONT_TTF_DEFAULT_SIZE, FONT_TTF_DEFAULT_NUMCHARS); } @@ -584,7 +584,7 @@ GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSiz glyphCount = (glyphCount > 0)? glyphCount : 95; // Fill fontChars in case not provided externally - // NOTE: By default we fill glyphCount consecutevely, starting at 32 (Space) + // NOTE: By default we fill glyphCount consecutively, starting at 32 (Space) if (fontChars == NULL) { @@ -647,7 +647,7 @@ GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSiz } } - // Get bounding box for character (may be offset to account for chars that dip above or below the line) + // Get bounding box for character (maybe offset to account for chars that dip above or below the line) /* int chX1, chY1, chX2, chY2; stbtt_GetCodepointBitmapBox(&fontInfo, ch, scaleFactor, scaleFactor, &chX1, &chY1, &chX2, &chY2); @@ -777,7 +777,7 @@ Image GenImageFontAtlas(const GlyphInfo *chars, Rectangle **charRecs, int glyphC for (int i = 0; i < glyphCount; i++) { - // It return char rectangles in atlas + // It returns char rectangles in atlas recs[i].x = rects[i].x + (float)padding; recs[i].y = rects[i].y + (float)padding; recs[i].width = (float)chars[i].image.width; @@ -1040,7 +1040,7 @@ void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, f int size = TextLength(text); // Total size in bytes of the text, scanned by codepoints in loop - int textOffsetY = 0; // Offset between lines (on line break '\n') + int textOffsetY = 0; // Offset between lines (on linebreak '\n') float textOffsetX = 0.0f; // Offset X to next character to draw float scaleFactor = fontSize/font.baseSize; // Character quad scaling factor @@ -1053,7 +1053,7 @@ void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, f int index = GetGlyphIndex(font, 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 + // but we need to draw all the bad bytes using the '?' symbol moving one byte if (codepoint == 0x3f) codepointByteCount = 1; if (codepoint == '\n') @@ -1119,7 +1119,7 @@ void DrawTextCodepoint(Font font, int codepoint, Vector2 position, float fontSiz // Draw multiple character (codepoints) void DrawTextCodepoints(Font font, const int *codepoints, int count, Vector2 position, float fontSize, float spacing, Color tint) { - int textOffsetY = 0; // Offset between lines (on line break '\n') + int textOffsetY = 0; // Offset between lines (on linebreak '\n') float textOffsetX = 0.0f; // Offset X to next character to draw float scaleFactor = fontSize/font.baseSize; // Character quad scaling factor @@ -1195,7 +1195,7 @@ Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing index = GetGlyphIndex(font, letter); // 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 so to not skip any we set next = 1 + // but we need to draw all the bad bytes using the '?' symbol so to not skip any we set next = 1 if (letter == 0x3f) next = 1; i += next - 1; @@ -1410,7 +1410,7 @@ char *TextReplace(char *text, const char *replace, const char *by) 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 replace by) + int byLen = 0; // Replacement length (the string to replace by) int lastReplacePos = 0; // Distance between replace and end of last replace int count = 0; // Number of replacements @@ -1756,7 +1756,7 @@ const char *CodepointToUTF8(int codepoint, int *utf8Size) #endif // SUPPORT_TEXT_MANIPULATION // 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 +// When an 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 diff --git a/src/rtextures.c b/src/rtextures.c index c3744f640f0b..9bce9c716931 100644 --- a/src/rtextures.c +++ b/src/rtextures.c @@ -751,7 +751,7 @@ Image GenImageGradientRadial(int width, int height, float density, Color inner, float factor = (dist - radius*density)/(radius*(1.0f - density)); factor = (float)fmax(factor, 0.0f); - factor = (float)fmin(factor, 1.f); // dist can be bigger than radius so we have to check + factor = (float)fmin(factor, 1.f); // dist can be bigger than radius, so we have to check pixels[y*width + x].r = (int)((float)outer.r*factor + (float)inner.r*(1.0f - factor)); pixels[y*width + x].g = (int)((float)outer.g*factor + (float)inner.g*(1.0f - factor)); @@ -898,7 +898,7 @@ Image GenImageCellular(int width, int height, int tileSize) } } - // I made this up but it seems to give good results at all tile sizes + // I made this up, but it seems to give good results at all tile sizes int intensity = (int)(minDistance*256.0f/tileSize); if (intensity > 255) intensity = 255; @@ -1176,7 +1176,7 @@ void ImageFormat(Image *image, int newFormat) } break; case PIXELFORMAT_UNCOMPRESSED_R32: { - // WARNING: Image is converted to GRAYSCALE eqeuivalent 32bit + // WARNING: Image is converted to GRAYSCALE equivalent 32bit image->data = (float *)RL_MALLOC(image->width*image->height*sizeof(float)); @@ -1214,7 +1214,7 @@ void ImageFormat(Image *image, int newFormat) RL_FREE(pixels); pixels = NULL; - // In case original image had mipmaps, generate mipmaps for formated image + // In case original image had mipmaps, generate mipmaps for formatted image // NOTE: Original mipmaps are replaced by new ones, if custom mipmaps were used, they are lost if (image->mipmaps > 1) { @@ -1269,7 +1269,7 @@ Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Co int size = (int)strlen(text); // Get size in bytes of text int textOffsetX = 0; // Image drawing position X - int textOffsetY = 0; // Offset between lines (on line break '\n') + int textOffsetY = 0; // Offset between lines (on linebreak '\n') // NOTE: Text image is generated at font base size, later scaled to desired font size Vector2 imSize = MeasureTextEx(font, text, (float)font.baseSize, spacing); // WARNING: Module required: rtext @@ -1286,7 +1286,7 @@ Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Co int index = GetGlyphIndex(font, codepoint); // WARNING: Module required: rtext // 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 + // but we need to draw all the bad bytes using the '?' symbol moving one byte if (codepoint == 0x3f) codepointByteCount = 1; if (codepoint == '\n') @@ -1331,7 +1331,7 @@ Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Co } // Crop image depending on alpha value -// NOTE: Threshold is defined as a percentatge: 0.0f -> 1.0f +// NOTE: Threshold is defined as a percentage: 0.0f -> 1.0f void ImageAlphaCrop(Image *image, float threshold) { // Security check to avoid program crash @@ -1711,7 +1711,7 @@ void ImageResize(Image *image, int newWidth, int newHeight) Color *pixels = LoadImageColors(*image); Color *output = (Color *)RL_MALLOC(newWidth*newHeight*sizeof(Color)); - // NOTE: Color data is casted to (unsigned char *), there shouldn't been any problem... + // NOTE: Color data is cast to (unsigned char *), there shouldn't been any problem... stbir_resize_uint8((unsigned char *)pixels, image->width, image->height, 0, (unsigned char *)output, newWidth, newHeight, 0, 4); int format = image->format; @@ -1891,7 +1891,7 @@ void ImageMipmaps(Image *image) } // Dither image data to 16bpp or lower (Floyd-Steinberg dithering) -// NOTE: In case selected bpp do not represent an known 16bit format, +// NOTE: In case selected bpp do not represent a known 16bit format, // dithered data is stored in the LSB part of the unsigned short void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp) { @@ -2531,7 +2531,7 @@ void UnloadImagePalette(Color *colors) } // Get image alpha border rectangle -// NOTE: Threshold is defined as a percentatge: 0.0f -> 1.0f +// NOTE: Threshold is defined as a percentage: 0.0f -> 1.0f Rectangle GetImageAlphaBorder(Image image, float threshold) { Rectangle crop = { 0 }; @@ -3049,7 +3049,7 @@ void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Color if ((srcRec.y + srcRec.height) > src.height) srcRec.height = src.height - srcRec.y; // Check if source rectangle needs to be resized to destination rectangle - // In that case, we make a copy of source and we apply all required transform + // In that case, we make a copy of source, and we apply all required transform if (((int)srcRec.width != (int)dstRec.width) || ((int)srcRec.height != (int)dstRec.height)) { srcMod = ImageFromImage(src, srcRec); // Create image from another image @@ -3273,7 +3273,7 @@ TextureCubemap LoadTextureCubemap(Image image, int layout) faces = GenImageColor(size, size*6, MAGENTA); ImageFormat(&faces, image.format); - // NOTE: Image formating does not work with compressed textures + // NOTE: Image formatting does not work with compressed textures for (int i = 0; i < 6; i++) ImageDraw(&faces, image, faceRecs[i], (Rectangle){ 0, (float)size*i, (float)size, (float)size }, WHITE); } @@ -3606,7 +3606,7 @@ void DrawTexturePro(Texture2D texture, Rectangle source, Rectangle dest, Vector2 // NOTE: Vertex position can be transformed using matrices // but the process is way more costly than just calculating // the vertex positions manually, like done above. - // I leave here the old implementation for educational pourposes, + // I leave here the old implementation for educational purposes, // just in case someone wants to do some performance test /* rlSetTexture(texture.id); diff --git a/src/shell.html b/src/shell.html index 3ab8c3a30b1a..b373394bb1f3 100644 --- a/src/shell.html +++ b/src/shell.html @@ -1,5 +1,5 @@ - + diff --git a/src/utils.c b/src/utils.c index 030e59734718..6843bd946e68 100644 --- a/src/utils.c +++ b/src/utils.c @@ -63,10 +63,10 @@ static int logTypeLevel = LOG_INFO; // Minimum log type level static TraceLogCallback traceLog = NULL; // TraceLog callback function pointer -static LoadFileDataCallback loadFileData = NULL; // LoadFileData callback funtion pointer -static SaveFileDataCallback saveFileData = NULL; // SaveFileText callback funtion pointer -static LoadFileTextCallback loadFileText = NULL; // LoadFileText callback funtion pointer -static SaveFileTextCallback saveFileText = NULL; // SaveFileText callback funtion pointer +static LoadFileDataCallback loadFileData = NULL; // LoadFileData callback function pointer +static SaveFileDataCallback saveFileData = NULL; // SaveFileText callback function pointer +static LoadFileTextCallback loadFileText = NULL; // LoadFileText callback function pointer +static SaveFileTextCallback saveFileText = NULL; // SaveFileText callback function pointer //---------------------------------------------------------------------------------- // Functions to set internal callbacks From 4ae0a416f44195317d6b20af5b357c88c294faf1 Mon Sep 17 00:00:00 2001 From: BugraAlptekinSari <94199723+BugraAlptekinSari@users.noreply.github.com> Date: Sat, 11 Feb 2023 15:37:50 +0300 Subject: [PATCH 092/192] Added raymarch example and thumbnail for write depth (#2919) --- examples/Makefile | 9 +- .../shaders/glsl100/hybrid_raster.fs | 16 + .../shaders/glsl100/hybrid_raymarch.fs | 288 ++++++++++++++++++ .../shaders/glsl330/hybrid_raster.fs | 14 + .../shaders/glsl330/hybrid_raymarch.fs | 284 +++++++++++++++++ examples/shaders/shaders_hybrid_render.c | 212 +++++++++++++ examples/shaders/shaders_hybrid_render.png | Bin 0 -> 111135 bytes examples/shaders/shaders_write_depth.png | Bin 0 -> 11174 bytes 8 files changed, 819 insertions(+), 4 deletions(-) create mode 100644 examples/shaders/resources/shaders/glsl100/hybrid_raster.fs create mode 100644 examples/shaders/resources/shaders/glsl100/hybrid_raymarch.fs create mode 100644 examples/shaders/resources/shaders/glsl330/hybrid_raster.fs create mode 100644 examples/shaders/resources/shaders/glsl330/hybrid_raymarch.fs create mode 100644 examples/shaders/shaders_hybrid_render.c create mode 100644 examples/shaders/shaders_hybrid_render.png create mode 100644 examples/shaders/shaders_write_depth.png diff --git a/examples/Makefile b/examples/Makefile index dce02218a8ca..574975d231ea 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -523,7 +523,8 @@ SHADERS = \ shaders/shaders_hot_reloading \ shaders/shaders_mesh_instancing \ shaders/shaders_multi_sample2d \ - shaders/shaders_write_depth + shaders/shaders_write_depth \ + shaders/shaders_hybrid_render AUDIO = \ audio/audio_module_playing \ @@ -581,10 +582,10 @@ ifeq ($(PLATFORM),PLATFORM_DRM) rm -fv *.o endif ifeq ($(PLATFORM),PLATFORM_WEB) - ifeq ($(PLATFORM_OS),WINDOWS) + ifeq ($(PLATFORM_OS),WINDOWS) del *.wasm *.html *.js *.data - else + else rm -f */*.wasm */*.html */*.js */*.data - endif + endif endif @echo Cleaning done diff --git a/examples/shaders/resources/shaders/glsl100/hybrid_raster.fs b/examples/shaders/resources/shaders/glsl100/hybrid_raster.fs new file mode 100644 index 000000000000..28188a454a82 --- /dev/null +++ b/examples/shaders/resources/shaders/glsl100/hybrid_raster.fs @@ -0,0 +1,16 @@ +#version 100 +#extension GL_EXT_frag_depth : enable // Extension required for writing depth +precision mediump float; // Precision required for OpenGL ES2 (WebGL) + +varying vec2 fragTexCoord; +varying vec4 fragColor; + +uniform sampler2D texture0; +uniform vec4 colDiffuse; + +void main() +{ + vec4 texelColor = texture2D(texture0, fragTexCoord); + gl_FragColor = texelColor*colDiffuse*fragColor; + gl_FragDepthEXT = gl_FragCoord.z; +} \ No newline at end of file diff --git a/examples/shaders/resources/shaders/glsl100/hybrid_raymarch.fs b/examples/shaders/resources/shaders/glsl100/hybrid_raymarch.fs new file mode 100644 index 000000000000..6241186de8ac --- /dev/null +++ b/examples/shaders/resources/shaders/glsl100/hybrid_raymarch.fs @@ -0,0 +1,288 @@ +#version 100 +#extension GL_EXT_frag_depth : enable //Extension required for writing depth +#extension GL_OES_standard_derivatives : enable //Extension used for fwidth() +precision mediump float; // Precision required for OpenGL ES2 (WebGL) + + +// Input vertex attributes (from vertex shader) +varying vec2 fragTexCoord; +varying vec4 fragColor; + +// Input uniform values +uniform sampler2D texture0; +uniform vec4 colDiffuse; + +// Custom Input Uniform +uniform vec3 camPos; +uniform vec3 camDir; +uniform vec2 screenCenter; + +#define ZERO 0 + +// https://learnopengl.com/Advanced-OpenGL/Depth-testing +float CalcDepth(in vec3 rd, in float Idist){ + float local_z = dot(normalize(camDir),rd)*Idist; + return (1.0/(local_z) - 1.0/0.01)/(1.0/1000.0 -1.0/0.01); +} + +// https://iquilezles.org/articles/distfunctions/ +float sdHorseshoe( in vec3 p, in vec2 c, in float r, in float le, vec2 w ) +{ + p.x = abs(p.x); + float l = length(p.xy); + p.xy = mat2(-c.x, c.y, + c.y, c.x)*p.xy; + p.xy = vec2((p.y>0.0 || p.x>0.0)?p.x:l*sign(-c.x), + (p.x>0.0)?p.y:l ); + p.xy = vec2(p.x,abs(p.y-r))-vec2(le,0.0); + + vec2 q = vec2(length(max(p.xy,0.0)) + min(0.0,max(p.x,p.y)),p.z); + vec2 d = abs(q) - w; + return min(max(d.x,d.y),0.0) + length(max(d,0.0)); +} + +// r = sphere's radius +// h = cutting's plane's position +// t = thickness +float sdSixWayCutHollowSphere( vec3 p, float r, float h, float t ) +{ + // Six way symetry Transformation + vec3 ap = abs(p); + if(ap.x < max(ap.y, ap.z)){ + if(ap.y < ap.z) ap.xz = ap.zx; + else ap.xy = ap.yx; + } + + vec2 q = vec2( length(ap.yz), ap.x ); + + float w = sqrt(r*r-h*h); + + return ((h*q.x0.0 ) + { + tmax = min( tmax, tp1 ); + res = vec2( tp1, 1.0 ); + } + + float t = tmin; + for( int i=0; i<70 ; i++ ) + { + if(t>tmax) break; + vec2 h = map( ro+rd*t ); + if( abs(h.x)<(0.0001*t) ) + { + res = vec2(t,h.y); + break; + } + t += h.x; + } + + return res; +} + + +// https://iquilezles.org/articles/rmshadows +float calcSoftshadow( in vec3 ro, in vec3 rd, in float mint, in float tmax ) +{ + // bounding volume + float tp = (0.8-ro.y)/rd.y; if( tp>0.0 ) tmax = min( tmax, tp ); + + float res = 1.0; + float t = mint; + for( int i=ZERO; i<24; i++ ) + { + float h = map( ro + rd*t ).x; + float s = clamp(8.0*h/t,0.0,1.0); + res = min( res, s ); + t += clamp( h, 0.01, 0.2 ); + if( res<0.004 || t>tmax ) break; + } + res = clamp( res, 0.0, 1.0 ); + return res*res*(3.0-2.0*res); +} + + +// https://iquilezles.org/articles/normalsSDF +vec3 calcNormal( in vec3 pos ) +{ + vec2 e = vec2(1.0,-1.0)*0.5773*0.0005; + return normalize( e.xyy*map( pos + e.xyy ).x + + e.yyx*map( pos + e.yyx ).x + + e.yxy*map( pos + e.yxy ).x + + e.xxx*map( pos + e.xxx ).x ); +} + +// https://iquilezles.org/articles/nvscene2008/rwwtt.pdf +float calcAO( in vec3 pos, in vec3 nor ) +{ + float occ = 0.0; + float sca = 1.0; + for( int i=ZERO; i<5; i++ ) + { + float h = 0.01 + 0.12*float(i)/4.0; + float d = map( pos + h*nor ).x; + occ += (h-d)*sca; + sca *= 0.95; + if( occ>0.35 ) break; + } + return clamp( 1.0 - 3.0*occ, 0.0, 1.0 ) * (0.5+0.5*nor.y); +} + +// https://iquilezles.org/articles/checkerfiltering +float checkersGradBox( in vec2 p ) +{ + // filter kernel + vec2 w = fwidth(p) + 0.001; + // analytical integral (box filter) + vec2 i = 2.0*(abs(fract((p-0.5*w)*0.5)-0.5)-abs(fract((p+0.5*w)*0.5)-0.5))/w; + // xor pattern + return 0.5 - 0.5*i.x*i.y; +} + +// https://www.shadertoy.com/view/tdS3DG +vec4 render( in vec3 ro, in vec3 rd) +{ + // background + vec3 col = vec3(0.7, 0.7, 0.9) - max(rd.y,0.0)*0.3; + + // raycast scene + vec2 res = raycast(ro,rd); + float t = res.x; + float m = res.y; + if( m>-0.5 ) + { + vec3 pos = ro + t*rd; + vec3 nor = (m<1.5) ? vec3(0.0,1.0,0.0) : calcNormal( pos ); + vec3 ref = reflect( rd, nor ); + + // material + col = 0.2 + 0.2*sin( m*2.0 + vec3(0.0,1.0,2.0) ); + float ks = 1.0; + + if( m<1.5 ) + { + float f = checkersGradBox( 3.0*pos.xz); + col = 0.15 + f*vec3(0.05); + ks = 0.4; + } + + // lighting + float occ = calcAO( pos, nor ); + + vec3 lin = vec3(0.0); + + // sun + { + vec3 lig = normalize( vec3(-0.5, 0.4, -0.6) ); + vec3 hal = normalize( lig-rd ); + float dif = clamp( dot( nor, lig ), 0.0, 1.0 ); + //if( dif>0.0001 ) + dif *= calcSoftshadow( pos, lig, 0.02, 2.5 ); + float spe = pow( clamp( dot( nor, hal ), 0.0, 1.0 ),16.0); + spe *= dif; + spe *= 0.04+0.96*pow(clamp(1.0-dot(hal,lig),0.0,1.0),5.0); + //spe *= 0.04+0.96*pow(clamp(1.0-sqrt(0.5*(1.0-dot(rd,lig))),0.0,1.0),5.0); + lin += col*2.20*dif*vec3(1.30,1.00,0.70); + lin += 5.00*spe*vec3(1.30,1.00,0.70)*ks; + } + // sky + { + float dif = sqrt(clamp( 0.5+0.5*nor.y, 0.0, 1.0 )); + dif *= occ; + float spe = smoothstep( -0.2, 0.2, ref.y ); + spe *= dif; + spe *= 0.04+0.96*pow(clamp(1.0+dot(nor,rd),0.0,1.0), 5.0 ); + //if( spe>0.001 ) + spe *= calcSoftshadow( pos, ref, 0.02, 2.5 ); + lin += col*0.60*dif*vec3(0.40,0.60,1.15); + lin += 2.00*spe*vec3(0.40,0.60,1.30)*ks; + } + // back + { + float dif = clamp( dot( nor, normalize(vec3(0.5,0.0,0.6))), 0.0, 1.0 )*clamp( 1.0-pos.y,0.0,1.0); + dif *= occ; + lin += col*0.55*dif*vec3(0.25,0.25,0.25); + } + // sss + { + float dif = pow(clamp(1.0+dot(nor,rd),0.0,1.0),2.0); + dif *= occ; + lin += col*0.25*dif*vec3(1.00,1.00,1.00); + } + + col = lin; + + col = mix( col, vec3(0.7,0.7,0.9), 1.0-exp( -0.0001*t*t*t ) ); + } + + return vec4(vec3( clamp(col,0.0,1.0) ),t); +} + +vec3 CalcRayDir(vec2 nCoord){ + vec3 horizontal = normalize(cross(camDir,vec3(.0 , 1.0, .0))); + vec3 vertical = normalize(cross(horizontal,camDir)); + return normalize(camDir + horizontal*nCoord.x + vertical*nCoord.y); +} + +mat3 setCamera() +{ + vec3 cw = normalize(camDir); + vec3 cp = vec3(0.0, 1.0 ,0.0); + vec3 cu = normalize( cross(cw,cp) ); + vec3 cv = ( cross(cu,cw) ); + return mat3( cu, cv, cw ); +} + +void main() +{ + vec2 nCoord = (gl_FragCoord.xy - screenCenter.xy)/screenCenter.y; + mat3 ca = setCamera(); + + // focal length + float fl = length(camDir); + vec3 rd = ca * normalize( vec3(nCoord,fl) ); + vec3 color = vec3(nCoord/2.0 + 0.5, 0.0); + float depth = gl_FragCoord.z; + { + vec4 res = render( camPos - vec3(0.0, 0.0, 0.0) , rd ); + color = res.xyz; + depth = CalcDepth(rd,res.w); + } + gl_FragColor = vec4(color , 1.0); + gl_FragDepthEXT = depth; +} \ No newline at end of file diff --git a/examples/shaders/resources/shaders/glsl330/hybrid_raster.fs b/examples/shaders/resources/shaders/glsl330/hybrid_raster.fs new file mode 100644 index 000000000000..85ef492c0058 --- /dev/null +++ b/examples/shaders/resources/shaders/glsl330/hybrid_raster.fs @@ -0,0 +1,14 @@ +#version 330 + +in vec2 fragTexCoord; +in vec4 fragColor; + +uniform sampler2D texture0; +uniform vec4 colDiffuse; + +void main() +{ + vec4 texelColor = texture2D(texture0, fragTexCoord); + gl_FragColor = texelColor*colDiffuse*fragColor; + gl_FragDepth = gl_FragCoord.z; +} \ No newline at end of file diff --git a/examples/shaders/resources/shaders/glsl330/hybrid_raymarch.fs b/examples/shaders/resources/shaders/glsl330/hybrid_raymarch.fs new file mode 100644 index 000000000000..5b66dd71c12c --- /dev/null +++ b/examples/shaders/resources/shaders/glsl330/hybrid_raymarch.fs @@ -0,0 +1,284 @@ +# version 330 + +// Input vertex attributes (from vertex shader) +in vec2 fragTexCoord; +in vec4 fragColor; + +// Input uniform values +uniform sampler2D texture0; +uniform vec4 colDiffuse; + +// Custom Input Uniform +uniform vec3 camPos; +uniform vec3 camDir; +uniform vec2 screenCenter; + +#define ZERO 0 + +// https://learnopengl.com/Advanced-OpenGL/Depth-testing +float CalcDepth(in vec3 rd, in float Idist){ + float local_z = dot(normalize(camDir),rd)*Idist; + return (1.0/(local_z) - 1.0/0.01)/(1.0/1000.0 -1.0/0.01); +} + +// https://iquilezles.org/articles/distfunctions/ +float sdHorseshoe( in vec3 p, in vec2 c, in float r, in float le, vec2 w ) +{ + p.x = abs(p.x); + float l = length(p.xy); + p.xy = mat2(-c.x, c.y, + c.y, c.x)*p.xy; + p.xy = vec2((p.y>0.0 || p.x>0.0)?p.x:l*sign(-c.x), + (p.x>0.0)?p.y:l ); + p.xy = vec2(p.x,abs(p.y-r))-vec2(le,0.0); + + vec2 q = vec2(length(max(p.xy,0.0)) + min(0.0,max(p.x,p.y)),p.z); + vec2 d = abs(q) - w; + return min(max(d.x,d.y),0.0) + length(max(d,0.0)); +} + +// r = sphere's radius +// h = cutting's plane's position +// t = thickness +float sdSixWayCutHollowSphere( vec3 p, float r, float h, float t ) +{ + // Six way symetry Transformation + vec3 ap = abs(p); + if(ap.x < max(ap.y, ap.z)){ + if(ap.y < ap.z) ap.xz = ap.zx; + else ap.xy = ap.yx; + } + + vec2 q = vec2( length(ap.yz), ap.x ); + + float w = sqrt(r*r-h*h); + + return ((h*q.x0.0 ) + { + tmax = min( tmax, tp1 ); + res = vec2( tp1, 1.0 ); + } + + float t = tmin; + for( int i=0; i<70 ; i++ ) + { + if(t>tmax) break; + vec2 h = map( ro+rd*t ); + if( abs(h.x)<(0.0001*t) ) + { + res = vec2(t,h.y); + break; + } + t += h.x; + } + + return res; +} + + +// https://iquilezles.org/articles/rmshadows +float calcSoftshadow( in vec3 ro, in vec3 rd, in float mint, in float tmax ) +{ + // bounding volume + float tp = (0.8-ro.y)/rd.y; if( tp>0.0 ) tmax = min( tmax, tp ); + + float res = 1.0; + float t = mint; + for( int i=ZERO; i<24; i++ ) + { + float h = map( ro + rd*t ).x; + float s = clamp(8.0*h/t,0.0,1.0); + res = min( res, s ); + t += clamp( h, 0.01, 0.2 ); + if( res<0.004 || t>tmax ) break; + } + res = clamp( res, 0.0, 1.0 ); + return res*res*(3.0-2.0*res); +} + + +// https://iquilezles.org/articles/normalsSDF +vec3 calcNormal( in vec3 pos ) +{ + vec2 e = vec2(1.0,-1.0)*0.5773*0.0005; + return normalize( e.xyy*map( pos + e.xyy ).x + + e.yyx*map( pos + e.yyx ).x + + e.yxy*map( pos + e.yxy ).x + + e.xxx*map( pos + e.xxx ).x ); +} + +// https://iquilezles.org/articles/nvscene2008/rwwtt.pdf +float calcAO( in vec3 pos, in vec3 nor ) +{ + float occ = 0.0; + float sca = 1.0; + for( int i=ZERO; i<5; i++ ) + { + float h = 0.01 + 0.12*float(i)/4.0; + float d = map( pos + h*nor ).x; + occ += (h-d)*sca; + sca *= 0.95; + if( occ>0.35 ) break; + } + return clamp( 1.0 - 3.0*occ, 0.0, 1.0 ) * (0.5+0.5*nor.y); +} + +// https://iquilezles.org/articles/checkerfiltering +float checkersGradBox( in vec2 p ) +{ + // filter kernel + vec2 w = fwidth(p) + 0.001; + // analytical integral (box filter) + vec2 i = 2.0*(abs(fract((p-0.5*w)*0.5)-0.5)-abs(fract((p+0.5*w)*0.5)-0.5))/w; + // xor pattern + return 0.5 - 0.5*i.x*i.y; +} + +// https://www.shadertoy.com/view/tdS3DG +vec4 render( in vec3 ro, in vec3 rd) +{ + // background + vec3 col = vec3(0.7, 0.7, 0.9) - max(rd.y,0.0)*0.3; + + // raycast scene + vec2 res = raycast(ro,rd); + float t = res.x; + float m = res.y; + if( m>-0.5 ) + { + vec3 pos = ro + t*rd; + vec3 nor = (m<1.5) ? vec3(0.0,1.0,0.0) : calcNormal( pos ); + vec3 ref = reflect( rd, nor ); + + // material + col = 0.2 + 0.2*sin( m*2.0 + vec3(0.0,1.0,2.0) ); + float ks = 1.0; + + if( m<1.5 ) + { + float f = checkersGradBox( 3.0*pos.xz); + col = 0.15 + f*vec3(0.05); + ks = 0.4; + } + + // lighting + float occ = calcAO( pos, nor ); + + vec3 lin = vec3(0.0); + + // sun + { + vec3 lig = normalize( vec3(-0.5, 0.4, -0.6) ); + vec3 hal = normalize( lig-rd ); + float dif = clamp( dot( nor, lig ), 0.0, 1.0 ); + //if( dif>0.0001 ) + dif *= calcSoftshadow( pos, lig, 0.02, 2.5 ); + float spe = pow( clamp( dot( nor, hal ), 0.0, 1.0 ),16.0); + spe *= dif; + spe *= 0.04+0.96*pow(clamp(1.0-dot(hal,lig),0.0,1.0),5.0); + //spe *= 0.04+0.96*pow(clamp(1.0-sqrt(0.5*(1.0-dot(rd,lig))),0.0,1.0),5.0); + lin += col*2.20*dif*vec3(1.30,1.00,0.70); + lin += 5.00*spe*vec3(1.30,1.00,0.70)*ks; + } + // sky + { + float dif = sqrt(clamp( 0.5+0.5*nor.y, 0.0, 1.0 )); + dif *= occ; + float spe = smoothstep( -0.2, 0.2, ref.y ); + spe *= dif; + spe *= 0.04+0.96*pow(clamp(1.0+dot(nor,rd),0.0,1.0), 5.0 ); + //if( spe>0.001 ) + spe *= calcSoftshadow( pos, ref, 0.02, 2.5 ); + lin += col*0.60*dif*vec3(0.40,0.60,1.15); + lin += 2.00*spe*vec3(0.40,0.60,1.30)*ks; + } + // back + { + float dif = clamp( dot( nor, normalize(vec3(0.5,0.0,0.6))), 0.0, 1.0 )*clamp( 1.0-pos.y,0.0,1.0); + dif *= occ; + lin += col*0.55*dif*vec3(0.25,0.25,0.25); + } + // sss + { + float dif = pow(clamp(1.0+dot(nor,rd),0.0,1.0),2.0); + dif *= occ; + lin += col*0.25*dif*vec3(1.00,1.00,1.00); + } + + col = lin; + + col = mix( col, vec3(0.7,0.7,0.9), 1.0-exp( -0.0001*t*t*t ) ); + } + + return vec4(vec3( clamp(col,0.0,1.0) ),t); +} + +vec3 CalcRayDir(vec2 nCoord){ + vec3 horizontal = normalize(cross(camDir,vec3(.0 , 1.0, .0))); + vec3 vertical = normalize(cross(horizontal,camDir)); + return normalize(camDir + horizontal*nCoord.x + vertical*nCoord.y); +} + +mat3 setCamera() +{ + vec3 cw = normalize(camDir); + vec3 cp = vec3(0.0, 1.0 ,0.0); + vec3 cu = normalize( cross(cw,cp) ); + vec3 cv = ( cross(cu,cw) ); + return mat3( cu, cv, cw ); +} + +void main() +{ + vec2 nCoord = (gl_FragCoord.xy - screenCenter.xy)/screenCenter.y; + mat3 ca = setCamera(); + + // focal length + float fl = length(camDir); + vec3 rd = ca * normalize( vec3(nCoord,fl) ); + vec3 color = vec3(nCoord/2.0 + 0.5, 0.0); + float depth = gl_FragCoord.z; + { + vec4 res = render( camPos - vec3(0.0, 0.0, 0.0) , rd ); + color = res.xyz; + depth = CalcDepth(rd,res.w); + } + gl_FragColor = vec4(color , 1.0); + gl_FragDepth = depth; +} \ No newline at end of file diff --git a/examples/shaders/shaders_hybrid_render.c b/examples/shaders/shaders_hybrid_render.c new file mode 100644 index 000000000000..86ba6397bac1 --- /dev/null +++ b/examples/shaders/shaders_hybrid_render.c @@ -0,0 +1,212 @@ +/******************************************************************************************* +* +* raylib [shaders] example - Hybrid Rendering +* +* Example originally created with raylib 4.2, last time updated with raylib 4.2 +* +* Example contributed by Buğra Alptekin Sarı (@BugraAlptekinSari) 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) 2022-2023 Buğra Alptekin Sarı (@BugraAlptekinSari) +* +********************************************************************************************/ + +#include "raylib.h" +#include "rlgl.h" +#include "math.h" // Used for tan() +#include "raymath.h" // Used to calculate camera Direction + +#if defined(PLATFORM_DESKTOP) +#define GLSL_VERSION 330 +#else // PLATFORM_RPI, PLATFORM_ANDROID, PLATFORM_WEB +#define GLSL_VERSION 100 +#endif + +//------------------------------------------------------------------------------------ +// Declare custom functions required for the example +//------------------------------------------------------------------------------------ +// Load custom render texture, create a writable depth texture buffer +static RenderTexture2D LoadRenderTextureDepthTex(int width, int height); +// Unload render texture from GPU memory (VRAM) +static void UnloadRenderTextureDepthTex(RenderTexture2D target); + +//------------------------------------------------------------------------------------ +// Declare custom Structs +//------------------------------------------------------------------------------------ + +typedef struct { + unsigned int camPos, camDir, screenCenter; +}RayLocs ; + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [shaders] example - write depth buffer"); + + // This Shader calculates pixel depth and color using raymarch. + Shader raymarch_shader = LoadShader(0, TextFormat("resources/shaders/glsl%i/hybrid_raymarch.fs", GLSL_VERSION)); + // This Shader is a standard rasterization fragment shader with the addition of depth writing. You are required to write depth for all shaders if one shader does it. + Shader raster_shader = LoadShader(0, TextFormat("resources/shaders/glsl%i/hybrid_raster.fs", GLSL_VERSION)); + + // Declare Struct used to store camera locs. + RayLocs march_locs = {0}; + + // Fill the struct with shader locs. + march_locs.camPos = GetShaderLocation(raymarch_shader, "camPos"); + march_locs.camDir = GetShaderLocation(raymarch_shader, "camDir"); + march_locs.screenCenter = GetShaderLocation(raymarch_shader, "screenCenter"); + + { // Transfer screenCenter position to shader. Which is used to calculate ray direction. + Vector2 screenCenter = {.x = screenWidth/2.0, .y = screenHeight/2.0}; + SetShaderValue(raymarch_shader, march_locs.screenCenter , &screenCenter , SHADER_UNIFORM_VEC2); + } + + + // Use Customized function to create writable depth texture buffer + RenderTexture2D target = LoadRenderTextureDepthTex(screenWidth, screenHeight); + + // Define the camera to look into our 3d world + Camera camera = { + .position = (Vector3){ 0.5f, 1.0f, 1.5f }, // Camera position + .target = (Vector3){ 0.0f, 0.5f, 0.0f }, // Camera looking at point + .up = (Vector3){ 0.0f, 1.0f, 0.0f }, // Camera up vector (rotation towards target) + .fovy = 45.0f, // Camera field-of-view Y + .projection = CAMERA_PERSPECTIVE // Camera mode type + }; + + // Camera FOV is pre-calculated in the camera Distance. + double camDist = 1.0/(tan(camera.fovy*0.5*DEG2RAD)); + + SetCameraMode(camera, CAMERA_FIRST_PERSON); + + SetTargetFPS(60); + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + UpdateCamera(&camera); + + //Update Camera Postion in the ray march shader. + SetShaderValue(raymarch_shader, march_locs.camPos, &(camera.position), RL_SHADER_UNIFORM_VEC3); + + { // Update Camera Looking Vector. Vector length determines FOV. + Vector3 camDir = Vector3Scale( Vector3Normalize( Vector3Subtract(camera.target, camera.position)) , camDist); + SetShaderValue(raymarch_shader, march_locs.camDir, &(camDir), RL_SHADER_UNIFORM_VEC3); + } + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + + // Draw into our custom render texture (framebuffer) + BeginTextureMode(target); + ClearBackground(WHITE); + + // Raymarch Scene + rlEnableDepthTest(); //Manually enable Depth Test to handle multiple rendering methods. + BeginShaderMode(raymarch_shader); + DrawRectangleRec((Rectangle){0,0,screenWidth,screenHeight},WHITE); + EndShaderMode(); + + // Raserize Scene + BeginMode3D(camera); + BeginShaderMode(raster_shader); + DrawCubeWiresV((Vector3){ 0.0f, 0.5f, 1.0f }, (Vector3){ 1.0f, 1.0f, 1.0f }, RED); + DrawCubeV((Vector3){ 0.0f, 0.5f, 1.0f }, (Vector3){ 1.0f, 1.0f, 1.0f }, PURPLE); + DrawCubeWiresV((Vector3){ 0.0f, 0.5f, -1.0f }, (Vector3){ 1.0f, 1.0f, 1.0f }, DARKGREEN); + DrawCubeV((Vector3) { 0.0f, 0.5f, -1.0f }, (Vector3){ 1.0f, 1.0f, 1.0f }, YELLOW); + DrawGrid(10, 1.0f); + EndShaderMode(); + EndMode3D(); + EndTextureMode(); + + // Draw into screen our custom render texture + BeginDrawing(); + ClearBackground(RAYWHITE); + + DrawTextureRec(target.texture, (Rectangle) { 0, 0, screenWidth, -screenHeight }, (Vector2) { 0, 0 }, WHITE); + DrawFPS(10, 10); + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + UnloadRenderTextureDepthTex(target); + UnloadShader(raymarch_shader); + UnloadShader(raster_shader); + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} + +//------------------------------------------------------------------------------------ +// Define custom functions required for the example +//------------------------------------------------------------------------------------ +// Load custom render texture, create a writable depth texture buffer +RenderTexture2D LoadRenderTextureDepthTex(int width, int height) +{ + RenderTexture2D target = { 0 }; + + target.id = rlLoadFramebuffer(width, height); // Load an empty framebuffer + + if (target.id > 0) + { + rlEnableFramebuffer(target.id); + + // Create color texture (default to RGBA) + target.texture.id = rlLoadTexture(0, width, height, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, 1); + target.texture.width = width; + target.texture.height = height; + target.texture.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; + target.texture.mipmaps = 1; + + // Create depth texture buffer (instead of raylib default renderbuffer) + target.depth.id = rlLoadTextureDepth(width, height, false); + target.depth.width = width; + target.depth.height = height; + target.depth.format = 19; //DEPTH_COMPONENT_24BIT? + target.depth.mipmaps = 1; + + // Attach color texture and depth texture to FBO + rlFramebufferAttach(target.id, target.texture.id, RL_ATTACHMENT_COLOR_CHANNEL0, RL_ATTACHMENT_TEXTURE2D, 0); + rlFramebufferAttach(target.id, target.depth.id, RL_ATTACHMENT_DEPTH, RL_ATTACHMENT_TEXTURE2D, 0); + + // Check if fbo is complete with attachments (valid) + if (rlFramebufferComplete(target.id)) TRACELOG(LOG_INFO, "FBO: [ID %i] Framebuffer object created successfully", target.id); + + rlDisableFramebuffer(); + } + else TRACELOG(LOG_WARNING, "FBO: Framebuffer object can not be created"); + + return target; +} + +// Unload render texture from GPU memory (VRAM) +void UnloadRenderTextureDepthTex(RenderTexture2D target) +{ + if (target.id > 0) + { + // Color texture attached to FBO is deleted + rlUnloadTexture(target.texture.id); + rlUnloadTexture(target.depth.id); + + // NOTE: Depth texture is automatically + // queried and deleted before deleting framebuffer + rlUnloadFramebuffer(target.id); + } +} \ No newline at end of file diff --git a/examples/shaders/shaders_hybrid_render.png b/examples/shaders/shaders_hybrid_render.png new file mode 100644 index 0000000000000000000000000000000000000000..0a63d19c20c026c2355bd80cefd38cbefd0e8a5b GIT binary patch literal 111135 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

    2PTj|lepQ;T_#AXy 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 literal 0 HcmV?d00001 diff --git a/examples/shaders/shaders_write_depth.png b/examples/shaders/shaders_write_depth.png new file mode 100644 index 0000000000000000000000000000000000000000..5a56d7d25a084c61a1fff502c3c55291a0f91fea GIT binary patch literal 11174 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 literal 0 HcmV?d00001 From 4647441ad81848334ff2827015a9e337a6a0393a Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 12 Feb 2023 01:10:54 +0100 Subject: [PATCH 093/192] Update rl_gputex.h --- src/external/rl_gputex.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/external/rl_gputex.h b/src/external/rl_gputex.h index 6d2e97b27ad2..c20bdc67e739 100644 --- a/src/external/rl_gputex.h +++ b/src/external/rl_gputex.h @@ -477,10 +477,10 @@ int rl_save_ktx(const char *file_name, void *data, int width, int height, int fo // Calculate file data_size required int data_size = sizeof(ktx_header); - for (int i = 0, width = width, height = height; i < mipmaps; i++) + for (int i = 0, w = width, h = height; i < mipmaps; i++) { - data_size += get_pixel_data_size(width, height, format); - width /= 2; height /= 2; + data_size += get_pixel_data_size(w, h, format); + w /= 2; h /= 2; } unsigned char *file_data = RL_CALLOC(data_size, 1); From 21961a786df76a86302942f3da8f7c08b7f31863 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 12 Feb 2023 12:10:01 +0100 Subject: [PATCH 094/192] REVIEWED: Vertex colors support on M3D loading #2878 --- src/rmodels.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/rmodels.c b/src/rmodels.c index 893c031ef5e5..2fd2d5a4a005 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -5633,8 +5633,9 @@ static Model LoadM3D(const char *fileName) model.meshes[k].texcoords = (float *)RL_CALLOC(model.meshes[k].vertexCount*2, sizeof(float)); model.meshes[k].normals = (float *)RL_CALLOC(model.meshes[k].vertexCount*3, sizeof(float)); - // If color map is provided, we allocate storage for vertex colors - if (m3d->cmap != NULL) model.meshes[k].colors = RL_CALLOC(model.meshes[k].vertexCount*4, sizeof(unsigned char)); + // If no map is provided, we allocate storage for vertex colors + // M3D specs only consider vertex colors if no material is provided + if (mi != M3D_UNDEF) model.meshes[k].colors = RL_CALLOC(model.meshes[k].vertexCount*4, sizeof(unsigned char)); if (m3d->numbone && m3d->numskin) { From 96a9b4e1f25819bef8198ad0a0412ac84025d179 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 12 Feb 2023 13:28:35 +0100 Subject: [PATCH 095/192] REVIEWED: config.h format and inconsistencies --- src/config.h | 148 ++++++++++++++++++++++++++------------------------- 1 file changed, 75 insertions(+), 73 deletions(-) diff --git a/src/config.h b/src/config.h index 48f66aba4a54..d5f8e486cdeb 100644 --- a/src/config.h +++ b/src/config.h @@ -24,66 +24,68 @@ * 3. This notice may not be removed or altered from any source distribution. * **********************************************************************************************/ + #ifndef CONFIG_H #define CONFIG_H + //------------------------------------------------------------------------------------ // Module selection - Some modules could be avoided // Mandatory modules: rcore, rlgl, utils //------------------------------------------------------------------------------------ -#define SUPPORT_MODULE_RSHAPES 1 -#define SUPPORT_MODULE_RTEXTURES 1 -#define SUPPORT_MODULE_RTEXT 1 // WARNING: It requires SUPPORT_MODULE_RTEXTURES to load sprite font textures -#define SUPPORT_MODULE_RMODELS 1 -#define SUPPORT_MODULE_RAUDIO 1 +#define SUPPORT_MODULE_RSHAPES 1 +#define SUPPORT_MODULE_RTEXTURES 1 +#define SUPPORT_MODULE_RTEXT 1 // WARNING: It requires SUPPORT_MODULE_RTEXTURES to load sprite font textures +#define SUPPORT_MODULE_RMODELS 1 +#define SUPPORT_MODULE_RAUDIO 1 //------------------------------------------------------------------------------------ // Module: rcore - Configuration Flags //------------------------------------------------------------------------------------ // Camera module is included (rcamera.h) and multiple predefined cameras are available: free, 1st/3rd person, orbital -#define SUPPORT_CAMERA_SYSTEM 1 +#define SUPPORT_CAMERA_SYSTEM 1 // Gestures module is included (rgestures.h) to support gestures detection: tap, hold, swipe, drag -#define SUPPORT_GESTURES_SYSTEM 1 +#define SUPPORT_GESTURES_SYSTEM 1 // Mouse gestures are directly mapped like touches and processed by gestures system -#define SUPPORT_MOUSE_GESTURES 1 +#define SUPPORT_MOUSE_GESTURES 1 // Reconfigure standard input to receive key inputs, works with SSH connection. -#define SUPPORT_SSH_KEYBOARD_RPI 1 +#define SUPPORT_SSH_KEYBOARD_RPI 1 // Setting a higher resolution can improve the accuracy of time-out intervals in wait functions. // However, it can also reduce overall system performance, because the thread scheduler switches tasks more often. -#define SUPPORT_WINMM_HIGHRES_TIMER 1 +#define SUPPORT_WINMM_HIGHRES_TIMER 1 // Use busy wait loop for timing sync, if not defined, a high-resolution timer is set up and used -//#define SUPPORT_BUSY_WAIT_LOOP 1 +//#define SUPPORT_BUSY_WAIT_LOOP 1 // Use a partial-busy wait loop, in this case frame sleeps for most of the time, but then runs a busy loop at the end for accuracy #define SUPPORT_PARTIALBUSY_WAIT_LOOP // Wait for events passively (sleeping while no events) instead of polling them actively every frame -//#define SUPPORT_EVENTS_WAITING 1 +//#define SUPPORT_EVENTS_WAITING 1 // Allow automatic screen capture of current screen pressing F12, defined in KeyCallback() -#define SUPPORT_SCREEN_CAPTURE 1 +#define SUPPORT_SCREEN_CAPTURE 1 // Allow automatic gif recording of current screen pressing CTRL+F12, defined in KeyCallback() -#define SUPPORT_GIF_RECORDING 1 +#define SUPPORT_GIF_RECORDING 1 // Support CompressData() and DecompressData() functions -#define SUPPORT_COMPRESSION_API 1 +#define SUPPORT_COMPRESSION_API 1 // Support automatic generated events, loading and recording of those events when required -//#define SUPPORT_EVENTS_AUTOMATION 1 +//#define SUPPORT_EVENTS_AUTOMATION 1 // Support custom frame control, only for advance users // By default EndDrawing() does this job: draws everything + SwapScreenBuffer() + manage frame timing + PollInputEvents() // Enabling this flag allows manual control of the frame processes, use at your own risk -//#define SUPPORT_CUSTOM_FRAME_CONTROL 1 +//#define SUPPORT_CUSTOM_FRAME_CONTROL 1 // rcore: Configuration values //------------------------------------------------------------------------------------ -#define MAX_FILEPATH_CAPACITY 8192 // Maximum file paths capacity -#define MAX_FILEPATH_LENGTH 4096 // Maximum length for filepaths (Linux PATH_MAX default value) +#define MAX_FILEPATH_CAPACITY 8192 // Maximum file paths capacity +#define MAX_FILEPATH_LENGTH 4096 // Maximum length for filepaths (Linux PATH_MAX default value) -#define MAX_KEYBOARD_KEYS 512 // Maximum number of keyboard keys supported -#define MAX_MOUSE_BUTTONS 8 // Maximum number of mouse buttons supported -#define MAX_GAMEPADS 4 // Maximum number of gamepads supported -#define MAX_GAMEPAD_AXIS 8 // Maximum number of axis supported (per gamepad) -#define MAX_GAMEPAD_BUTTONS 32 // Maximum number of buttons supported (per gamepad) -#define MAX_TOUCH_POINTS 8 // Maximum number of touch points supported -#define MAX_KEY_PRESSED_QUEUE 16 // Maximum number of keys in the key input queue -#define MAX_CHAR_PRESSED_QUEUE 16 // Maximum number of characters in the char input queue +#define MAX_KEYBOARD_KEYS 512 // Maximum number of keyboard keys supported +#define MAX_MOUSE_BUTTONS 8 // Maximum number of mouse buttons supported +#define MAX_GAMEPADS 4 // Maximum number of gamepads supported +#define MAX_GAMEPAD_AXIS 8 // Maximum number of axis supported (per gamepad) +#define MAX_GAMEPAD_BUTTONS 32 // Maximum number of buttons supported (per gamepad) +#define MAX_TOUCH_POINTS 8 // Maximum number of touch points supported +#define MAX_KEY_PRESSED_QUEUE 16 // Maximum number of keys in the key input queue +#define MAX_CHAR_PRESSED_QUEUE 16 // Maximum number of characters in the char input queue -#define MAX_DECOMPRESSION_SIZE 64 // Max size allocated for decompression in MB +#define MAX_DECOMPRESSION_SIZE 64 // Max size allocated for decompression in MB //------------------------------------------------------------------------------------ @@ -133,36 +135,36 @@ //------------------------------------------------------------------------------------ // Use QUADS instead of TRIANGLES for drawing when possible // Some lines-based shapes could still use lines -#define SUPPORT_QUADS_DRAW_MODE 1 +#define SUPPORT_QUADS_DRAW_MODE 1 //------------------------------------------------------------------------------------ // Module: rtextures - Configuration Flags //------------------------------------------------------------------------------------ // Select the desired fileformats to be supported for image data loading -#define SUPPORT_FILEFORMAT_PNG 1 -//#define SUPPORT_FILEFORMAT_BMP 1 -//#define SUPPORT_FILEFORMAT_TGA 1 -//#define SUPPORT_FILEFORMAT_JPG 1 -#define SUPPORT_FILEFORMAT_GIF 1 -#define SUPPORT_FILEFORMAT_QOI 1 -//#define SUPPORT_FILEFORMAT_PSD 1 -#define SUPPORT_FILEFORMAT_DDS 1 -#define SUPPORT_FILEFORMAT_HDR 1 -//#define SUPPORT_FILEFORMAT_PIC 1 -//#define SUPPORT_FILEFORMAT_PNM 1 -//#define SUPPORT_FILEFORMAT_KTX 1 -//#define SUPPORT_FILEFORMAT_ASTC 1 -//#define SUPPORT_FILEFORMAT_PKM 1 -//#define SUPPORT_FILEFORMAT_PVR 1 +#define SUPPORT_FILEFORMAT_PNG 1 +//#define SUPPORT_FILEFORMAT_BMP 1 +//#define SUPPORT_FILEFORMAT_TGA 1 +//#define SUPPORT_FILEFORMAT_JPG 1 +#define SUPPORT_FILEFORMAT_GIF 1 +#define SUPPORT_FILEFORMAT_QOI 1 +//#define SUPPORT_FILEFORMAT_PSD 1 +#define SUPPORT_FILEFORMAT_DDS 1 +#define SUPPORT_FILEFORMAT_HDR 1 +//#define SUPPORT_FILEFORMAT_PIC 1 +//#define SUPPORT_FILEFORMAT_PNM 1 +//#define SUPPORT_FILEFORMAT_KTX 1 +//#define SUPPORT_FILEFORMAT_ASTC 1 +//#define SUPPORT_FILEFORMAT_PKM 1 +//#define SUPPORT_FILEFORMAT_PVR 1 // Support image export functionality (.png, .bmp, .tga, .jpg, .qoi) -#define SUPPORT_IMAGE_EXPORT 1 +#define SUPPORT_IMAGE_EXPORT 1 // Support procedural image generation functionality (gradient, spot, perlin-noise, cellular) -#define SUPPORT_IMAGE_GENERATION 1 +#define SUPPORT_IMAGE_GENERATION 1 // Support multiple image editing functions to scale, adjust colors, flip, draw on images, crop... // If not defined, still some functions are supported: ImageFormat(), ImageCrop(), ImageToPOT() -#define SUPPORT_IMAGE_MANIPULATION 1 +#define SUPPORT_IMAGE_MANIPULATION 1 //------------------------------------------------------------------------------------ @@ -170,52 +172,52 @@ //------------------------------------------------------------------------------------ // Default font is loaded on window initialization to be available for the user to render simple text // NOTE: If enabled, uses external module functions to load default raylib font -#define SUPPORT_DEFAULT_FONT 1 +#define SUPPORT_DEFAULT_FONT 1 // Selected desired font fileformats to be supported for loading -#define SUPPORT_FILEFORMAT_FNT 1 -#define SUPPORT_FILEFORMAT_TTF 1 +#define SUPPORT_FILEFORMAT_FNT 1 +#define SUPPORT_FILEFORMAT_TTF 1 // Support text management functions // If not defined, still some functions are supported: TextLength(), TextFormat() -#define SUPPORT_TEXT_MANIPULATION 1 +#define SUPPORT_TEXT_MANIPULATION 1 // rtext: Configuration values //------------------------------------------------------------------------------------ -#define MAX_TEXT_BUFFER_LENGTH 1024 // Size of internal static buffers used on some functions: +#define MAX_TEXT_BUFFER_LENGTH 1024 // Size of internal static buffers used on some functions: // TextFormat(), TextSubtext(), TextToUpper(), TextToLower(), TextToPascal(), TextSplit() -#define MAX_TEXTSPLIT_COUNT 128 // Maximum number of substrings to split: TextSplit() +#define MAX_TEXTSPLIT_COUNT 128 // Maximum number of substrings to split: TextSplit() //------------------------------------------------------------------------------------ // Module: rmodels - Configuration Flags //------------------------------------------------------------------------------------ // Selected desired model fileformats to be supported for loading -#define SUPPORT_FILEFORMAT_OBJ 1 -#define SUPPORT_FILEFORMAT_MTL 1 -#define SUPPORT_FILEFORMAT_IQM 1 -#define SUPPORT_FILEFORMAT_GLTF 1 -#define SUPPORT_FILEFORMAT_VOX 1 -#define SUPPORT_FILEFORMAT_M3D 1 +#define SUPPORT_FILEFORMAT_OBJ 1 +#define SUPPORT_FILEFORMAT_MTL 1 +#define SUPPORT_FILEFORMAT_IQM 1 +#define SUPPORT_FILEFORMAT_GLTF 1 +#define SUPPORT_FILEFORMAT_VOX 1 +#define SUPPORT_FILEFORMAT_M3D 1 // Support procedural mesh generation functions, uses external par_shapes.h library // NOTE: Some generated meshes DO NOT include generated texture coordinates -#define SUPPORT_MESH_GENERATION 1 +#define SUPPORT_MESH_GENERATION 1 // rmodels: Configuration values //------------------------------------------------------------------------------------ -#define MAX_MATERIAL_MAPS 12 // Maximum number of shader maps supported -#define MAX_MESH_VERTEX_BUFFERS 7 // Maximum vertex buffers (VBO) per mesh +#define MAX_MATERIAL_MAPS 12 // Maximum number of shader maps supported +#define MAX_MESH_VERTEX_BUFFERS 7 // Maximum vertex buffers (VBO) per mesh //------------------------------------------------------------------------------------ // Module: raudio - Configuration Flags //------------------------------------------------------------------------------------ // Desired audio fileformats to be supported for loading -#define SUPPORT_FILEFORMAT_WAV 1 -#define SUPPORT_FILEFORMAT_OGG 1 -#define SUPPORT_FILEFORMAT_MP3 1 -//#define SUPPORT_FILEFORMAT_QOA 1 -//#define SUPPORT_FILEFORMAT_FLAC 1 -#define SUPPORT_FILEFORMAT_XM 1 -#define SUPPORT_FILEFORMAT_MOD 1 +#define SUPPORT_FILEFORMAT_WAV 1 +#define SUPPORT_FILEFORMAT_OGG 1 +#define SUPPORT_FILEFORMAT_MP3 1 +//#define SUPPORT_FILEFORMAT_QOA 1 +//#define SUPPORT_FILEFORMAT_FLAC 1 +#define SUPPORT_FILEFORMAT_XM 1 +#define SUPPORT_FILEFORMAT_MOD 1 // raudio: Configuration values //------------------------------------------------------------------------------------ @@ -229,14 +231,14 @@ // Module: utils - Configuration Flags //------------------------------------------------------------------------------------ // Standard file io library (stdio.h) included -#define SUPPORT_STANDARD_FILEIO +#define SUPPORT_STANDARD_FILEIO 1 // Show TRACELOG() output messages // NOTE: By default LOG_DEBUG traces not shown -#define SUPPORT_TRACELOG 1 -//#define SUPPORT_TRACELOG_DEBUG 1 +#define SUPPORT_TRACELOG 1 +//#define SUPPORT_TRACELOG_DEBUG 1 // utils: Configuration values //------------------------------------------------------------------------------------ -#define MAX_TRACELOG_MSG_LENGTH 128 // Max length of one trace-log message +#define MAX_TRACELOG_MSG_LENGTH 128 // Max length of one trace-log message #endif // CONFIG_H From 22287a78c5f4b34b0d57d060dd7f68b51e70d363 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 12 Feb 2023 13:29:39 +0100 Subject: [PATCH 096/192] Update qoa.h --- src/external/qoa.h | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/external/qoa.h b/src/external/qoa.h index aae575512081..65752d1b7c7a 100644 --- a/src/external/qoa.h +++ b/src/external/qoa.h @@ -274,24 +274,26 @@ static inline int qoa_clamp(int v, int min, int max) { } static inline qoa_uint64_t qoa_read_u64(const unsigned char *bytes, unsigned int *p) { - qoa_uint64_t v = - (qoa_uint64_t)bytes[(*p)+0] << 56 | (qoa_uint64_t)bytes[(*p)+1] << 48 | - (qoa_uint64_t)bytes[(*p)+2] << 40 | (qoa_uint64_t)bytes[(*p)+3] << 32 | - (qoa_uint64_t)bytes[(*p)+4] << 24 | (qoa_uint64_t)bytes[(*p)+5] << 16 | - (qoa_uint64_t)bytes[(*p)+6] << 8 | (qoa_uint64_t)bytes[(*p)+7]; + bytes += *p; *p += 8; - return v; + return + ((qoa_uint64_t)(bytes[0]) << 56) | ((qoa_uint64_t)(bytes[1]) << 48) | + ((qoa_uint64_t)(bytes[2]) << 40) | ((qoa_uint64_t)(bytes[3]) << 32) | + ((qoa_uint64_t)(bytes[4]) << 24) | ((qoa_uint64_t)(bytes[5]) << 16) | + ((qoa_uint64_t)(bytes[6]) << 8) | ((qoa_uint64_t)(bytes[7]) << 0); } static inline void qoa_write_u64(qoa_uint64_t v, unsigned char *bytes, unsigned int *p) { - bytes[(*p)++] = (v >> 56) & 0xff; - bytes[(*p)++] = (v >> 48) & 0xff; - bytes[(*p)++] = (v >> 40) & 0xff; - bytes[(*p)++] = (v >> 32) & 0xff; - bytes[(*p)++] = (v >> 24) & 0xff; - bytes[(*p)++] = (v >> 16) & 0xff; - bytes[(*p)++] = (v >> 8) & 0xff; - bytes[(*p)++] = (v >> 0) & 0xff; + bytes += *p; + *p += 8; + bytes[0] = (v >> 56) & 0xff; + bytes[1] = (v >> 48) & 0xff; + bytes[2] = (v >> 40) & 0xff; + bytes[3] = (v >> 32) & 0xff; + bytes[4] = (v >> 24) & 0xff; + bytes[5] = (v >> 16) & 0xff; + bytes[6] = (v >> 8) & 0xff; + bytes[7] = (v >> 0) & 0xff; } From a9c28d75837f98f9aef083af495a7be25ae9e0d6 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 12 Feb 2023 13:46:26 +0100 Subject: [PATCH 097/192] Update CHANGELOG --- CHANGELOG | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 602e9a4e003a..f9bb27ec94ad 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -43,6 +43,7 @@ Detailed changes: [core] REVIEWED: GetClipboardText() on PLATFORM_WEB, permissions issues [core] REVIEWED: Initial window position for display-sized fullscreen (#2742) by @daipom [core] REVIEWED: Sticky touches input (#2857) by @ImazighenGhost +[core] REVIEWED: Enable GetWindowHandle() on macOS (#2915) by @Not-Nik [rlgl] ADDED: OpenGL ES 2.0 support on PLATFORM_DESKTOP (#2840) by @wtnbgo [rlgl] ADDED: Separate blending modes for color and alpha, BLEND_CUSTOM_SEPARATE (#2741) [rlgl] ADDED: rlSetBlendFactorsSeparate and custom blend mode modification checks (#2741) by @pure01fx @@ -58,7 +59,8 @@ Detailed changes: [rlgl] REVIEWED: rlMultMatrixf(), use const pointer (#2807) by @planetis-m [rlgl] REVIEWED: Expose OpenGL blending mode factors and functions/equations [rlgl] REVIEWED: rLoadTextureDepth(), issue with depth textures on WebGL (#2824) -[raymath] REVIEWED: Vector2Angle() (#2829, #2832) by @AlxHnr and @planetis-m +[raymath] ADDED: Vector2LineAngle() (#2887) +[raymath] REVIEWED: Vector2Angle() (#2829, #2832) by @AlxHnr, @planetis-m [shapes] ADDED: CheckCollisionPointPoly() (#2685) by @acejacek [shapes] REVIEWED: DrawPixel*(), use RL_QUADS/RL_TRIANGLES (#2750) by @hatkidchan [shapes] REVIEWED: DrawLineBezier*(), fix bezier line breaking (#2735, #2767) by @nobytesgiven @@ -88,21 +90,29 @@ Detailed changes: [models] ADDED: GLTF animation support (#2844) by @charles-l [models] ADDED: DrawCapsule() and DrawCapsuleWires() (#2761) by @IanBand [models] ADDED: LoadMaterials(), MTL files loading, same code as OBJ loader (#2872) by @JeffM2501 +[models] REVIEWED: DrawMesh(), using SHADER_LOC_COLOR_SPECULAR as a material map (#2908) by @haved +[models] REVIEWED: LoadM3D() vertex color support (#2878) by @GithubPrankster, @bztsrc [models] REVIEWED: GenMeshHeightmap() (#2716) [models] REVIEWED: LoadIQM() (#2676) [models] REVIEWED: Simplify .vox signature check (#2752) by @CrezyDud [models] REVIEWED: LoadIQM(), support bone names loading if available (#2882) by @PencilAmazing [models] `WARNING`: REMOVED: DrawCubeTexture(), DrawCubeTextureRec(), functions moved to new example: `models_draw_cube_texture` +[audio] ADDED: IsWaveReady()`, IsSoundReady(), IsMusicReady() (#2892) by @RobLoach [audio] REVIEWED: Clear PCM buffer state when closing audio device (#2736) by @veins1 [audio] REVIEWED: Android backend selected (#2118, #2875) by @planetis-m +[multi] ADDED: IsShaderReady(), IsImageReady(), IsFontReady() (#2892) by @RobLoach +[multi] ADDED: IsModelReady(), IsMaterialReady(), IsTextureReady(), IsRenderTextureReady() (#2895) by @RobLoach [multi] REVIEWED: Multiple code/comment typos by @sDos280 +[multi] REVIEWED: Grammar mistakes and typos (#2914) by @stickM4N [multi] REVIEWED: Use TRACELOG() macro instead of TraceLog() in internal modules (#2881) by @RobLoach [examples] ADDED: textures_textured_curve (#2821) by @JeffM2501 [examples] ADDED: shaders_write_depth (#2836) by @BugraAlptekinSari +[examples] ADDED: shaders_hybrid_render (#2919) by @BugraAlptekinSari [examples] RENAMED: Several shaders for naming consistency (#2707) [examples] RENAMED: lighting_instanced.fs to lighting_instancing.fs (glsl100) (#2805) by @gtrxAC [examples] REVIEWED: core_custom_logging.c (#2692) by @hartmannathan [examples] REVIEWED: core_camera_2d_platformer (#2687) by @skylar779 +[examples] REVIEWED: core_input_gamepad.c (#2903) by @planetis-m [examples] REVIEWED: core_custom_frame_control [examples] REVIEWED: text_rectangle_bounds (#2746) by @SzieberthAdam [examples] REVIEWED: textures_image_processing, added gaussian blurring (#2775) by @nobytesgiven @@ -114,6 +124,9 @@ Detailed changes: [build] ADDED: Packaging for distros with deb-based and rpm-based packages (#2877) by @KOLANICH [build] ADDED: Linkage library -latomic on Linux (only required for ARM32) [build] ADDED: Required frameworks on macOS (#2793) by @SpexGuy +[build] ADDED: WASM support for Zig build (#2901) by @Not-Nik +[build] REVIEWED: config.h format and inconsistencies +[build] REVIEWED: Zig build to latest master, avoid deprecated functions (#2910) by @star-tek-mb [build] REVIEWED: CMake project template to easily target raylib version (#2700) by @RobLoach [build] REVIEWED: PATH for PLATFORM_WEB target (#2647) by @futureapricot [build] REVIEWED: build.zig to let user decide how to set build mode and linker fixes by @InKryption @@ -141,7 +154,7 @@ Detailed changes: [bindings] ADDED: TurboRaylib (Object Pascal) by @turborium [bindings] ADDED: Kaylib (Kotlin/Native) by @Its-Kenta [bindings] ADDED: Raylib-Nelua (Nelua) by @Its-Kenta -[misc] REVIEWED: Update some external libraries to latest versions +[misc] REVIEWED: Update external libraries to latest versions ------------------------------------------------------------------------- Release: raylib 4.2 (11 August 2022) From f1bcabcc3799df741d54593980ac06afe2e0f081 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 12 Feb 2023 13:48:11 +0100 Subject: [PATCH 098/192] Update CHANGELOG --- CHANGELOG | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index f9bb27ec94ad..8cbbaa2b1928 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -9,14 +9,13 @@ Release: raylib 4.5 (xx February 2023) -WIP- KEY CHANGES: - ADDED: M3D model format support with animations - ADDED: GLTF animation support + - ADDED: QOA audio format support (import/export) -WIP- - rlgl redesign to avoid render batch triangles limits pre-check: rlCheckRenderBatchLimit() - rshapes simplification to minimize the requirement of rlgl functionality, now it only depends on 6 functions - rl_gputex.h: Compressed textures loading, required by rtextures module, has been moved to a separate self-contained library - raygui 3.5: New version of the immediate-mode gui system for tools development with raylib - Detailed changes: - [core] ADDED: RAYLIB_VERSION_* values to raylib.h (#2856) by @RobLoach [core] ADDED: Basic gamepad support for Android (#2709) by @deniska [core] ADDED: Support CAPS/NUM lock keys registering if locked From 73989a49817225f11f547d270598e93745bf7df0 Mon Sep 17 00:00:00 2001 From: Crydsch Cube Date: Tue, 14 Feb 2023 17:47:21 +0100 Subject: [PATCH 099/192] WIP rcamera redesign vector (#2563) * core functionality CAMERA_FREE * fix example * add remaining camera modes * add view bobbing * view bobbing * catch curser in SetCameraMode * adjust examples * fix compilation on linux * fix example text_draw_3d * actually fix text_draw_3d * Updated camera API * Improve Vector3RotateByAxisAngle() function * remove camera.mode dependency from low-level functions * remove camera.mode from struct * fixes after rebase * adjust examples for new UpdateCamera function * adjust example models_loading_m3d --------- Co-authored-by: Ray --- examples/core/core_3d_camera_first_person.c | 94 ++- examples/core/core_3d_camera_free.c | 4 +- examples/core/core_3d_picking.c | 15 +- examples/core/core_vr_simulator.c | 6 +- examples/core/core_world_screen.c | 7 +- examples/models/models_animation.c | 5 +- examples/models/models_billboard.c | 6 +- examples/models/models_cubicmap.c | 5 +- examples/models/models_first_person_maze.c | 5 +- examples/models/models_heightmap.c | 5 +- examples/models/models_loading.c | 5 +- examples/models/models_loading_gltf.c | 6 +- examples/models/models_loading_m3d.c | 5 +- examples/models/models_loading_vox.c | 5 +- examples/models/models_mesh_generation.c | 5 +- examples/models/models_mesh_picking.c | 14 +- examples/models/models_rlgl_solar_system.c | 5 +- examples/models/models_skybox.c | 5 +- examples/shaders/shaders_basic_lighting.c | 5 +- examples/shaders/shaders_custom_uniform.c | 6 +- examples/shaders/shaders_fog.c | 5 +- examples/shaders/shaders_mesh_instancing.c | 6 +- examples/shaders/shaders_model_shader.c | 5 +- examples/shaders/shaders_postprocessing.c | 6 +- examples/shaders/shaders_raymarching.c | 5 +- examples/shaders/shaders_simple_mask.c | 3 +- examples/text/text_draw_3d.c | 9 +- src/raylib.h | 8 +- src/rcamera.h | 670 +++++++++----------- src/rcamera_old.h | 567 +++++++++++++++++ 30 files changed, 1008 insertions(+), 489 deletions(-) create mode 100644 src/rcamera_old.h diff --git a/examples/core/core_3d_camera_first_person.c b/examples/core/core_3d_camera_first_person.c index a7aa5f49a6e7..d98a002fd0c7 100644 --- a/examples/core/core_3d_camera_first_person.c +++ b/examples/core/core_3d_camera_first_person.c @@ -12,6 +12,7 @@ ********************************************************************************************/ #include "raylib.h" +#include "rcamera.h" #define MAX_COLUMNS 20 @@ -29,11 +30,14 @@ int main(void) // Define the camera to look into our 3d world (position, target, up vector) Camera camera = { 0 }; - camera.position = (Vector3){ 4.0f, 2.0f, 4.0f }; - camera.target = (Vector3){ 0.0f, 1.8f, 0.0f }; + camera.position = (Vector3){ 0.0f, 2.0f, 4.0f }; + camera.target = (Vector3){ 0.0f, 2.0f, 0.0f }; camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; camera.fovy = 60.0f; camera.projection = CAMERA_PERSPECTIVE; + camera.swingCounter = 1; // Enable view bobbing + + int cameraMode = CAMERA_FIRST_PERSON; // Generates some random columns float heights[MAX_COLUMNS] = { 0 }; @@ -47,8 +51,7 @@ int main(void) colors[i] = (Color){ GetRandomValue(20, 255), GetRandomValue(10, 55), 30, 255 }; } - SetCameraMode(camera, CAMERA_FIRST_PERSON); // Set a first person camera mode - + DisableCursor(); // Catch cursor SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- @@ -57,7 +60,51 @@ int main(void) { // Update //---------------------------------------------------------------------------------- - UpdateCamera(&camera); + // Switch camera mode + if (IsKeyPressed(KEY_ONE)) { + cameraMode = CAMERA_FREE; + camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Reset roll + } + if (IsKeyPressed(KEY_TWO)) { + cameraMode = CAMERA_FIRST_PERSON; + camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Reset roll + } + if (IsKeyPressed(KEY_THREE)) { + cameraMode = CAMERA_THIRD_PERSON; + camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Reset roll + } + if (IsKeyPressed(KEY_FOUR)) { + cameraMode = CAMERA_ORBITAL; + camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Reset roll + } + + // Switch camera projection + if (IsKeyPressed(KEY_P)) { + if (camera.projection == CAMERA_PERSPECTIVE) { + // Create isometric view + cameraMode = CAMERA_THIRD_PERSON; + // Note: The target distance is related to the render distance in the orthographic projection + camera.position = (Vector3){ 0.0f, 2.0f, -100.0f }; + camera.target = (Vector3){ 0.0f, 2.0f, 0.0f }; + camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; + camera.projection = CAMERA_ORTHOGRAPHIC; + camera.fovy = 20.0f; // near plane width in CAMERA_ORTHOGRAPHIC + CameraYaw(&camera, -135 * DEG2RAD, true); + CameraPitch(&camera, -45 * DEG2RAD, true, true, false); + } + else if (camera.projection == CAMERA_ORTHOGRAPHIC) + { + // Reset to default view + cameraMode = CAMERA_THIRD_PERSON; + camera.position = (Vector3){ 0.0f, 2.0f, 10.0f }; + camera.target = (Vector3){ 0.0f, 2.0f, 0.0f }; + camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; + camera.projection = CAMERA_PERSPECTIVE; + camera.fovy = 60.0f; + } + } + + UpdateCamera(&camera, cameraMode); // Update camera //---------------------------------------------------------------------------------- // Draw @@ -80,14 +127,39 @@ int main(void) DrawCubeWires(positions[i], 2.0f, heights[i], 2.0f, MAROON); } - EndMode3D(); + // Draw player cube + if (cameraMode == CAMERA_THIRD_PERSON) + { + DrawCube(camera.target, 0.5f, 0.5f, 0.5f, PURPLE); + DrawCubeWires(camera.target, 0.5f, 0.5f, 0.5f, DARKPURPLE); + } - DrawRectangle( 10, 10, 220, 70, Fade(SKYBLUE, 0.5f)); - DrawRectangleLines( 10, 10, 220, 70, BLUE); + EndMode3D(); - DrawText("First person camera default controls:", 20, 20, 10, BLACK); - DrawText("- Move with keys: W, A, S, D", 40, 40, 10, DARKGRAY); - DrawText("- Mouse move to look around", 40, 60, 10, DARKGRAY); + // Draw info boxes + DrawRectangle(5, 5, 330, 100, Fade(SKYBLUE, 0.5f)); + DrawRectangleLines(5, 5, 330, 100, BLUE); + + DrawText("Camera controls:", 15, 15, 10, BLACK); + DrawText("- Move keys: W, A, S, D, Space, Left-Ctrl", 15, 30, 10, BLACK); + DrawText("- Look around: arrow keys or mouse", 15, 45, 10, BLACK); + DrawText("- Camera mode keys: 1, 2, 3, 4", 15, 60, 10, BLACK); + DrawText("- Zoom keys: num-plus, num-minus or mouse scroll", 15, 75, 10, BLACK); + DrawText("- Camera projection key: P", 15, 90, 10, BLACK); + + DrawRectangle(600, 5, 195, 100, Fade(SKYBLUE, 0.5f)); + DrawRectangleLines(600, 5, 195, 100, BLUE); + + DrawText("Camera status:", 610, 15, 10, BLACK); + DrawText(TextFormat("- Mode: %s", (cameraMode == CAMERA_FREE) ? "FREE" : + (cameraMode == CAMERA_FIRST_PERSON) ? "FIRST_PERSON" : + (cameraMode == CAMERA_THIRD_PERSON) ? "THIRD_PERSON" : + (cameraMode == CAMERA_ORBITAL) ? "ORBITAL" : "CUSTOM"), 610, 30, 10, BLACK); + DrawText(TextFormat("- Projection: %s", (camera.projection == CAMERA_PERSPECTIVE) ? "PERSPECTIVE" : + (camera.projection == CAMERA_ORTHOGRAPHIC) ? "ORTHOGRAPHIC" : "CUSTOM"), 610, 45, 10, BLACK); + DrawText(TextFormat("- Position: (%06.3f, %06.3f, %06.3f)", camera.position.x, camera.position.y, camera.position.z), 610, 60, 10, BLACK); + DrawText(TextFormat("- Target: (%06.3f, %06.3f, %06.3f)", camera.target.x, camera.target.y, camera.target.z), 610, 75, 10, BLACK); + DrawText(TextFormat("- Up: (%06.3f, %06.3f, %06.3f)", camera.up.x, camera.up.y, camera.up.z), 610, 90, 10, BLACK); EndDrawing(); //---------------------------------------------------------------------------------- diff --git a/examples/core/core_3d_camera_free.c b/examples/core/core_3d_camera_free.c index af7ab8d72dc2..887a1df33464 100644 --- a/examples/core/core_3d_camera_free.c +++ b/examples/core/core_3d_camera_free.c @@ -35,8 +35,6 @@ int main(void) Vector3 cubePosition = { 0.0f, 0.0f, 0.0f }; - SetCameraMode(camera, CAMERA_FREE); // Set a free camera mode - SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- @@ -45,7 +43,7 @@ int main(void) { // Update //---------------------------------------------------------------------------------- - UpdateCamera(&camera); + UpdateCamera(&camera, CAMERA_FREE); if (IsKeyDown('Z')) camera.target = (Vector3){ 0.0f, 0.0f, 0.0f }; //---------------------------------------------------------------------------------- diff --git a/examples/core/core_3d_picking.c b/examples/core/core_3d_picking.c index 8c0df9663fe9..0cf56f5feaed 100644 --- a/examples/core/core_3d_picking.c +++ b/examples/core/core_3d_picking.c @@ -40,7 +40,7 @@ int main(void) RayCollision collision = { 0 }; - SetCameraMode(camera, CAMERA_FREE); // Set a free camera mode + EnableCursor(); // Disable camera controls SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- @@ -50,7 +50,14 @@ int main(void) { // Update //---------------------------------------------------------------------------------- - UpdateCamera(&camera); + if (IsCursorHidden()) UpdateCamera(&camera, CAMERA_FIRST_PERSON); // Update camera + + // Toggle camera controls + if (IsMouseButtonPressed(MOUSE_BUTTON_RIGHT)) + { + if (IsCursorHidden()) EnableCursor(); + else DisableCursor(); + } if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) { @@ -93,10 +100,12 @@ int main(void) EndMode3D(); - DrawText("Try selecting the box with mouse!", 240, 10, 20, DARKGRAY); + DrawText("Try clicking on the box with your mouse!", 240, 10, 20, DARKGRAY); if (collision.hit) DrawText("BOX SELECTED", (screenWidth - MeasureText("BOX SELECTED", 30)) / 2, (int)(screenHeight * 0.1f), 30, GREEN); + DrawText("Right click mouse to toggle camera controls", 10, 430, 10, GRAY); + DrawFPS(10, 10); EndDrawing(); diff --git a/examples/core/core_vr_simulator.c b/examples/core/core_vr_simulator.c index 5914897b0974..3024b7853756 100644 --- a/examples/core/core_vr_simulator.c +++ b/examples/core/core_vr_simulator.c @@ -96,11 +96,11 @@ int main(void) camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Camera up vector camera.fovy = 60.0f; // Camera field-of-view Y camera.projection = CAMERA_PERSPECTIVE; // Camera type + camera.swingCounter = 1; // Enable view bobbing Vector3 cubePosition = { 0.0f, 0.0f, 0.0f }; - SetCameraMode(camera, CAMERA_FIRST_PERSON); // Set first person camera mode - + DisableCursor(); // Catch cursor SetTargetFPS(90); // Set our game to run at 90 frames-per-second //-------------------------------------------------------------------------------------- @@ -109,7 +109,7 @@ int main(void) { // Update //---------------------------------------------------------------------------------- - UpdateCamera(&camera); + UpdateCamera(&camera, CAMERA_FIRST_PERSON); //---------------------------------------------------------------------------------- // Draw diff --git a/examples/core/core_world_screen.c b/examples/core/core_world_screen.c index d86adf877160..f96690ba53d1 100644 --- a/examples/core/core_world_screen.c +++ b/examples/core/core_world_screen.c @@ -23,7 +23,7 @@ int main(void) const int screenWidth = 800; const int screenHeight = 450; - InitWindow(screenWidth, screenHeight, "raylib [core] example - 3d camera free"); + InitWindow(screenWidth, screenHeight, "raylib [core] example - core world screen"); // Define the camera to look into our 3d world Camera camera = { 0 }; @@ -36,8 +36,7 @@ int main(void) Vector3 cubePosition = { 0.0f, 0.0f, 0.0f }; Vector2 cubeScreenPosition = { 0.0f, 0.0f }; - SetCameraMode(camera, CAMERA_FREE); // Set a free camera mode - + DisableCursor(); // Catch cursor SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- @@ -46,7 +45,7 @@ int main(void) { // Update //---------------------------------------------------------------------------------- - UpdateCamera(&camera); + UpdateCamera(&camera, CAMERA_THIRD_PERSON); // Calculate cube screen space position (with a little offset to be in top) cubeScreenPosition = GetWorldToScreen((Vector3){cubePosition.x, cubePosition.y + 2.5f, cubePosition.z}, camera); diff --git a/examples/models/models_animation.c b/examples/models/models_animation.c index b9216b21f960..a36f3fe5b40c 100644 --- a/examples/models/models_animation.c +++ b/examples/models/models_animation.c @@ -54,8 +54,7 @@ int main(void) ModelAnimation *anims = LoadModelAnimations("resources/models/iqm/guyanim.iqm", &animsCount); int animFrameCounter = 0; - SetCameraMode(camera, CAMERA_FREE); // Set free camera mode - + DisableCursor(); // Catch cursor SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- @@ -64,7 +63,7 @@ int main(void) { // Update //---------------------------------------------------------------------------------- - UpdateCamera(&camera); + UpdateCamera(&camera, CAMERA_FIRST_PERSON); // Play animation when spacebar is held down if (IsKeyDown(KEY_SPACE)) diff --git a/examples/models/models_billboard.c b/examples/models/models_billboard.c index ce313949bcf5..6d16cf01fc4e 100644 --- a/examples/models/models_billboard.c +++ b/examples/models/models_billboard.c @@ -48,14 +48,13 @@ int main(void) // Here we choose to rotate around the image center // NOTE: (-1, 1) is the range where origin.x, origin.y is inside the texture Vector2 rotateOrigin = { 0.0f }; - SetCameraMode(camera, CAMERA_ORBITAL); // Set an orbital camera mode // Distance is needed for the correct billboard draw order // Larger distance (further away from the camera) should be drawn prior to smaller distance. float distanceStatic; float distanceRotating; - float rotation = 0.0f; + SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- @@ -64,7 +63,8 @@ int main(void) { // Update //---------------------------------------------------------------------------------- - UpdateCamera(&camera); + UpdateCamera(&camera, CAMERA_ORBITAL); + rotation += 0.4f; distanceStatic = Vector3Distance(camera.position, billPositionStatic); distanceRotating = Vector3Distance(camera.position, billPositionRotating); diff --git a/examples/models/models_cubicmap.c b/examples/models/models_cubicmap.c index 4953a99fcbd2..83bfab68bd02 100644 --- a/examples/models/models_cubicmap.c +++ b/examples/models/models_cubicmap.c @@ -42,8 +42,7 @@ int main(void) UnloadImage(image); // Unload cubesmap image from RAM, already uploaded to VRAM - SetCameraMode(camera, CAMERA_ORBITAL); // Set an orbital camera mode - + DisableCursor(); // Catch cursor SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- @@ -52,7 +51,7 @@ int main(void) { // Update //---------------------------------------------------------------------------------- - UpdateCamera(&camera); + UpdateCamera(&camera, CAMERA_ORBITAL); //---------------------------------------------------------------------------------- // Draw diff --git a/examples/models/models_first_person_maze.c b/examples/models/models_first_person_maze.c index b5e35b585023..3f6a935c3544 100644 --- a/examples/models/models_first_person_maze.c +++ b/examples/models/models_first_person_maze.c @@ -45,8 +45,7 @@ int main(void) Vector3 mapPosition = { -16.0f, 0.0f, -8.0f }; // Set model position - SetCameraMode(camera, CAMERA_FIRST_PERSON); // Set camera mode - + DisableCursor(); // Catch cursor SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- @@ -57,7 +56,7 @@ int main(void) //---------------------------------------------------------------------------------- Vector3 oldCamPos = camera.position; // Store old camera position - UpdateCamera(&camera); + UpdateCamera(&camera, CAMERA_FIRST_PERSON); // Check player collision (we simplify to 2D collision detection) Vector2 playerPos = { camera.position.x, camera.position.z }; diff --git a/examples/models/models_heightmap.c b/examples/models/models_heightmap.c index a5d17b02eeeb..25dc004d513b 100644 --- a/examples/models/models_heightmap.c +++ b/examples/models/models_heightmap.c @@ -39,8 +39,7 @@ int main(void) UnloadImage(image); // Unload heightmap image from RAM, already uploaded to VRAM - SetCameraMode(camera, CAMERA_ORBITAL); // Set an orbital camera mode - + DisableCursor(); // Catch cursor SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- @@ -49,7 +48,7 @@ int main(void) { // Update //---------------------------------------------------------------------------------- - UpdateCamera(&camera); + UpdateCamera(&camera, CAMERA_ORBITAL); //---------------------------------------------------------------------------------- // Draw diff --git a/examples/models/models_loading.c b/examples/models/models_loading.c index 7bdf1772f9fc..56dad4084392 100644 --- a/examples/models/models_loading.c +++ b/examples/models/models_loading.c @@ -57,10 +57,9 @@ int main(void) // NOTE: bounds are calculated from the original size of the model, // if model is scaled on drawing, bounds must be also scaled - SetCameraMode(camera, CAMERA_FREE); // Set a free camera mode - bool selected = false; // Selected object flag + DisableCursor(); // Catch cursor SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- @@ -69,7 +68,7 @@ int main(void) { // Update //---------------------------------------------------------------------------------- - UpdateCamera(&camera); + UpdateCamera(&camera, CAMERA_FIRST_PERSON); // Load new models/textures on drag&drop if (IsFileDropped()) diff --git a/examples/models/models_loading_gltf.c b/examples/models/models_loading_gltf.c index 92b517a1c772..0c90707134a5 100644 --- a/examples/models/models_loading_gltf.c +++ b/examples/models/models_loading_gltf.c @@ -51,8 +51,6 @@ int main(void) Vector3 position = { 0.0f, 0.0f, 0.0f }; // Set model position - SetCameraMode(camera, CAMERA_FREE); // Set free camera mode - SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- @@ -61,6 +59,7 @@ int main(void) { // Update //---------------------------------------------------------------------------------- + UpdateCamera(&camera, CAMERA_THIRD_PERSON); // Select current animation if (IsKeyPressed(KEY_UP)) animIndex = (animIndex + 1)%animsCount; else if (IsKeyPressed(KEY_DOWN)) animIndex = (animIndex + animsCount - 1)%animsCount; @@ -69,9 +68,6 @@ int main(void) ModelAnimation anim = modelAnimations[animIndex]; animCurrentFrame = (animCurrentFrame + 1)%anim.frameCount; UpdateModelAnimation(model, anim, animCurrentFrame); - - // Update camera - UpdateCamera(&camera); //---------------------------------------------------------------------------------- // Draw diff --git a/examples/models/models_loading_m3d.c b/examples/models/models_loading_m3d.c index 52dc952269cc..c1a4af07de86 100644 --- a/examples/models/models_loading_m3d.c +++ b/examples/models/models_loading_m3d.c @@ -53,8 +53,7 @@ int main(void) int animFrameCounter = 0, animId = 0; ModelAnimation *anims = LoadModelAnimations(modelFileName, &animsCount); // Load skeletal animation data - SetCameraMode(camera, CAMERA_FREE); // Set free camera mode - + DisableCursor(); // Catch cursor SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- @@ -63,7 +62,7 @@ int main(void) { // Update //---------------------------------------------------------------------------------- - UpdateCamera(&camera); + UpdateCamera(&camera, CAMERA_FIRST_PERSON); if (animsCount) { diff --git a/examples/models/models_loading_vox.c b/examples/models/models_loading_vox.c index 49477cd9c0e8..6a38fe89a86a 100644 --- a/examples/models/models_loading_vox.c +++ b/examples/models/models_loading_vox.c @@ -69,8 +69,7 @@ int main(void) int currentModel = 0; - SetCameraMode(camera, CAMERA_ORBITAL); // Set a orbital camera mode - + DisableCursor(); // Catch cursor SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- @@ -79,7 +78,7 @@ int main(void) { // Update //---------------------------------------------------------------------------------- - UpdateCamera(&camera); + UpdateCamera(&camera, CAMERA_ORBITAL); // Cycle between models on mouse click if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) currentModel = (currentModel + 1)%MAX_VOX_FILES; diff --git a/examples/models/models_mesh_generation.c b/examples/models/models_mesh_generation.c index b4ff018cc5f7..8e9fdf900ace 100644 --- a/examples/models/models_mesh_generation.c +++ b/examples/models/models_mesh_generation.c @@ -68,8 +68,7 @@ int main(void) int currentModel = 0; - SetCameraMode(camera, CAMERA_ORBITAL); // Set a orbital camera mode - + DisableCursor(); // Catch cursor SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- @@ -78,7 +77,7 @@ int main(void) { // Update //---------------------------------------------------------------------------------- - UpdateCamera(&camera); + UpdateCamera(&camera, CAMERA_ORBITAL); if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) { diff --git a/examples/models/models_mesh_picking.c b/examples/models/models_mesh_picking.c index 52f9974d3770..1118168cb4eb 100644 --- a/examples/models/models_mesh_picking.c +++ b/examples/models/models_mesh_picking.c @@ -64,8 +64,7 @@ int main(void) Vector3 sp = (Vector3){ -30.0f, 5.0f, 5.0f }; float sr = 4.0f; - SetCameraMode(camera, CAMERA_FREE); // Set a free camera mode - + EnableCursor(); // Disable camera controls SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- // Main game loop @@ -73,7 +72,14 @@ int main(void) { // Update //---------------------------------------------------------------------------------- - UpdateCamera(&camera); + if (IsCursorHidden()) UpdateCamera(&camera, CAMERA_FIRST_PERSON); // Update camera + + // Toggle camera controls + if (IsMouseButtonPressed(MOUSE_BUTTON_RIGHT)) + { + if (IsCursorHidden()) EnableCursor(); + else DisableCursor(); + } // Display information about closest hit RayCollision collision = { 0 }; @@ -219,7 +225,7 @@ int main(void) DrawText(TextFormat("Barycenter: %3.2f %3.2f %3.2f", bary.x, bary.y, bary.z), 10, ypos + 45, 10, BLACK); } - DrawText("Use Mouse to Move Camera", 10, 430, 10, GRAY); + DrawText("Right click mouse to toggle camera controls", 10, 430, 10, GRAY); DrawText("(c) Turret 3D model by Alberto Cano", screenWidth - 200, screenHeight - 20, 10, GRAY); diff --git a/examples/models/models_rlgl_solar_system.c b/examples/models/models_rlgl_solar_system.c index 903752f76138..24f8b9a548e4 100644 --- a/examples/models/models_rlgl_solar_system.c +++ b/examples/models/models_rlgl_solar_system.c @@ -49,8 +49,6 @@ int main(void) camera.fovy = 45.0f; camera.projection = CAMERA_PERSPECTIVE; - SetCameraMode(camera, CAMERA_FREE); - float rotationSpeed = 0.2f; // General system rotation speed float earthRotation = 0.0f; // Rotation of earth around itself (days) in degrees @@ -58,6 +56,7 @@ int main(void) float moonRotation = 0.0f; // Rotation of moon around itself float moonOrbitRotation = 0.0f; // Rotation of moon around earth in degrees + DisableCursor(); // Catch cursor SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- @@ -66,7 +65,7 @@ int main(void) { // Update //---------------------------------------------------------------------------------- - UpdateCamera(&camera); + UpdateCamera(&camera, CAMERA_ORBITAL); earthRotation += (5.0f*rotationSpeed); earthOrbitRotation += (365/360.0f*(5.0f*rotationSpeed)*rotationSpeed); diff --git a/examples/models/models_skybox.c b/examples/models/models_skybox.c index 1b9923334b05..d12cc557d580 100644 --- a/examples/models/models_skybox.c +++ b/examples/models/models_skybox.c @@ -87,8 +87,7 @@ int main(void) UnloadImage(img); } - SetCameraMode(camera, CAMERA_FIRST_PERSON); // Set a first person camera mode - + DisableCursor(); // Catch cursor SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- @@ -97,7 +96,7 @@ int main(void) { // Update //---------------------------------------------------------------------------------- - UpdateCamera(&camera); + UpdateCamera(&camera, CAMERA_FIRST_PERSON); // Load new cubemap texture on drag&drop if (IsFileDropped()) diff --git a/examples/shaders/shaders_basic_lighting.c b/examples/shaders/shaders_basic_lighting.c index 1b29b8522ca0..702177f163a2 100644 --- a/examples/shaders/shaders_basic_lighting.c +++ b/examples/shaders/shaders_basic_lighting.c @@ -80,8 +80,7 @@ int main(void) lights[2] = CreateLight(LIGHT_POINT, (Vector3){ -2, 1, 2 }, Vector3Zero(), GREEN, shader); lights[3] = CreateLight(LIGHT_POINT, (Vector3){ 2, 1, -2 }, Vector3Zero(), BLUE, shader); - SetCameraMode(camera, CAMERA_ORBITAL); // Set an orbital camera mode - + DisableCursor(); // Catch cursor SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- @@ -90,7 +89,7 @@ int main(void) { // Update //---------------------------------------------------------------------------------- - UpdateCamera(&camera); + UpdateCamera(&camera, CAMERA_ORBITAL); // Update the shader with the camera view vector (points towards { 0.0f, 0.0f, 0.0f }) float cameraPos[3] = { camera.position.x, camera.position.y, camera.position.z }; diff --git a/examples/shaders/shaders_custom_uniform.c b/examples/shaders/shaders_custom_uniform.c index 75f6112e5023..c617a6d1f078 100644 --- a/examples/shaders/shaders_custom_uniform.c +++ b/examples/shaders/shaders_custom_uniform.c @@ -67,9 +67,7 @@ int main(void) // Create a RenderTexture2D to be used for render to texture RenderTexture2D target = LoadRenderTexture(screenWidth, screenHeight); - // Setup orbital camera - SetCameraMode(camera, CAMERA_ORBITAL); // Set an orbital camera mode - + DisableCursor(); // Catch cursor SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- @@ -78,7 +76,7 @@ int main(void) { // Update //---------------------------------------------------------------------------------- - UpdateCamera(&camera); + UpdateCamera(&camera, CAMERA_ORBITAL); Vector2 mousePosition = GetMousePosition(); diff --git a/examples/shaders/shaders_fog.c b/examples/shaders/shaders_fog.c index ac84a018047d..c4b619edca22 100644 --- a/examples/shaders/shaders_fog.c +++ b/examples/shaders/shaders_fog.c @@ -84,8 +84,7 @@ int main(void) // Using just 1 point lights CreateLight(LIGHT_POINT, (Vector3){ 0, 2, 6 }, Vector3Zero(), WHITE, shader); - SetCameraMode(camera, CAMERA_ORBITAL); // Set an orbital camera mode - + DisableCursor(); // Catch cursor SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- @@ -94,7 +93,7 @@ int main(void) { // Update //---------------------------------------------------------------------------------- - UpdateCamera(&camera); + UpdateCamera(&camera, CAMERA_ORBITAL); if (IsKeyDown(KEY_UP)) { diff --git a/examples/shaders/shaders_mesh_instancing.c b/examples/shaders/shaders_mesh_instancing.c index f4e6b40b0cb9..0c2f9e1d9789 100644 --- a/examples/shaders/shaders_mesh_instancing.c +++ b/examples/shaders/shaders_mesh_instancing.c @@ -94,9 +94,7 @@ int main(void) Material matDefault = LoadMaterialDefault(); matDefault.maps[MATERIAL_MAP_DIFFUSE].color = BLUE; - // Set an orbital camera mode - SetCameraMode(camera, CAMERA_ORBITAL); - + DisableCursor(); // Catch cursor SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- @@ -105,7 +103,7 @@ int main(void) { // Update //---------------------------------------------------------------------------------- - UpdateCamera(&camera); + UpdateCamera(&camera, CAMERA_ORBITAL); // Update the light shader with the camera view position float cameraPos[3] = { camera.position.x, camera.position.y, camera.position.z }; diff --git a/examples/shaders/shaders_model_shader.c b/examples/shaders/shaders_model_shader.c index de3cb5f8d48f..069d0ee25d1a 100644 --- a/examples/shaders/shaders_model_shader.c +++ b/examples/shaders/shaders_model_shader.c @@ -60,8 +60,7 @@ int main(void) Vector3 position = { 0.0f, 0.0f, 0.0f }; // Set model position - SetCameraMode(camera, CAMERA_FREE); // Set an orbital camera mode - + DisableCursor(); // Catch cursor SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- @@ -70,7 +69,7 @@ int main(void) { // Update //---------------------------------------------------------------------------------- - UpdateCamera(&camera); + UpdateCamera(&camera, CAMERA_FIRST_PERSON); //---------------------------------------------------------------------------------- // Draw diff --git a/examples/shaders/shaders_postprocessing.c b/examples/shaders/shaders_postprocessing.c index d0555f219e30..688ca9092929 100644 --- a/examples/shaders/shaders_postprocessing.c +++ b/examples/shaders/shaders_postprocessing.c @@ -107,9 +107,7 @@ int main(void) // Create a RenderTexture2D to be used for render to texture RenderTexture2D target = LoadRenderTexture(screenWidth, screenHeight); - // Setup orbital camera - SetCameraMode(camera, CAMERA_ORBITAL); // Set an orbital camera mode - + DisableCursor(); // Catch cursor SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- @@ -118,7 +116,7 @@ int main(void) { // Update //---------------------------------------------------------------------------------- - UpdateCamera(&camera); + UpdateCamera(&camera, CAMERA_ORBITAL); if (IsKeyPressed(KEY_RIGHT)) currentShader++; else if (IsKeyPressed(KEY_LEFT)) currentShader--; diff --git a/examples/shaders/shaders_raymarching.c b/examples/shaders/shaders_raymarching.c index 9b8bc30cd789..5cc9af050cf0 100644 --- a/examples/shaders/shaders_raymarching.c +++ b/examples/shaders/shaders_raymarching.c @@ -41,8 +41,6 @@ int main(void) camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Camera up vector (rotation towards target) camera.fovy = 65.0f; // Camera field-of-view Y - SetCameraMode(camera, CAMERA_FREE); // Set camera mode - // Load raymarching shader // NOTE: Defining 0 (NULL) for vertex shader forces usage of internal default vertex shader Shader shader = LoadShader(0, TextFormat("resources/shaders/glsl%i/raymarching.fs", GLSL_VERSION)); @@ -58,6 +56,7 @@ int main(void) float runTime = 0.0f; + DisableCursor(); // Catch cursor SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- @@ -66,7 +65,7 @@ int main(void) { // Update //---------------------------------------------------------------------------------- - UpdateCamera(&camera); + UpdateCamera(&camera, CAMERA_FIRST_PERSON); float cameraPos[3] = { camera.position.x, camera.position.y, camera.position.z }; float cameraTarget[3] = { camera.target.x, camera.target.y, camera.target.z }; diff --git a/examples/shaders/shaders_simple_mask.c b/examples/shaders/shaders_simple_mask.c index ce3fc8bb91e4..49470294b940 100644 --- a/examples/shaders/shaders_simple_mask.c +++ b/examples/shaders/shaders_simple_mask.c @@ -85,6 +85,7 @@ int main(void) int framesCounter = 0; Vector3 rotation = { 0 }; // Model rotation angles + DisableCursor(); // Catch cursor SetTargetFPS(60); // Set to run at 60 frames-per-second //-------------------------------------------------------------------------------------- @@ -93,7 +94,7 @@ int main(void) { // Update //---------------------------------------------------------------------------------- - UpdateCamera(&camera); + UpdateCamera(&camera, CAMERA_FIRST_PERSON); framesCounter++; rotation.x += 0.01f; diff --git a/examples/text/text_draw_3d.c b/examples/text/text_draw_3d.c index 127eb7c6a278..c90ea6658ddf 100644 --- a/examples/text/text_draw_3d.c +++ b/examples/text/text_draw_3d.c @@ -98,11 +98,12 @@ int main(void) camera.fovy = 45.0f; // Camera field-of-view Y camera.projection = CAMERA_PERSPECTIVE; // Camera mode type - SetCameraMode(camera, CAMERA_ORBITAL); + int camera_mode = CAMERA_ORBITAL; Vector3 cubePosition = { 0.0f, 1.0f, 0.0f }; Vector3 cubeSize = { 2.0f, 2.0f, 2.0f }; + DisableCursor(); // Catch cursor SetTargetFPS(60); // Set our game to run at 60 frames-per-second // Use the default font @@ -141,7 +142,7 @@ int main(void) { // Update //---------------------------------------------------------------------------------- - UpdateCamera(&camera); + UpdateCamera(&camera, camera_mode); // Handle font files dropped if (IsFileDropped()) @@ -181,12 +182,12 @@ int main(void) if (spin) { camera.position = (Vector3){ -10.0f, 15.0f, -10.0f }; // Camera position - SetCameraMode(camera, CAMERA_ORBITAL); + camera_mode = CAMERA_ORBITAL; } else { camera.position = (Vector3){ 10.0f, 10.0f, -10.0f }; // Camera position - SetCameraMode(camera, CAMERA_FREE); + camera_mode = CAMERA_FREE; } } diff --git a/src/raylib.h b/src/raylib.h index e31a514a6738..650b5b29c98c 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1156,13 +1156,7 @@ RLAPI float GetGesturePinchAngle(void); // Get gesture pinch ang //------------------------------------------------------------------------------------ // Camera System Functions (Module: rcamera) //------------------------------------------------------------------------------------ -RLAPI void SetCameraMode(Camera camera, int mode); // Set camera mode (multiple camera modes available) -RLAPI void UpdateCamera(Camera *camera); // Update camera position for selected mode - -RLAPI void SetCameraPanControl(int keyPan); // Set camera pan key to combine with mouse movement (free camera) -RLAPI void SetCameraAltControl(int keyAlt); // Set camera alt key to combine with mouse movement (free camera) -RLAPI void SetCameraSmoothZoomControl(int keySmoothZoom); // Set camera smooth zoom key to combine with mouse (free camera) -RLAPI void SetCameraMoveControls(int keyFront, int keyBack, int keyRight, int keyLeft, int keyUp, int keyDown); // Set camera move controls (1st person and 3rd person cameras) +RLAPI void UpdateCamera(Camera3D *camera, int mode); // Update camera position for selected mode //------------------------------------------------------------------------------------ // Basic Shapes Drawing Functions (Module: shapes) diff --git a/src/rcamera.h b/src/rcamera.h index 0caad666da86..60ac642a594c 100644 --- a/src/rcamera.h +++ b/src/rcamera.h @@ -2,8 +2,6 @@ * * rcamera - Basic camera system for multiple camera modes * -* NOTE: Memory footprint of this library is aproximately 52 bytes (global variables) -* * CONFIGURATION: * * #define CAMERA_IMPLEMENTATION @@ -17,6 +15,7 @@ * * CONTRIBUTORS: * Ramon Santamaria: Supervision, review, update and maintenance +* Christoph Wagner: Redesign (2022) * Marc Palau: Initial implementation (2014) * * @@ -44,15 +43,26 @@ #ifndef RCAMERA_H #define RCAMERA_H +// The only dependency // TODO review standalone mode +#include "raymath.h" + //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- //... +#if defined(CAMERA_STANDALONE) +#define CAMERA_CULL_DISTANCE_NEAR 0.01 +#define CAMERA_CULL_DISTANCE_FAR 1000.0 +#else +#define CAMERA_CULL_DISTANCE_NEAR RL_CULL_DISTANCE_NEAR +#define CAMERA_CULL_DISTANCE_FAR RL_CULL_DISTANCE_FAR +#endif //---------------------------------------------------------------------------------- // Types and Structures Definition // NOTE: Below types are required for CAMERA_STANDALONE usage //---------------------------------------------------------------------------------- +// TODO review #if defined(CAMERA_STANDALONE) // Vector2 type typedef struct Vector2 { @@ -76,8 +86,6 @@ int projection; // Camera type, defines projection type: CAMERA_PERSPECTIVE or CAMERA_ORTHOGRAPHIC } Camera3D; - typedef Camera3D Camera; // Camera type fallback, defaults to Camera3D - // Camera system modes typedef enum { CAMERA_CUSTOM = 0, @@ -97,7 +105,7 @@ //---------------------------------------------------------------------------------- // Global Variables Definition //---------------------------------------------------------------------------------- -//... + //---------------------------------------------------------------------------------- // Module Functions Declaration @@ -107,17 +115,19 @@ extern "C" { // Prevents name mangling of functions #endif -#if defined(CAMERA_STANDALONE) -void SetCameraMode(Camera camera, int mode); // Set camera mode (multiple camera modes available) -void UpdateCamera(Camera *camera); // Update camera position for selected mode - -void SetCameraPanControl(int keyPan); // Set camera pan key to combine with mouse movement (free camera) -void SetCameraAltControl(int keyAlt); // Set camera alt key to combine with mouse movement (free camera) -void SetCameraSmoothZoomControl(int szoomKey); // Set camera smooth zoom key to combine with mouse (free camera) -void SetCameraMoveControls(int keyFront, int keyBack, - int keyRight, int keyLeft, - int keyUp, int keyDown); // Set camera move controls (1st person and 3rd person cameras) -#endif +Vector3 GetCameraForward(Camera3D* camera); +Vector3 GetCameraUp(Camera3D* camera); +Vector3 GetCameraRight(Camera3D* camera); +void CameraMoveForward(Camera3D* camera, float distance, bool moveInWorldPlane); +void CameraMoveUp(Camera3D* camera, float distance); +void CameraMoveRight(Camera3D* camera, float distance, bool moveInWorldPlane); +void CameraZoom(Camera3D* camera, float delta); +void CameraYaw(Camera3D* camera, float angle, bool rotateAroundTarget); +void CameraPitch(Camera3D* camera, float angle, bool lockView, bool rotateAroundTarget, bool rotateUp); +void CameraRoll(Camera3D* camera, float angle); +void CameraViewBobbing(Camera3D* camera); +Matrix GetCameraViewMatrix(Camera3D* camera); +Matrix GetCameraProjectionMatrix(Camera3D* camera, float aspect); #if defined(__cplusplus) } @@ -134,424 +144,310 @@ void SetCameraMoveControls(int keyFront, int keyBack, #if defined(CAMERA_IMPLEMENTATION) -#include // Required for: sinf(), cosf(), sqrtf() - //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- -#ifndef PI - #define PI 3.14159265358979323846 -#endif -#ifndef DEG2RAD - #define DEG2RAD (PI/180.0f) -#endif -#ifndef RAD2DEG - #define RAD2DEG (180.0f/PI) -#endif + +#define CAMERA_MOVE_SPEED 0.09f +#define CAMERA_ROTATION_SPEED 0.03f // Camera mouse movement sensitivity -#define CAMERA_MOUSE_MOVE_SENSITIVITY 0.5f // TODO: it should be independent of framerate +#define CAMERA_MOUSE_MOVE_SENSITIVITY 0.003f // TODO: it should be independant of framerate #define CAMERA_MOUSE_SCROLL_SENSITIVITY 1.5f -// FREE_CAMERA -#define CAMERA_FREE_MOUSE_SENSITIVITY 0.01f -#define CAMERA_FREE_DISTANCE_MIN_CLAMP 0.3f -#define CAMERA_FREE_DISTANCE_MAX_CLAMP 120.0f -#define CAMERA_FREE_MIN_CLAMP 85.0f -#define CAMERA_FREE_MAX_CLAMP -85.0f -#define CAMERA_FREE_SMOOTH_ZOOM_SENSITIVITY 0.05f -#define CAMERA_FREE_PANNING_DIVIDER 5.1f - -// ORBITAL_CAMERA -#define CAMERA_ORBITAL_SPEED 0.5f // Radians per second - -// FIRST_PERSON -//#define CAMERA_FIRST_PERSON_MOUSE_SENSITIVITY 0.003f -#define CAMERA_FIRST_PERSON_FOCUS_DISTANCE 25.0f -#define CAMERA_FIRST_PERSON_MIN_CLAMP 89.0f -#define CAMERA_FIRST_PERSON_MAX_CLAMP -89.0f - -// When walking, y-position of the player moves up-down at step frequency (swinging) but -// also the body slightly tilts left-right on every step, when all the body weight is left over one foot (tilting) -#define CAMERA_FIRST_PERSON_STEP_FREQUENCY 1.8f // Step frequency when walking (steps per second) -#define CAMERA_FIRST_PERSON_SWINGING_DELTA 0.03f // Maximum up-down swinging distance when walking -#define CAMERA_FIRST_PERSON_TILTING_DELTA 0.005f // Maximum left-right tilting distance when walking - -// THIRD_PERSON -//#define CAMERA_THIRD_PERSON_MOUSE_SENSITIVITY 0.003f -#define CAMERA_THIRD_PERSON_DISTANCE_CLAMP 1.2f -#define CAMERA_THIRD_PERSON_MIN_CLAMP 5.0f -#define CAMERA_THIRD_PERSON_MAX_CLAMP -85.0f -#define CAMERA_THIRD_PERSON_OFFSET (Vector3){ 0.4f, 0.0f, 0.0f } +#define CAMERA_ORBITAL_SPEED 0.01f // Radians per frame + + +#define CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER 8.0f +#define CAMERA_FIRST_PERSON_STEP_DIVIDER 30.0f +#define CAMERA_FIRST_PERSON_WAVING_DIVIDER 200.0f // PLAYER (used by camera) -#define PLAYER_MOVEMENT_SENSITIVITY 2.0f +#define PLAYER_MOVEMENT_SENSITIVITY 20.0f //---------------------------------------------------------------------------------- // Types and Structures Definition //---------------------------------------------------------------------------------- -// Camera move modes (first person and third person cameras) -typedef enum { - MOVE_FRONT = 0, - MOVE_BACK, - MOVE_RIGHT, - MOVE_LEFT, - MOVE_UP, - MOVE_DOWN -} CameraMove; - -// Camera global state context data [56 bytes] -typedef struct { - unsigned int mode; // Current camera mode - float targetDistance; // Camera distance from position to target - float playerEyesPosition; // Player eyes position from ground (in meters) - Vector2 angle; // Camera angle in plane XZ - - // Camera movement control keys - int moveControl[6]; // Move controls (CAMERA_FIRST_PERSON) - int smoothZoomControl; // Smooth zoom control key - int altControl; // Alternative control key - int panControl; // Pan view control key -} CameraData; + //---------------------------------------------------------------------------------- // Global Variables Definition //---------------------------------------------------------------------------------- -static CameraData CAMERA = { // Global CAMERA state context - .mode = 0, - .targetDistance = 0, - .playerEyesPosition = 1.85f, - .angle = { 0 }, - .moveControl = { 'W', 'S', 'D', 'A', 'E', 'Q' }, - .smoothZoomControl = 341, // raylib: KEY_LEFT_CONTROL - .altControl = 342, // raylib: KEY_LEFT_ALT - .panControl = 2 // raylib: MOUSE_BUTTON_MIDDLE -}; + //---------------------------------------------------------------------------------- // Module specific Functions Declaration //---------------------------------------------------------------------------------- -#if defined(CAMERA_STANDALONE) -// NOTE: Camera controls depend on some raylib input functions -static void EnableCursor() {} // Unlock cursor -static void DisableCursor() {} // Lock cursor -static int IsKeyDown(int key) { return 0; } - -static int IsMouseButtonDown(int button) { return 0;} -static float GetMouseWheelMove() { return 0.0f; } -static Vector2 GetMousePosition() { return (Vector2){ 0.0f, 0.0f }; } -#endif //---------------------------------------------------------------------------------- // Module Functions Definition //---------------------------------------------------------------------------------- -// Select camera mode (multiple camera modes available) -void SetCameraMode(Camera camera, int mode) +// Returns the cameras forward vector (normalized) +Vector3 GetCameraForward(Camera3D *camera) { - Vector3 v1 = camera.position; - Vector3 v2 = camera.target; + return Vector3Normalize(Vector3Subtract(camera->target, camera->position)); +} - float dx = v2.x - v1.x; - float dy = v2.y - v1.y; - float dz = v2.z - v1.z; +// Returns the cameras up vector (normalized) +// Note: The up vector might not be perpendicular to the forward vector +Vector3 GetCameraUp(Camera3D *camera) +{ + return Vector3Normalize(camera->up); +} - CAMERA.targetDistance = sqrtf(dx*dx + dy*dy + dz*dz); // Distance to target +// Returns the cameras right vector (normalized) +Vector3 GetCameraRight(Camera3D *camera) +{ + Vector3 forward = GetCameraForward(camera); + Vector3 up = GetCameraUp(camera); + return Vector3CrossProduct(forward, up); +} - // Camera angle calculation - CAMERA.angle.x = atan2f(dx, dz); // Camera angle in plane XZ (0 aligned with Z, move positive CCW) - CAMERA.angle.y = atan2f(dy, sqrtf(dx*dx + dz*dz)); // Camera angle in plane XY (0 aligned with X, move positive CW) +// Moves the camera in its forward direction +void CameraMoveForward(Camera3D *camera, float distance, bool moveInWorldPlane) +{ + Vector3 forward = GetCameraForward(camera); - CAMERA.playerEyesPosition = camera.position.y; // Init player eyes position to camera Y position + if (moveInWorldPlane) + { + // Project vector onto world plane + forward.y = 0; + forward = Vector3Normalize(forward); + } - // Lock cursor for first person and third person cameras - if ((mode == CAMERA_FIRST_PERSON) || (mode == CAMERA_THIRD_PERSON)) DisableCursor(); - else EnableCursor(); + // Scale by distance + forward = Vector3Scale(forward, distance); - CAMERA.mode = mode; + // Move position and target + camera->position = Vector3Add(camera->position, forward); + camera->target = Vector3Add(camera->target, forward); } -// Update camera depending on selected mode -// NOTE: Camera controls depend on some raylib functions: -// System: EnableCursor(), DisableCursor() -// Mouse: IsMouseButtonDown(), GetMousePosition(), GetMouseWheelMove() -// Keys: IsKeyDown() -void UpdateCamera(Camera *camera) +// Moves the camera in its up direction +void CameraMoveUp(Camera3D *camera, float distance) { - static float swingCounter = 0.0f; // Used for 1st person swinging movement + Vector3 up = GetCameraUp(camera); + + // Scale by distance + up = Vector3Scale(up, distance); + + // Move position and target + camera->position = Vector3Add(camera->position, up); + camera->target = Vector3Add(camera->target, up); +} - // TODO: Compute CAMERA.targetDistance and CAMERA.angle here (?) +// Moves the camera target in its current right direction +void CameraMoveRight(Camera3D *camera, float distance, bool moveInWorldPlane) +{ + Vector3 right = GetCameraRight(camera); - // Mouse movement detection - Vector2 mousePositionDelta = GetMouseDelta(); - float mouseWheelMove = GetMouseWheelMove(); - - // Keys input detection - // TODO: Input detection is raylib-dependant, it could be moved outside the module - bool keyPan = IsMouseButtonDown(CAMERA.panControl); - bool keyAlt = IsKeyDown(CAMERA.altControl); - bool szoomKey = IsKeyDown(CAMERA.smoothZoomControl); - bool direction[6] = { IsKeyDown(CAMERA.moveControl[MOVE_FRONT]), - IsKeyDown(CAMERA.moveControl[MOVE_BACK]), - IsKeyDown(CAMERA.moveControl[MOVE_RIGHT]), - IsKeyDown(CAMERA.moveControl[MOVE_LEFT]), - IsKeyDown(CAMERA.moveControl[MOVE_UP]), - IsKeyDown(CAMERA.moveControl[MOVE_DOWN]) }; - - // Support for multiple automatic camera modes - // NOTE: In case of CAMERA_CUSTOM nothing happens here, user must update it manually - switch (CAMERA.mode) + if (moveInWorldPlane) { - case CAMERA_FREE: // Camera free controls, using standard 3d-content-creation scheme - { - // Camera zoom - if ((CAMERA.targetDistance < CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0)) - { - CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY); - if (CAMERA.targetDistance > CAMERA_FREE_DISTANCE_MAX_CLAMP) CAMERA.targetDistance = CAMERA_FREE_DISTANCE_MAX_CLAMP; - } - - // Camera looking down - else if ((camera->position.y > camera->target.y) && (CAMERA.targetDistance == CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0)) - { - camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; - camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; - camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; - } - else if ((camera->position.y > camera->target.y) && (camera->target.y >= 0)) - { - camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; - camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; - camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; - - // if (camera->target.y < 0) camera->target.y = -0.001; - } - else if ((camera->position.y > camera->target.y) && (camera->target.y < 0) && (mouseWheelMove > 0)) - { - CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY); - if (CAMERA.targetDistance < CAMERA_FREE_DISTANCE_MIN_CLAMP) CAMERA.targetDistance = CAMERA_FREE_DISTANCE_MIN_CLAMP; - } - // Camera looking up - else if ((camera->position.y < camera->target.y) && (CAMERA.targetDistance == CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0)) - { - camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; - camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; - camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; - } - else if ((camera->position.y < camera->target.y) && (camera->target.y <= 0)) - { - camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; - camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; - camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; - - // if (camera->target.y > 0) camera->target.y = 0.001; - } - else if ((camera->position.y < camera->target.y) && (camera->target.y > 0) && (mouseWheelMove > 0)) - { - CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY); - if (CAMERA.targetDistance < CAMERA_FREE_DISTANCE_MIN_CLAMP) CAMERA.targetDistance = CAMERA_FREE_DISTANCE_MIN_CLAMP; - } - - // Input keys checks - if (keyPan) - { - if (keyAlt) // Alternative key behaviour - { - if (szoomKey) - { - // Camera smooth zoom - CAMERA.targetDistance += (mousePositionDelta.y*CAMERA_FREE_SMOOTH_ZOOM_SENSITIVITY); - } - else - { - // Camera rotation - CAMERA.angle.x += mousePositionDelta.x*-CAMERA_FREE_MOUSE_SENSITIVITY; - CAMERA.angle.y += mousePositionDelta.y*-CAMERA_FREE_MOUSE_SENSITIVITY; - - // Angle clamp - if (CAMERA.angle.y > CAMERA_FREE_MIN_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FREE_MIN_CLAMP*DEG2RAD; - else if (CAMERA.angle.y < CAMERA_FREE_MAX_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FREE_MAX_CLAMP*DEG2RAD; - } - } - else - { - // Camera panning - camera->target.x += ((mousePositionDelta.x*CAMERA_FREE_MOUSE_SENSITIVITY)*cosf(CAMERA.angle.x) + (mousePositionDelta.y*-CAMERA_FREE_MOUSE_SENSITIVITY)*sinf(CAMERA.angle.x)*sinf(CAMERA.angle.y))*(CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER); - camera->target.y += ((mousePositionDelta.y*CAMERA_FREE_MOUSE_SENSITIVITY)*cosf(CAMERA.angle.y))*(CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER); - camera->target.z += ((mousePositionDelta.x*-CAMERA_FREE_MOUSE_SENSITIVITY)*sinf(CAMERA.angle.x) + (mousePositionDelta.y*-CAMERA_FREE_MOUSE_SENSITIVITY)*cosf(CAMERA.angle.x)*sinf(CAMERA.angle.y))*(CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER); - } - } - - // Update camera position with changes - camera->position.x = -sinf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.x; - camera->position.y = -sinf(CAMERA.angle.y)*CAMERA.targetDistance + camera->target.y; - camera->position.z = -cosf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.z; - - } break; - case CAMERA_ORBITAL: // Camera just orbits around target, only zoom allowed - { - CAMERA.angle.x += CAMERA_ORBITAL_SPEED*GetFrameTime(); // Camera orbit angle - CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY); // Camera zoom - - // Camera distance clamp - if (CAMERA.targetDistance < CAMERA_THIRD_PERSON_DISTANCE_CLAMP) CAMERA.targetDistance = CAMERA_THIRD_PERSON_DISTANCE_CLAMP; - - // Update camera position with changes - camera->position.x = sinf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.x; - camera->position.y = ((CAMERA.angle.y <= 0.0f)? 1 : -1)*sinf(CAMERA.angle.y)*CAMERA.targetDistance*sinf(CAMERA.angle.y) + camera->target.y; - camera->position.z = cosf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.z; - - } break; - case CAMERA_FIRST_PERSON: // Camera moves as in a first-person game, controls are configurable - { - // NOTE: On CAMERA_FIRST_PERSON player Y-movement is limited to player 'eyes position' - camera->position.y = CAMERA.playerEyesPosition; - - camera->position.x += (sinf(CAMERA.angle.x)*direction[MOVE_BACK] - - sinf(CAMERA.angle.x)*direction[MOVE_FRONT] - - cosf(CAMERA.angle.x)*direction[MOVE_LEFT] + - cosf(CAMERA.angle.x)*direction[MOVE_RIGHT])*PLAYER_MOVEMENT_SENSITIVITY*GetFrameTime(); - - camera->position.y += (sinf(CAMERA.angle.y)*direction[MOVE_FRONT] - - sinf(CAMERA.angle.y)*direction[MOVE_BACK] + - 1.0f*direction[MOVE_UP] - 1.0f*direction[MOVE_DOWN])*PLAYER_MOVEMENT_SENSITIVITY*GetFrameTime(); - - camera->position.z += (cosf(CAMERA.angle.x)*direction[MOVE_BACK] - - cosf(CAMERA.angle.x)*direction[MOVE_FRONT] + - sinf(CAMERA.angle.x)*direction[MOVE_LEFT] - - sinf(CAMERA.angle.x)*direction[MOVE_RIGHT])*PLAYER_MOVEMENT_SENSITIVITY*GetFrameTime(); - - // Camera orientation calculation - CAMERA.angle.x -= mousePositionDelta.x*CAMERA_MOUSE_MOVE_SENSITIVITY*GetFrameTime(); - CAMERA.angle.y -= mousePositionDelta.y*CAMERA_MOUSE_MOVE_SENSITIVITY*GetFrameTime(); - - // Angle clamp - if (CAMERA.angle.y > CAMERA_FIRST_PERSON_MIN_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FIRST_PERSON_MIN_CLAMP*DEG2RAD; - else if (CAMERA.angle.y < CAMERA_FIRST_PERSON_MAX_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FIRST_PERSON_MAX_CLAMP*DEG2RAD; - - // Calculate translation matrix - Matrix matTranslation = { 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, (CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER), - 0.0f, 0.0f, 0.0f, 1.0f }; - - // Calculate rotation matrix - Matrix matRotation = { 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f }; - - float cosz = cosf(0.0f); - float sinz = sinf(0.0f); - float cosy = cosf(-(PI*2 - CAMERA.angle.x)); - float siny = sinf(-(PI*2 - CAMERA.angle.x)); - float cosx = cosf(-(PI*2 - CAMERA.angle.y)); - float sinx = sinf(-(PI*2 - CAMERA.angle.y)); - - matRotation.m0 = cosz*cosy; - matRotation.m4 = (cosz*siny*sinx) - (sinz*cosx); - matRotation.m8 = (cosz*siny*cosx) + (sinz*sinx); - matRotation.m1 = sinz*cosy; - matRotation.m5 = (sinz*siny*sinx) + (cosz*cosx); - matRotation.m9 = (sinz*siny*cosx) - (cosz*sinx); - matRotation.m2 = -siny; - matRotation.m6 = cosy*sinx; - matRotation.m10= cosy*cosx; - - // Multiply translation and rotation matrices - Matrix matTransform = { 0 }; - matTransform.m0 = matTranslation.m0*matRotation.m0 + matTranslation.m1*matRotation.m4 + matTranslation.m2*matRotation.m8 + matTranslation.m3*matRotation.m12; - matTransform.m1 = matTranslation.m0*matRotation.m1 + matTranslation.m1*matRotation.m5 + matTranslation.m2*matRotation.m9 + matTranslation.m3*matRotation.m13; - matTransform.m2 = matTranslation.m0*matRotation.m2 + matTranslation.m1*matRotation.m6 + matTranslation.m2*matRotation.m10 + matTranslation.m3*matRotation.m14; - matTransform.m3 = matTranslation.m0*matRotation.m3 + matTranslation.m1*matRotation.m7 + matTranslation.m2*matRotation.m11 + matTranslation.m3*matRotation.m15; - matTransform.m4 = matTranslation.m4*matRotation.m0 + matTranslation.m5*matRotation.m4 + matTranslation.m6*matRotation.m8 + matTranslation.m7*matRotation.m12; - matTransform.m5 = matTranslation.m4*matRotation.m1 + matTranslation.m5*matRotation.m5 + matTranslation.m6*matRotation.m9 + matTranslation.m7*matRotation.m13; - matTransform.m6 = matTranslation.m4*matRotation.m2 + matTranslation.m5*matRotation.m6 + matTranslation.m6*matRotation.m10 + matTranslation.m7*matRotation.m14; - matTransform.m7 = matTranslation.m4*matRotation.m3 + matTranslation.m5*matRotation.m7 + matTranslation.m6*matRotation.m11 + matTranslation.m7*matRotation.m15; - matTransform.m8 = matTranslation.m8*matRotation.m0 + matTranslation.m9*matRotation.m4 + matTranslation.m10*matRotation.m8 + matTranslation.m11*matRotation.m12; - matTransform.m9 = matTranslation.m8*matRotation.m1 + matTranslation.m9*matRotation.m5 + matTranslation.m10*matRotation.m9 + matTranslation.m11*matRotation.m13; - matTransform.m10 = matTranslation.m8*matRotation.m2 + matTranslation.m9*matRotation.m6 + matTranslation.m10*matRotation.m10 + matTranslation.m11*matRotation.m14; - matTransform.m11 = matTranslation.m8*matRotation.m3 + matTranslation.m9*matRotation.m7 + matTranslation.m10*matRotation.m11 + matTranslation.m11*matRotation.m15; - matTransform.m12 = matTranslation.m12*matRotation.m0 + matTranslation.m13*matRotation.m4 + matTranslation.m14*matRotation.m8 + matTranslation.m15*matRotation.m12; - matTransform.m13 = matTranslation.m12*matRotation.m1 + matTranslation.m13*matRotation.m5 + matTranslation.m14*matRotation.m9 + matTranslation.m15*matRotation.m13; - matTransform.m14 = matTranslation.m12*matRotation.m2 + matTranslation.m13*matRotation.m6 + matTranslation.m14*matRotation.m10 + matTranslation.m15*matRotation.m14; - matTransform.m15 = matTranslation.m12*matRotation.m3 + matTranslation.m13*matRotation.m7 + matTranslation.m14*matRotation.m11 + matTranslation.m15*matRotation.m15; - - camera->target.x = camera->position.x - matTransform.m12; - camera->target.y = camera->position.y - matTransform.m13; - camera->target.z = camera->position.z - matTransform.m14; - - // Camera swinging (y-movement), only when walking (some key pressed) - for (int i = 0; i < 6; i++) if (direction[i]) { swingCounter += GetFrameTime(); break; } - camera->position.y -= sinf(2*PI*CAMERA_FIRST_PERSON_STEP_FREQUENCY*swingCounter)*CAMERA_FIRST_PERSON_SWINGING_DELTA; - - // Camera waiving (xz-movement), only when walking (some key pressed) - camera->up.x = sinf(2*PI*CAMERA_FIRST_PERSON_STEP_FREQUENCY*swingCounter)*CAMERA_FIRST_PERSON_TILTING_DELTA; - camera->up.z = -sinf(2*PI*CAMERA_FIRST_PERSON_STEP_FREQUENCY*swingCounter)*CAMERA_FIRST_PERSON_TILTING_DELTA; - - } break; - case CAMERA_THIRD_PERSON: // Camera moves as in a third-person game, following target at a distance, controls are configurable - { - camera->position.x += (sinf(CAMERA.angle.x)*direction[MOVE_BACK] - - sinf(CAMERA.angle.x)*direction[MOVE_FRONT] - - cosf(CAMERA.angle.x)*direction[MOVE_LEFT] + - cosf(CAMERA.angle.x)*direction[MOVE_RIGHT])*PLAYER_MOVEMENT_SENSITIVITY*GetFrameTime(); - - camera->position.y += (sinf(CAMERA.angle.y)*direction[MOVE_FRONT] - - sinf(CAMERA.angle.y)*direction[MOVE_BACK] + - 1.0f*direction[MOVE_UP] - 1.0f*direction[MOVE_DOWN])*PLAYER_MOVEMENT_SENSITIVITY*GetFrameTime(); - - camera->position.z += (cosf(CAMERA.angle.x)*direction[MOVE_BACK] - - cosf(CAMERA.angle.x)*direction[MOVE_FRONT] + - sinf(CAMERA.angle.x)*direction[MOVE_LEFT] - - sinf(CAMERA.angle.x)*direction[MOVE_RIGHT])*PLAYER_MOVEMENT_SENSITIVITY*GetFrameTime(); - - // Camera orientation calculation - CAMERA.angle.x += (mousePositionDelta.x*-CAMERA_MOUSE_MOVE_SENSITIVITY); - CAMERA.angle.y += (mousePositionDelta.y*-CAMERA_MOUSE_MOVE_SENSITIVITY); - - // Angle clamp - if (CAMERA.angle.y > CAMERA_THIRD_PERSON_MIN_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_THIRD_PERSON_MIN_CLAMP*DEG2RAD; - else if (CAMERA.angle.y < CAMERA_THIRD_PERSON_MAX_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_THIRD_PERSON_MAX_CLAMP*DEG2RAD; - - // Camera zoom - CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY); - - // Camera distance clamp - if (CAMERA.targetDistance < CAMERA_THIRD_PERSON_DISTANCE_CLAMP) CAMERA.targetDistance = CAMERA_THIRD_PERSON_DISTANCE_CLAMP; - - camera->position.x = sinf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.x; - - if (CAMERA.angle.y <= 0.0f) camera->position.y = sinf(CAMERA.angle.y)*CAMERA.targetDistance*sinf(CAMERA.angle.y) + camera->target.y; - else camera->position.y = -sinf(CAMERA.angle.y)*CAMERA.targetDistance*sinf(CAMERA.angle.y) + camera->target.y; - - camera->position.z = cosf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.z; - - } break; - case CAMERA_CUSTOM: break; - default: break; + // Project vector onto world plane + right.y = 0; + right = Vector3Normalize(right); } + + // Scale by distance + right = Vector3Scale(right, distance); + + // Move position and target + camera->position = Vector3Add(camera->position, right); + camera->target = Vector3Add(camera->target, right); } -// Set camera pan key to combine with mouse movement (free camera) -void SetCameraPanControl(int keyPan) { CAMERA.panControl = keyPan; } +// Moves the camera position closer/farther to/from the camera target +void CameraZoom(Camera3D *camera, float delta) +{ + float distance = Vector3Distance(camera->position, camera->target); + + // Apply delta + distance += delta; -// Set camera alt key to combine with mouse movement (free camera) -void SetCameraAltControl(int keyAlt) { CAMERA.altControl = keyAlt; } + // Distance must be greater than 0 + if (distance < 0) distance = 0.001f; -// Set camera smooth zoom key to combine with mouse (free camera) -void SetCameraSmoothZoomControl(int szoomKey) { CAMERA.smoothZoomControl = szoomKey; } + // Set new distance by moving the position along the forward vector + Vector3 forward = GetCameraForward(camera); + camera->position = Vector3Add(camera->target, Vector3Scale(forward, -distance)); +} -// Set camera move controls (1st person and 3rd person cameras) -void SetCameraMoveControls(int keyFront, int keyBack, int keyRight, int keyLeft, int keyUp, int keyDown) +// Rotates the camera around its up vector +// Yaw is "looking left and right" +// If rotateAroundTarget is false, the camera rotates around its position +// Note: angle must be provided in radians +void CameraYaw(Camera3D *camera, float angle, bool rotateAroundTarget) { - CAMERA.moveControl[MOVE_FRONT] = keyFront; - CAMERA.moveControl[MOVE_BACK] = keyBack; - CAMERA.moveControl[MOVE_RIGHT] = keyRight; - CAMERA.moveControl[MOVE_LEFT] = keyLeft; - CAMERA.moveControl[MOVE_UP] = keyUp; - CAMERA.moveControl[MOVE_DOWN] = keyDown; + // Rotation axis + Vector3 up = GetCameraUp(camera); + + // View vector + Vector3 target_position = Vector3Subtract(camera->target, camera->position); + + // Rotate view vector around up axis + target_position = Vector3RotateByAxisAngle(target_position, up, angle); + + if (rotateAroundTarget) + { + // Move position relative to target + camera->position = Vector3Subtract(camera->target, target_position); + } + else // rotate around camera.position + { + // Move target relative to position + camera->target = Vector3Add(camera->position, target_position); + } +} + +// Rotates the camera around its right vector +// Pitch is "looking up and down" +// lockView prevents camera overrotation (aka "somersaults") +// If rotateAroundTarget is false, the camera rotates around its position +// rotateUp rotates the up direction as well (typically only usefull in CAMERA_FREE) +// Note: angle must be provided in radians +void CameraPitch(Camera3D *camera, float angle, bool lockView, bool rotateAroundTarget, bool rotateUp) +{ + // Up direction + Vector3 up = GetCameraUp(camera); + + // View vector + Vector3 target_position = Vector3Subtract(camera->target, camera->position); + + if (lockView) + { + // In these camera modes we clamp the Pitch angle + // to allow only viewing straight up or down. + + // Clamp view up + float max_angle_up = Vector3Angle(up, target_position); + max_angle_up -= 0.001f; // avoid numerical errors + if (angle > max_angle_up) angle = max_angle_up; + + // Clamp view down + float max_angle_down = Vector3Angle(Vector3Negate(up), target_position); + max_angle_down *= -1.0f; // downwards angle is negative + max_angle_down += 0.001f; // avoid numerical errors + if (angle < max_angle_down) angle = max_angle_down; + } + + // Rotation axis + Vector3 right = GetCameraRight(camera); + + // Rotate view vector around right axis + target_position = Vector3RotateByAxisAngle(target_position, right, angle); + + if (rotateAroundTarget) + { + // Move position relative to target + camera->position = Vector3Subtract(camera->target, target_position); + } + else // rotate around camera.position + { + // Move target relative to position + camera->target = Vector3Add(camera->position, target_position); + } + + if (rotateUp) + { + // Rotate up direction around right axis + camera->up = Vector3RotateByAxisAngle(camera->up, right, angle); + } +} + +// Rotates the camera around its forward vector +// Roll is "turning your head sideways to the left or right" +// Note: angle must be provided in radians +void CameraRoll(Camera3D *camera, float angle) +{ + // Rotation axis + Vector3 forward = GetCameraForward(camera); + + // Rotate up direction around forward axis + camera->up = Vector3RotateByAxisAngle(camera->up, forward, angle); +} + +// Moves camera slightly to simulate a walking motion +// Note: Only active if camera->swingCounter > 0 +void CameraViewBobbing(Camera3D *camera) +{ + if (camera->swingCounter > 0) + { + // NOTE: We delay the target movement relative to the position movement to create a little pitch with each step. + camera->position.y = camera->position.y - 0.25f * sinf((camera->swingCounter + 1) / CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER) / CAMERA_FIRST_PERSON_STEP_DIVIDER; + camera->target.y = camera->target.y - 0.25f * sinf((camera->swingCounter - 1) / CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER) / CAMERA_FIRST_PERSON_STEP_DIVIDER; + + // Update counter for next frame + camera->swingCounter %= 2147483647 /* INT_MAX */; // Counter must be positive + camera->swingCounter++; + } +} + +// Returns the camera view matrix +Matrix GetCameraViewMatrix(Camera3D *camera) +{ + return MatrixLookAt(camera->position, camera->target, camera->up); +} + +// Returns the camera projection matrix +Matrix GetCameraProjectionMatrix(Camera3D *camera, float aspect) +{ + if (camera->projection == CAMERA_PERSPECTIVE) + { + return MatrixPerspective(camera->fovy * DEG2RAD, aspect, CAMERA_CULL_DISTANCE_NEAR, CAMERA_CULL_DISTANCE_FAR); + } + else if (camera->projection == CAMERA_ORTHOGRAPHIC) + { + double top = camera->fovy / 2.0; + double right = top * aspect; + return MatrixOrtho(-right, right, -top, top, CAMERA_CULL_DISTANCE_NEAR, CAMERA_CULL_DISTANCE_FAR); + } + + return MatrixIdentity(); +} + + +#ifndef CAMERA_STANDALONE +// Update camera position for selected mode +// Camera mode: CAMERA_FREE, CAMERA_FIRST_PERSON, CAMERA_THIRD_PERSON, CAMERA_ORBITAL or CUSTOM +void UpdateCamera(Camera3D *camera, int mode) +{ + Vector2 mousePositionDelta = GetMouseDelta(); + + bool moveInWorldPlane = mode == CAMERA_FIRST_PERSON || mode == CAMERA_THIRD_PERSON; + bool rotateAroundTarget = mode == CAMERA_THIRD_PERSON || mode == CAMERA_ORBITAL; + bool lockView = mode == CAMERA_FIRST_PERSON || mode == CAMERA_THIRD_PERSON || mode == CAMERA_ORBITAL; + bool rotateUp = mode == CAMERA_FREE; + + // Camera movement + if (IsKeyDown(KEY_W)) CameraMoveForward(camera, CAMERA_MOVE_SPEED, moveInWorldPlane); + if (IsKeyDown(KEY_S)) CameraMoveForward(camera, -CAMERA_MOVE_SPEED, moveInWorldPlane); + if (IsKeyDown(KEY_D)) CameraMoveRight(camera, CAMERA_MOVE_SPEED, moveInWorldPlane); + if (IsKeyDown(KEY_A)) CameraMoveRight(camera, -CAMERA_MOVE_SPEED, moveInWorldPlane); + if (IsKeyDown(KEY_SPACE)) CameraMoveUp(camera, CAMERA_MOVE_SPEED); + if (IsKeyDown(KEY_LEFT_CONTROL)) CameraMoveUp(camera, -CAMERA_MOVE_SPEED); + + // Camera rotation + if (IsKeyDown(KEY_DOWN)) CameraPitch(camera, -CAMERA_ROTATION_SPEED, lockView, rotateAroundTarget, rotateUp); + if (IsKeyDown(KEY_UP)) CameraPitch(camera, CAMERA_ROTATION_SPEED, lockView, rotateAroundTarget, rotateUp); + if (IsKeyDown(KEY_RIGHT)) CameraYaw(camera, -CAMERA_ROTATION_SPEED, rotateAroundTarget); + if (IsKeyDown(KEY_LEFT)) CameraYaw(camera, CAMERA_ROTATION_SPEED, rotateAroundTarget); + if (IsKeyDown(KEY_Q)) CameraRoll(camera, -CAMERA_ROTATION_SPEED); + if (IsKeyDown(KEY_E)) CameraRoll(camera, CAMERA_ROTATION_SPEED); + + CameraYaw(camera, mousePositionDelta.x * -CAMERA_MOUSE_MOVE_SENSITIVITY, rotateAroundTarget); + CameraPitch(camera, mousePositionDelta.y * -CAMERA_MOUSE_MOVE_SENSITIVITY, lockView, rotateAroundTarget, rotateUp); + + // Zoom target distance + CameraZoom(camera, -GetMouseWheelMove()); + if (IsKeyPressed(KEY_KP_SUBTRACT)) CameraZoom(camera, 2.0f); + if (IsKeyPressed(KEY_KP_ADD)) CameraZoom(camera, -2.0f); + + + // Apply view bobbing when moving around (per default only active in CAMERA_FIRST_PERSON) + if (mode == CAMERA_FIRST_PERSON && (IsKeyDown(KEY_W) || IsKeyDown(KEY_A) || IsKeyDown(KEY_S) || IsKeyDown(KEY_D))) CameraViewBobbing(camera); } +#endif // !CAMERA_STANDALONE #endif // CAMERA_IMPLEMENTATION diff --git a/src/rcamera_old.h b/src/rcamera_old.h new file mode 100644 index 000000000000..08c37669049e --- /dev/null +++ b/src/rcamera_old.h @@ -0,0 +1,567 @@ +/******************************************************************************************* +* +* rcamera - Basic camera system for multiple camera modes +* +* NOTE: Memory footprint of this library is aproximately 52 bytes (global variables) +* +* CONFIGURATION: +* +* #define CAMERA_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 CAMERA_STANDALONE +* If defined, the library can be used as standalone as a camera system but some +* functions must be redefined to manage inputs accordingly. +* +* CONTRIBUTORS: +* Ramon Santamaria: Supervision, review, update and maintenance +* Marc Palau: Initial implementation (2014) +* +* +* LICENSE: zlib/libpng +* +* Copyright (c) 2015-2022 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 RCAMERA_H +#define RCAMERA_H + +//---------------------------------------------------------------------------------- +// Defines and Macros +//---------------------------------------------------------------------------------- +//... + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +// NOTE: Below types are required for CAMERA_STANDALONE usage +//---------------------------------------------------------------------------------- +#if defined(CAMERA_STANDALONE) + // Vector2 type + typedef struct Vector2 { + float x; + float y; + } Vector2; + + // Vector3 type + typedef struct Vector3 { + float x; + float y; + float z; + } Vector3; + + // Camera type, defines a camera position/orientation in 3d space + typedef struct Camera3D { + Vector3 position; // Camera position + Vector3 target; // Camera target it looks-at + Vector3 up; // Camera up vector (rotation over its axis) + float fovy; // Camera field-of-view apperture in Y (degrees) in perspective, used as near plane width in orthographic + int type; // Camera type, defines projection type: CAMERA_PERSPECTIVE or CAMERA_ORTHOGRAPHIC + } Camera3D; + + typedef Camera3D Camera; // Camera type fallback, defaults to Camera3D + + // Camera system modes + typedef enum { + CAMERA_CUSTOM = 0, + CAMERA_FREE, + CAMERA_ORBITAL, + CAMERA_FIRST_PERSON, + CAMERA_THIRD_PERSON + } CameraMode; + + // Camera projection modes + typedef enum { + CAMERA_PERSPECTIVE = 0, + CAMERA_ORTHOGRAPHIC + } CameraProjection; +#endif + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +//... + +//---------------------------------------------------------------------------------- +// Module Functions Declaration +//---------------------------------------------------------------------------------- + +#ifdef __cplusplus +extern "C" { // Prevents name mangling of functions +#endif + +#if defined(CAMERA_STANDALONE) +void SetCameraMode(Camera camera, int mode); // Set camera mode (multiple camera modes available) +void UpdateCamera(Camera *camera); // Update camera position for selected mode + +void SetCameraPanControl(int keyPan); // Set camera pan key to combine with mouse movement (free camera) +void SetCameraAltControl(int keyAlt); // Set camera alt key to combine with mouse movement (free camera) +void SetCameraSmoothZoomControl(int szoomKey); // Set camera smooth zoom key to combine with mouse (free camera) +void SetCameraMoveControls(int keyFront, int keyBack, + int keyRight, int keyLeft, + int keyUp, int keyDown); // Set camera move controls (1st person and 3rd person cameras) +#endif + +#ifdef __cplusplus +} +#endif + +#endif // CAMERA_H + + +/*********************************************************************************** +* +* CAMERA IMPLEMENTATION +* +************************************************************************************/ + +#if defined(CAMERA_IMPLEMENTATION) + +#include // Required for: sinf(), cosf(), sqrtf() + +//---------------------------------------------------------------------------------- +// Defines and Macros +//---------------------------------------------------------------------------------- +#ifndef PI + #define PI 3.14159265358979323846 +#endif +#ifndef DEG2RAD + #define DEG2RAD (PI/180.0f) +#endif +#ifndef RAD2DEG + #define RAD2DEG (180.0f/PI) +#endif + +// Camera mouse movement sensitivity +#define CAMERA_MOUSE_MOVE_SENSITIVITY 0.003f +#define CAMERA_MOUSE_SCROLL_SENSITIVITY 1.5f + +// FREE_CAMERA +#define CAMERA_FREE_MOUSE_SENSITIVITY 0.01f +#define CAMERA_FREE_DISTANCE_MIN_CLAMP 0.3f +#define CAMERA_FREE_DISTANCE_MAX_CLAMP 120.0f +#define CAMERA_FREE_MIN_CLAMP 85.0f +#define CAMERA_FREE_MAX_CLAMP -85.0f +#define CAMERA_FREE_SMOOTH_ZOOM_SENSITIVITY 0.05f +#define CAMERA_FREE_PANNING_DIVIDER 5.1f + +// ORBITAL_CAMERA +#define CAMERA_ORBITAL_SPEED 0.01f // Radians per frame + +// FIRST_PERSON +//#define CAMERA_FIRST_PERSON_MOUSE_SENSITIVITY 0.003f +#define CAMERA_FIRST_PERSON_FOCUS_DISTANCE 25.0f +#define CAMERA_FIRST_PERSON_MIN_CLAMP 89.0f +#define CAMERA_FIRST_PERSON_MAX_CLAMP -89.0f + +#define CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER 8.0f +#define CAMERA_FIRST_PERSON_STEP_DIVIDER 30.0f +#define CAMERA_FIRST_PERSON_WAVING_DIVIDER 200.0f + +// THIRD_PERSON +//#define CAMERA_THIRD_PERSON_MOUSE_SENSITIVITY 0.003f +#define CAMERA_THIRD_PERSON_DISTANCE_CLAMP 1.2f +#define CAMERA_THIRD_PERSON_MIN_CLAMP 5.0f +#define CAMERA_THIRD_PERSON_MAX_CLAMP -85.0f +#define CAMERA_THIRD_PERSON_OFFSET (Vector3){ 0.4f, 0.0f, 0.0f } + +// PLAYER (used by camera) +#define PLAYER_MOVEMENT_SENSITIVITY 20.0f + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- +// Camera move modes (first person and third person cameras) +typedef enum { + MOVE_FRONT = 0, + MOVE_BACK, + MOVE_RIGHT, + MOVE_LEFT, + MOVE_UP, + MOVE_DOWN +} CameraMove; + +// Camera global state context data [56 bytes] +typedef struct { + unsigned int mode; // Current camera mode + float targetDistance; // Camera distance from position to target + float playerEyesPosition; // Player eyes position from ground (in meters) + Vector2 angle; // Camera angle in plane XZ + Vector2 previousMousePosition; // Previous mouse position + + // Camera movement control keys + int moveControl[6]; // Move controls (CAMERA_FIRST_PERSON) + int smoothZoomControl; // Smooth zoom control key + int altControl; // Alternative control key + int panControl; // Pan view control key +} CameraData; + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +static CameraData CAMERA = { // Global CAMERA state context + .mode = 0, + .targetDistance = 0, + .playerEyesPosition = 1.85f, + .angle = { 0 }, + .previousMousePosition = { 0 }, + .moveControl = { 'W', 'S', 'D', 'A', 'E', 'Q' }, + .smoothZoomControl = 341, // raylib: KEY_LEFT_CONTROL + .altControl = 342, // raylib: KEY_LEFT_ALT + .panControl = 2 // raylib: MOUSE_BUTTON_MIDDLE +}; + +//---------------------------------------------------------------------------------- +// Module specific Functions Declaration +//---------------------------------------------------------------------------------- +#if defined(CAMERA_STANDALONE) +// NOTE: Camera controls depend on some raylib input functions +static void EnableCursor() {} // Unlock cursor +static void DisableCursor() {} // Lock cursor + +static int IsKeyDown(int key) { return 0; } + +static int IsMouseButtonDown(int button) { return 0;} +static float GetMouseWheelMove() { return 0.0f; } +static Vector2 GetMousePosition() { return (Vector2){ 0.0f, 0.0f }; } +#endif + +//---------------------------------------------------------------------------------- +// Module Functions Definition +//---------------------------------------------------------------------------------- + +// Select camera mode (multiple camera modes available) +void SetCameraMode(Camera camera, int mode) +{ + Vector3 v1 = camera.position; + Vector3 v2 = camera.target; + + float dx = v2.x - v1.x; + float dy = v2.y - v1.y; + float dz = v2.z - v1.z; + + CAMERA.targetDistance = sqrtf(dx*dx + dy*dy + dz*dz); // Distance to target + + // Camera angle calculation + CAMERA.angle.x = atan2f(dx, dz); // Camera angle in plane XZ (0 aligned with Z, move positive CCW) + CAMERA.angle.y = atan2f(dy, sqrtf(dx*dx + dz*dz)); // Camera angle in plane XY (0 aligned with X, move positive CW) + + CAMERA.playerEyesPosition = camera.position.y; // Init player eyes position to camera Y position + + CAMERA.previousMousePosition = GetMousePosition(); // Init mouse position + + // Lock cursor for first person and third person cameras + if ((mode == CAMERA_FIRST_PERSON) || (mode == CAMERA_THIRD_PERSON)) DisableCursor(); + else EnableCursor(); + + CAMERA.mode = mode; +} + +// Update camera depending on selected mode +// NOTE: Camera controls depend on some raylib functions: +// System: EnableCursor(), DisableCursor() +// Mouse: IsMouseButtonDown(), GetMousePosition(), GetMouseWheelMove() +// Keys: IsKeyDown() +void UpdateCamera(Camera *camera) +{ + static int swingCounter = 0; // Used for 1st person swinging movement + + // TODO: Compute CAMERA.targetDistance and CAMERA.angle here (?) + + // Mouse movement detection + Vector2 mousePositionDelta = { 0.0f, 0.0f }; + Vector2 mousePosition = GetMousePosition(); + float mouseWheelMove = GetMouseWheelMove(); + + // Keys input detection + // TODO: Input detection is raylib-dependant, it could be moved outside the module + bool keyPan = IsMouseButtonDown(CAMERA.panControl); + bool keyAlt = IsKeyDown(CAMERA.altControl); + bool szoomKey = IsKeyDown(CAMERA.smoothZoomControl); + bool direction[6] = { IsKeyDown(CAMERA.moveControl[MOVE_FRONT]), + IsKeyDown(CAMERA.moveControl[MOVE_BACK]), + IsKeyDown(CAMERA.moveControl[MOVE_RIGHT]), + IsKeyDown(CAMERA.moveControl[MOVE_LEFT]), + IsKeyDown(CAMERA.moveControl[MOVE_UP]), + IsKeyDown(CAMERA.moveControl[MOVE_DOWN]) }; + + if (CAMERA.mode != CAMERA_CUSTOM) + { + mousePositionDelta.x = mousePosition.x - CAMERA.previousMousePosition.x; + mousePositionDelta.y = mousePosition.y - CAMERA.previousMousePosition.y; + + CAMERA.previousMousePosition = mousePosition; + } + + // Support for multiple automatic camera modes + // NOTE: In case of CAMERA_CUSTOM nothing happens here, user must update it manually + switch (CAMERA.mode) + { + case CAMERA_FREE: // Camera free controls, using standard 3d-content-creation scheme + { + // Camera zoom + if ((CAMERA.targetDistance < CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0)) + { + CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY); + if (CAMERA.targetDistance > CAMERA_FREE_DISTANCE_MAX_CLAMP) CAMERA.targetDistance = CAMERA_FREE_DISTANCE_MAX_CLAMP; + } + + // Camera looking down + else if ((camera->position.y > camera->target.y) && (CAMERA.targetDistance == CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0)) + { + camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; + camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; + camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; + } + else if ((camera->position.y > camera->target.y) && (camera->target.y >= 0)) + { + camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; + camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; + camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; + + // if (camera->target.y < 0) camera->target.y = -0.001; + } + else if ((camera->position.y > camera->target.y) && (camera->target.y < 0) && (mouseWheelMove > 0)) + { + CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY); + if (CAMERA.targetDistance < CAMERA_FREE_DISTANCE_MIN_CLAMP) CAMERA.targetDistance = CAMERA_FREE_DISTANCE_MIN_CLAMP; + } + // Camera looking up + else if ((camera->position.y < camera->target.y) && (CAMERA.targetDistance == CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0)) + { + camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; + camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; + camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; + } + else if ((camera->position.y < camera->target.y) && (camera->target.y <= 0)) + { + camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; + camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; + camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; + + // if (camera->target.y > 0) camera->target.y = 0.001; + } + else if ((camera->position.y < camera->target.y) && (camera->target.y > 0) && (mouseWheelMove > 0)) + { + CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY); + if (CAMERA.targetDistance < CAMERA_FREE_DISTANCE_MIN_CLAMP) CAMERA.targetDistance = CAMERA_FREE_DISTANCE_MIN_CLAMP; + } + + // Input keys checks + if (keyPan) + { + if (keyAlt) // Alternative key behaviour + { + if (szoomKey) + { + // Camera smooth zoom + CAMERA.targetDistance += (mousePositionDelta.y*CAMERA_FREE_SMOOTH_ZOOM_SENSITIVITY); + } + else + { + // Camera rotation + CAMERA.angle.x += mousePositionDelta.x*-CAMERA_FREE_MOUSE_SENSITIVITY; + CAMERA.angle.y += mousePositionDelta.y*-CAMERA_FREE_MOUSE_SENSITIVITY; + + // Angle clamp + if (CAMERA.angle.y > CAMERA_FREE_MIN_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FREE_MIN_CLAMP*DEG2RAD; + else if (CAMERA.angle.y < CAMERA_FREE_MAX_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FREE_MAX_CLAMP*DEG2RAD; + } + } + else + { + // Camera panning + camera->target.x += ((mousePositionDelta.x*CAMERA_FREE_MOUSE_SENSITIVITY)*cosf(CAMERA.angle.x) + (mousePositionDelta.y*-CAMERA_FREE_MOUSE_SENSITIVITY)*sinf(CAMERA.angle.x)*sinf(CAMERA.angle.y))*(CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER); + camera->target.y += ((mousePositionDelta.y*CAMERA_FREE_MOUSE_SENSITIVITY)*cosf(CAMERA.angle.y))*(CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER); + camera->target.z += ((mousePositionDelta.x*-CAMERA_FREE_MOUSE_SENSITIVITY)*sinf(CAMERA.angle.x) + (mousePositionDelta.y*-CAMERA_FREE_MOUSE_SENSITIVITY)*cosf(CAMERA.angle.x)*sinf(CAMERA.angle.y))*(CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER); + } + } + + // Update camera position with changes + camera->position.x = -sinf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.x; + camera->position.y = -sinf(CAMERA.angle.y)*CAMERA.targetDistance + camera->target.y; + camera->position.z = -cosf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.z; + + } break; + case CAMERA_ORBITAL: // Camera just orbits around target, only zoom allowed + { + CAMERA.angle.x += CAMERA_ORBITAL_SPEED; // Camera orbit angle + CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY); // Camera zoom + + // Camera distance clamp + if (CAMERA.targetDistance < CAMERA_THIRD_PERSON_DISTANCE_CLAMP) CAMERA.targetDistance = CAMERA_THIRD_PERSON_DISTANCE_CLAMP; + + // Update camera position with changes + camera->position.x = sinf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.x; + camera->position.y = ((CAMERA.angle.y <= 0.0f)? 1 : -1)*sinf(CAMERA.angle.y)*CAMERA.targetDistance*sinf(CAMERA.angle.y) + camera->target.y; + camera->position.z = cosf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.z; + + } break; + case CAMERA_FIRST_PERSON: // Camera moves as in a first-person game, controls are configurable + { + camera->position.x += (sinf(CAMERA.angle.x)*direction[MOVE_BACK] - + sinf(CAMERA.angle.x)*direction[MOVE_FRONT] - + cosf(CAMERA.angle.x)*direction[MOVE_LEFT] + + cosf(CAMERA.angle.x)*direction[MOVE_RIGHT])/PLAYER_MOVEMENT_SENSITIVITY; + + camera->position.y += (sinf(CAMERA.angle.y)*direction[MOVE_FRONT] - + sinf(CAMERA.angle.y)*direction[MOVE_BACK] + + 1.0f*direction[MOVE_UP] - 1.0f*direction[MOVE_DOWN])/PLAYER_MOVEMENT_SENSITIVITY; + + camera->position.z += (cosf(CAMERA.angle.x)*direction[MOVE_BACK] - + cosf(CAMERA.angle.x)*direction[MOVE_FRONT] + + sinf(CAMERA.angle.x)*direction[MOVE_LEFT] - + sinf(CAMERA.angle.x)*direction[MOVE_RIGHT])/PLAYER_MOVEMENT_SENSITIVITY; + + // Camera orientation calculation + CAMERA.angle.x += (mousePositionDelta.x*-CAMERA_MOUSE_MOVE_SENSITIVITY); + CAMERA.angle.y += (mousePositionDelta.y*-CAMERA_MOUSE_MOVE_SENSITIVITY); + + // Angle clamp + if (CAMERA.angle.y > CAMERA_FIRST_PERSON_MIN_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FIRST_PERSON_MIN_CLAMP*DEG2RAD; + else if (CAMERA.angle.y < CAMERA_FIRST_PERSON_MAX_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FIRST_PERSON_MAX_CLAMP*DEG2RAD; + + // Calculate translation matrix + Matrix matTranslation = { 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, (CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER), + 0.0f, 0.0f, 0.0f, 1.0f }; + + // Calculate rotation matrix + Matrix matRotation = { 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f }; + + float cosz = cosf(0.0f); + float sinz = sinf(0.0f); + float cosy = cosf(-(PI*2 - CAMERA.angle.x)); + float siny = sinf(-(PI*2 - CAMERA.angle.x)); + float cosx = cosf(-(PI*2 - CAMERA.angle.y)); + float sinx = sinf(-(PI*2 - CAMERA.angle.y)); + + matRotation.m0 = cosz*cosy; + matRotation.m4 = (cosz*siny*sinx) - (sinz*cosx); + matRotation.m8 = (cosz*siny*cosx) + (sinz*sinx); + matRotation.m1 = sinz*cosy; + matRotation.m5 = (sinz*siny*sinx) + (cosz*cosx); + matRotation.m9 = (sinz*siny*cosx) - (cosz*sinx); + matRotation.m2 = -siny; + matRotation.m6 = cosy*sinx; + matRotation.m10= cosy*cosx; + + // Multiply translation and rotation matrices + Matrix matTransform = { 0 }; + matTransform.m0 = matTranslation.m0*matRotation.m0 + matTranslation.m1*matRotation.m4 + matTranslation.m2*matRotation.m8 + matTranslation.m3*matRotation.m12; + matTransform.m1 = matTranslation.m0*matRotation.m1 + matTranslation.m1*matRotation.m5 + matTranslation.m2*matRotation.m9 + matTranslation.m3*matRotation.m13; + matTransform.m2 = matTranslation.m0*matRotation.m2 + matTranslation.m1*matRotation.m6 + matTranslation.m2*matRotation.m10 + matTranslation.m3*matRotation.m14; + matTransform.m3 = matTranslation.m0*matRotation.m3 + matTranslation.m1*matRotation.m7 + matTranslation.m2*matRotation.m11 + matTranslation.m3*matRotation.m15; + matTransform.m4 = matTranslation.m4*matRotation.m0 + matTranslation.m5*matRotation.m4 + matTranslation.m6*matRotation.m8 + matTranslation.m7*matRotation.m12; + matTransform.m5 = matTranslation.m4*matRotation.m1 + matTranslation.m5*matRotation.m5 + matTranslation.m6*matRotation.m9 + matTranslation.m7*matRotation.m13; + matTransform.m6 = matTranslation.m4*matRotation.m2 + matTranslation.m5*matRotation.m6 + matTranslation.m6*matRotation.m10 + matTranslation.m7*matRotation.m14; + matTransform.m7 = matTranslation.m4*matRotation.m3 + matTranslation.m5*matRotation.m7 + matTranslation.m6*matRotation.m11 + matTranslation.m7*matRotation.m15; + matTransform.m8 = matTranslation.m8*matRotation.m0 + matTranslation.m9*matRotation.m4 + matTranslation.m10*matRotation.m8 + matTranslation.m11*matRotation.m12; + matTransform.m9 = matTranslation.m8*matRotation.m1 + matTranslation.m9*matRotation.m5 + matTranslation.m10*matRotation.m9 + matTranslation.m11*matRotation.m13; + matTransform.m10 = matTranslation.m8*matRotation.m2 + matTranslation.m9*matRotation.m6 + matTranslation.m10*matRotation.m10 + matTranslation.m11*matRotation.m14; + matTransform.m11 = matTranslation.m8*matRotation.m3 + matTranslation.m9*matRotation.m7 + matTranslation.m10*matRotation.m11 + matTranslation.m11*matRotation.m15; + matTransform.m12 = matTranslation.m12*matRotation.m0 + matTranslation.m13*matRotation.m4 + matTranslation.m14*matRotation.m8 + matTranslation.m15*matRotation.m12; + matTransform.m13 = matTranslation.m12*matRotation.m1 + matTranslation.m13*matRotation.m5 + matTranslation.m14*matRotation.m9 + matTranslation.m15*matRotation.m13; + matTransform.m14 = matTranslation.m12*matRotation.m2 + matTranslation.m13*matRotation.m6 + matTranslation.m14*matRotation.m10 + matTranslation.m15*matRotation.m14; + matTransform.m15 = matTranslation.m12*matRotation.m3 + matTranslation.m13*matRotation.m7 + matTranslation.m14*matRotation.m11 + matTranslation.m15*matRotation.m15; + + camera->target.x = camera->position.x - matTransform.m12; + camera->target.y = camera->position.y - matTransform.m13; + camera->target.z = camera->position.z - matTransform.m14; + + // If movement detected (some key pressed), increase swinging + for (int i = 0; i < 6; i++) if (direction[i]) { swingCounter++; break; } + + // Camera position update + // NOTE: On CAMERA_FIRST_PERSON player Y-movement is limited to player 'eyes position' + camera->position.y = CAMERA.playerEyesPosition - sinf(swingCounter/CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER)/CAMERA_FIRST_PERSON_STEP_DIVIDER; + + camera->up.x = sinf(swingCounter/(CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER*2))/CAMERA_FIRST_PERSON_WAVING_DIVIDER; + camera->up.z = -sinf(swingCounter/(CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER*2))/CAMERA_FIRST_PERSON_WAVING_DIVIDER; + + } break; + case CAMERA_THIRD_PERSON: // Camera moves as in a third-person game, following target at a distance, controls are configurable + { + camera->position.x += (sinf(CAMERA.angle.x)*direction[MOVE_BACK] - + sinf(CAMERA.angle.x)*direction[MOVE_FRONT] - + cosf(CAMERA.angle.x)*direction[MOVE_LEFT] + + cosf(CAMERA.angle.x)*direction[MOVE_RIGHT])/PLAYER_MOVEMENT_SENSITIVITY; + + camera->position.y += (sinf(CAMERA.angle.y)*direction[MOVE_FRONT] - + sinf(CAMERA.angle.y)*direction[MOVE_BACK] + + 1.0f*direction[MOVE_UP] - 1.0f*direction[MOVE_DOWN])/PLAYER_MOVEMENT_SENSITIVITY; + + camera->position.z += (cosf(CAMERA.angle.x)*direction[MOVE_BACK] - + cosf(CAMERA.angle.x)*direction[MOVE_FRONT] + + sinf(CAMERA.angle.x)*direction[MOVE_LEFT] - + sinf(CAMERA.angle.x)*direction[MOVE_RIGHT])/PLAYER_MOVEMENT_SENSITIVITY; + + // Camera orientation calculation + CAMERA.angle.x += (mousePositionDelta.x*-CAMERA_MOUSE_MOVE_SENSITIVITY); + CAMERA.angle.y += (mousePositionDelta.y*-CAMERA_MOUSE_MOVE_SENSITIVITY); + + // Angle clamp + if (CAMERA.angle.y > CAMERA_THIRD_PERSON_MIN_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_THIRD_PERSON_MIN_CLAMP*DEG2RAD; + else if (CAMERA.angle.y < CAMERA_THIRD_PERSON_MAX_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_THIRD_PERSON_MAX_CLAMP*DEG2RAD; + + // Camera zoom + CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY); + + // Camera distance clamp + if (CAMERA.targetDistance < CAMERA_THIRD_PERSON_DISTANCE_CLAMP) CAMERA.targetDistance = CAMERA_THIRD_PERSON_DISTANCE_CLAMP; + + camera->position.x = sinf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.x; + + if (CAMERA.angle.y <= 0.0f) camera->position.y = sinf(CAMERA.angle.y)*CAMERA.targetDistance*sinf(CAMERA.angle.y) + camera->target.y; + else camera->position.y = -sinf(CAMERA.angle.y)*CAMERA.targetDistance*sinf(CAMERA.angle.y) + camera->target.y; + + camera->position.z = cosf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.z; + + } break; + case CAMERA_CUSTOM: break; + default: break; + } +} + +// Set camera pan key to combine with mouse movement (free camera) +void SetCameraPanControl(int keyPan) { CAMERA.panControl = keyPan; } + +// Set camera alt key to combine with mouse movement (free camera) +void SetCameraAltControl(int keyAlt) { CAMERA.altControl = keyAlt; } + +// Set camera smooth zoom key to combine with mouse (free camera) +void SetCameraSmoothZoomControl(int szoomKey) { CAMERA.smoothZoomControl = szoomKey; } + +// Set camera move controls (1st person and 3rd person cameras) +void SetCameraMoveControls(int keyFront, int keyBack, int keyRight, int keyLeft, int keyUp, int keyDown) +{ + CAMERA.moveControl[MOVE_FRONT] = keyFront; + CAMERA.moveControl[MOVE_BACK] = keyBack; + CAMERA.moveControl[MOVE_RIGHT] = keyRight; + CAMERA.moveControl[MOVE_LEFT] = keyLeft; + CAMERA.moveControl[MOVE_UP] = keyUp; + CAMERA.moveControl[MOVE_DOWN] = keyDown; +} + +#endif // CAMERA_IMPLEMENTATION From ea590c44a967075b3f6b420fa76e6387075ecf1d Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 14 Feb 2023 20:00:51 +0100 Subject: [PATCH 100/192] REVIEWED: Camera redesign PR --- examples/core/core_3d_camera_first_person.c | 41 +++++--- examples/core/core_3d_camera_free.c | 4 +- examples/core/core_3d_picking.c | 9 +- examples/core/core_vr_simulator.c | 6 +- examples/core/core_world_screen.c | 17 ++-- examples/models/models_animation.c | 14 +-- examples/models/models_billboard.c | 22 ++-- examples/models/models_cubicmap.c | 16 ++- examples/models/models_first_person_maze.c | 13 ++- examples/models/models_heightmap.c | 28 ++++-- examples/models/models_loading.c | 3 +- examples/models/models_loading_gltf.c | 10 +- examples/models/models_loading_m3d.c | 12 ++- examples/models/models_loading_vox.c | 5 +- examples/models/models_mesh_generation.c | 3 +- examples/models/models_mesh_picking.c | 3 +- examples/models/models_rlgl_solar_system.c | 13 +-- examples/models/models_skybox.c | 14 ++- examples/models/models_waving_cubes.c | 10 +- examples/shaders/shaders_basic_lighting.c | 8 +- examples/shaders/shaders_custom_uniform.c | 11 +- examples/shaders/shaders_fog.c | 17 ++-- examples/shaders/shaders_mesh_instancing.c | 16 +-- examples/shaders/shaders_model_shader.c | 16 +-- examples/shaders/shaders_postprocessing.c | 17 ++-- examples/shaders/shaders_raymarching.c | 7 +- examples/shaders/shaders_simple_mask.c | 26 ++--- examples/shaders/shaders_spotlight.c | 79 +++++++-------- examples/text/text_draw_3d.c | 9 +- projects/VS2022/raylib.sln | 19 ++++ src/raylib.h | 2 +- src/rcamera.h | 106 ++++++++------------ src/{rcamera_old.h => rcamera.old.h} | 0 src/rcore.c | 13 ++- 34 files changed, 321 insertions(+), 268 deletions(-) rename src/{rcamera_old.h => rcamera.old.h} (100%) diff --git a/examples/core/core_3d_camera_first_person.c b/examples/core/core_3d_camera_first_person.c index d98a002fd0c7..0fc784fa65f1 100644 --- a/examples/core/core_3d_camera_first_person.c +++ b/examples/core/core_3d_camera_first_person.c @@ -30,13 +30,12 @@ int main(void) // Define the camera to look into our 3d world (position, target, up vector) Camera camera = { 0 }; - camera.position = (Vector3){ 0.0f, 2.0f, 4.0f }; - camera.target = (Vector3){ 0.0f, 2.0f, 0.0f }; - camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; - camera.fovy = 60.0f; - camera.projection = CAMERA_PERSPECTIVE; - camera.swingCounter = 1; // Enable view bobbing - + camera.position = (Vector3){ 0.0f, 2.0f, 4.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 = 60.0f; // Camera field-of-view Y + camera.projection = CAMERA_PERSPECTIVE; // Camera projection type + int cameraMode = CAMERA_FIRST_PERSON; // Generates some random columns @@ -51,36 +50,46 @@ int main(void) colors[i] = (Color){ GetRandomValue(20, 255), GetRandomValue(10, 55), 30, 255 }; } - DisableCursor(); // Catch cursor - SetTargetFPS(60); // Set our game to run at 60 frames-per-second + 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 + while (!WindowShouldClose()) // Detect window close button or ESC key { // Update //---------------------------------------------------------------------------------- // Switch camera mode - if (IsKeyPressed(KEY_ONE)) { + if (IsKeyPressed(KEY_ONE)) + { cameraMode = CAMERA_FREE; camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Reset roll } - if (IsKeyPressed(KEY_TWO)) { + + if (IsKeyPressed(KEY_TWO)) + { cameraMode = CAMERA_FIRST_PERSON; camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Reset roll } - if (IsKeyPressed(KEY_THREE)) { + + if (IsKeyPressed(KEY_THREE)) + { cameraMode = CAMERA_THIRD_PERSON; camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Reset roll } - if (IsKeyPressed(KEY_FOUR)) { + + if (IsKeyPressed(KEY_FOUR)) + { cameraMode = CAMERA_ORBITAL; camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Reset roll } // Switch camera projection - if (IsKeyPressed(KEY_P)) { - if (camera.projection == CAMERA_PERSPECTIVE) { + if (IsKeyPressed(KEY_P)) + { + if (camera.projection == CAMERA_PERSPECTIVE) + { // Create isometric view cameraMode = CAMERA_THIRD_PERSON; // Note: The target distance is related to the render distance in the orthographic projection diff --git a/examples/core/core_3d_camera_free.c b/examples/core/core_3d_camera_free.c index 887a1df33464..59bd158a214e 100644 --- a/examples/core/core_3d_camera_free.c +++ b/examples/core/core_3d_camera_free.c @@ -31,10 +31,12 @@ int main(void) 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 (rotation towards target) camera.fovy = 45.0f; // Camera field-of-view Y - camera.projection = CAMERA_PERSPECTIVE; // Camera mode type + camera.projection = CAMERA_PERSPECTIVE; // Camera projection type Vector3 cubePosition = { 0.0f, 0.0f, 0.0f }; + DisableCursor(); // Limit cursor to relative movement inside the window + SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- diff --git a/examples/core/core_3d_picking.c b/examples/core/core_3d_picking.c index 0cf56f5feaed..c7bf94663643 100644 --- a/examples/core/core_3d_picking.c +++ b/examples/core/core_3d_picking.c @@ -31,16 +31,13 @@ int main(void) 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 (rotation towards target) camera.fovy = 45.0f; // Camera field-of-view Y - camera.projection = CAMERA_PERSPECTIVE; // Camera mode type + camera.projection = CAMERA_PERSPECTIVE; // Camera projection type Vector3 cubePosition = { 0.0f, 1.0f, 0.0f }; Vector3 cubeSize = { 2.0f, 2.0f, 2.0f }; Ray ray = { 0 }; // Picking line ray - - RayCollision collision = { 0 }; - - EnableCursor(); // Disable camera controls + RayCollision collision = { 0 }; // Ray collision hit info SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- @@ -50,7 +47,7 @@ int main(void) { // Update //---------------------------------------------------------------------------------- - if (IsCursorHidden()) UpdateCamera(&camera, CAMERA_FIRST_PERSON); // Update camera + if (IsCursorHidden()) UpdateCamera(&camera, CAMERA_FIRST_PERSON); // Toggle camera controls if (IsMouseButtonPressed(MOUSE_BUTTON_RIGHT)) diff --git a/examples/core/core_vr_simulator.c b/examples/core/core_vr_simulator.c index 3024b7853756..bc69cc69850c 100644 --- a/examples/core/core_vr_simulator.c +++ b/examples/core/core_vr_simulator.c @@ -95,12 +95,12 @@ int main(void) 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 camera.fovy = 60.0f; // Camera field-of-view Y - camera.projection = CAMERA_PERSPECTIVE; // Camera type - camera.swingCounter = 1; // Enable view bobbing + camera.projection = CAMERA_PERSPECTIVE; // Camera projection type Vector3 cubePosition = { 0.0f, 0.0f, 0.0f }; - DisableCursor(); // Catch cursor + DisableCursor(); // Limit cursor to relative movement inside the window + SetTargetFPS(90); // Set our game to run at 90 frames-per-second //-------------------------------------------------------------------------------------- diff --git a/examples/core/core_world_screen.c b/examples/core/core_world_screen.c index f96690ba53d1..6c811a5096da 100644 --- a/examples/core/core_world_screen.c +++ b/examples/core/core_world_screen.c @@ -27,16 +27,17 @@ int main(void) // Define the camera to look into our 3d world Camera camera = { 0 }; - camera.position = (Vector3){ 10.0f, 10.0f, 10.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; + camera.position = (Vector3){ 10.0f, 10.0f, 10.0f }; // Camera position + 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 (rotation towards target) + camera.fovy = 45.0f; // Camera field-of-view Y + camera.projection = CAMERA_PERSPECTIVE; // Camera projection type Vector3 cubePosition = { 0.0f, 0.0f, 0.0f }; Vector2 cubeScreenPosition = { 0.0f, 0.0f }; - DisableCursor(); // Catch cursor + DisableCursor(); // Limit cursor to relative movement inside the window + SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- @@ -67,7 +68,9 @@ int main(void) EndMode3D(); DrawText("Enemy: 100 / 100", (int)cubeScreenPosition.x - MeasureText("Enemy: 100/100", 20)/2, (int)cubeScreenPosition.y, 20, BLACK); - DrawText("Text is always on top of the cube", (screenWidth - MeasureText("Text is always on top of the cube", 20))/2, 25, 20, GRAY); + + DrawText(TextFormat("Cube position in screen space coordinates: [%i, %i]", (int)cubeScreenPosition.x, (int)cubeScreenPosition.y), 10, 10, 20, LIME); + DrawText("Text 2d should be always on top of the cube", 10, 40, 20, GRAY); EndDrawing(); //---------------------------------------------------------------------------------- diff --git a/examples/models/models_animation.c b/examples/models/models_animation.c index a36f3fe5b40c..ffe2d01248a8 100644 --- a/examples/models/models_animation.c +++ b/examples/models/models_animation.c @@ -21,8 +21,6 @@ #include "raylib.h" -#include - //------------------------------------------------------------------------------------ // Program main entry point //------------------------------------------------------------------------------------ @@ -102,15 +100,11 @@ int main(void) // De-Initialization //-------------------------------------------------------------------------------------- - UnloadTexture(texture); // Unload texture - - // Unload model animations data - for (unsigned int i = 0; i < animsCount; i++) UnloadModelAnimation(anims[i]); - RL_FREE(anims); - - UnloadModel(model); // Unload model + UnloadTexture(texture); // Unload texture + UnloadModelAnimations(anims, animsCount); // Unload model animations data + UnloadModel(model); // Unload model - CloseWindow(); // Close window and OpenGL context + CloseWindow(); // Close window and OpenGL context //-------------------------------------------------------------------------------------- return 0; diff --git a/examples/models/models_billboard.c b/examples/models/models_billboard.c index 6d16cf01fc4e..596a09d3bc0d 100644 --- a/examples/models/models_billboard.c +++ b/examples/models/models_billboard.c @@ -28,15 +28,15 @@ int main(void) // Define the camera to look into our 3d world Camera camera = { 0 }; - camera.position = (Vector3){ 5.0f, 4.0f, 5.0f }; - camera.target = (Vector3){ 0.0f, 2.0f, 0.0f }; - camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; - camera.fovy = 45.0f; - camera.projection = CAMERA_PERSPECTIVE; + camera.position = (Vector3){ 5.0f, 4.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 - Texture2D bill = LoadTexture("resources/billboard.png"); // Our billboard texture - Vector3 billPositionStatic = { 0.0f, 2.0f, 0.0f }; // Position of billboard - Vector3 billPositionRotating = { 1.0f, 2.0f, 1.0f }; + Texture2D bill = LoadTexture("resources/billboard.png"); // Our billboard texture + Vector3 billPositionStatic = { 0.0f, 2.0f, 0.0f }; // Position of static billboard + Vector3 billPositionRotating = { 1.0f, 2.0f, 1.0f }; // Position of rotating billboard // Entire billboard texture, source is used to take a segment from a larger texture. Rectangle source = { 0.0f, 0.0f, (float)bill.width, (float)bill.height }; @@ -55,11 +55,13 @@ int main(void) float distanceRotating; float rotation = 0.0f; - SetTargetFPS(60); // Set our game to run at 60 frames-per-second + 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 + while (!WindowShouldClose()) // Detect window close button or ESC key { // Update //---------------------------------------------------------------------------------- diff --git a/examples/models/models_cubicmap.c b/examples/models/models_cubicmap.c index 83bfab68bd02..714918e41cbf 100644 --- a/examples/models/models_cubicmap.c +++ b/examples/models/models_cubicmap.c @@ -26,7 +26,12 @@ int main(void) InitWindow(screenWidth, screenHeight, "raylib [models] example - cubesmap loading and drawing"); // Define the camera to look into our 3d world - Camera camera = { { 16.0f, 14.0f, 16.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 45.0f, 0 }; + Camera camera = { 0 }; + camera.position = (Vector3){ 16.0f, 14.0f, 16.0f }; // Camera position + 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 (rotation towards target) + camera.fovy = 45.0f; // Camera field-of-view Y + camera.projection = CAMERA_PERSPECTIVE; // Camera projection type Image image = LoadImage("resources/cubicmap.png"); // Load cubicmap image (RAM) Texture2D cubicmap = LoadTextureFromImage(image); // Convert image to texture to display (VRAM) @@ -36,18 +41,19 @@ int main(void) // NOTE: By default each cube is mapped to one part of texture atlas Texture2D texture = LoadTexture("resources/cubicmap_atlas.png"); // Load map texture - model.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = texture; // Set map diffuse texture + model.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = texture; // Set map diffuse texture Vector3 mapPosition = { -16.0f, 0.0f, -8.0f }; // Set model position UnloadImage(image); // Unload cubesmap image from RAM, already uploaded to VRAM - DisableCursor(); // Catch cursor - SetTargetFPS(60); // Set our game to run at 60 frames-per-second + 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 + while (!WindowShouldClose()) // Detect window close button or ESC key { // Update //---------------------------------------------------------------------------------- diff --git a/examples/models/models_first_person_maze.c b/examples/models/models_first_person_maze.c index 3f6a935c3544..6a4345a8b18e 100644 --- a/examples/models/models_first_person_maze.c +++ b/examples/models/models_first_person_maze.c @@ -28,7 +28,13 @@ int main(void) InitWindow(screenWidth, screenHeight, "raylib [models] example - first person maze"); // Define the camera to look into our 3d world - Camera camera = { { 0.2f, 0.4f, 0.2f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 45.0f, 0 }; + Camera camera = { 0 }; + camera.position = (Vector3){ 0.2f, 0.4f, 0.2f }; // Camera position + camera.target = (Vector3){ 0.185f, 0.4f, 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 + Vector3 position = { 0.0f, 0.0f, 0.0f }; // Set model position Image imMap = LoadImage("resources/cubicmap.png"); // Load cubicmap image (RAM) Texture2D cubicmap = LoadTextureFromImage(imMap); // Convert image to texture to display (VRAM) @@ -37,7 +43,7 @@ int main(void) // NOTE: By default each cube is mapped to one part of texture atlas Texture2D texture = LoadTexture("resources/cubicmap_atlas.png"); // Load map texture - model.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = texture; // Set map diffuse texture + model.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = texture; // Set map diffuse texture // Get map image data to be used for collision detection Color *mapPixels = LoadImageColors(imMap); @@ -45,7 +51,8 @@ int main(void) Vector3 mapPosition = { -16.0f, 0.0f, -8.0f }; // Set model position - DisableCursor(); // Catch cursor + DisableCursor(); // Limit cursor to relative movement inside the window + SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- diff --git a/examples/models/models_heightmap.c b/examples/models/models_heightmap.c index 25dc004d513b..8f32de9febe9 100644 --- a/examples/models/models_heightmap.c +++ b/examples/models/models_heightmap.c @@ -26,25 +26,31 @@ int main(void) InitWindow(screenWidth, screenHeight, "raylib [models] example - heightmap loading and drawing"); // Define our custom camera to look into our 3d world - Camera camera = { { 18.0f, 18.0f, 18.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 45.0f, 0 }; + Camera camera = { 0 }; + camera.position = (Vector3){ 18.0f, 21.0f, 18.0f }; // Camera position + 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 (rotation towards target) + camera.fovy = 45.0f; // Camera field-of-view Y + camera.projection = CAMERA_PERSPECTIVE; // Camera projection type - Image image = LoadImage("resources/heightmap.png"); // Load heightmap image (RAM) - Texture2D texture = LoadTextureFromImage(image); // Convert image to texture (VRAM) + Image image = LoadImage("resources/heightmap.png"); // Load heightmap image (RAM) + Texture2D texture = LoadTextureFromImage(image); // Convert image to texture (VRAM) - Mesh mesh = GenMeshHeightmap(image, (Vector3){ 16, 8, 16 }); // Generate heightmap mesh (RAM and VRAM) - Model model = LoadModelFromMesh(mesh); // Load model from generated mesh + Mesh mesh = GenMeshHeightmap(image, (Vector3){ 16, 8, 16 }); // Generate heightmap mesh (RAM and VRAM) + Model model = LoadModelFromMesh(mesh); // Load model from generated mesh - model.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = texture; // Set map diffuse texture - Vector3 mapPosition = { -8.0f, 0.0f, -8.0f }; // Define model position + model.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = texture; // Set map diffuse texture + Vector3 mapPosition = { -8.0f, 0.0f, -8.0f }; // Define model position - UnloadImage(image); // Unload heightmap image from RAM, already uploaded to VRAM + UnloadImage(image); // Unload heightmap image from RAM, already uploaded to VRAM - DisableCursor(); // Catch cursor - SetTargetFPS(60); // Set our game to run at 60 frames-per-second + 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 + while (!WindowShouldClose()) // Detect window close button or ESC key { // Update //---------------------------------------------------------------------------------- diff --git a/examples/models/models_loading.c b/examples/models/models_loading.c index 56dad4084392..4bce2a79e5a0 100644 --- a/examples/models/models_loading.c +++ b/examples/models/models_loading.c @@ -59,7 +59,8 @@ int main(void) bool selected = false; // Selected object flag - DisableCursor(); // Catch cursor + DisableCursor(); // Limit cursor to relative movement inside the window + SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- diff --git a/examples/models/models_loading_gltf.c b/examples/models/models_loading_gltf.c index 0c90707134a5..d8b34efed6ce 100644 --- a/examples/models/models_loading_gltf.c +++ b/examples/models/models_loading_gltf.c @@ -34,11 +34,11 @@ int main(void) // Define the camera to look into our 3d world Camera camera = { 0 }; - camera.position = (Vector3){ 5.0f, 5.0f, 5.0f }; // Camera position + 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 mode type + camera.projection = CAMERA_PERSPECTIVE; // Camera projection type // Load gltf model Model model = LoadModel("resources/models/gltf/robot.glb"); @@ -51,11 +51,13 @@ int main(void) Vector3 position = { 0.0f, 0.0f, 0.0f }; // Set model position - SetTargetFPS(60); // Set our game to run at 60 frames-per-second + 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 + while (!WindowShouldClose()) // Detect window close button or ESC key { // Update //---------------------------------------------------------------------------------- diff --git a/examples/models/models_loading_m3d.c b/examples/models/models_loading_m3d.c index c1a4af07de86..42d3416deab0 100644 --- a/examples/models/models_loading_m3d.c +++ b/examples/models/models_loading_m3d.c @@ -33,11 +33,12 @@ int main(void) // Define the camera to look into our 3d world Camera camera = { 0 }; - camera.position = (Vector3){ 1.5f, 1.5f, 1.5f }; // Camera position + camera.position = (Vector3){ 1.5f, 1.5f, 1.5f }; // Camera position camera.target = (Vector3){ 0.0f, 0.4f, 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 mode type + camera.projection = CAMERA_PERSPECTIVE; // Camera projection type + Vector3 position = { 0.0f, 0.0f, 0.0f }; // Set model position char modelFileName[128] = "resources/models/m3d/CesiumMan.m3d"; @@ -53,12 +54,13 @@ int main(void) int animFrameCounter = 0, animId = 0; ModelAnimation *anims = LoadModelAnimations(modelFileName, &animsCount); // Load skeletal animation data - DisableCursor(); // Catch cursor - SetTargetFPS(60); // Set our game to run at 60 frames-per-second + 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 + while (!WindowShouldClose()) // Detect window close button or ESC key { // Update //---------------------------------------------------------------------------------- diff --git a/examples/models/models_loading_vox.c b/examples/models/models_loading_vox.c index 6a38fe89a86a..d17fd6ee61a9 100644 --- a/examples/models/models_loading_vox.c +++ b/examples/models/models_loading_vox.c @@ -43,7 +43,7 @@ int main(void) 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 (rotation towards target) camera.fovy = 45.0f; // Camera field-of-view Y - camera.projection = CAMERA_PERSPECTIVE; // Camera mode type + camera.projection = CAMERA_PERSPECTIVE; // Camera projection type // Load MagicaVoxel files Model models[MAX_VOX_FILES] = { 0 }; @@ -69,7 +69,8 @@ int main(void) int currentModel = 0; - DisableCursor(); // Catch cursor + DisableCursor(); // Limit cursor to relative movement inside the window + SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- diff --git a/examples/models/models_mesh_generation.c b/examples/models/models_mesh_generation.c index 8e9fdf900ace..6189fb46d8ef 100644 --- a/examples/models/models_mesh_generation.c +++ b/examples/models/models_mesh_generation.c @@ -68,7 +68,8 @@ int main(void) int currentModel = 0; - DisableCursor(); // Catch cursor + DisableCursor(); // Limit cursor to relative movement inside the window + SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- diff --git a/examples/models/models_mesh_picking.c b/examples/models/models_mesh_picking.c index 1118168cb4eb..69d98aa18569 100644 --- a/examples/models/models_mesh_picking.c +++ b/examples/models/models_mesh_picking.c @@ -36,7 +36,7 @@ int main(void) camera.target = (Vector3){ 0.0f, 8.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 mode type + camera.projection = CAMERA_PERSPECTIVE; // Camera projection type Ray ray = { 0 }; // Picking ray @@ -64,7 +64,6 @@ int main(void) Vector3 sp = (Vector3){ -30.0f, 5.0f, 5.0f }; float sr = 4.0f; - EnableCursor(); // Disable camera controls SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- // Main game loop diff --git a/examples/models/models_rlgl_solar_system.c b/examples/models/models_rlgl_solar_system.c index 24f8b9a548e4..fc2a1f02099a 100644 --- a/examples/models/models_rlgl_solar_system.c +++ b/examples/models/models_rlgl_solar_system.c @@ -43,11 +43,11 @@ int main(void) // Define the camera to look into our 3d world Camera camera = { 0 }; - camera.position = (Vector3){ 16.0f, 16.0f, 16.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; + camera.position = (Vector3){ 16.0f, 16.0f, 16.0f }; // Camera position + 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 (rotation towards target) + camera.fovy = 45.0f; // Camera field-of-view Y + camera.projection = CAMERA_PERSPECTIVE; // Camera projection type float rotationSpeed = 0.2f; // General system rotation speed @@ -56,7 +56,8 @@ int main(void) float moonRotation = 0.0f; // Rotation of moon around itself float moonOrbitRotation = 0.0f; // Rotation of moon around earth in degrees - DisableCursor(); // Catch cursor + DisableCursor(); // Limit cursor to relative movement inside the window + SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- diff --git a/examples/models/models_skybox.c b/examples/models/models_skybox.c index d12cc557d580..34616de59ca6 100644 --- a/examples/models/models_skybox.c +++ b/examples/models/models_skybox.c @@ -38,7 +38,12 @@ int main(void) InitWindow(screenWidth, screenHeight, "raylib [models] example - skybox loading and drawing"); // Define the camera to look into our 3d world - Camera camera = { { 1.0f, 1.0f, 1.0f }, { 4.0f, 1.0f, 4.0f }, { 0.0f, 1.0f, 0.0f }, 45.0f, 0 }; + Camera camera = { 0 }; + camera.position = (Vector3){ 1.0f, 1.0f, 1.0f }; // Camera position + camera.target = (Vector3){ 4.0f, 1.0f, 4.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 skybox model Mesh cube = GenMeshCube(1.0f, 1.0f, 1.0f); @@ -87,12 +92,13 @@ int main(void) UnloadImage(img); } - DisableCursor(); // Catch cursor - SetTargetFPS(60); // Set our game to run at 60 frames-per-second + 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 + while (!WindowShouldClose()) // Detect window close button or ESC key { // Update //---------------------------------------------------------------------------------- diff --git a/examples/models/models_waving_cubes.c b/examples/models/models_waving_cubes.c index 31ed4ff419f2..d382c998d1db 100644 --- a/examples/models/models_waving_cubes.c +++ b/examples/models/models_waving_cubes.c @@ -31,11 +31,11 @@ int main() // Initialize the camera Camera3D camera = { 0 }; - camera.position = (Vector3){ 30.0f, 20.0f, 30.0f }; - camera.target = (Vector3){ 0.0f, 0.0f, 0.0f }; - camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; - camera.fovy = 70.0f; - camera.projection = CAMERA_PERSPECTIVE; + camera.position = (Vector3){ 30.0f, 20.0f, 30.0f }; // Camera position + 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 (rotation towards target) + camera.fovy = 70.0f; // Camera field-of-view Y + camera.projection = CAMERA_PERSPECTIVE; // Camera projection type // Specify the amount of blocks in each direction const int numBlocks = 15; diff --git a/examples/shaders/shaders_basic_lighting.c b/examples/shaders/shaders_basic_lighting.c index 702177f163a2..49dc1e7d4b8a 100644 --- a/examples/shaders/shaders_basic_lighting.c +++ b/examples/shaders/shaders_basic_lighting.c @@ -50,7 +50,7 @@ int main(void) camera.target = (Vector3){ 0.0f, 0.5f, 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 mode type + camera.projection = CAMERA_PERSPECTIVE; // Camera projection type // Load plane model from a generated mesh Model model = LoadModelFromMesh(GenMeshPlane(10.0f, 10.0f, 3, 3)); @@ -80,12 +80,12 @@ int main(void) lights[2] = CreateLight(LIGHT_POINT, (Vector3){ -2, 1, 2 }, Vector3Zero(), GREEN, shader); lights[3] = CreateLight(LIGHT_POINT, (Vector3){ 2, 1, -2 }, Vector3Zero(), BLUE, shader); - DisableCursor(); // Catch cursor - SetTargetFPS(60); // Set our game to run at 60 frames-per-second + 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 + while (!WindowShouldClose()) // Detect window close button or ESC key { // Update //---------------------------------------------------------------------------------- diff --git a/examples/shaders/shaders_custom_uniform.c b/examples/shaders/shaders_custom_uniform.c index c617a6d1f078..eaeca5e517a0 100644 --- a/examples/shaders/shaders_custom_uniform.c +++ b/examples/shaders/shaders_custom_uniform.c @@ -42,11 +42,11 @@ int main(void) // Define the camera to look into our 3d world Camera camera = { 0 }; - camera.position = (Vector3){ 8.0f, 8.0f, 8.0f }; - camera.target = (Vector3){ 0.0f, 1.5f, 0.0f }; - camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; - camera.fovy = 45.0f; - camera.projection = CAMERA_PERSPECTIVE; + camera.position = (Vector3){ 8.0f, 8.0f, 8.0f }; // Camera position + camera.target = (Vector3){ 0.0f, 1.5f, 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 Model model = LoadModel("resources/models/barracks.obj"); // Load OBJ model Texture2D texture = LoadTexture("resources/models/barracks_diffuse.png"); // Load model texture (diffuse map) @@ -67,7 +67,6 @@ int main(void) // Create a RenderTexture2D to be used for render to texture RenderTexture2D target = LoadRenderTexture(screenWidth, screenHeight); - DisableCursor(); // Catch cursor SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- diff --git a/examples/shaders/shaders_fog.c b/examples/shaders/shaders_fog.c index c4b619edca22..ddd721d46528 100644 --- a/examples/shaders/shaders_fog.c +++ b/examples/shaders/shaders_fog.c @@ -45,11 +45,12 @@ int main(void) InitWindow(screenWidth, screenHeight, "raylib [shaders] example - fog"); // Define the camera to look into our 3d world - Camera camera = { - (Vector3){ 2.0f, 2.0f, 6.0f }, // position - (Vector3){ 0.0f, 0.5f, 0.0f }, // target - (Vector3){ 0.0f, 1.0f, 0.0f }, // up - 45.0f, CAMERA_PERSPECTIVE }; // fov, type + Camera camera = { 0 }; + camera.position = (Vector3){ 2.0f, 2.0f, 6.0f }; // Camera position + camera.target = (Vector3){ 0.0f, 0.5f, 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 models and texture Model modelA = LoadModelFromMesh(GenMeshTorus(0.4f, 1.0f, 16, 32)); @@ -84,12 +85,12 @@ int main(void) // Using just 1 point lights CreateLight(LIGHT_POINT, (Vector3){ 0, 2, 6 }, Vector3Zero(), WHITE, shader); - DisableCursor(); // Catch cursor - SetTargetFPS(60); // Set our game to run at 60 frames-per-second + 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 + while (!WindowShouldClose()) // Detect window close button or ESC key { // Update //---------------------------------------------------------------------------------- diff --git a/examples/shaders/shaders_mesh_instancing.c b/examples/shaders/shaders_mesh_instancing.c index 0c2f9e1d9789..02a7ee8f00a7 100644 --- a/examples/shaders/shaders_mesh_instancing.c +++ b/examples/shaders/shaders_mesh_instancing.c @@ -44,11 +44,11 @@ int main(void) // Define the camera to look into our 3d world Camera camera = { 0 }; - camera.position = (Vector3){ -125.0f, 125.0f, -125.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; + camera.position = (Vector3){ -125.0f, 125.0f, -125.0f }; // Camera position + 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 (rotation towards target) + camera.fovy = 45.0f; // Camera field-of-view Y + camera.projection = CAMERA_PERSPECTIVE; // Camera projection type // Define mesh to be instanced Mesh cube = GenMeshCube(1.0f, 1.0f, 1.0f); @@ -94,12 +94,12 @@ int main(void) Material matDefault = LoadMaterialDefault(); matDefault.maps[MATERIAL_MAP_DIFFUSE].color = BLUE; - DisableCursor(); // Catch cursor - SetTargetFPS(60); // Set our game to run at 60 frames-per-second + 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 + while (!WindowShouldClose()) // Detect window close button or ESC key { // Update //---------------------------------------------------------------------------------- diff --git a/examples/shaders/shaders_model_shader.c b/examples/shaders/shaders_model_shader.c index 069d0ee25d1a..e84ecbfbe6de 100644 --- a/examples/shaders/shaders_model_shader.c +++ b/examples/shaders/shaders_model_shader.c @@ -42,11 +42,11 @@ int main(void) // Define the camera to look into our 3d world Camera camera = { 0 }; - camera.position = (Vector3){ 4.0f, 4.0f, 4.0f }; - camera.target = (Vector3){ 0.0f, 1.0f, -1.0f }; - camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; - camera.fovy = 45.0f; - camera.projection = CAMERA_PERSPECTIVE; + camera.position = (Vector3){ 4.0f, 4.0f, 4.0f }; // Camera position + camera.target = (Vector3){ 0.0f, 1.0f, -1.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 Model model = LoadModel("resources/models/watermill.obj"); // Load OBJ model Texture2D texture = LoadTexture("resources/models/watermill_diffuse.png"); // Load model texture @@ -60,12 +60,12 @@ int main(void) Vector3 position = { 0.0f, 0.0f, 0.0f }; // Set model position - DisableCursor(); // Catch cursor - SetTargetFPS(60); // Set our game to run at 60 frames-per-second + 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 + while (!WindowShouldClose()) // Detect window close button or ESC key { // Update //---------------------------------------------------------------------------------- diff --git a/examples/shaders/shaders_postprocessing.c b/examples/shaders/shaders_postprocessing.c index 688ca9092929..991e9839bcf2 100644 --- a/examples/shaders/shaders_postprocessing.c +++ b/examples/shaders/shaders_postprocessing.c @@ -75,13 +75,18 @@ int main(void) InitWindow(screenWidth, screenHeight, "raylib [shaders] example - postprocessing shader"); // Define the camera to look into our 3d world - Camera camera = { { 2.0f, 3.0f, 2.0f }, { 0.0f, 1.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 45.0f, 0 }; + Camera camera = { 0 }; + camera.position = (Vector3){ 2.0f, 3.0f, 2.0f }; // Camera position + camera.target = (Vector3){ 0.0f, 1.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 Model model = LoadModel("resources/models/church.obj"); // Load OBJ model Texture2D texture = LoadTexture("resources/models/church_diffuse.png"); // Load model texture (diffuse map) - model.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = texture; // Set model diffuse texture + model.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = texture; // Set model diffuse texture - Vector3 position = { 0.0f, 0.0f, 0.0f }; // Set model position + Vector3 position = { 0.0f, 0.0f, 0.0f }; // Set model position // Load all postpro shaders // NOTE 1: All postpro shader use the base vertex shader (DEFAULT_VERTEX_SHADER) @@ -107,12 +112,12 @@ int main(void) // Create a RenderTexture2D to be used for render to texture RenderTexture2D target = LoadRenderTexture(screenWidth, screenHeight); - DisableCursor(); // Catch cursor - SetTargetFPS(60); // Set our game to run at 60 frames-per-second + 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 + while (!WindowShouldClose()) // Detect window close button or ESC key { // Update //---------------------------------------------------------------------------------- diff --git a/examples/shaders/shaders_raymarching.c b/examples/shaders/shaders_raymarching.c index 5cc9af050cf0..7b34a5233fde 100644 --- a/examples/shaders/shaders_raymarching.c +++ b/examples/shaders/shaders_raymarching.c @@ -40,6 +40,7 @@ int main(void) camera.target = (Vector3){ 0.0f, 0.0f, 0.7f }; // Camera looking at point camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Camera up vector (rotation towards target) camera.fovy = 65.0f; // Camera field-of-view Y + camera.projection = CAMERA_PERSPECTIVE; // Camera projection type // Load raymarching shader // NOTE: Defining 0 (NULL) for vertex shader forces usage of internal default vertex shader @@ -56,12 +57,12 @@ int main(void) float runTime = 0.0f; - DisableCursor(); // Catch cursor - SetTargetFPS(60); // Set our game to run at 60 frames-per-second + 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 + while (!WindowShouldClose()) // Detect window close button or ESC key { // Update //---------------------------------------------------------------------------------- diff --git a/examples/shaders/shaders_simple_mask.c b/examples/shaders/shaders_simple_mask.c index 49470294b940..6283ccbccbe0 100644 --- a/examples/shaders/shaders_simple_mask.c +++ b/examples/shaders/shaders_simple_mask.c @@ -39,15 +39,15 @@ int main(void) const int screenWidth = 800; const int screenHeight = 450; - InitWindow(screenWidth, screenHeight, "raylib - simple shader mask"); + InitWindow(screenWidth, screenHeight, "raylib [shaders] example - simple shader mask"); // Define the camera to look into our 3d world Camera camera = { 0 }; - camera.position = (Vector3){ 0.0f, 1.0f, 2.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; + camera.position = (Vector3){ 0.0f, 1.0f, 2.0f }; // Camera position + 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 (rotation towards target) + camera.fovy = 45.0f; // Camera field-of-view Y + camera.projection = CAMERA_PERSPECTIVE; // Camera projection type // Define our three models to show the shader on Mesh torus = GenMeshTorus(0.3f, 1, 16, 32); @@ -83,14 +83,14 @@ int main(void) model2.materials[0].shader = shader; int framesCounter = 0; - Vector3 rotation = { 0 }; // Model rotation angles + Vector3 rotation = { 0 }; // Model rotation angles - DisableCursor(); // Catch cursor - SetTargetFPS(60); // Set to run at 60 frames-per-second + DisableCursor(); // Limit cursor to relative movement inside the window + SetTargetFPS(60); // Set to run at 60 frames-per-second //-------------------------------------------------------------------------------------- // Main game loop - while (!WindowShouldClose()) // Detect window close button or ESC key + while (!WindowShouldClose()) // Detect window close button or ESC key { // Update //---------------------------------------------------------------------------------- @@ -116,9 +116,9 @@ int main(void) BeginMode3D(camera); - DrawModel(model1, (Vector3){0.5,0,0}, 1, WHITE); - DrawModelEx(model2, (Vector3){-.5,0,0}, (Vector3){1,1,0}, 50, (Vector3){1,1,1}, WHITE); - DrawModel(model3,(Vector3){0,0,-1.5}, 1, WHITE); + DrawModel(model1, (Vector3){ 0.5f, 0.0f, 0.0f }, 1, WHITE); + DrawModelEx(model2, (Vector3){ -0.5f, 0.0f, 0.0f }, (Vector3){ 1.0f, 1.0f, 0.0f }, 50, (Vector3){ 1.0f, 1.0f, 1.0f }, WHITE); + DrawModel(model3,(Vector3){ 0.0f, 0.0f, -1.5f }, 1, WHITE); DrawGrid(10, 1.0f); // Draw a grid EndMode3D(); diff --git a/examples/shaders/shaders_spotlight.c b/examples/shaders/shaders_spotlight.c index a21e3c82a48e..c96c983d0afb 100644 --- a/examples/shaders/shaders_spotlight.c +++ b/examples/shaders/shaders_spotlight.c @@ -29,10 +29,8 @@ ********************************************************************************************/ #include "raylib.h" -#include "raymath.h" -#include -#include +#include "raymath.h" #if defined(PLATFORM_DESKTOP) #define GLSL_VERSION 330 @@ -44,26 +42,26 @@ #define MAX_STARS 400 // Spot data -typedef struct { - Vector2 pos; - Vector2 vel; +typedef struct Spot { + Vector2 position; + Vector2 speed; float inner; float radius; // Shader locations - unsigned int posLoc; + unsigned int positionLoc; unsigned int innerLoc; unsigned int radiusLoc; } Spot; // Stars in the star field have a position and velocity typedef struct Star { - Vector2 pos; - Vector2 vel; + Vector2 position; + Vector2 speed; } Star; -void UpdateStar(Star *s); -void ResetStar(Star *s); +static void UpdateStar(Star *s); +static void ResetStar(Star *s); //------------------------------------------------------------------------------------ // Program main entry point @@ -75,7 +73,7 @@ int main(void) const int screenWidth = 800; const int screenHeight = 450; - InitWindow(screenWidth, screenHeight, "raylib - shader spotlight"); + InitWindow(screenWidth, screenHeight, "raylib [shaders] example - shader spotlight"); HideCursor(); Texture texRay = LoadTexture("resources/raysan.png"); @@ -108,7 +106,7 @@ int main(void) innerName[6] = '0' + i; radiusName[6] = '0' + i; - spots[i].posLoc = GetShaderLocation(shdrSpot, posName); + spots[i].positionLoc = GetShaderLocation(shdrSpot, posName); spots[i].innerLoc = GetShaderLocation(shdrSpot, innerName); spots[i].radiusLoc = GetShaderLocation(shdrSpot, radiusName); @@ -124,20 +122,20 @@ int main(void) // and initialize the shader locations for (int i = 0; i < MAX_SPOTS; i++) { - spots[i].pos.x = (float)GetRandomValue(64, screenWidth - 64); - spots[i].pos.y = (float)GetRandomValue(64, screenHeight - 64); - spots[i].vel = (Vector2){ 0, 0 }; + spots[i].position.x = (float)GetRandomValue(64, screenWidth - 64); + spots[i].position.y = (float)GetRandomValue(64, screenHeight - 64); + spots[i].speed = (Vector2){ 0, 0 }; - while ((fabs(spots[i].vel.x) + fabs(spots[i].vel.y)) < 2) + while ((fabs(spots[i].speed.x) + fabs(spots[i].speed.y)) < 2) { - spots[i].vel.x = GetRandomValue(-400, 40) / 10.0f; - spots[i].vel.y = GetRandomValue(-400, 40) / 10.0f; + spots[i].speed.x = GetRandomValue(-400, 40) / 10.0f; + spots[i].speed.y = GetRandomValue(-400, 40) / 10.0f; } spots[i].inner = 28.0f * (i + 1); spots[i].radius = 48.0f * (i + 1); - SetShaderValue(shdrSpot, spots[i].posLoc, &spots[i].pos.x, SHADER_UNIFORM_VEC2); + SetShaderValue(shdrSpot, spots[i].positionLoc, &spots[i].position.x, SHADER_UNIFORM_VEC2); SetShaderValue(shdrSpot, spots[i].innerLoc, &spots[i].inner, SHADER_UNIFORM_FLOAT); SetShaderValue(shdrSpot, spots[i].radiusLoc, &spots[i].radius, SHADER_UNIFORM_FLOAT); } @@ -161,21 +159,21 @@ int main(void) if (i == 0) { Vector2 mp = GetMousePosition(); - spots[i].pos.x = mp.x; - spots[i].pos.y = screenHeight - mp.y; + spots[i].position.x = mp.x; + spots[i].position.y = screenHeight - mp.y; } else { - spots[i].pos.x += spots[i].vel.x; - spots[i].pos.y += spots[i].vel.y; + spots[i].position.x += spots[i].speed.x; + spots[i].position.y += spots[i].speed.y; - if (spots[i].pos.x < 64) spots[i].vel.x = -spots[i].vel.x; - if (spots[i].pos.x > (screenWidth - 64)) spots[i].vel.x = -spots[i].vel.x; - if (spots[i].pos.y < 64) spots[i].vel.y = -spots[i].vel.y; - if (spots[i].pos.y > (screenHeight - 64)) spots[i].vel.y = -spots[i].vel.y; + if (spots[i].position.x < 64) spots[i].speed.x = -spots[i].speed.x; + if (spots[i].position.x > (screenWidth - 64)) spots[i].speed.x = -spots[i].speed.x; + if (spots[i].position.y < 64) spots[i].speed.y = -spots[i].speed.y; + if (spots[i].position.y > (screenHeight - 64)) spots[i].speed.y = -spots[i].speed.y; } - SetShaderValue(shdrSpot, spots[i].posLoc, &spots[i].pos.x, SHADER_UNIFORM_VEC2); + SetShaderValue(shdrSpot, spots[i].positionLoc, &spots[i].position.x, SHADER_UNIFORM_VEC2); } // Draw @@ -188,7 +186,7 @@ int main(void) for (int n = 0; n < MAX_STARS; n++) { // Single pixel is just too small these days! - DrawRectangle((int)stars[n].pos.x, (int)stars[n].pos.y, 2, 2, WHITE); + DrawRectangle((int)stars[n].position.x, (int)stars[n].position.y, 2, 2, WHITE); } for (int i = 0; i < 16; i++) @@ -213,7 +211,6 @@ int main(void) DrawText("Pitch Black", (int)(screenWidth*0.2f), screenHeight/2, 20, GREEN); DrawText("Dark", (int)(screenWidth*.66f), screenHeight/2, 20, GREEN); - EndDrawing(); //---------------------------------------------------------------------------------- } @@ -230,26 +227,26 @@ int main(void) } -void ResetStar(Star *s) +static void ResetStar(Star *s) { - s->pos = (Vector2){ GetScreenWidth()/2.0f, GetScreenHeight()/2.0f }; + s->position = (Vector2){ GetScreenWidth()/2.0f, GetScreenHeight()/2.0f }; do { - s->vel.x = (float)GetRandomValue(-1000, 1000)/100.0f; - s->vel.y = (float)GetRandomValue(-1000, 1000)/100.0f; + s->speed.x = (float)GetRandomValue(-1000, 1000)/100.0f; + s->speed.y = (float)GetRandomValue(-1000, 1000)/100.0f; - } while (!(fabs(s->vel.x) + (fabs(s->vel.y) > 1))); + } while (!(fabs(s->speed.x) + (fabs(s->speed.y) > 1))); - s->pos = Vector2Add(s->pos, Vector2Multiply(s->vel, (Vector2){ 8.0f, 8.0f })); + s->position = Vector2Add(s->position, Vector2Multiply(s->speed, (Vector2){ 8.0f, 8.0f })); } -void UpdateStar(Star *s) +static void UpdateStar(Star *s) { - s->pos = Vector2Add(s->pos, s->vel); + s->position = Vector2Add(s->position, s->speed); - if ((s->pos.x < 0) || (s->pos.x > GetScreenWidth()) || - (s->pos.y < 0) || (s->pos.y > GetScreenHeight())) + if ((s->position.x < 0) || (s->position.x > GetScreenWidth()) || + (s->position.y < 0) || (s->position.y > GetScreenHeight())) { ResetStar(s); } diff --git a/examples/text/text_draw_3d.c b/examples/text/text_draw_3d.c index c90ea6658ddf..097e4fc676da 100644 --- a/examples/text/text_draw_3d.c +++ b/examples/text/text_draw_3d.c @@ -96,16 +96,13 @@ int main(void) 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 (rotation towards target) camera.fovy = 45.0f; // Camera field-of-view Y - camera.projection = CAMERA_PERSPECTIVE; // Camera mode type + camera.projection = CAMERA_PERSPECTIVE; // Camera projection type int camera_mode = CAMERA_ORBITAL; Vector3 cubePosition = { 0.0f, 1.0f, 0.0f }; Vector3 cubeSize = { 2.0f, 2.0f, 2.0f }; - DisableCursor(); // Catch cursor - SetTargetFPS(60); // Set our game to run at 60 frames-per-second - // Use the default font Font font = GetFontDefault(); float fontSize = 8.0f; @@ -135,6 +132,10 @@ int main(void) // Array filled with multiple random colors (when multicolor mode is set) Color multi[TEXT_MAX_LAYERS] = {0}; + + DisableCursor(); // Limit cursor to relative movement inside the window + + SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- // Main game loop diff --git a/projects/VS2022/raylib.sln b/projects/VS2022/raylib.sln index 13d0df6de25a..5033ca12480b 100644 --- a/projects/VS2022/raylib.sln +++ b/projects/VS2022/raylib.sln @@ -265,6 +265,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "audio_stream_effects", "exa EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "textures_textured_curve", "examples\textures_textured_curve.vcxproj", "{769FF0C1-4424-4FA3-BC44-D7A7DA312A06}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "models_loading_m3d", "examples\models_loading_m3d.vcxproj", "{6D9E00D8-2893-45E4-9363-3F7F61D416BD}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug.DLL|x64 = Debug.DLL|x64 @@ -2225,6 +2227,22 @@ Global {769FF0C1-4424-4FA3-BC44-D7A7DA312A06}.Release|x64.Build.0 = Release|x64 {769FF0C1-4424-4FA3-BC44-D7A7DA312A06}.Release|x86.ActiveCfg = Release|Win32 {769FF0C1-4424-4FA3-BC44-D7A7DA312A06}.Release|x86.Build.0 = Release|Win32 + {6D9E00D8-2893-45E4-9363-3F7F61D416BD}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {6D9E00D8-2893-45E4-9363-3F7F61D416BD}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {6D9E00D8-2893-45E4-9363-3F7F61D416BD}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {6D9E00D8-2893-45E4-9363-3F7F61D416BD}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {6D9E00D8-2893-45E4-9363-3F7F61D416BD}.Debug|x64.ActiveCfg = Debug|x64 + {6D9E00D8-2893-45E4-9363-3F7F61D416BD}.Debug|x64.Build.0 = Debug|x64 + {6D9E00D8-2893-45E4-9363-3F7F61D416BD}.Debug|x86.ActiveCfg = Debug|Win32 + {6D9E00D8-2893-45E4-9363-3F7F61D416BD}.Debug|x86.Build.0 = Debug|Win32 + {6D9E00D8-2893-45E4-9363-3F7F61D416BD}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {6D9E00D8-2893-45E4-9363-3F7F61D416BD}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {6D9E00D8-2893-45E4-9363-3F7F61D416BD}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {6D9E00D8-2893-45E4-9363-3F7F61D416BD}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {6D9E00D8-2893-45E4-9363-3F7F61D416BD}.Release|x64.ActiveCfg = Release|x64 + {6D9E00D8-2893-45E4-9363-3F7F61D416BD}.Release|x64.Build.0 = Release|x64 + {6D9E00D8-2893-45E4-9363-3F7F61D416BD}.Release|x86.ActiveCfg = Release|Win32 + {6D9E00D8-2893-45E4-9363-3F7F61D416BD}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -2359,6 +2377,7 @@ Global {1DE84812-E143-4C4B-A61D-9267AAD55401} = {DA049009-21FF-4AC0-84E4-830DD1BCD0CE} {4A87569C-4BD3-4113-B4B9-573D65B3D3F8} = {CC132A4D-D081-4C26-BFB9-AB11984054F8} {769FF0C1-4424-4FA3-BC44-D7A7DA312A06} = {DA049009-21FF-4AC0-84E4-830DD1BCD0CE} + {6D9E00D8-2893-45E4-9363-3F7F61D416BD} = {AF5BEC5C-1F2B-4DA8-B12D-D09FE569237C} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {E926C768-6307-4423-A1EC-57E95B1FAB29} diff --git a/src/raylib.h b/src/raylib.h index 650b5b29c98c..c1b85abdfdc4 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1156,7 +1156,7 @@ RLAPI float GetGesturePinchAngle(void); // Get gesture pinch ang //------------------------------------------------------------------------------------ // Camera System Functions (Module: rcamera) //------------------------------------------------------------------------------------ -RLAPI void UpdateCamera(Camera3D *camera, int mode); // Update camera position for selected mode +RLAPI void UpdateCamera(Camera *camera, int mode); // Update camera position for selected mode //------------------------------------------------------------------------------------ // Basic Shapes Drawing Functions (Module: shapes) diff --git a/src/rcamera.h b/src/rcamera.h index 60ac642a594c..d1871cdf220a 100644 --- a/src/rcamera.h +++ b/src/rcamera.h @@ -1,6 +1,6 @@ /******************************************************************************************* * -* rcamera - Basic camera system for multiple camera modes +* rcamera - Basic camera system with support for multiple camera modes * * CONFIGURATION: * @@ -15,13 +15,13 @@ * * CONTRIBUTORS: * Ramon Santamaria: Supervision, review, update and maintenance -* Christoph Wagner: Redesign (2022) +* Christoph Wagner: Complete redesign, using raymath (2022) * Marc Palau: Initial implementation (2014) * * * LICENSE: zlib/libpng * -* Copyright (c) 2015-2023 Ramon Santamaria (@raysan5) +* Copyright (c) 2022-2023 Christoph Wagner (@Crydsch) & 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. @@ -43,9 +43,6 @@ #ifndef RCAMERA_H #define RCAMERA_H -// The only dependency // TODO review standalone mode -#include "raymath.h" - //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- @@ -86,6 +83,8 @@ int projection; // Camera type, defines projection type: CAMERA_PERSPECTIVE or CAMERA_ORTHOGRAPHIC } Camera3D; + typedef Camera3D Camera; // Camera type fallback, defaults to Camera3D + // Camera system modes typedef enum { CAMERA_CUSTOM = 0, @@ -115,19 +114,21 @@ extern "C" { // Prevents name mangling of functions #endif -Vector3 GetCameraForward(Camera3D* camera); -Vector3 GetCameraUp(Camera3D* camera); -Vector3 GetCameraRight(Camera3D* camera); -void CameraMoveForward(Camera3D* camera, float distance, bool moveInWorldPlane); -void CameraMoveUp(Camera3D* camera, float distance); -void CameraMoveRight(Camera3D* camera, float distance, bool moveInWorldPlane); -void CameraZoom(Camera3D* camera, float delta); -void CameraYaw(Camera3D* camera, float angle, bool rotateAroundTarget); -void CameraPitch(Camera3D* camera, float angle, bool lockView, bool rotateAroundTarget, bool rotateUp); -void CameraRoll(Camera3D* camera, float angle); -void CameraViewBobbing(Camera3D* camera); -Matrix GetCameraViewMatrix(Camera3D* camera); -Matrix GetCameraProjectionMatrix(Camera3D* camera, float aspect); +Vector3 GetCameraForward(Camera *camera); +Vector3 GetCameraUp(Camera *camera); +Vector3 GetCameraRight(Camera *camera); + +void CameraMoveForward(Camera *camera, float distance, bool moveInWorldPlane); +void CameraMoveUp(Camera *camera, float distance); +void CameraMoveRight(Camera *camera, float distance, bool moveInWorldPlane); +void CameraMoveToTarget(Camera *camera, float delta); + +void CameraYaw(Camera *camera, float angle, bool rotateAroundTarget); +void CameraPitch(Camera *camera, float angle, bool lockView, bool rotateAroundTarget, bool rotateUp); +void CameraRoll(Camera *camera, float angle); + +Matrix GetCameraViewMatrix(Camera *camera); +Matrix GetCameraProjectionMatrix(Camera* camera, float aspect); #if defined(__cplusplus) } @@ -144,10 +145,12 @@ Matrix GetCameraProjectionMatrix(Camera3D* camera, float aspect); #if defined(CAMERA_IMPLEMENTATION) + +#include "raymath.h" // Required for some vector maths + //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- - #define CAMERA_MOVE_SPEED 0.09f #define CAMERA_ROTATION_SPEED 0.03f @@ -185,20 +188,20 @@ Matrix GetCameraProjectionMatrix(Camera3D* camera, float aspect); //---------------------------------------------------------------------------------- // Returns the cameras forward vector (normalized) -Vector3 GetCameraForward(Camera3D *camera) +Vector3 GetCameraForward(Camera *camera) { return Vector3Normalize(Vector3Subtract(camera->target, camera->position)); } // Returns the cameras up vector (normalized) // Note: The up vector might not be perpendicular to the forward vector -Vector3 GetCameraUp(Camera3D *camera) +Vector3 GetCameraUp(Camera *camera) { return Vector3Normalize(camera->up); } // Returns the cameras right vector (normalized) -Vector3 GetCameraRight(Camera3D *camera) +Vector3 GetCameraRight(Camera *camera) { Vector3 forward = GetCameraForward(camera); Vector3 up = GetCameraUp(camera); @@ -206,7 +209,7 @@ Vector3 GetCameraRight(Camera3D *camera) } // Moves the camera in its forward direction -void CameraMoveForward(Camera3D *camera, float distance, bool moveInWorldPlane) +void CameraMoveForward(Camera *camera, float distance, bool moveInWorldPlane) { Vector3 forward = GetCameraForward(camera); @@ -226,7 +229,7 @@ void CameraMoveForward(Camera3D *camera, float distance, bool moveInWorldPlane) } // Moves the camera in its up direction -void CameraMoveUp(Camera3D *camera, float distance) +void CameraMoveUp(Camera *camera, float distance) { Vector3 up = GetCameraUp(camera); @@ -239,7 +242,7 @@ void CameraMoveUp(Camera3D *camera, float distance) } // Moves the camera target in its current right direction -void CameraMoveRight(Camera3D *camera, float distance, bool moveInWorldPlane) +void CameraMoveRight(Camera *camera, float distance, bool moveInWorldPlane) { Vector3 right = GetCameraRight(camera); @@ -259,7 +262,7 @@ void CameraMoveRight(Camera3D *camera, float distance, bool moveInWorldPlane) } // Moves the camera position closer/farther to/from the camera target -void CameraZoom(Camera3D *camera, float delta) +void CameraMoveToTarget(Camera *camera, float delta) { float distance = Vector3Distance(camera->position, camera->target); @@ -278,7 +281,7 @@ void CameraZoom(Camera3D *camera, float delta) // Yaw is "looking left and right" // If rotateAroundTarget is false, the camera rotates around its position // Note: angle must be provided in radians -void CameraYaw(Camera3D *camera, float angle, bool rotateAroundTarget) +void CameraYaw(Camera *camera, float angle, bool rotateAroundTarget) { // Rotation axis Vector3 up = GetCameraUp(camera); @@ -307,7 +310,7 @@ void CameraYaw(Camera3D *camera, float angle, bool rotateAroundTarget) // If rotateAroundTarget is false, the camera rotates around its position // rotateUp rotates the up direction as well (typically only usefull in CAMERA_FREE) // Note: angle must be provided in radians -void CameraPitch(Camera3D *camera, float angle, bool lockView, bool rotateAroundTarget, bool rotateUp) +void CameraPitch(Camera *camera, float angle, bool lockView, bool rotateAroundTarget, bool rotateUp) { // Up direction Vector3 up = GetCameraUp(camera); @@ -359,7 +362,7 @@ void CameraPitch(Camera3D *camera, float angle, bool lockView, bool rotateAround // Rotates the camera around its forward vector // Roll is "turning your head sideways to the left or right" // Note: angle must be provided in radians -void CameraRoll(Camera3D *camera, float angle) +void CameraRoll(Camera *camera, float angle) { // Rotation axis Vector3 forward = GetCameraForward(camera); @@ -368,30 +371,14 @@ void CameraRoll(Camera3D *camera, float angle) camera->up = Vector3RotateByAxisAngle(camera->up, forward, angle); } -// Moves camera slightly to simulate a walking motion -// Note: Only active if camera->swingCounter > 0 -void CameraViewBobbing(Camera3D *camera) -{ - if (camera->swingCounter > 0) - { - // NOTE: We delay the target movement relative to the position movement to create a little pitch with each step. - camera->position.y = camera->position.y - 0.25f * sinf((camera->swingCounter + 1) / CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER) / CAMERA_FIRST_PERSON_STEP_DIVIDER; - camera->target.y = camera->target.y - 0.25f * sinf((camera->swingCounter - 1) / CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER) / CAMERA_FIRST_PERSON_STEP_DIVIDER; - - // Update counter for next frame - camera->swingCounter %= 2147483647 /* INT_MAX */; // Counter must be positive - camera->swingCounter++; - } -} - // Returns the camera view matrix -Matrix GetCameraViewMatrix(Camera3D *camera) +Matrix GetCameraViewMatrix(Camera *camera) { return MatrixLookAt(camera->position, camera->target, camera->up); } // Returns the camera projection matrix -Matrix GetCameraProjectionMatrix(Camera3D *camera, float aspect) +Matrix GetCameraProjectionMatrix(Camera *camera, float aspect) { if (camera->projection == CAMERA_PERSPECTIVE) { @@ -407,11 +394,10 @@ Matrix GetCameraProjectionMatrix(Camera3D *camera, float aspect) return MatrixIdentity(); } - #ifndef CAMERA_STANDALONE // Update camera position for selected mode // Camera mode: CAMERA_FREE, CAMERA_FIRST_PERSON, CAMERA_THIRD_PERSON, CAMERA_ORBITAL or CUSTOM -void UpdateCamera(Camera3D *camera, int mode) +void UpdateCamera(Camera *camera, int mode) { Vector2 mousePositionDelta = GetMouseDelta(); @@ -422,11 +408,11 @@ void UpdateCamera(Camera3D *camera, int mode) // Camera movement if (IsKeyDown(KEY_W)) CameraMoveForward(camera, CAMERA_MOVE_SPEED, moveInWorldPlane); + if (IsKeyDown(KEY_A)) CameraMoveRight(camera, -CAMERA_MOVE_SPEED, moveInWorldPlane); if (IsKeyDown(KEY_S)) CameraMoveForward(camera, -CAMERA_MOVE_SPEED, moveInWorldPlane); if (IsKeyDown(KEY_D)) CameraMoveRight(camera, CAMERA_MOVE_SPEED, moveInWorldPlane); - if (IsKeyDown(KEY_A)) CameraMoveRight(camera, -CAMERA_MOVE_SPEED, moveInWorldPlane); - if (IsKeyDown(KEY_SPACE)) CameraMoveUp(camera, CAMERA_MOVE_SPEED); - if (IsKeyDown(KEY_LEFT_CONTROL)) CameraMoveUp(camera, -CAMERA_MOVE_SPEED); + //if (IsKeyDown(KEY_SPACE)) CameraMoveUp(camera, CAMERA_MOVE_SPEED); + //if (IsKeyDown(KEY_LEFT_CONTROL)) CameraMoveUp(camera, -CAMERA_MOVE_SPEED); // Camera rotation if (IsKeyDown(KEY_DOWN)) CameraPitch(camera, -CAMERA_ROTATION_SPEED, lockView, rotateAroundTarget, rotateUp); @@ -436,17 +422,13 @@ void UpdateCamera(Camera3D *camera, int mode) if (IsKeyDown(KEY_Q)) CameraRoll(camera, -CAMERA_ROTATION_SPEED); if (IsKeyDown(KEY_E)) CameraRoll(camera, CAMERA_ROTATION_SPEED); - CameraYaw(camera, mousePositionDelta.x * -CAMERA_MOUSE_MOVE_SENSITIVITY, rotateAroundTarget); - CameraPitch(camera, mousePositionDelta.y * -CAMERA_MOUSE_MOVE_SENSITIVITY, lockView, rotateAroundTarget, rotateUp); + CameraYaw(camera, -mousePositionDelta.x*CAMERA_MOUSE_MOVE_SENSITIVITY, rotateAroundTarget); + CameraPitch(camera, -mousePositionDelta.y*CAMERA_MOUSE_MOVE_SENSITIVITY, lockView, rotateAroundTarget, rotateUp); // Zoom target distance - CameraZoom(camera, -GetMouseWheelMove()); - if (IsKeyPressed(KEY_KP_SUBTRACT)) CameraZoom(camera, 2.0f); - if (IsKeyPressed(KEY_KP_ADD)) CameraZoom(camera, -2.0f); - - - // Apply view bobbing when moving around (per default only active in CAMERA_FIRST_PERSON) - if (mode == CAMERA_FIRST_PERSON && (IsKeyDown(KEY_W) || IsKeyDown(KEY_A) || IsKeyDown(KEY_S) || IsKeyDown(KEY_D))) CameraViewBobbing(camera); + CameraMoveToTarget(camera, -GetMouseWheelMove()); + if (IsKeyPressed(KEY_KP_SUBTRACT)) CameraMoveToTarget(camera, 2.0f); + if (IsKeyPressed(KEY_KP_ADD)) CameraMoveToTarget(camera, -2.0f); } #endif // !CAMERA_STANDALONE diff --git a/src/rcamera_old.h b/src/rcamera.old.h similarity index 100% rename from src/rcamera_old.h rename to src/rcamera.old.h diff --git a/src/rcore.c b/src/rcore.c index 83a70632eee4..f81d23186e53 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -925,6 +925,8 @@ void InitWindow(int width, int height, const char *title) CORE.Input.Mouse.currentPosition.x = (float)CORE.Window.screen.width/2.0f; CORE.Input.Mouse.currentPosition.y = (float)CORE.Window.screen.height/2.0f; + + SetMousePosition((int)CORE.Input.Mouse.currentPosition.x, (int)CORE.Input.Mouse.currentPosition.x); #if defined(SUPPORT_EVENTS_AUTOMATION) events = (AutomationEvent *)malloc(MAX_CODE_AUTOMATION_EVENTS*sizeof(AutomationEvent)); @@ -2024,6 +2026,13 @@ void DisableCursor(void) { #if defined(PLATFORM_DESKTOP) glfwSetInputMode(CORE.Window.handle, GLFW_CURSOR, GLFW_CURSOR_DISABLED); + + // Set cursor position in the middle of screen and update delta accordingly + SetMousePosition(CORE.Window.screen.width/2, CORE.Window.screen.height/2); + CORE.Input.Mouse.currentPosition.x = CORE.Window.screen.width/2; + CORE.Input.Mouse.currentPosition.y = CORE.Window.screen.width/2; + CORE.Input.Mouse.previousPosition.x = CORE.Input.Mouse.currentPosition.x; + CORE.Input.Mouse.previousPosition.y = CORE.Input.Mouse.currentPosition.y; #endif #if defined(PLATFORM_WEB) emscripten_request_pointerlock("#canvas", 1); @@ -2189,7 +2198,7 @@ void EndMode2D(void) } // Initializes 3D mode with custom camera (3D) -void BeginMode3D(Camera3D camera) +void BeginMode3D(Camera camera) { rlDrawRenderBatchActive(); // Update and draw internal render batch @@ -3788,7 +3797,7 @@ Vector2 GetMousePosition(void) // Get mouse delta between frames Vector2 GetMouseDelta(void) { - Vector2 delta = {0}; + Vector2 delta = { 0 }; delta.x = CORE.Input.Mouse.currentPosition.x - CORE.Input.Mouse.previousPosition.x; delta.y = CORE.Input.Mouse.currentPosition.y - CORE.Input.Mouse.previousPosition.y; From 50d17393a5a3ece1e4290c86655c65b70ff390a4 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 14 Feb 2023 20:00:56 +0100 Subject: [PATCH 101/192] Create models_loading_m3d.vcxproj --- .../examples/models_loading_m3d.vcxproj | 387 ++++++++++++++++++ 1 file changed, 387 insertions(+) create mode 100644 projects/VS2022/examples/models_loading_m3d.vcxproj diff --git a/projects/VS2022/examples/models_loading_m3d.vcxproj b/projects/VS2022/examples/models_loading_m3d.vcxproj new file mode 100644 index 000000000000..f08b1ebb2ab6 --- /dev/null +++ b/projects/VS2022/examples/models_loading_m3d.vcxproj @@ -0,0 +1,387 @@ + + + + + Debug.DLL + Win32 + + + Debug.DLL + x64 + + + Debug + Win32 + + + Debug + x64 + + + Release.DLL + Win32 + + + Release.DLL + x64 + + + Release + Win32 + + + Release + x64 + + + + {6D9E00D8-2893-45E4-9363-3F7F61D416BD} + Win32Proj + models_loading_m3d + 10.0 + models_loading_m3d + + + + 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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)\ + + + $(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) + + + 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)\ + + + 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 From 547819766faca80482371902acd908c0c4c3f7e0 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 14 Feb 2023 20:12:53 +0100 Subject: [PATCH 102/192] ADDED: Example project to VS2022 solution --- examples/shaders/shaders_write_depth.c | 14 +- .../examples/shaders_write_depth.vcxproj | 387 ++++++++++++++++++ projects/VS2022/raylib.sln | 19 + 3 files changed, 413 insertions(+), 7 deletions(-) create mode 100644 projects/VS2022/examples/shaders_write_depth.vcxproj diff --git a/examples/shaders/shaders_write_depth.c b/examples/shaders/shaders_write_depth.c index 317f6ac7585c..b7f69ddbf6e9 100644 --- a/examples/shaders/shaders_write_depth.c +++ b/examples/shaders/shaders_write_depth.c @@ -14,6 +14,7 @@ ********************************************************************************************/ #include "raylib.h" + #include "rlgl.h" #if defined(PLATFORM_DESKTOP) @@ -27,10 +28,10 @@ //------------------------------------------------------------------------------------ // Load custom render texture, create a writable depth texture buffer static RenderTexture2D LoadRenderTextureDepthTex(int width, int height); + // Unload render texture from GPU memory (VRAM) static void UnloadRenderTextureDepthTex(RenderTexture2D target); - //------------------------------------------------------------------------------------ // Program main entry point //------------------------------------------------------------------------------------ @@ -55,20 +56,19 @@ int main(void) .target = (Vector3){ 0.0f, 0.5f, 0.0f }, // Camera looking at point .up = (Vector3){ 0.0f, 1.0f, 0.0f }, // Camera up vector (rotation towards target) .fovy = 45.0f, // Camera field-of-view Y - .projection = CAMERA_PERSPECTIVE // Camera mode type + .projection = CAMERA_PERSPECTIVE // Camera projection type }; - SetCameraMode(camera, CAMERA_ORBITAL); - - SetTargetFPS(60); + 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 + while (!WindowShouldClose()) // Detect window close button or ESC key { // Update //---------------------------------------------------------------------------------- - UpdateCamera(&camera); + UpdateCamera(&camera, CAMERA_ORBITAL); //---------------------------------------------------------------------------------- // Draw diff --git a/projects/VS2022/examples/shaders_write_depth.vcxproj b/projects/VS2022/examples/shaders_write_depth.vcxproj new file mode 100644 index 000000000000..18b1d87978fc --- /dev/null +++ b/projects/VS2022/examples/shaders_write_depth.vcxproj @@ -0,0 +1,387 @@ + + + + + Debug.DLL + Win32 + + + Debug.DLL + x64 + + + Debug + Win32 + + + Debug + x64 + + + Release.DLL + Win32 + + + Release.DLL + x64 + + + Release + Win32 + + + Release + x64 + + + + {70B35F59-AFC2-4D8F-8833-5314D2047A81} + Win32Proj + shaders_write_depth + 10.0 + shaders_write_depth + + + + 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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)\ + + + $(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) + + + 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)\ + + + 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 5033ca12480b..153628063d33 100644 --- a/projects/VS2022/raylib.sln +++ b/projects/VS2022/raylib.sln @@ -267,6 +267,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "textures_textured_curve", " EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "models_loading_m3d", "examples\models_loading_m3d.vcxproj", "{6D9E00D8-2893-45E4-9363-3F7F61D416BD}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shaders_write_depth", "examples\shaders_write_depth.vcxproj", "{70B35F59-AFC2-4D8F-8833-5314D2047A81}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug.DLL|x64 = Debug.DLL|x64 @@ -2243,6 +2245,22 @@ Global {6D9E00D8-2893-45E4-9363-3F7F61D416BD}.Release|x64.Build.0 = Release|x64 {6D9E00D8-2893-45E4-9363-3F7F61D416BD}.Release|x86.ActiveCfg = Release|Win32 {6D9E00D8-2893-45E4-9363-3F7F61D416BD}.Release|x86.Build.0 = Release|Win32 + {70B35F59-AFC2-4D8F-8833-5314D2047A81}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {70B35F59-AFC2-4D8F-8833-5314D2047A81}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {70B35F59-AFC2-4D8F-8833-5314D2047A81}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {70B35F59-AFC2-4D8F-8833-5314D2047A81}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {70B35F59-AFC2-4D8F-8833-5314D2047A81}.Debug|x64.ActiveCfg = Debug|x64 + {70B35F59-AFC2-4D8F-8833-5314D2047A81}.Debug|x64.Build.0 = Debug|x64 + {70B35F59-AFC2-4D8F-8833-5314D2047A81}.Debug|x86.ActiveCfg = Debug|Win32 + {70B35F59-AFC2-4D8F-8833-5314D2047A81}.Debug|x86.Build.0 = Debug|Win32 + {70B35F59-AFC2-4D8F-8833-5314D2047A81}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {70B35F59-AFC2-4D8F-8833-5314D2047A81}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {70B35F59-AFC2-4D8F-8833-5314D2047A81}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {70B35F59-AFC2-4D8F-8833-5314D2047A81}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {70B35F59-AFC2-4D8F-8833-5314D2047A81}.Release|x64.ActiveCfg = Release|x64 + {70B35F59-AFC2-4D8F-8833-5314D2047A81}.Release|x64.Build.0 = Release|x64 + {70B35F59-AFC2-4D8F-8833-5314D2047A81}.Release|x86.ActiveCfg = Release|Win32 + {70B35F59-AFC2-4D8F-8833-5314D2047A81}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -2378,6 +2396,7 @@ Global {4A87569C-4BD3-4113-B4B9-573D65B3D3F8} = {CC132A4D-D081-4C26-BFB9-AB11984054F8} {769FF0C1-4424-4FA3-BC44-D7A7DA312A06} = {DA049009-21FF-4AC0-84E4-830DD1BCD0CE} {6D9E00D8-2893-45E4-9363-3F7F61D416BD} = {AF5BEC5C-1F2B-4DA8-B12D-D09FE569237C} + {70B35F59-AFC2-4D8F-8833-5314D2047A81} = {5317807F-61D4-4E0F-B6DC-2D9F12621ED9} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {E926C768-6307-4423-A1EC-57E95B1FAB29} From e843be7ea53a9ec3b460ccecb9587f26721e4b96 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 14 Feb 2023 20:13:13 +0100 Subject: [PATCH 103/192] ADDED: rcamera dependencies details --- src/rcamera.h | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/src/rcamera.h b/src/rcamera.h index d1871cdf220a..7770071e8fb9 100644 --- a/src/rcamera.h +++ b/src/rcamera.h @@ -48,11 +48,11 @@ //---------------------------------------------------------------------------------- //... #if defined(CAMERA_STANDALONE) -#define CAMERA_CULL_DISTANCE_NEAR 0.01 -#define CAMERA_CULL_DISTANCE_FAR 1000.0 +#define CAMERA_CULL_DISTANCE_NEAR 0.01 +#define CAMERA_CULL_DISTANCE_FAR 1000.0 #else -#define CAMERA_CULL_DISTANCE_NEAR RL_CULL_DISTANCE_NEAR -#define CAMERA_CULL_DISTANCE_FAR RL_CULL_DISTANCE_FAR +#define CAMERA_CULL_DISTANCE_NEAR RL_CULL_DISTANCE_NEAR +#define CAMERA_CULL_DISTANCE_FAR RL_CULL_DISTANCE_FAR #endif //---------------------------------------------------------------------------------- @@ -145,8 +145,22 @@ Matrix GetCameraProjectionMatrix(Camera* camera, float aspect); #if defined(CAMERA_IMPLEMENTATION) - -#include "raymath.h" // Required for some vector maths +#include "raymath.h" // Required for vector maths: + // Vector3Add() + // Vector3Subtract() + // Vector3Scale() + // Vector3Normalize() + // Vector3Distance() + // Vector3CrossProduct() + // Vector3RotateByAxisAngle() + // Vector3Angle() + // Vector3Negate() + // MatrixLookAt() + // MatrixPerspective() + // MatrixOrtho() + // MatrixIdentity() + +// raylib input functionality required: GetMouseDelta(), GetMouseWheelMove(), IsKeyDown(), IsKeyPressed() //---------------------------------------------------------------------------------- // Defines and Macros @@ -171,12 +185,12 @@ Matrix GetCameraProjectionMatrix(Camera* camera, float aspect); //---------------------------------------------------------------------------------- // Types and Structures Definition //---------------------------------------------------------------------------------- - +//... //---------------------------------------------------------------------------------- // Global Variables Definition //---------------------------------------------------------------------------------- - +//... //---------------------------------------------------------------------------------- // Module specific Functions Declaration @@ -186,7 +200,6 @@ Matrix GetCameraProjectionMatrix(Camera* camera, float aspect); //---------------------------------------------------------------------------------- // Module Functions Definition //---------------------------------------------------------------------------------- - // Returns the cameras forward vector (normalized) Vector3 GetCameraForward(Camera *camera) { From 1cfb48410013399348c56be39135dbc922ccd792 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 14 Feb 2023 20:31:42 +0100 Subject: [PATCH 104/192] ADDED: Example project to VS --- examples/shaders/shaders_hybrid_render.c | 55 ++- .../examples/shaders_hybrid_render.vcxproj | 387 ++++++++++++++++++ projects/VS2022/raylib.sln | 19 + 3 files changed, 432 insertions(+), 29 deletions(-) create mode 100644 projects/VS2022/examples/shaders_hybrid_render.vcxproj diff --git a/examples/shaders/shaders_hybrid_render.c b/examples/shaders/shaders_hybrid_render.c index 86ba6397bac1..0f30680c8ead 100644 --- a/examples/shaders/shaders_hybrid_render.c +++ b/examples/shaders/shaders_hybrid_render.c @@ -52,24 +52,24 @@ int main(void) InitWindow(screenWidth, screenHeight, "raylib [shaders] example - write depth buffer"); - // This Shader calculates pixel depth and color using raymarch. - Shader raymarch_shader = LoadShader(0, TextFormat("resources/shaders/glsl%i/hybrid_raymarch.fs", GLSL_VERSION)); - // This Shader is a standard rasterization fragment shader with the addition of depth writing. You are required to write depth for all shaders if one shader does it. - Shader raster_shader = LoadShader(0, TextFormat("resources/shaders/glsl%i/hybrid_raster.fs", GLSL_VERSION)); + // This Shader calculates pixel depth and color using raymarch + Shader shdrRaymarch = LoadShader(0, TextFormat("resources/shaders/glsl%i/hybrid_raymarch.fs", GLSL_VERSION)); + + // This Shader is a standard rasterization fragment shader with the addition of depth writing + // You are required to write depth for all shaders if one shader does it + Shader shdrRaster = LoadShader(0, TextFormat("resources/shaders/glsl%i/hybrid_raster.fs", GLSL_VERSION)); // Declare Struct used to store camera locs. - RayLocs march_locs = {0}; + RayLocs marchLocs = {0}; // Fill the struct with shader locs. - march_locs.camPos = GetShaderLocation(raymarch_shader, "camPos"); - march_locs.camDir = GetShaderLocation(raymarch_shader, "camDir"); - march_locs.screenCenter = GetShaderLocation(raymarch_shader, "screenCenter"); - - { // Transfer screenCenter position to shader. Which is used to calculate ray direction. - Vector2 screenCenter = {.x = screenWidth/2.0, .y = screenHeight/2.0}; - SetShaderValue(raymarch_shader, march_locs.screenCenter , &screenCenter , SHADER_UNIFORM_VEC2); - } + marchLocs.camPos = GetShaderLocation(shdrRaymarch, "camPos"); + marchLocs.camDir = GetShaderLocation(shdrRaymarch, "camDir"); + marchLocs.screenCenter = GetShaderLocation(shdrRaymarch, "screenCenter"); + // Transfer screenCenter position to shader. Which is used to calculate ray direction. + Vector2 screenCenter = {.x = screenWidth/2.0, .y = screenHeight/2.0}; + SetShaderValue(shdrRaymarch, marchLocs.screenCenter , &screenCenter , SHADER_UNIFORM_VEC2); // Use Customized function to create writable depth texture buffer RenderTexture2D target = LoadRenderTextureDepthTex(screenWidth, screenHeight); @@ -80,15 +80,14 @@ int main(void) .target = (Vector3){ 0.0f, 0.5f, 0.0f }, // Camera looking at point .up = (Vector3){ 0.0f, 1.0f, 0.0f }, // Camera up vector (rotation towards target) .fovy = 45.0f, // Camera field-of-view Y - .projection = CAMERA_PERSPECTIVE // Camera mode type + .projection = CAMERA_PERSPECTIVE // Camera projection type }; // Camera FOV is pre-calculated in the camera Distance. double camDist = 1.0/(tan(camera.fovy*0.5*DEG2RAD)); - - SetCameraMode(camera, CAMERA_FIRST_PERSON); - SetTargetFPS(60); + DisableCursor(); // Limit cursor to relative movement inside the window + SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- // Main game loop @@ -96,33 +95,31 @@ int main(void) { // Update //---------------------------------------------------------------------------------- - UpdateCamera(&camera); + UpdateCamera(&camera, CAMERA_ORBITAL); - //Update Camera Postion in the ray march shader. - SetShaderValue(raymarch_shader, march_locs.camPos, &(camera.position), RL_SHADER_UNIFORM_VEC3); + // Update Camera Postion in the ray march shader. + SetShaderValue(shdrRaymarch, marchLocs.camPos, &(camera.position), RL_SHADER_UNIFORM_VEC3); - { // Update Camera Looking Vector. Vector length determines FOV. - Vector3 camDir = Vector3Scale( Vector3Normalize( Vector3Subtract(camera.target, camera.position)) , camDist); - SetShaderValue(raymarch_shader, march_locs.camDir, &(camDir), RL_SHADER_UNIFORM_VEC3); - } + // Update Camera Looking Vector. Vector length determines FOV. + Vector3 camDir = Vector3Scale( Vector3Normalize( Vector3Subtract(camera.target, camera.position)) , camDist); + SetShaderValue(shdrRaymarch, marchLocs.camDir, &(camDir), RL_SHADER_UNIFORM_VEC3); //---------------------------------------------------------------------------------- // Draw //---------------------------------------------------------------------------------- - // Draw into our custom render texture (framebuffer) BeginTextureMode(target); ClearBackground(WHITE); // Raymarch Scene rlEnableDepthTest(); //Manually enable Depth Test to handle multiple rendering methods. - BeginShaderMode(raymarch_shader); + BeginShaderMode(shdrRaymarch); DrawRectangleRec((Rectangle){0,0,screenWidth,screenHeight},WHITE); EndShaderMode(); // Raserize Scene BeginMode3D(camera); - BeginShaderMode(raster_shader); + BeginShaderMode(shdrRaster); DrawCubeWiresV((Vector3){ 0.0f, 0.5f, 1.0f }, (Vector3){ 1.0f, 1.0f, 1.0f }, RED); DrawCubeV((Vector3){ 0.0f, 0.5f, 1.0f }, (Vector3){ 1.0f, 1.0f, 1.0f }, PURPLE); DrawCubeWiresV((Vector3){ 0.0f, 0.5f, -1.0f }, (Vector3){ 1.0f, 1.0f, 1.0f }, DARKGREEN); @@ -145,8 +142,8 @@ int main(void) // De-Initialization //-------------------------------------------------------------------------------------- UnloadRenderTextureDepthTex(target); - UnloadShader(raymarch_shader); - UnloadShader(raster_shader); + UnloadShader(shdrRaymarch); + UnloadShader(shdrRaster); CloseWindow(); // Close window and OpenGL context //-------------------------------------------------------------------------------------- diff --git a/projects/VS2022/examples/shaders_hybrid_render.vcxproj b/projects/VS2022/examples/shaders_hybrid_render.vcxproj new file mode 100644 index 000000000000..ba8cdc58b62e --- /dev/null +++ b/projects/VS2022/examples/shaders_hybrid_render.vcxproj @@ -0,0 +1,387 @@ + + + + + Debug.DLL + Win32 + + + Debug.DLL + x64 + + + Debug + Win32 + + + Debug + x64 + + + Release.DLL + Win32 + + + Release.DLL + x64 + + + Release + Win32 + + + Release + x64 + + + + {3755E9F4-CB48-4EC3-B561-3B85964EBDEF} + Win32Proj + shaders_hybrid_render + 10.0 + shaders_hybrid_render + + + + 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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)\ + + + $(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) + + + 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)\ + + + 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 153628063d33..06166cdd0240 100644 --- a/projects/VS2022/raylib.sln +++ b/projects/VS2022/raylib.sln @@ -269,6 +269,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "models_loading_m3d", "examp EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shaders_write_depth", "examples\shaders_write_depth.vcxproj", "{70B35F59-AFC2-4D8F-8833-5314D2047A81}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shaders_hybrid_render", "examples\shaders_hybrid_render.vcxproj", "{3755E9F4-CB48-4EC3-B561-3B85964EBDEF}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug.DLL|x64 = Debug.DLL|x64 @@ -2261,6 +2263,22 @@ Global {70B35F59-AFC2-4D8F-8833-5314D2047A81}.Release|x64.Build.0 = Release|x64 {70B35F59-AFC2-4D8F-8833-5314D2047A81}.Release|x86.ActiveCfg = Release|Win32 {70B35F59-AFC2-4D8F-8833-5314D2047A81}.Release|x86.Build.0 = Release|Win32 + {3755E9F4-CB48-4EC3-B561-3B85964EBDEF}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {3755E9F4-CB48-4EC3-B561-3B85964EBDEF}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {3755E9F4-CB48-4EC3-B561-3B85964EBDEF}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {3755E9F4-CB48-4EC3-B561-3B85964EBDEF}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {3755E9F4-CB48-4EC3-B561-3B85964EBDEF}.Debug|x64.ActiveCfg = Debug|x64 + {3755E9F4-CB48-4EC3-B561-3B85964EBDEF}.Debug|x64.Build.0 = Debug|x64 + {3755E9F4-CB48-4EC3-B561-3B85964EBDEF}.Debug|x86.ActiveCfg = Debug|Win32 + {3755E9F4-CB48-4EC3-B561-3B85964EBDEF}.Debug|x86.Build.0 = Debug|Win32 + {3755E9F4-CB48-4EC3-B561-3B85964EBDEF}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {3755E9F4-CB48-4EC3-B561-3B85964EBDEF}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {3755E9F4-CB48-4EC3-B561-3B85964EBDEF}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {3755E9F4-CB48-4EC3-B561-3B85964EBDEF}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {3755E9F4-CB48-4EC3-B561-3B85964EBDEF}.Release|x64.ActiveCfg = Release|x64 + {3755E9F4-CB48-4EC3-B561-3B85964EBDEF}.Release|x64.Build.0 = Release|x64 + {3755E9F4-CB48-4EC3-B561-3B85964EBDEF}.Release|x86.ActiveCfg = Release|Win32 + {3755E9F4-CB48-4EC3-B561-3B85964EBDEF}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -2397,6 +2415,7 @@ Global {769FF0C1-4424-4FA3-BC44-D7A7DA312A06} = {DA049009-21FF-4AC0-84E4-830DD1BCD0CE} {6D9E00D8-2893-45E4-9363-3F7F61D416BD} = {AF5BEC5C-1F2B-4DA8-B12D-D09FE569237C} {70B35F59-AFC2-4D8F-8833-5314D2047A81} = {5317807F-61D4-4E0F-B6DC-2D9F12621ED9} + {3755E9F4-CB48-4EC3-B561-3B85964EBDEF} = {5317807F-61D4-4E0F-B6DC-2D9F12621ED9} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {E926C768-6307-4423-A1EC-57E95B1FAB29} From ec95aa2e04e5c4df49dbe25a64e9239db66d0fc2 Mon Sep 17 00:00:00 2001 From: veins1 <19636663+veins1@users.noreply.github.com> Date: Wed, 15 Feb 2023 02:29:32 +0500 Subject: [PATCH 105/192] Move camera after rotation (#2923) Moving camera after rotation is set to avoid 1 frame delay in movement direction --- src/rcamera.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/rcamera.h b/src/rcamera.h index 7770071e8fb9..8184e625cb66 100644 --- a/src/rcamera.h +++ b/src/rcamera.h @@ -418,14 +418,6 @@ void UpdateCamera(Camera *camera, int mode) bool rotateAroundTarget = mode == CAMERA_THIRD_PERSON || mode == CAMERA_ORBITAL; bool lockView = mode == CAMERA_FIRST_PERSON || mode == CAMERA_THIRD_PERSON || mode == CAMERA_ORBITAL; bool rotateUp = mode == CAMERA_FREE; - - // Camera movement - if (IsKeyDown(KEY_W)) CameraMoveForward(camera, CAMERA_MOVE_SPEED, moveInWorldPlane); - if (IsKeyDown(KEY_A)) CameraMoveRight(camera, -CAMERA_MOVE_SPEED, moveInWorldPlane); - if (IsKeyDown(KEY_S)) CameraMoveForward(camera, -CAMERA_MOVE_SPEED, moveInWorldPlane); - if (IsKeyDown(KEY_D)) CameraMoveRight(camera, CAMERA_MOVE_SPEED, moveInWorldPlane); - //if (IsKeyDown(KEY_SPACE)) CameraMoveUp(camera, CAMERA_MOVE_SPEED); - //if (IsKeyDown(KEY_LEFT_CONTROL)) CameraMoveUp(camera, -CAMERA_MOVE_SPEED); // Camera rotation if (IsKeyDown(KEY_DOWN)) CameraPitch(camera, -CAMERA_ROTATION_SPEED, lockView, rotateAroundTarget, rotateUp); @@ -438,6 +430,14 @@ void UpdateCamera(Camera *camera, int mode) CameraYaw(camera, -mousePositionDelta.x*CAMERA_MOUSE_MOVE_SENSITIVITY, rotateAroundTarget); CameraPitch(camera, -mousePositionDelta.y*CAMERA_MOUSE_MOVE_SENSITIVITY, lockView, rotateAroundTarget, rotateUp); + // Camera movement + if (IsKeyDown(KEY_W)) CameraMoveForward(camera, CAMERA_MOVE_SPEED, moveInWorldPlane); + if (IsKeyDown(KEY_A)) CameraMoveRight(camera, -CAMERA_MOVE_SPEED, moveInWorldPlane); + if (IsKeyDown(KEY_S)) CameraMoveForward(camera, -CAMERA_MOVE_SPEED, moveInWorldPlane); + if (IsKeyDown(KEY_D)) CameraMoveRight(camera, CAMERA_MOVE_SPEED, moveInWorldPlane); + //if (IsKeyDown(KEY_SPACE)) CameraMoveUp(camera, CAMERA_MOVE_SPEED); + //if (IsKeyDown(KEY_LEFT_CONTROL)) CameraMoveUp(camera, -CAMERA_MOVE_SPEED); + // Zoom target distance CameraMoveToTarget(camera, -GetMouseWheelMove()); if (IsKeyPressed(KEY_KP_SUBTRACT)) CameraMoveToTarget(camera, 2.0f); From 5dedb27ce01fc649b4b81b582418b31f4435da98 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 14 Feb 2023 22:51:34 +0100 Subject: [PATCH 106/192] REVIEWED: Issue with camera jump on first frame --- src/rcore.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/rcore.c b/src/rcore.c index f81d23186e53..d47aaab079f1 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -2017,6 +2017,8 @@ void EnableCursor(void) #if defined(PLATFORM_WEB) emscripten_exit_pointerlock(); #endif + // Set cursor position in the middle + SetMousePosition(CORE.Window.screen.width/2, CORE.Window.screen.height/2); CORE.Input.Mouse.cursorHidden = false; } @@ -2026,17 +2028,12 @@ void DisableCursor(void) { #if defined(PLATFORM_DESKTOP) glfwSetInputMode(CORE.Window.handle, GLFW_CURSOR, GLFW_CURSOR_DISABLED); - - // Set cursor position in the middle of screen and update delta accordingly - SetMousePosition(CORE.Window.screen.width/2, CORE.Window.screen.height/2); - CORE.Input.Mouse.currentPosition.x = CORE.Window.screen.width/2; - CORE.Input.Mouse.currentPosition.y = CORE.Window.screen.width/2; - CORE.Input.Mouse.previousPosition.x = CORE.Input.Mouse.currentPosition.x; - CORE.Input.Mouse.previousPosition.y = CORE.Input.Mouse.currentPosition.y; #endif #if defined(PLATFORM_WEB) emscripten_request_pointerlock("#canvas", 1); #endif + // Set cursor position in the middle + SetMousePosition(CORE.Window.screen.width/2, CORE.Window.screen.height/2); CORE.Input.Mouse.cursorHidden = true; } @@ -3809,6 +3806,8 @@ Vector2 GetMouseDelta(void) void SetMousePosition(int x, int y) { CORE.Input.Mouse.currentPosition = (Vector2){ (float)x, (float)y }; + CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition; + #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) // NOTE: emscripten not implemented glfwSetCursorPos(CORE.Window.handle, CORE.Input.Mouse.currentPosition.x, CORE.Input.Mouse.currentPosition.y); From 903d85e3233c9a8b1908bc2b9322e1251d100bbe Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 15 Feb 2023 12:53:41 +0100 Subject: [PATCH 107/192] Make sure window position always inits in the middle of the current monitor --- src/rcore.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/rcore.c b/src/rcore.c index d47aaab079f1..0c4691eba2bd 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -849,6 +849,7 @@ void InitWindow(int width, int height, const char *title) TRACELOG(LOG_FATAL, "Failed to initialize Graphic Device"); return; } + else SetWindowPosition(GetMonitorWidth(GetCurrentMonitor())/2 - CORE.Window.screen.width/2, GetMonitorHeight(GetCurrentMonitor())/2 - CORE.Window.screen.height/2); // Initialize hi-res timer InitTimer(); @@ -923,10 +924,7 @@ void InitWindow(int width, int height, const char *title) emscripten_set_gamepaddisconnected_callback(NULL, 1, EmscriptenGamepadCallback); #endif - CORE.Input.Mouse.currentPosition.x = (float)CORE.Window.screen.width/2.0f; - CORE.Input.Mouse.currentPosition.y = (float)CORE.Window.screen.height/2.0f; - - SetMousePosition((int)CORE.Input.Mouse.currentPosition.x, (int)CORE.Input.Mouse.currentPosition.x); + SetMousePosition(CORE.Window.screen.width/2, CORE.Window.screen.height/2); #if defined(SUPPORT_EVENTS_AUTOMATION) events = (AutomationEvent *)malloc(MAX_CODE_AUTOMATION_EVENTS*sizeof(AutomationEvent)); From beb44f1dacce8aef0df3740e341582ca79e040e1 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 15 Feb 2023 13:11:26 +0100 Subject: [PATCH 108/192] Avoid centering mouse when program launches --- src/rcore.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/rcore.c b/src/rcore.c index 0c4691eba2bd..3de0f3f3cc56 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -924,8 +924,6 @@ void InitWindow(int width, int height, const char *title) emscripten_set_gamepaddisconnected_callback(NULL, 1, EmscriptenGamepadCallback); #endif - SetMousePosition(CORE.Window.screen.width/2, CORE.Window.screen.height/2); - #if defined(SUPPORT_EVENTS_AUTOMATION) events = (AutomationEvent *)malloc(MAX_CODE_AUTOMATION_EVENTS*sizeof(AutomationEvent)); CORE.Time.frameCounter = 0; From 9eaed07b77bd6c9004175c9a641a573671cadb29 Mon Sep 17 00:00:00 2001 From: Jeffery Myers Date: Wed, 15 Feb 2023 08:17:00 -0800 Subject: [PATCH 109/192] Make the oribital camera work like it used to (it is not just a copy of third person) (#2926) --- examples/models/models_billboard.c | 2 - examples/models/models_cubicmap.c | 2 - examples/models/models_heightmap.c | 2 - examples/models/models_loading_vox.c | 2 - examples/models/models_mesh_generation.c | 2 - examples/models/models_rlgl_solar_system.c | 2 - examples/shaders/shaders_basic_lighting.c | 1 - examples/shaders/shaders_fog.c | 1 - examples/shaders/shaders_hybrid_render.c | 1 - examples/shaders/shaders_mesh_instancing.c | 1 - examples/shaders/shaders_postprocessing.c | 1 - examples/shaders/shaders_write_depth.c | 1 - src/rcamera.h | 62 +++++++++++++--------- 13 files changed, 38 insertions(+), 42 deletions(-) diff --git a/examples/models/models_billboard.c b/examples/models/models_billboard.c index 596a09d3bc0d..9b02a8af1f5f 100644 --- a/examples/models/models_billboard.c +++ b/examples/models/models_billboard.c @@ -55,8 +55,6 @@ int main(void) float distanceRotating; float rotation = 0.0f; - DisableCursor(); // Limit cursor to relative movement inside the window - SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- diff --git a/examples/models/models_cubicmap.c b/examples/models/models_cubicmap.c index 714918e41cbf..e0a2b3089b84 100644 --- a/examples/models/models_cubicmap.c +++ b/examples/models/models_cubicmap.c @@ -47,8 +47,6 @@ int main(void) UnloadImage(image); // Unload cubesmap image from RAM, already uploaded to VRAM - DisableCursor(); // Limit cursor to relative movement inside the window - SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- diff --git a/examples/models/models_heightmap.c b/examples/models/models_heightmap.c index 8f32de9febe9..e1c3e4fb6b9e 100644 --- a/examples/models/models_heightmap.c +++ b/examples/models/models_heightmap.c @@ -44,8 +44,6 @@ int main(void) UnloadImage(image); // Unload heightmap image from RAM, already uploaded to VRAM - DisableCursor(); // Limit cursor to relative movement inside the window - SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- diff --git a/examples/models/models_loading_vox.c b/examples/models/models_loading_vox.c index d17fd6ee61a9..e148fd91acd7 100644 --- a/examples/models/models_loading_vox.c +++ b/examples/models/models_loading_vox.c @@ -69,8 +69,6 @@ int main(void) int currentModel = 0; - DisableCursor(); // Limit cursor to relative movement inside the window - SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- diff --git a/examples/models/models_mesh_generation.c b/examples/models/models_mesh_generation.c index 6189fb46d8ef..d17a20a12d05 100644 --- a/examples/models/models_mesh_generation.c +++ b/examples/models/models_mesh_generation.c @@ -68,8 +68,6 @@ int main(void) int currentModel = 0; - DisableCursor(); // Limit cursor to relative movement inside the window - SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- diff --git a/examples/models/models_rlgl_solar_system.c b/examples/models/models_rlgl_solar_system.c index fc2a1f02099a..e458036fe992 100644 --- a/examples/models/models_rlgl_solar_system.c +++ b/examples/models/models_rlgl_solar_system.c @@ -56,8 +56,6 @@ int main(void) float moonRotation = 0.0f; // Rotation of moon around itself float moonOrbitRotation = 0.0f; // Rotation of moon around earth in degrees - DisableCursor(); // Limit cursor to relative movement inside the window - SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- diff --git a/examples/shaders/shaders_basic_lighting.c b/examples/shaders/shaders_basic_lighting.c index 49dc1e7d4b8a..61cec2e808ec 100644 --- a/examples/shaders/shaders_basic_lighting.c +++ b/examples/shaders/shaders_basic_lighting.c @@ -80,7 +80,6 @@ int main(void) lights[2] = CreateLight(LIGHT_POINT, (Vector3){ -2, 1, 2 }, Vector3Zero(), GREEN, shader); lights[3] = CreateLight(LIGHT_POINT, (Vector3){ 2, 1, -2 }, Vector3Zero(), BLUE, shader); - DisableCursor(); // Limit cursor to relative movement inside the window SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- diff --git a/examples/shaders/shaders_fog.c b/examples/shaders/shaders_fog.c index ddd721d46528..24a1c106835a 100644 --- a/examples/shaders/shaders_fog.c +++ b/examples/shaders/shaders_fog.c @@ -85,7 +85,6 @@ int main(void) // Using just 1 point lights CreateLight(LIGHT_POINT, (Vector3){ 0, 2, 6 }, Vector3Zero(), WHITE, shader); - DisableCursor(); // Limit cursor to relative movement inside the window SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- diff --git a/examples/shaders/shaders_hybrid_render.c b/examples/shaders/shaders_hybrid_render.c index 0f30680c8ead..f07917fb08cf 100644 --- a/examples/shaders/shaders_hybrid_render.c +++ b/examples/shaders/shaders_hybrid_render.c @@ -86,7 +86,6 @@ int main(void) // Camera FOV is pre-calculated in the camera Distance. double camDist = 1.0/(tan(camera.fovy*0.5*DEG2RAD)); - DisableCursor(); // Limit cursor to relative movement inside the window SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- diff --git a/examples/shaders/shaders_mesh_instancing.c b/examples/shaders/shaders_mesh_instancing.c index 02a7ee8f00a7..7789f2cb0ff2 100644 --- a/examples/shaders/shaders_mesh_instancing.c +++ b/examples/shaders/shaders_mesh_instancing.c @@ -94,7 +94,6 @@ int main(void) Material matDefault = LoadMaterialDefault(); matDefault.maps[MATERIAL_MAP_DIFFUSE].color = BLUE; - DisableCursor(); // Limit cursor to relative movement inside the window SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- diff --git a/examples/shaders/shaders_postprocessing.c b/examples/shaders/shaders_postprocessing.c index 991e9839bcf2..7f6bd00920a1 100644 --- a/examples/shaders/shaders_postprocessing.c +++ b/examples/shaders/shaders_postprocessing.c @@ -112,7 +112,6 @@ int main(void) // Create a RenderTexture2D to be used for render to texture RenderTexture2D target = LoadRenderTexture(screenWidth, screenHeight); - DisableCursor(); // Limit cursor to relative movement inside the window SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- diff --git a/examples/shaders/shaders_write_depth.c b/examples/shaders/shaders_write_depth.c index b7f69ddbf6e9..048e297ad28b 100644 --- a/examples/shaders/shaders_write_depth.c +++ b/examples/shaders/shaders_write_depth.c @@ -59,7 +59,6 @@ int main(void) .projection = CAMERA_PERSPECTIVE // Camera projection type }; - DisableCursor(); // Limit cursor to relative movement inside the window SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- diff --git a/src/rcamera.h b/src/rcamera.h index 8184e625cb66..c0c28209da50 100644 --- a/src/rcamera.h +++ b/src/rcamera.h @@ -172,7 +172,7 @@ Matrix GetCameraProjectionMatrix(Camera* camera, float aspect); #define CAMERA_MOUSE_MOVE_SENSITIVITY 0.003f // TODO: it should be independant of framerate #define CAMERA_MOUSE_SCROLL_SENSITIVITY 1.5f -#define CAMERA_ORBITAL_SPEED 0.01f // Radians per frame +#define CAMERA_ORBITAL_SPEED 0.5f // Radians per second #define CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER 8.0f @@ -418,30 +418,44 @@ void UpdateCamera(Camera *camera, int mode) bool rotateAroundTarget = mode == CAMERA_THIRD_PERSON || mode == CAMERA_ORBITAL; bool lockView = mode == CAMERA_FIRST_PERSON || mode == CAMERA_THIRD_PERSON || mode == CAMERA_ORBITAL; bool rotateUp = mode == CAMERA_FREE; - - // Camera rotation - if (IsKeyDown(KEY_DOWN)) CameraPitch(camera, -CAMERA_ROTATION_SPEED, lockView, rotateAroundTarget, rotateUp); - if (IsKeyDown(KEY_UP)) CameraPitch(camera, CAMERA_ROTATION_SPEED, lockView, rotateAroundTarget, rotateUp); - if (IsKeyDown(KEY_RIGHT)) CameraYaw(camera, -CAMERA_ROTATION_SPEED, rotateAroundTarget); - if (IsKeyDown(KEY_LEFT)) CameraYaw(camera, CAMERA_ROTATION_SPEED, rotateAroundTarget); - if (IsKeyDown(KEY_Q)) CameraRoll(camera, -CAMERA_ROTATION_SPEED); - if (IsKeyDown(KEY_E)) CameraRoll(camera, CAMERA_ROTATION_SPEED); - - CameraYaw(camera, -mousePositionDelta.x*CAMERA_MOUSE_MOVE_SENSITIVITY, rotateAroundTarget); - CameraPitch(camera, -mousePositionDelta.y*CAMERA_MOUSE_MOVE_SENSITIVITY, lockView, rotateAroundTarget, rotateUp); - - // Camera movement - if (IsKeyDown(KEY_W)) CameraMoveForward(camera, CAMERA_MOVE_SPEED, moveInWorldPlane); - if (IsKeyDown(KEY_A)) CameraMoveRight(camera, -CAMERA_MOVE_SPEED, moveInWorldPlane); - if (IsKeyDown(KEY_S)) CameraMoveForward(camera, -CAMERA_MOVE_SPEED, moveInWorldPlane); - if (IsKeyDown(KEY_D)) CameraMoveRight(camera, CAMERA_MOVE_SPEED, moveInWorldPlane); - //if (IsKeyDown(KEY_SPACE)) CameraMoveUp(camera, CAMERA_MOVE_SPEED); - //if (IsKeyDown(KEY_LEFT_CONTROL)) CameraMoveUp(camera, -CAMERA_MOVE_SPEED); - // Zoom target distance - CameraMoveToTarget(camera, -GetMouseWheelMove()); - if (IsKeyPressed(KEY_KP_SUBTRACT)) CameraMoveToTarget(camera, 2.0f); - if (IsKeyPressed(KEY_KP_ADD)) CameraMoveToTarget(camera, -2.0f); + if (mode == CAMERA_ORBITAL) + { + // Obital can just orbit + Matrix rotatation = MatrixRotate(GetCameraUp(camera), CAMERA_ORBITAL_SPEED * GetFrameTime()); + Vector3 viewVector = Vector3Subtract(camera->position, camera->target); + viewVector = Vector3Transform(viewVector, rotatation); + camera->position = Vector3Add(camera->target, viewVector); + } + else + { + // Camera rotation + if (IsKeyDown(KEY_DOWN)) CameraPitch(camera, -CAMERA_ROTATION_SPEED, lockView, rotateAroundTarget, rotateUp); + if (IsKeyDown(KEY_UP)) CameraPitch(camera, CAMERA_ROTATION_SPEED, lockView, rotateAroundTarget, rotateUp); + if (IsKeyDown(KEY_RIGHT)) CameraYaw(camera, -CAMERA_ROTATION_SPEED, rotateAroundTarget); + if (IsKeyDown(KEY_LEFT)) CameraYaw(camera, CAMERA_ROTATION_SPEED, rotateAroundTarget); + if (IsKeyDown(KEY_Q)) CameraRoll(camera, -CAMERA_ROTATION_SPEED); + if (IsKeyDown(KEY_E)) CameraRoll(camera, CAMERA_ROTATION_SPEED); + + CameraYaw(camera, -mousePositionDelta.x * CAMERA_MOUSE_MOVE_SENSITIVITY, rotateAroundTarget); + CameraPitch(camera, -mousePositionDelta.y * CAMERA_MOUSE_MOVE_SENSITIVITY, lockView, rotateAroundTarget, rotateUp); + + // Camera movement + if (IsKeyDown(KEY_W)) CameraMoveForward(camera, CAMERA_MOVE_SPEED, moveInWorldPlane); + if (IsKeyDown(KEY_A)) CameraMoveRight(camera, -CAMERA_MOVE_SPEED, moveInWorldPlane); + if (IsKeyDown(KEY_S)) CameraMoveForward(camera, -CAMERA_MOVE_SPEED, moveInWorldPlane); + if (IsKeyDown(KEY_D)) CameraMoveRight(camera, CAMERA_MOVE_SPEED, moveInWorldPlane); + //if (IsKeyDown(KEY_SPACE)) CameraMoveUp(camera, CAMERA_MOVE_SPEED); + //if (IsKeyDown(KEY_LEFT_CONTROL)) CameraMoveUp(camera, -CAMERA_MOVE_SPEED); + } + + if (mode == CAMERA_THIRD_PERSON || mode == CAMERA_ORBITAL) + { + // Zoom target distance + CameraMoveToTarget(camera, -GetMouseWheelMove()); + if (IsKeyPressed(KEY_KP_SUBTRACT)) CameraMoveToTarget(camera, 2.0f); + if (IsKeyPressed(KEY_KP_ADD)) CameraMoveToTarget(camera, -2.0f); + } } #endif // !CAMERA_STANDALONE From 2766835ed432a2ad575635ce338aa1389078cb12 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 15 Feb 2023 17:36:31 +0100 Subject: [PATCH 110/192] REPLACE: TABS by 4 spaces --- examples/textures/textures_textured_curve.c | 222 ++++++++++---------- parser/raylib_parser.c | 4 +- src/rcamera.h | 41 ++-- 3 files changed, 134 insertions(+), 133 deletions(-) diff --git a/examples/textures/textures_textured_curve.c b/examples/textures/textures_textured_curve.c index 201b01fecfb6..7945d8e32cbe 100644 --- a/examples/textures/textures_textured_curve.c +++ b/examples/textures/textures_textured_curve.c @@ -59,19 +59,19 @@ int main() const int screenWidth = 800; const int screenHeight = 450; - SetConfigFlags(FLAG_VSYNC_HINT | FLAG_MSAA_4X_HINT); - InitWindow(screenWidth, screenHeight, "raylib [textures] examples - textured curve"); + SetConfigFlags(FLAG_VSYNC_HINT | FLAG_MSAA_4X_HINT); + InitWindow(screenWidth, screenHeight, "raylib [textures] examples - textured curve"); - // Load the road texture - texRoad = LoadTexture("resources/road.png"); + // Load the road texture + texRoad = LoadTexture("resources/road.png"); SetTextureFilter(texRoad, TEXTURE_FILTER_BILINEAR); - // Setup the curve - curveStartPosition = (Vector2){ 80, 100 }; - curveStartPositionTangent = (Vector2){ 100, 300 }; + // Setup the curve + curveStartPosition = (Vector2){ 80, 100 }; + curveStartPositionTangent = (Vector2){ 100, 300 }; - curveEndPosition = (Vector2){ 700, 350 }; - curveEndPositionTangent = (Vector2){ 600, 100 }; + curveEndPosition = (Vector2){ 700, 350 }; + curveEndPositionTangent = (Vector2){ 600, 100 }; SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- @@ -81,8 +81,8 @@ int main() { // Update //---------------------------------------------------------------------------------- - UpdateCurve(); - UpdateOptions(); + UpdateCurve(); + UpdateOptions(); //---------------------------------------------------------------------------------- @@ -99,13 +99,13 @@ int main() DrawText(TextFormat("Curve width: %2.0f (Use + and - to adjust)", curveWidth), 10, 30, 10, DARKGRAY); DrawText(TextFormat("Curve segments: %d (Use LEFT and RIGHT to adjust)", curveSegments), 10, 50, 10, DARKGRAY); - EndDrawing(); + EndDrawing(); //---------------------------------------------------------------------------------- } // De-Initialization //-------------------------------------------------------------------------------------- - UnloadTexture(texRoad); + UnloadTexture(texRoad); CloseWindow(); // Close window and OpenGL context //-------------------------------------------------------------------------------------- @@ -118,142 +118,142 @@ int main() //---------------------------------------------------------------------------------- static void DrawCurve(void) { - if (showCurve) DrawLineBezierCubic(curveStartPosition, curveEndPosition, curveStartPositionTangent, curveEndPositionTangent, 2, BLUE); + if (showCurve) DrawLineBezierCubic(curveStartPosition, curveEndPosition, curveStartPositionTangent, curveEndPositionTangent, 2, BLUE); - // Draw the various control points and highlight where the mouse is - DrawLineV(curveStartPosition, curveStartPositionTangent, SKYBLUE); - DrawLineV(curveEndPosition, curveEndPositionTangent, PURPLE); - Vector2 mouse = GetMousePosition(); + // Draw the various control points and highlight where the mouse is + DrawLineV(curveStartPosition, curveStartPositionTangent, SKYBLUE); + DrawLineV(curveEndPosition, curveEndPositionTangent, PURPLE); + Vector2 mouse = GetMousePosition(); - if (CheckCollisionPointCircle(mouse, curveStartPosition, 6)) DrawCircleV(curveStartPosition, 7, YELLOW); - DrawCircleV(curveStartPosition, 5, RED); + if (CheckCollisionPointCircle(mouse, curveStartPosition, 6)) DrawCircleV(curveStartPosition, 7, YELLOW); + DrawCircleV(curveStartPosition, 5, RED); - if (CheckCollisionPointCircle(mouse, curveStartPositionTangent, 6)) DrawCircleV(curveStartPositionTangent, 7, YELLOW); - DrawCircleV(curveStartPositionTangent, 5, MAROON); + if (CheckCollisionPointCircle(mouse, curveStartPositionTangent, 6)) DrawCircleV(curveStartPositionTangent, 7, YELLOW); + DrawCircleV(curveStartPositionTangent, 5, MAROON); - if (CheckCollisionPointCircle(mouse, curveEndPosition, 6)) DrawCircleV(curveEndPosition, 7, YELLOW); - DrawCircleV(curveEndPosition, 5, GREEN); + if (CheckCollisionPointCircle(mouse, curveEndPosition, 6)) DrawCircleV(curveEndPosition, 7, YELLOW); + DrawCircleV(curveEndPosition, 5, GREEN); - if (CheckCollisionPointCircle(mouse, curveEndPositionTangent, 6)) DrawCircleV(curveEndPositionTangent, 7, YELLOW); - DrawCircleV(curveEndPositionTangent, 5, DARKGREEN); + if (CheckCollisionPointCircle(mouse, curveEndPositionTangent, 6)) DrawCircleV(curveEndPositionTangent, 7, YELLOW); + DrawCircleV(curveEndPositionTangent, 5, DARKGREEN); } static void UpdateCurve(void) { - // If the mouse is not down, we are not editing the curve so clear the selection - if (!IsMouseButtonDown(MOUSE_LEFT_BUTTON)) - { - curveSelectedPoint = NULL; - return; - } - - // If a point was selected, move it - if (curveSelectedPoint) - { - *curveSelectedPoint = Vector2Add(*curveSelectedPoint, GetMouseDelta()); - return; - } - - // The mouse is down, and nothing was selected, so see if anything was picked - Vector2 mouse = GetMousePosition(); - - if (CheckCollisionPointCircle(mouse, curveStartPosition, 6)) curveSelectedPoint = &curveStartPosition; - else if (CheckCollisionPointCircle(mouse, curveStartPositionTangent, 6)) curveSelectedPoint = &curveStartPositionTangent; - else if (CheckCollisionPointCircle(mouse, curveEndPosition, 6)) curveSelectedPoint = &curveEndPosition; - else if (CheckCollisionPointCircle(mouse, curveEndPositionTangent, 6)) curveSelectedPoint = &curveEndPositionTangent; + // If the mouse is not down, we are not editing the curve so clear the selection + if (!IsMouseButtonDown(MOUSE_LEFT_BUTTON)) + { + curveSelectedPoint = NULL; + return; + } + + // If a point was selected, move it + if (curveSelectedPoint) + { + *curveSelectedPoint = Vector2Add(*curveSelectedPoint, GetMouseDelta()); + return; + } + + // The mouse is down, and nothing was selected, so see if anything was picked + Vector2 mouse = GetMousePosition(); + + if (CheckCollisionPointCircle(mouse, curveStartPosition, 6)) curveSelectedPoint = &curveStartPosition; + else if (CheckCollisionPointCircle(mouse, curveStartPositionTangent, 6)) curveSelectedPoint = &curveStartPositionTangent; + else if (CheckCollisionPointCircle(mouse, curveEndPosition, 6)) curveSelectedPoint = &curveEndPosition; + else if (CheckCollisionPointCircle(mouse, curveEndPositionTangent, 6)) curveSelectedPoint = &curveEndPositionTangent; } static void DrawTexturedCurve(void) { - const float step = 1.0f/curveSegments; + const float step = 1.0f/curveSegments; - Vector2 previous = curveStartPosition; - Vector2 previousTangent = { 0 }; - float previousV = 0; + Vector2 previous = curveStartPosition; + Vector2 previousTangent = { 0 }; + float previousV = 0; - // We can't compute a tangent for the first point, so we need to reuse the tangent from the first segment - bool tangentSet = false; + // We can't compute a tangent for the first point, so we need to reuse the tangent from the first segment + bool tangentSet = false; - Vector2 current = { 0 }; - float t = 0.0f; + Vector2 current = { 0 }; + float t = 0.0f; - for (int i = 1; i <= curveSegments; i++) - { - // Segment the curve - t = step*i; - float a = powf(1 - t, 3); - float b = 3*powf(1 - t, 2)*t; - float c = 3*(1 - t)*powf(t, 2); - float d = powf(t, 3); + for (int i = 1; i <= curveSegments; i++) + { + // Segment the curve + t = step*i; + float a = powf(1 - t, 3); + float b = 3*powf(1 - t, 2)*t; + float c = 3*(1 - t)*powf(t, 2); + float d = powf(t, 3); - // Compute the endpoint for this segment - current.y = a*curveStartPosition.y + b*curveStartPositionTangent.y + c*curveEndPositionTangent.y + d*curveEndPosition.y; - current.x = a*curveStartPosition.x + b*curveStartPositionTangent.x + c*curveEndPositionTangent.x + d*curveEndPosition.x; + // Compute the endpoint for this segment + current.y = a*curveStartPosition.y + b*curveStartPositionTangent.y + c*curveEndPositionTangent.y + d*curveEndPosition.y; + current.x = a*curveStartPosition.x + b*curveStartPositionTangent.x + c*curveEndPositionTangent.x + d*curveEndPosition.x; - // Vector from previous to current - Vector2 delta = { current.x - previous.x, current.y - previous.y }; + // Vector from previous to current + Vector2 delta = { current.x - previous.x, current.y - previous.y }; - // The right hand normal to the delta vector - Vector2 normal = Vector2Normalize((Vector2){ -delta.y, delta.x }); + // The right hand normal to the delta vector + Vector2 normal = Vector2Normalize((Vector2){ -delta.y, delta.x }); - // The v texture coordinate of the segment (add up the length of all the segments so far) - float v = previousV + Vector2Length(delta); + // The v texture coordinate of the segment (add up the length of all the segments so far) + float v = previousV + Vector2Length(delta); - // Make sure the start point has a normal - if (!tangentSet) - { - previousTangent = normal; - tangentSet = true; - } + // Make sure the start point has a normal + if (!tangentSet) + { + previousTangent = normal; + tangentSet = true; + } - // Extend out the normals from the previous and current points to get the quad for this segment - Vector2 prevPosNormal = Vector2Add(previous, Vector2Scale(previousTangent, curveWidth)); - Vector2 prevNegNormal = Vector2Add(previous, Vector2Scale(previousTangent, -curveWidth)); + // Extend out the normals from the previous and current points to get the quad for this segment + Vector2 prevPosNormal = Vector2Add(previous, Vector2Scale(previousTangent, curveWidth)); + Vector2 prevNegNormal = Vector2Add(previous, Vector2Scale(previousTangent, -curveWidth)); - Vector2 currentPosNormal = Vector2Add(current, Vector2Scale(normal, curveWidth)); - Vector2 currentNegNormal = Vector2Add(current, Vector2Scale(normal, -curveWidth)); + Vector2 currentPosNormal = Vector2Add(current, Vector2Scale(normal, curveWidth)); + Vector2 currentNegNormal = Vector2Add(current, Vector2Scale(normal, -curveWidth)); - // Draw the segment as a quad - rlSetTexture(texRoad.id); - rlBegin(RL_QUADS); + // Draw the segment as a quad + rlSetTexture(texRoad.id); + rlBegin(RL_QUADS); - rlColor4ub(255,255,255,255); - rlNormal3f(0.0f, 0.0f, 1.0f); + rlColor4ub(255,255,255,255); + rlNormal3f(0.0f, 0.0f, 1.0f); - rlTexCoord2f(0, previousV); - rlVertex2f(prevNegNormal.x, prevNegNormal.y); + rlTexCoord2f(0, previousV); + rlVertex2f(prevNegNormal.x, prevNegNormal.y); - rlTexCoord2f(1, previousV); - rlVertex2f(prevPosNormal.x, prevPosNormal.y); + rlTexCoord2f(1, previousV); + rlVertex2f(prevPosNormal.x, prevPosNormal.y); - rlTexCoord2f(1, v); - rlVertex2f(currentPosNormal.x, currentPosNormal.y); + rlTexCoord2f(1, v); + rlVertex2f(currentPosNormal.x, currentPosNormal.y); - rlTexCoord2f(0, v); - rlVertex2f(currentNegNormal.x, currentNegNormal.y); + rlTexCoord2f(0, v); + rlVertex2f(currentNegNormal.x, currentNegNormal.y); - rlEnd(); + rlEnd(); - // The current step is the start of the next step - previous = current; - previousTangent = normal; - previousV = v; - } + // The current step is the start of the next step + previous = current; + previousTangent = normal; + previousV = v; + } } static void UpdateOptions(void) { - if (IsKeyPressed(KEY_SPACE)) showCurve = !showCurve; + if (IsKeyPressed(KEY_SPACE)) showCurve = !showCurve; - // Update with - if (IsKeyPressed(KEY_EQUAL)) curveWidth += 2; - if (IsKeyPressed(KEY_MINUS)) curveWidth -= 2; + // Update with + if (IsKeyPressed(KEY_EQUAL)) curveWidth += 2; + if (IsKeyPressed(KEY_MINUS)) curveWidth -= 2; - if (curveWidth < 2) curveWidth = 2; + if (curveWidth < 2) curveWidth = 2; - // Update segments - if (IsKeyPressed(KEY_LEFT)) curveSegments -= 2; - if (IsKeyPressed(KEY_RIGHT)) curveSegments += 2; + // Update segments + if (IsKeyPressed(KEY_LEFT)) curveSegments -= 2; + if (IsKeyPressed(KEY_RIGHT)) curveSegments += 2; - if (curveSegments < 2) curveSegments = 2; + if (curveSegments < 2) curveSegments = 2; } diff --git a/parser/raylib_parser.c b/parser/raylib_parser.c index 7bb8cf7fad86..94ff956268f1 100644 --- a/parser/raylib_parser.c +++ b/parser/raylib_parser.c @@ -209,8 +209,8 @@ int main(int argc, char* argv[]) if (buffer == NULL) { - printf("Could not read input file: %s\n", inFileName); - return 1; + printf("Could not read input file: %s\n", inFileName); + return 1; } // Preprocess buffer to get separate lines diff --git a/src/rcamera.h b/src/rcamera.h index c0c28209da50..edcd5ee30bb5 100644 --- a/src/rcamera.h +++ b/src/rcamera.h @@ -160,7 +160,7 @@ Matrix GetCameraProjectionMatrix(Camera* camera, float aspect); // MatrixOrtho() // MatrixIdentity() -// raylib input functionality required: GetMouseDelta(), GetMouseWheelMove(), IsKeyDown(), IsKeyPressed() +// raylib required functionality: GetMouseDelta(), GetMouseWheelMove(), IsKeyDown(), IsKeyPressed(), GetFrameTime() //---------------------------------------------------------------------------------- // Defines and Macros @@ -195,7 +195,7 @@ Matrix GetCameraProjectionMatrix(Camera* camera, float aspect); //---------------------------------------------------------------------------------- // Module specific Functions Declaration //---------------------------------------------------------------------------------- - +//... //---------------------------------------------------------------------------------- // Module Functions Definition @@ -218,6 +218,7 @@ Vector3 GetCameraRight(Camera *camera) { Vector3 forward = GetCameraForward(camera); Vector3 up = GetCameraUp(camera); + return Vector3CrossProduct(forward, up); } @@ -419,26 +420,26 @@ void UpdateCamera(Camera *camera, int mode) bool lockView = mode == CAMERA_FIRST_PERSON || mode == CAMERA_THIRD_PERSON || mode == CAMERA_ORBITAL; bool rotateUp = mode == CAMERA_FREE; - if (mode == CAMERA_ORBITAL) - { - // Obital can just orbit - Matrix rotatation = MatrixRotate(GetCameraUp(camera), CAMERA_ORBITAL_SPEED * GetFrameTime()); - Vector3 viewVector = Vector3Subtract(camera->position, camera->target); - viewVector = Vector3Transform(viewVector, rotatation); - camera->position = Vector3Add(camera->target, viewVector); - } + if (mode == CAMERA_ORBITAL) + { + // Orbital can just orbit + Matrix rotatation = MatrixRotate(GetCameraUp(camera), CAMERA_ORBITAL_SPEED*GetFrameTime()); + Vector3 viewVector = Vector3Subtract(camera->position, camera->target); + viewVector = Vector3Transform(viewVector, rotatation); + camera->position = Vector3Add(camera->target, viewVector); + } else { - // Camera rotation - if (IsKeyDown(KEY_DOWN)) CameraPitch(camera, -CAMERA_ROTATION_SPEED, lockView, rotateAroundTarget, rotateUp); - if (IsKeyDown(KEY_UP)) CameraPitch(camera, CAMERA_ROTATION_SPEED, lockView, rotateAroundTarget, rotateUp); - if (IsKeyDown(KEY_RIGHT)) CameraYaw(camera, -CAMERA_ROTATION_SPEED, rotateAroundTarget); - if (IsKeyDown(KEY_LEFT)) CameraYaw(camera, CAMERA_ROTATION_SPEED, rotateAroundTarget); - if (IsKeyDown(KEY_Q)) CameraRoll(camera, -CAMERA_ROTATION_SPEED); - if (IsKeyDown(KEY_E)) CameraRoll(camera, CAMERA_ROTATION_SPEED); - - CameraYaw(camera, -mousePositionDelta.x * CAMERA_MOUSE_MOVE_SENSITIVITY, rotateAroundTarget); - CameraPitch(camera, -mousePositionDelta.y * CAMERA_MOUSE_MOVE_SENSITIVITY, lockView, rotateAroundTarget, rotateUp); + // Camera rotation + if (IsKeyDown(KEY_DOWN)) CameraPitch(camera, -CAMERA_ROTATION_SPEED, lockView, rotateAroundTarget, rotateUp); + if (IsKeyDown(KEY_UP)) CameraPitch(camera, CAMERA_ROTATION_SPEED, lockView, rotateAroundTarget, rotateUp); + if (IsKeyDown(KEY_RIGHT)) CameraYaw(camera, -CAMERA_ROTATION_SPEED, rotateAroundTarget); + if (IsKeyDown(KEY_LEFT)) CameraYaw(camera, CAMERA_ROTATION_SPEED, rotateAroundTarget); + if (IsKeyDown(KEY_Q)) CameraRoll(camera, -CAMERA_ROTATION_SPEED); + if (IsKeyDown(KEY_E)) CameraRoll(camera, CAMERA_ROTATION_SPEED); + + CameraYaw(camera, -mousePositionDelta.x * CAMERA_MOUSE_MOVE_SENSITIVITY, rotateAroundTarget); + CameraPitch(camera, -mousePositionDelta.y * CAMERA_MOUSE_MOVE_SENSITIVITY, lockView, rotateAroundTarget, rotateUp); // Camera movement if (IsKeyDown(KEY_W)) CameraMoveForward(camera, CAMERA_MOVE_SPEED, moveInWorldPlane); From f594f14510984c43f38e4296d854a0c88633ad63 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 15 Feb 2023 18:01:42 +0100 Subject: [PATCH 111/192] Reviewed typo and formating --- src/rcamera.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/rcamera.h b/src/rcamera.h index edcd5ee30bb5..9aab3a3487fb 100644 --- a/src/rcamera.h +++ b/src/rcamera.h @@ -423,10 +423,10 @@ void UpdateCamera(Camera *camera, int mode) if (mode == CAMERA_ORBITAL) { // Orbital can just orbit - Matrix rotatation = MatrixRotate(GetCameraUp(camera), CAMERA_ORBITAL_SPEED*GetFrameTime()); - Vector3 viewVector = Vector3Subtract(camera->position, camera->target); - viewVector = Vector3Transform(viewVector, rotatation); - camera->position = Vector3Add(camera->target, viewVector); + Matrix rotation = MatrixRotate(GetCameraUp(camera), CAMERA_ORBITAL_SPEED*GetFrameTime()); + Vector3 view = Vector3Subtract(camera->position, camera->target); + view = Vector3Transform(view, rotation); + camera->position = Vector3Add(camera->target, view); } else { @@ -438,8 +438,8 @@ void UpdateCamera(Camera *camera, int mode) if (IsKeyDown(KEY_Q)) CameraRoll(camera, -CAMERA_ROTATION_SPEED); if (IsKeyDown(KEY_E)) CameraRoll(camera, CAMERA_ROTATION_SPEED); - CameraYaw(camera, -mousePositionDelta.x * CAMERA_MOUSE_MOVE_SENSITIVITY, rotateAroundTarget); - CameraPitch(camera, -mousePositionDelta.y * CAMERA_MOUSE_MOVE_SENSITIVITY, lockView, rotateAroundTarget, rotateUp); + CameraYaw(camera, -mousePositionDelta.x*CAMERA_MOUSE_MOVE_SENSITIVITY, rotateAroundTarget); + CameraPitch(camera, -mousePositionDelta.y*CAMERA_MOUSE_MOVE_SENSITIVITY, lockView, rotateAroundTarget, rotateUp); // Camera movement if (IsKeyDown(KEY_W)) CameraMoveForward(camera, CAMERA_MOVE_SPEED, moveInWorldPlane); From 47dd842e8163d43587c7f6bb91bbf88dbdbb24b1 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 15 Feb 2023 18:11:46 +0100 Subject: [PATCH 112/192] Minor format tweaks --- src/rcamera.h | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/rcamera.h b/src/rcamera.h index 9aab3a3487fb..6aee26f385b9 100644 --- a/src/rcamera.h +++ b/src/rcamera.h @@ -160,7 +160,12 @@ Matrix GetCameraProjectionMatrix(Camera* camera, float aspect); // MatrixOrtho() // MatrixIdentity() -// raylib required functionality: GetMouseDelta(), GetMouseWheelMove(), IsKeyDown(), IsKeyPressed(), GetFrameTime() +// raylib required functionality: + // GetMouseDelta() + // GetMouseWheelMove() + // IsKeyDown() + // IsKeyPressed() + // GetFrameTime() //---------------------------------------------------------------------------------- // Defines and Macros @@ -396,12 +401,13 @@ Matrix GetCameraProjectionMatrix(Camera *camera, float aspect) { if (camera->projection == CAMERA_PERSPECTIVE) { - return MatrixPerspective(camera->fovy * DEG2RAD, aspect, CAMERA_CULL_DISTANCE_NEAR, CAMERA_CULL_DISTANCE_FAR); + return MatrixPerspective(camera->fovy*DEG2RAD, aspect, CAMERA_CULL_DISTANCE_NEAR, CAMERA_CULL_DISTANCE_FAR); } else if (camera->projection == CAMERA_ORTHOGRAPHIC) { - double top = camera->fovy / 2.0; - double right = top * aspect; + double top = camera->fovy/2.0; + double right = top*aspect; + return MatrixOrtho(-right, right, -top, top, CAMERA_CULL_DISTANCE_NEAR, CAMERA_CULL_DISTANCE_FAR); } @@ -415,10 +421,10 @@ void UpdateCamera(Camera *camera, int mode) { Vector2 mousePositionDelta = GetMouseDelta(); - bool moveInWorldPlane = mode == CAMERA_FIRST_PERSON || mode == CAMERA_THIRD_PERSON; - bool rotateAroundTarget = mode == CAMERA_THIRD_PERSON || mode == CAMERA_ORBITAL; - bool lockView = mode == CAMERA_FIRST_PERSON || mode == CAMERA_THIRD_PERSON || mode == CAMERA_ORBITAL; - bool rotateUp = mode == CAMERA_FREE; + bool moveInWorldPlane = ((mode == CAMERA_FIRST_PERSON) || (mode == CAMERA_THIRD_PERSON)); + bool rotateAroundTarget = ((mode == CAMERA_THIRD_PERSON) || (mode == CAMERA_ORBITAL)); + bool lockView = ((mode == CAMERA_FIRST_PERSON) || (mode == CAMERA_THIRD_PERSON) || (mode == CAMERA_ORBITAL)); + bool rotateUp = (mode == CAMERA_FREE); if (mode == CAMERA_ORBITAL) { @@ -450,7 +456,7 @@ void UpdateCamera(Camera *camera, int mode) //if (IsKeyDown(KEY_LEFT_CONTROL)) CameraMoveUp(camera, -CAMERA_MOVE_SPEED); } - if (mode == CAMERA_THIRD_PERSON || mode == CAMERA_ORBITAL) + if ((mode == CAMERA_THIRD_PERSON) || (mode == CAMERA_ORBITAL)) { // Zoom target distance CameraMoveToTarget(camera, -GetMouseWheelMove()); From d26a56d4e1d8168912e3670a2ff3122b125fd94c Mon Sep 17 00:00:00 2001 From: hkc Date: Mon, 20 Feb 2023 13:13:24 +0300 Subject: [PATCH 113/192] Added mixed audio processor (#2929) * Use RL_QUADS/RL_TRIANGLES for single-pixel drawing Addresses problem mentioned in https://github.com/raysan5/raylib/issues/2744#issuecomment-1273568263 (in short: when drawing pixels using DrawPixel{,V} in camera mode, upscaled pixel becomes a line instead of bigger pixel) * [rtextures] Fixed scaling down in ImageTextEx Closes #2755 * Added global audio processor * Renamed struct member to follow naming conventions * Added example for AttachAudioMixedProcessor --- examples/audio/audio_mixed_processor.c | 123 +++++++++++++++++++++++ examples/audio/audio_mixed_processor.png | Bin 0 -> 8708 bytes src/raudio.c | 65 +++++++++++- src/raylib.h | 3 + 4 files changed, 190 insertions(+), 1 deletion(-) create mode 100644 examples/audio/audio_mixed_processor.c create mode 100644 examples/audio/audio_mixed_processor.png diff --git a/examples/audio/audio_mixed_processor.c b/examples/audio/audio_mixed_processor.c new file mode 100644 index 000000000000..3a008f3e22cd --- /dev/null +++ b/examples/audio/audio_mixed_processor.c @@ -0,0 +1,123 @@ +/******************************************************************************************* +* +* raylib [audio] example - Mixed audio processing +* +* Example originally created with raylib 4.2, last time updated with raylib 4.2 +* +* Example contributed by hkc (@hatkidchan) 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) 2023 hkc (@hatkidchan) +* +********************************************************************************************/ +#include "raylib.h" +#include + +static float exponent = 1.0f; // Audio exponentiation value +static float averageVolume[400] = { 0.0f }; // Average volume history + +//------------------------------------------------------------------------------------ +// Audio processing function +//------------------------------------------------------------------------------------ +void ProcessAudio(void *buffer, unsigned int frames) +{ + float *samples = (float *)buffer; // Samples internally stored as s + float average = 0.0f; // Temporary average volume + + for (unsigned int frame = 0; frame < frames; frame++) + { + float *left = &samples[frame * 2 + 0], *right = &samples[frame * 2 + 1]; + + *left = powf(fabsf(*left), exponent) * ( (*left < 0.0f)? -1.0f : 1.0f ); + *right = powf(fabsf(*right), exponent) * ( (*right < 0.0f)? -1.0f : 1.0f ); + + average += fabsf(*left) / frames; // accumulating average volume + average += fabsf(*right) / frames; + } + + // Moving history to the left + for (int i = 0; i < 399; i++) averageVolume[i] = averageVolume[i + 1]; + + averageVolume[399] = average; // Adding last average value +} + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [audio] example - processing mixed output"); + + InitAudioDevice(); // Initialize audio device + + AttachAudioMixedProcessor(ProcessAudio); + + Music music = LoadMusicStream("resources/country.mp3"); + Sound sound = LoadSound("resources/coin.wav"); + + PlayMusicStream(music); + + 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 + //---------------------------------------------------------------------------------- + UpdateMusicStream(music); // Update music buffer with new stream data + + // Modify processing variables + //---------------------------------------------------------------------------------- + if (IsKeyPressed(KEY_LEFT)) exponent -= 0.05f; + if (IsKeyPressed(KEY_RIGHT)) exponent += 0.05f; + + if (exponent <= 0.5f) exponent = 0.5f; + if (exponent >= 3.0f) exponent = 3.0f; + + if (IsKeyPressed(KEY_SPACE)) PlaySound(sound); + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + DrawText("MUSIC SHOULD BE PLAYING!", 255, 150, 20, LIGHTGRAY); + + DrawText(TextFormat("EXPONENT = %.2f", exponent), 215, 180, 20, LIGHTGRAY); + + DrawRectangle(199, 199, 402, 34, LIGHTGRAY); + for (int i = 0; i < 400; i++) + { + DrawLine(201 + i, 232 - averageVolume[i] * 32, 201 + i, 232, MAROON); + } + DrawRectangleLines(199, 199, 402, 34, GRAY); + + DrawText("PRESS SPACE TO PLAY OTHER SOUND", 200, 250, 20, LIGHTGRAY); + DrawText("USE LEFT AND RIGHT ARROWS TO ALTER DISTORTION", 140, 280, 20, LIGHTGRAY); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + UnloadMusicStream(music); // Unload music stream buffers from RAM + + DetachAudioMixedProcessor(ProcessAudio); // Disconnect audio processor + + CloseAudioDevice(); // Close audio device (music streaming is automatically stopped) + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} diff --git a/examples/audio/audio_mixed_processor.png b/examples/audio/audio_mixed_processor.png new file mode 100644 index 0000000000000000000000000000000000000000..8575a836df6c39d1a35c82f10c0837262eb7f368 GIT binary patch literal 8708 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 z%p+%>9dklHUpnT?process = process; + + rAudioProcessor *last = AUDIO.mixedProcessor; + + while (last && last->next) + { + last = last->next; + } + if (last) + { + processor->prev = last; + last->next = processor; + } + else AUDIO.mixedProcessor = processor; + + ma_mutex_unlock(&AUDIO.System.lock); +} + +void DetachAudioMixedProcessor(AudioCallback process) +{ + ma_mutex_lock(&AUDIO.System.lock); + + rAudioProcessor *processor = AUDIO.mixedProcessor; + + while (processor) + { + rAudioProcessor *next = processor->next; + rAudioProcessor *prev = processor->prev; + + if (processor->process == process) + { + if (AUDIO.mixedProcessor == processor) AUDIO.mixedProcessor = next; + if (prev) prev->next = next; + if (next) next->prev = prev; + + RL_FREE(processor); + } + + processor = next; + } + + ma_mutex_unlock(&AUDIO.System.lock); +} + + //---------------------------------------------------------------------------------- // Module specific Functions Definition //---------------------------------------------------------------------------------- @@ -2519,6 +2575,13 @@ static void OnSendAudioDataToDevice(ma_device *pDevice, void *pFramesOut, const } } + rAudioProcessor *processor = AUDIO.mixedProcessor; + while (processor) + { + processor->process(pFramesOut, frameCount); + processor = processor->next; + } + ma_mutex_unlock(&AUDIO.System.lock); } diff --git a/src/raylib.h b/src/raylib.h index c1b85abdfdc4..73c6d22426eb 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1580,6 +1580,9 @@ RLAPI void SetAudioStreamCallback(AudioStream stream, AudioCallback callback); RLAPI void AttachAudioStreamProcessor(AudioStream stream, AudioCallback processor); // Attach audio stream processor to stream RLAPI void DetachAudioStreamProcessor(AudioStream stream, AudioCallback processor); // Detach audio stream processor from stream +RLAPI void AttachAudioMixedProcessor(AudioCallback processor); // Attach audio stream processor to the entire audio pipeline +RLAPI void DetachAudioMixedProcessor(AudioCallback processor); // Detach audio stream processor from the entire audio pipeline + #if defined(__cplusplus) } #endif From 1347a155397621d789f23a4bd1f49e3652cb125d Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 21 Feb 2023 13:14:51 +0100 Subject: [PATCH 114/192] ADDED: `SetWindowIcons()` to set multiple icon image sizes --- src/raylib.h | 3 ++- src/rcore.c | 66 ++++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 58 insertions(+), 11 deletions(-) diff --git a/src/raylib.h b/src/raylib.h index 73c6d22426eb..6bc81fe75f59 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -941,7 +941,8 @@ RLAPI void ToggleFullscreen(void); // Toggle wind RLAPI void MaximizeWindow(void); // Set window state: maximized, if resizable (only PLATFORM_DESKTOP) RLAPI void MinimizeWindow(void); // Set window state: minimized, if resizable (only PLATFORM_DESKTOP) RLAPI void RestoreWindow(void); // Set window state: not minimized/maximized (only PLATFORM_DESKTOP) -RLAPI void SetWindowIcon(Image image); // Set icon for window (only PLATFORM_DESKTOP) +RLAPI void SetWindowIcon(Image image); // Set icon for window (single image, RGBA 32bit, only PLATFORM_DESKTOP) +RLAPI void SetWindowIcons(Image *images, int count); // Set icon for window (multiple images, RGBA 32bit, only PLATFORM_DESKTOP) RLAPI void SetWindowTitle(const char *title); // Set title for window (only PLATFORM_DESKTOP) RLAPI void SetWindowPosition(int x, int y); // Set window position on screen (only PLATFORM_DESKTOP) RLAPI void SetWindowMonitor(int monitor); // Set monitor for the current window (fullscreen mode) diff --git a/src/rcore.c b/src/rcore.c index 3de0f3f3cc56..df5f193c5181 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -1554,23 +1554,69 @@ void ClearWindowState(unsigned int flags) } // Set icon for window (only PLATFORM_DESKTOP) -// NOTE: Image must be in RGBA format, 8bit per channel +// NOTE 1: Image must be in RGBA format, 8bit per channel +// NOTE 2: Image is scaled by the OS for all required sizes void SetWindowIcon(Image image) { #if defined(PLATFORM_DESKTOP) - if (image.format == PIXELFORMAT_UNCOMPRESSED_R8G8B8A8) + if (image.data == NULL) { - GLFWimage icon[1] = { 0 }; + // Revert to the default window icon, pass in an empty image array + glfwSetWindowIcon(CORE.Window.handle, 0, NULL); + } + else + { + if (image.format == PIXELFORMAT_UNCOMPRESSED_R8G8B8A8) + { + GLFWimage icon[1] = { 0 }; + + icon[0].width = image.width; + icon[0].height = image.height; + icon[0].pixels = (unsigned char *)image.data; + + // NOTE 1: We only support one image icon + // NOTE 2: The specified image data is copied before this function returns + glfwSetWindowIcon(CORE.Window.handle, 1, icon); + } + else TRACELOG(LOG_WARNING, "GLFW: Window icon image must be in R8G8B8A8 pixel format"); + } +#endif +} - icon[0].width = image.width; - icon[0].height = image.height; - icon[0].pixels = (unsigned char *)image.data; +// Set icon for window (multiple images, only PLATFORM_DESKTOP) +// NOTE 1: Images must be in RGBA format, 8bit per channel +// NOTE 2: The multiple images are used depending on provided sizes +// Standard Windows icon sizes: 256, 128, 96, 64, 48, 32, 24, 16 +void SetWindowIcons(Image *images, int count) +{ +#if defined(PLATFORM_DESKTOP) + if ((images == NULL) || (count <= 0)) + { + // Revert to the default window icon, pass in an empty image array + glfwSetWindowIcon(CORE.Window.handle, 0, NULL); + } + else + { + int valid = 0; + GLFWimage *icons = RL_CALLOC(count, sizeof(GLFWimage)); + + for (int i = 0; i < count; i++) + { + if (images[i].format == PIXELFORMAT_UNCOMPRESSED_R8G8B8A8) + { + icons[valid].width = images[i].width; + icons[valid].height = images[i].height; + icons[valid].pixels = (unsigned char *)images[i].data; + + valid++; + } + else TRACELOG(LOG_WARNING, "GLFW: Window icon image must be in R8G8B8A8 pixel format"); + } + // NOTE: Images data is copied internally before this function returns + glfwSetWindowIcon(CORE.Window.handle, valid, icons); - // NOTE 1: We only support one image icon - // NOTE 2: The specified image data is copied before this function returns - glfwSetWindowIcon(CORE.Window.handle, 1, icon); + RL_FREE(icons); } - else TRACELOG(LOG_WARNING, "GLFW: Window icon image must be in R8G8B8A8 pixel format"); #endif } From bcae065c8851eacb1ab1e60cf085dd7edcf2a8f7 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 21 Feb 2023 13:15:11 +0100 Subject: [PATCH 115/192] REVIEWED: `IsShaderReady()` --- src/rcore.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/rcore.c b/src/rcore.c index df5f193c5181..6fdeb94e69c4 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -2561,7 +2561,33 @@ Shader LoadShaderFromMemory(const char *vsCode, const char *fsCode) // Check if a shader is ready bool IsShaderReady(Shader shader) { - return shader.locs != NULL; + return ((shader.id > 0) && // Validate shader id (loaded successfully) + (shader.locs != NULL)); // Validate memory has been allocated for default shader locations + + // The following locations are tried to be set automatically (locs[i] >= 0), + // any of them can be checked for validation but the only mandatory one is, afaik, SHADER_LOC_VERTEX_POSITION + // NOTE: Users can also setup manually their own attributes/uniforms and do not used the default raylib ones + + // Vertex shader attribute locations (default) + // shader.locs[SHADER_LOC_VERTEX_POSITION] // Set by default internal shader + // shader.locs[SHADER_LOC_VERTEX_TEXCOORD01] // Set by default internal shader + // shader.locs[SHADER_LOC_VERTEX_TEXCOORD02] + // shader.locs[SHADER_LOC_VERTEX_NORMAL] + // shader.locs[SHADER_LOC_VERTEX_TANGENT] + // shader.locs[SHADER_LOC_VERTEX_COLOR] // Set by default internal shader + + // Vertex shader uniform locations (default) + // shader.locs[SHADER_LOC_MATRIX_MVP] // Set by default internal shader + // shader.locs[SHADER_LOC_MATRIX_VIEW] + // shader.locs[SHADER_LOC_MATRIX_PROJECTION] + // shader.locs[SHADER_LOC_MATRIX_MODEL] + // shader.locs[SHADER_LOC_MATRIX_NORMAL] + + // Fragment shader uniform locations (default) + // shader.locs[SHADER_LOC_COLOR_DIFFUSE] // Set by default internal shader + // shader.locs[SHADER_LOC_MAP_DIFFUSE] // Set by default internal shader + // shader.locs[SHADER_LOC_MAP_SPECULAR] + // shader.locs[SHADER_LOC_MAP_NORMAL] } // Unload shader from GPU memory (VRAM) From 3cade2a1a033d8c1f5ab62cfaa24e5f65d424576 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 21 Feb 2023 13:20:04 +0100 Subject: [PATCH 116/192] REVIEWED: `IsImageReady()` and `IsTexureReady()` Reordered some functions to avoid config.h issues when disabling some features. --- src/rtextures.c | 358 +++++++++++++++++++++++++----------------------- 1 file changed, 183 insertions(+), 175 deletions(-) diff --git a/src/rtextures.c b/src/rtextures.c index 9bce9c716931..c5636563792c 100644 --- a/src/rtextures.c +++ b/src/rtextures.c @@ -30,7 +30,7 @@ * * #define SUPPORT_IMAGE_MANIPULATION * Support multiple image editing functions to scale, adjust colors, flip, draw on images, crop... -* If not defined only three image editing functions supported: ImageFormat(), ImageAlphaMask(), ImageToPOT() +* If not defined only some image editing functions supported: ImageFormat(), ImageAlphaMask(), ImageResize*() * * #define SUPPORT_IMAGE_GENERATION * Support procedural image generation functionality (gradient, spot, perlin-noise, cellular) @@ -190,13 +190,10 @@ #include "external/stb_perlin.h" // Required for: stb_perlin_fbm_noise3 #endif -#if defined(SUPPORT_IMAGE_MANIPULATION) - #define STBIR_MALLOC(size,c) ((void)(c), RL_MALLOC(size)) - #define STBIR_FREE(ptr,c) ((void)(c), RL_FREE(ptr)) - - #define STB_IMAGE_RESIZE_IMPLEMENTATION - #include "external/stb_image_resize.h" // Required for: stbir_resize_uint8() [ImageResize()] -#endif +#define STBIR_MALLOC(size,c) ((void)(c), RL_MALLOC(size)) +#define STBIR_FREE(ptr,c) ((void)(c), RL_FREE(ptr)) +#define STB_IMAGE_RESIZE_IMPLEMENTATION +#include "external/stb_image_resize.h" // Required for: stbir_resize_uint8() [ImageResize()] //---------------------------------------------------------------------------------- // Defines and Macros @@ -505,7 +502,11 @@ Image LoadImageFromScreen(void) // Check if an image is ready bool IsImageReady(Image image) { - return image.data != NULL && image.width > 0 && image.height > 0 && image.format > 0; + return ((image.data != NULL) && // Validate pixel data available + (image.width > 0) && + (image.height > 0) && // Validate image size + (image.format > 0) && // Validate image format + (image.mipmaps > 0)); // Validate image mipmaps (at least 1 for basic mipmap level) } // Unload image from CPU memory (RAM) @@ -1228,23 +1229,6 @@ void ImageFormat(Image *image, int newFormat) } } -// Convert image to POT (power-of-two) -// NOTE: It could be useful on OpenGL ES 2.0 (RPI, HTML5) -void ImageToPOT(Image *image, Color fill) -{ - // Security check to avoid program crash - if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return; - - // Calculate next power-of-two values - // NOTE: Just add the required amount of pixels at the right and bottom sides of image... - int potWidth = (int)powf(2, ceilf(logf((float)image->width)/logf(2))); - int potHeight = (int)powf(2, ceilf(logf((float)image->height)/logf(2))); - - // Check if POT texture generation is required (if texture is not already POT) - if ((potWidth != image->width) || (potHeight != image->height)) ImageResizeCanvas(image, potWidth, potHeight, 0, 0, fill); -} - -#if defined(SUPPORT_IMAGE_MANIPULATION) // Create an image from text (default font) Image ImageText(const char *text, int fontSize, Color color) { @@ -1330,6 +1314,172 @@ Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Co return imText; } +// Resize and image to new size using Nearest-Neighbor scaling algorithm +void ImageResizeNN(Image *image,int newWidth,int newHeight) +{ + // Security check to avoid program crash + if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return; + + Color *pixels = LoadImageColors(*image); + Color *output = (Color *)RL_MALLOC(newWidth*newHeight*sizeof(Color)); + + // EDIT: added +1 to account for an early rounding problem + int xRatio = (int)((image->width << 16)/newWidth) + 1; + int yRatio = (int)((image->height << 16)/newHeight) + 1; + + int x2, y2; + for (int y = 0; y < newHeight; y++) + { + for (int x = 0; x < newWidth; x++) + { + x2 = ((x*xRatio) >> 16); + y2 = ((y*yRatio) >> 16); + + output[(y*newWidth) + x] = pixels[(y2*image->width) + x2] ; + } + } + + int format = image->format; + + RL_FREE(image->data); + + image->data = output; + image->width = newWidth; + image->height = newHeight; + image->format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; + + ImageFormat(image, format); // Reformat 32bit RGBA image to original format + + UnloadImageColors(pixels); +} + + +// Resize and image to new size +// NOTE: Uses stb default scaling filters (both bicubic): +// STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_CATMULLROM +// STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_MITCHELL (high-quality Catmull-Rom) +void ImageResize(Image *image, int newWidth, int newHeight) +{ + // Security check to avoid program crash + if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return; + + // Check if we can use a fast path on image scaling + // It can be for 8 bit per channel images with 1 to 4 channels per pixel + if ((image->format == PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) || + (image->format == PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA) || + (image->format == PIXELFORMAT_UNCOMPRESSED_R8G8B8) || + (image->format == PIXELFORMAT_UNCOMPRESSED_R8G8B8A8)) + { + int bytesPerPixel = GetPixelDataSize(1, 1, image->format); + unsigned char *output = (unsigned char *)RL_MALLOC(newWidth*newHeight*bytesPerPixel); + + switch (image->format) + { + case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: stbir_resize_uint8((unsigned char *)image->data, image->width, image->height, 0, output, newWidth, newHeight, 0, 1); break; + case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: stbir_resize_uint8((unsigned char *)image->data, image->width, image->height, 0, output, newWidth, newHeight, 0, 2); break; + case PIXELFORMAT_UNCOMPRESSED_R8G8B8: stbir_resize_uint8((unsigned char *)image->data, image->width, image->height, 0, output, newWidth, newHeight, 0, 3); break; + case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: stbir_resize_uint8((unsigned char *)image->data, image->width, image->height, 0, output, newWidth, newHeight, 0, 4); break; + default: break; + } + + RL_FREE(image->data); + image->data = output; + image->width = newWidth; + image->height = newHeight; + } + else + { + // Get data as Color pixels array to work with it + Color *pixels = LoadImageColors(*image); + Color *output = (Color *)RL_MALLOC(newWidth*newHeight*sizeof(Color)); + + // NOTE: Color data is cast to (unsigned char *), there shouldn't been any problem... + stbir_resize_uint8((unsigned char *)pixels, image->width, image->height, 0, (unsigned char *)output, newWidth, newHeight, 0, 4); + + int format = image->format; + + UnloadImageColors(pixels); + RL_FREE(image->data); + + image->data = output; + image->width = newWidth; + image->height = newHeight; + image->format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; + + ImageFormat(image, format); // Reformat 32bit RGBA image to original format + } +} + +// Resize canvas and fill with color +// NOTE: Resize offset is relative to the top-left corner of the original image +void ImageResizeCanvas(Image *image, int newWidth, int newHeight, int offsetX, int offsetY, Color fill) +{ + // Security check to avoid program crash + if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return; + + if (image->mipmaps > 1) TRACELOG(LOG_WARNING, "Image manipulation only applied to base mipmap level"); + if (image->format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) TRACELOG(LOG_WARNING, "Image manipulation not supported for compressed formats"); + else if ((newWidth != image->width) || (newHeight != image->height)) + { + Rectangle srcRec = { 0, 0, (float)image->width, (float)image->height }; + Vector2 dstPos = { (float)offsetX, (float)offsetY }; + + if (offsetX < 0) + { + srcRec.x = (float)-offsetX; + srcRec.width += (float)offsetX; + dstPos.x = 0; + } + else if ((offsetX + image->width) > newWidth) srcRec.width = (float)(newWidth - offsetX); + + if (offsetY < 0) + { + srcRec.y = (float)-offsetY; + srcRec.height += (float)offsetY; + dstPos.y = 0; + } + else if ((offsetY + image->height) > newHeight) srcRec.height = (float)(newHeight - offsetY); + + if (newWidth < srcRec.width) srcRec.width = (float)newWidth; + if (newHeight < srcRec.height) srcRec.height = (float)newHeight; + + int bytesPerPixel = GetPixelDataSize(1, 1, image->format); + unsigned char *resizedData = (unsigned char *)RL_CALLOC(newWidth*newHeight*bytesPerPixel, 1); + + // TODO: Fill resized canvas with fill color (must be formatted to image->format) + + int dstOffsetSize = ((int)dstPos.y*newWidth + (int)dstPos.x)*bytesPerPixel; + + for (int y = 0; y < (int)srcRec.height; y++) + { + memcpy(resizedData + dstOffsetSize, ((unsigned char *)image->data) + ((y + (int)srcRec.y)*image->width + (int)srcRec.x)*bytesPerPixel, (int)srcRec.width*bytesPerPixel); + dstOffsetSize += (newWidth*bytesPerPixel); + } + + RL_FREE(image->data); + image->data = resizedData; + image->width = newWidth; + image->height = newHeight; + } +} + +#if defined(SUPPORT_IMAGE_MANIPULATION) +// Convert image to POT (power-of-two) +// NOTE: It could be useful on OpenGL ES 2.0 (RPI, HTML5) +void ImageToPOT(Image *image, Color fill) +{ + // Security check to avoid program crash + if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return; + + // Calculate next power-of-two values + // NOTE: Just add the required amount of pixels at the right and bottom sides of image... + int potWidth = (int)powf(2, ceilf(logf((float)image->width)/logf(2))); + int potHeight = (int)powf(2, ceilf(logf((float)image->height)/logf(2))); + + // Check if POT texture generation is required (if texture is not already POT) + if ((potWidth != image->width) || (potHeight != image->height)) ImageResizeCanvas(image, potWidth, potHeight, 0, 0, fill); +} + // Crop image depending on alpha value // NOTE: Threshold is defined as a percentage: 0.0f -> 1.0f void ImageAlphaCrop(Image *image, float threshold) @@ -1672,154 +1822,6 @@ void ImageBlurGaussian(Image *image, int blurSize) { ImageFormat(image, format); } -// Resize and image to new size -// NOTE: Uses stb default scaling filters (both bicubic): -// STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_CATMULLROM -// STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_MITCHELL (high-quality Catmull-Rom) -void ImageResize(Image *image, int newWidth, int newHeight) -{ - // Security check to avoid program crash - if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return; - - // Check if we can use a fast path on image scaling - // It can be for 8 bit per channel images with 1 to 4 channels per pixel - if ((image->format == PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) || - (image->format == PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA) || - (image->format == PIXELFORMAT_UNCOMPRESSED_R8G8B8) || - (image->format == PIXELFORMAT_UNCOMPRESSED_R8G8B8A8)) - { - int bytesPerPixel = GetPixelDataSize(1, 1, image->format); - unsigned char *output = (unsigned char *)RL_MALLOC(newWidth*newHeight*bytesPerPixel); - - switch (image->format) - { - case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: stbir_resize_uint8((unsigned char *)image->data, image->width, image->height, 0, output, newWidth, newHeight, 0, 1); break; - case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: stbir_resize_uint8((unsigned char *)image->data, image->width, image->height, 0, output, newWidth, newHeight, 0, 2); break; - case PIXELFORMAT_UNCOMPRESSED_R8G8B8: stbir_resize_uint8((unsigned char *)image->data, image->width, image->height, 0, output, newWidth, newHeight, 0, 3); break; - case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: stbir_resize_uint8((unsigned char *)image->data, image->width, image->height, 0, output, newWidth, newHeight, 0, 4); break; - default: break; - } - - RL_FREE(image->data); - image->data = output; - image->width = newWidth; - image->height = newHeight; - } - else - { - // Get data as Color pixels array to work with it - Color *pixels = LoadImageColors(*image); - Color *output = (Color *)RL_MALLOC(newWidth*newHeight*sizeof(Color)); - - // NOTE: Color data is cast to (unsigned char *), there shouldn't been any problem... - stbir_resize_uint8((unsigned char *)pixels, image->width, image->height, 0, (unsigned char *)output, newWidth, newHeight, 0, 4); - - int format = image->format; - - UnloadImageColors(pixels); - RL_FREE(image->data); - - image->data = output; - image->width = newWidth; - image->height = newHeight; - image->format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; - - ImageFormat(image, format); // Reformat 32bit RGBA image to original format - } -} - -// Resize and image to new size using Nearest-Neighbor scaling algorithm -void ImageResizeNN(Image *image,int newWidth,int newHeight) -{ - // Security check to avoid program crash - if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return; - - Color *pixels = LoadImageColors(*image); - Color *output = (Color *)RL_MALLOC(newWidth*newHeight*sizeof(Color)); - - // EDIT: added +1 to account for an early rounding problem - int xRatio = (int)((image->width << 16)/newWidth) + 1; - int yRatio = (int)((image->height << 16)/newHeight) + 1; - - int x2, y2; - for (int y = 0; y < newHeight; y++) - { - for (int x = 0; x < newWidth; x++) - { - x2 = ((x*xRatio) >> 16); - y2 = ((y*yRatio) >> 16); - - output[(y*newWidth) + x] = pixels[(y2*image->width) + x2] ; - } - } - - int format = image->format; - - RL_FREE(image->data); - - image->data = output; - image->width = newWidth; - image->height = newHeight; - image->format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; - - ImageFormat(image, format); // Reformat 32bit RGBA image to original format - - UnloadImageColors(pixels); -} - -// Resize canvas and fill with color -// NOTE: Resize offset is relative to the top-left corner of the original image -void ImageResizeCanvas(Image *image, int newWidth, int newHeight, int offsetX, int offsetY, Color fill) -{ - // Security check to avoid program crash - if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return; - - if (image->mipmaps > 1) TRACELOG(LOG_WARNING, "Image manipulation only applied to base mipmap level"); - if (image->format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) TRACELOG(LOG_WARNING, "Image manipulation not supported for compressed formats"); - else if ((newWidth != image->width) || (newHeight != image->height)) - { - Rectangle srcRec = { 0, 0, (float)image->width, (float)image->height }; - Vector2 dstPos = { (float)offsetX, (float)offsetY }; - - if (offsetX < 0) - { - srcRec.x = (float)-offsetX; - srcRec.width += (float)offsetX; - dstPos.x = 0; - } - else if ((offsetX + image->width) > newWidth) srcRec.width = (float)(newWidth - offsetX); - - if (offsetY < 0) - { - srcRec.y = (float)-offsetY; - srcRec.height += (float)offsetY; - dstPos.y = 0; - } - else if ((offsetY + image->height) > newHeight) srcRec.height = (float)(newHeight - offsetY); - - if (newWidth < srcRec.width) srcRec.width = (float)newWidth; - if (newHeight < srcRec.height) srcRec.height = (float)newHeight; - - int bytesPerPixel = GetPixelDataSize(1, 1, image->format); - unsigned char *resizedData = (unsigned char *)RL_CALLOC(newWidth*newHeight*bytesPerPixel, 1); - - // TODO: Fill resized canvas with fill color (must be formatted to image->format) - - int dstOffsetSize = ((int)dstPos.y*newWidth + (int)dstPos.x)*bytesPerPixel; - - for (int y = 0; y < (int)srcRec.height; y++) - { - memcpy(resizedData + dstOffsetSize, ((unsigned char *)image->data) + ((y + (int)srcRec.y)*image->width + (int)srcRec.x)*bytesPerPixel, (int)srcRec.width*bytesPerPixel); - dstOffsetSize += (newWidth*bytesPerPixel); - } - - RL_FREE(image->data); - image->data = resizedData; - image->width = newWidth; - image->height = newHeight; - } -} - // Generate all mipmap levels for a provided image // NOTE 1: Supports POT and NPOT images // NOTE 2: image.data is scaled to include mipmap levels @@ -3333,7 +3335,13 @@ RenderTexture2D LoadRenderTexture(int width, int height) // Check if a texture is ready bool IsTextureReady(Texture2D texture) { - return texture.id > 0 && texture.width > 0 && texture.height > 0 && texture.format > 0; + // TODO: Validate maximum texture size supported by GPU? + + return ((texture.id > 0) && // Validate OpenGL id + (texture.width > 0) && + (texture.height > 0) && // Validate texture size + (texture.format > 0) && // Validate texture pixel format + (texture.mipmap > 0)); // Validate texture mipmaps (at least 1 for basic mipmap level) } // Unload texture from GPU memory (VRAM) From b2926b2d28accb1616db72489f5ee123c41c01d2 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 21 Feb 2023 13:20:52 +0100 Subject: [PATCH 117/192] Update rtextures.c --- src/rtextures.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rtextures.c b/src/rtextures.c index c5636563792c..7ae96c67f37f 100644 --- a/src/rtextures.c +++ b/src/rtextures.c @@ -3341,7 +3341,7 @@ bool IsTextureReady(Texture2D texture) (texture.width > 0) && (texture.height > 0) && // Validate texture size (texture.format > 0) && // Validate texture pixel format - (texture.mipmap > 0)); // Validate texture mipmaps (at least 1 for basic mipmap level) + (texture.mipmaps > 0)); // Validate texture mipmaps (at least 1 for basic mipmap level) } // Unload texture from GPU memory (VRAM) From 8169d0eab249c0a639bca16c721f8bfe1b3ef4b1 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 21 Feb 2023 23:01:23 +0100 Subject: [PATCH 118/192] REVIEWED: `IsWindowFocused()` to consider Android App state #2935 --- src/rcore.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/rcore.c b/src/rcore.c index 6fdeb94e69c4..327921fec46d 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -1141,9 +1141,8 @@ bool IsWindowMinimized(void) { #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) return ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0); -#else - return false; #endif + return false; } // Check if window has been maximized (only PLATFORM_DESKTOP) @@ -1151,9 +1150,8 @@ bool IsWindowMaximized(void) { #if defined(PLATFORM_DESKTOP) return ((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) > 0); -#else - return false; #endif + return false; } // Check if window has the focus @@ -1161,9 +1159,11 @@ bool IsWindowFocused(void) { #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) return ((CORE.Window.flags & FLAG_WINDOW_UNFOCUSED) == 0); -#else - return true; #endif +#if defined(PLATFORM_ANDROID) + return CORE.Android.appEnabled; +#endif + return true; } // Check if window has been resizedLastFrame From b4d824d6fcdbfb64023664ebd1c9b258d021a0cc Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 21 Feb 2023 23:10:03 +0100 Subject: [PATCH 119/192] REVIEWED: `GetMonitorWidth()` and `GetMonitorHeight()` #2934 --- src/rcore.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/rcore.c b/src/rcore.c index 327921fec46d..807d58f91558 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -1831,6 +1831,12 @@ int GetMonitorWidth(int monitor) else TRACELOG(LOG_WARNING, "GLFW: Failed to find video mode for selected monitor"); } else TRACELOG(LOG_WARNING, "GLFW: Failed to find selected monitor"); +#endif +#if defined(PLATFORM_ANDROID) + if (CORE.Android.app->window != NULL) + { + return ANativeWindow_getWidth(CORE.Android.app->window); + } #endif return 0; } @@ -1850,6 +1856,12 @@ int GetMonitorHeight(int monitor) else TRACELOG(LOG_WARNING, "GLFW: Failed to find video mode for selected monitor"); } else TRACELOG(LOG_WARNING, "GLFW: Failed to find selected monitor"); +#endif +#if defined(PLATFORM_ANDROID) + if (CORE.Android.app->window != NULL) + { + return ANativeWindow_getHeight(CORE.Android.app->window); + } #endif return 0; } From 153470d60503e840d5b0a15abe3647a4316e988c Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 21 Feb 2023 23:55:55 +0100 Subject: [PATCH 120/192] REVIEWED: `GenMeshTangents()`, avoid crash on missing texcoords data #2927 --- src/rmodels.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/rmodels.c b/src/rmodels.c index 2fd2d5a4a005..f8d6ec1352c5 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -3326,9 +3326,15 @@ BoundingBox GetMeshBoundingBox(Mesh mesh) // Compute mesh tangents // NOTE: To calculate mesh tangents and binormals we need mesh vertex positions and texture coordinates -// Implementation base don: https://answers.unity.com/questions/7789/calculating-tangents-vector4.html +// Implementation based on: https://answers.unity.com/questions/7789/calculating-tangents-vector4.html void GenMeshTangents(Mesh *mesh) { + if ((mesh->vertices == NULL) || (mesh->texcoords == NULL)) + { + TRACELOG(LOG_WARNING, "MESH: Tangents generation requires texcoord vertex attribute data"); + return; + } + if (mesh->tangents == NULL) mesh->tangents = (float *)RL_MALLOC(mesh->vertexCount*4*sizeof(float)); else { From d652b95fbfc06b7a996386c9d212e9fe2d669ed8 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 22 Feb 2023 17:28:25 +0100 Subject: [PATCH 121/192] ADDED: Security checks --- src/rtext.c | 51 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/src/rtext.c b/src/rtext.c index 3e838f85cc56..7cce1eb8727a 100644 --- a/src/rtext.c +++ b/src/rtext.c @@ -1568,17 +1568,20 @@ const char *TextToUpper(const char *text) static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 }; memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH); - for (int i = 0; i < MAX_TEXT_BUFFER_LENGTH; i++) + if (text != NULL) { - if (text[i] != '\0') + for (int i = 0; i < MAX_TEXT_BUFFER_LENGTH; i++) { - buffer[i] = (char)toupper(text[i]); - //if ((text[i] >= 'a') && (text[i] <= 'z')) buffer[i] = text[i] - 32; + if (text[i] != '\0') + { + buffer[i] = (char)toupper(text[i]); + //if ((text[i] >= 'a') && (text[i] <= 'z')) buffer[i] = text[i] - 32; - // TODO: Support UTF-8 diacritics to upper-case - //if ((text[i] >= 'à') && (text[i] <= 'ý')) buffer[i] = text[i] - 32; + // TODO: Support UTF-8 diacritics to upper-case + //if ((text[i] >= 'à') && (text[i] <= 'ý')) buffer[i] = text[i] - 32; + } + else { buffer[i] = '\0'; break; } } - else { buffer[i] = '\0'; break; } } return buffer; @@ -1591,14 +1594,17 @@ const char *TextToLower(const char *text) static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 }; memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH); - for (int i = 0; i < MAX_TEXT_BUFFER_LENGTH; i++) + if (text != NULL) { - if (text[i] != '\0') + for (int i = 0; i < MAX_TEXT_BUFFER_LENGTH; i++) { - buffer[i] = (char)tolower(text[i]); - //if ((text[i] >= 'A') && (text[i] <= 'Z')) buffer[i] = text[i] + 32; + if (text[i] != '\0') + { + buffer[i] = (char)tolower(text[i]); + //if ((text[i] >= 'A') && (text[i] <= 'Z')) buffer[i] = text[i] + 32; + } + else { buffer[i] = '\0'; break; } } - else { buffer[i] = '\0'; break; } } return buffer; @@ -1611,20 +1617,23 @@ const char *TextToPascal(const char *text) static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 }; memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH); - buffer[0] = (char)toupper(text[0]); - - for (int i = 1, j = 1; i < MAX_TEXT_BUFFER_LENGTH; i++, j++) + if (text != NULL) { - if (text[j] != '\0') + buffer[0] = (char)toupper(text[0]); + + for (int i = 1, j = 1; i < MAX_TEXT_BUFFER_LENGTH; i++, j++) { - if (text[j] != '_') buffer[i] = text[j]; - else + if (text[j] != '\0') { - j++; - buffer[i] = (char)toupper(text[j]); + if (text[j] != '_') buffer[i] = text[j]; + else + { + j++; + buffer[i] = (char)toupper(text[j]); + } } + else { buffer[i] = '\0'; break; } } - else { buffer[i] = '\0'; break; } } return buffer; From d5a31168ce768ef9c1e11fe4734285770a33aba4 Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 23 Feb 2023 18:08:15 +0100 Subject: [PATCH 122/192] REVIEWED: Data validation --- src/raudio.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/raudio.c b/src/raudio.c index 5f5332153e76..04386167d5b9 100644 --- a/src/raudio.c +++ b/src/raudio.c @@ -868,7 +868,11 @@ Wave LoadWaveFromMemory(const char *fileType, const unsigned char *fileData, int // Checks if wave data is ready bool IsWaveReady(Wave wave) { - return wave.data != NULL; + return ((wave.data != NULL) && // Validate wave data available + (wave.frameCount > 0) && // Validate frame count + (wave.sampleRate > 0) && // Validate sample rate is supported + (wave.sampleSize > 0) && // Validate sample size is supported + (wave.channels > 0)); // Validate number of channels supported } // Load sound from file @@ -930,7 +934,11 @@ Sound LoadSoundFromWave(Wave wave) // Checks if a sound is ready bool IsSoundReady(Sound sound) { - return sound.stream.buffer != NULL; + return ((sound.frameCount > 0) && // Validate frame count + (sound.stream.buffer != NULL) && // Validate stream buffer + (sound.stream.sampleRate > 0) && // Validate sample rate is supported + (sound.stream.sampleSize > 0) && // Validate sample size is supported + (sound.stream.channels > 0)); // Validate number of channels supported } // Unload wave data @@ -1722,7 +1730,11 @@ Music LoadMusicStreamFromMemory(const char *fileType, const unsigned char *data, // Checks if a music stream is ready bool IsMusicReady(Music music) { - return music.ctxData != NULL; + return ((music.ctxData != NULL) && // Validate context loaded + (music.frameCount > 0) && // Validate audio frame count + (music.stream.sampleRate > 0) && // Validate sample rate is supported + (music.stream.sampleSize > 0) && // Validate sample size is supported + (music.stream.channels > 0)); // Validate number of channels supported } // Unload music stream @@ -2097,7 +2109,10 @@ AudioStream LoadAudioStream(unsigned int sampleRate, unsigned int sampleSize, un // Checks if an audio stream is ready RLAPI bool IsAudioStreamReady(AudioStream stream) { - return stream.buffer != NULL; + return ((stream.buffer != NULL) && // Validate stream buffer + (stream.sampleRate > 0) && // Validate sample rate is supported + (stream.sampleSize > 0) && // Validate sample size is supported + (stream.channels > 0)); // Validate number of channels supported } // Unload audio stream and free memory From 110eab56a701bbd65f8762cbf6d11ca4e6925fbd Mon Sep 17 00:00:00 2001 From: fubark Date: Thu, 23 Feb 2023 15:48:28 -0800 Subject: [PATCH 123/192] Add Cyber to BINDINGS.md (#2939) --- BINDINGS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/BINDINGS.md b/BINDINGS.md index f703296a7895..e232b1b6c37c 100644 --- a/BINDINGS.md +++ b/BINDINGS.md @@ -14,6 +14,7 @@ Some people ported raylib to other languages in form of bindings or wrappers to | claylib/wrap | **4.2** | [Common Lisp](https://common-lisp.net/) | Zlib | https://github.com/defun-games/claylib | | chez-raylib | auto | [Chez Scheme](https://cisco.github.io/ChezScheme/) | GPLv3 | https://github.com/Yunoinsky/chez-raylib | | raylib-cr | **4.5-dev (7e7939e)** | [Crystal](https://crystal-lang.org/) | Apache-2.0 | https://github.com/sol-vin/raylib-cr | +| ray-cyber | **4.2** | [Cyber](https://cyberscript.dev) | MIT | https://github.com/fubark/ray-cyber | | raylib-c3 | **4.5-dev** | [C3](https://c3-lang.org/) | MIT | https://github.com/Its-Kenta/Raylib-C3 | | dart-raylib | **4.0** | [Dart](https://dart.dev/) | MIT | https://gitlab.com/wolfenrain/dart-raylib | | bindbc-raylib3 | **4.0** | [D](https://dlang.org/) | BSL-1.0 | https://github.com/o3o/bindbc-raylib3 | From ca98a84d68ea6f70112de57a68866b4bb55edbe5 Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 24 Feb 2023 15:27:25 +0100 Subject: [PATCH 124/192] Update rtext.c --- src/rtext.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rtext.c b/src/rtext.c index 7cce1eb8727a..f07261121d38 100644 --- a/src/rtext.c +++ b/src/rtext.c @@ -1339,7 +1339,7 @@ int TextCopy(char *dst, const char *src) { int bytes = 0; - if (dst != NULL) + if ((src != NULL) && (dst != NULL)) { while (*src != '\0') { From cb2ba3675c3928a2937f84e4c6503a659375ca0a Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 24 Feb 2023 16:19:25 +0100 Subject: [PATCH 125/192] REVIEWED: `rlUnloadFramebuffer()` #2937 --- src/rlgl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rlgl.h b/src/rlgl.h index f7d73edaf11b..7e9fee68a6cf 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -3473,7 +3473,7 @@ void rlUnloadFramebuffer(unsigned int id) unsigned int depthIdU = (unsigned int)depthId; if (depthType == GL_RENDERBUFFER) glDeleteRenderbuffers(1, &depthIdU); - else if (depthType == GL_RENDERBUFFER) glDeleteTextures(1, &depthIdU); + else if (depthType == GL_TEXTURE) glDeleteTextures(1, &depthIdU); // NOTE: If a texture object is deleted while its image is attached to the *currently bound* framebuffer, // the texture image is automatically detached from the currently bound framebuffer. From 215eb967e84c4bd9e193e242b586e7f1e67010a5 Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 24 Feb 2023 18:31:16 +0100 Subject: [PATCH 126/192] Update rcore.c --- src/rcore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rcore.c b/src/rcore.c index 807d58f91558..8e7adda97bcd 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -6996,7 +6996,7 @@ static void ExportAutomationEvents(const char *fileName) // Save as binary /* FILE *repFile = fopen(fileName, "wb"); - fwrite(fileId, 4, 1, repFile); + fwrite(fileId, sizeof(unsigned char), 4, repFile); fwrite(&eventCount, sizeof(int), 1, repFile); fwrite(events, sizeof(AutomationEvent), eventCount, repFile); fclose(repFile); From 7fd2bf1a32c3ed7c932fe7c020858ecadb3b2056 Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 25 Feb 2023 01:07:52 +0100 Subject: [PATCH 127/192] Minimal tweak --- src/rcore.c | 2 +- src/rmodels.c | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/rcore.c b/src/rcore.c index 8e7adda97bcd..443ef8e3a14f 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -6944,7 +6944,7 @@ static void LoadAutomationEvents(const char *fileName) // Load binary /* FILE *repFile = fopen(fileName, "rb"); - fread(fileId, 4, 1, repFile); + fread(fileId, 1, 4, repFile); if ((fileId[0] == 'r') && (fileId[1] == 'E') && (fileId[2] == 'P') && (fileId[1] == ' ')) { diff --git a/src/rmodels.c b/src/rmodels.c index f8d6ec1352c5..b28e14dc1ad4 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -4222,11 +4222,11 @@ static Model LoadIQM(const char *fileName) for (int i = 0; i < model.meshCount; i++) { //fseek(iqmFile, iqmHeader->ofs_text + imesh[i].name, SEEK_SET); - //fread(name, sizeof(char)*MESH_NAME_LENGTH, 1, iqmFile); + //fread(name, sizeof(char), MESH_NAME_LENGTH, iqmFile); memcpy(name, fileDataPtr + iqmHeader->ofs_text + imesh[i].name, MESH_NAME_LENGTH*sizeof(char)); //fseek(iqmFile, iqmHeader->ofs_text + imesh[i].material, SEEK_SET); - //fread(material, sizeof(char)*MATERIAL_NAME_LENGTH, 1, iqmFile); + //fread(material, sizeof(char), MATERIAL_NAME_LENGTH, iqmFile); memcpy(material, fileDataPtr + iqmHeader->ofs_text + imesh[i].material, MATERIAL_NAME_LENGTH*sizeof(char)); model.materials[i] = LoadMaterialDefault(); @@ -4254,7 +4254,7 @@ static Model LoadIQM(const char *fileName) // Triangles data processing tri = RL_MALLOC(iqmHeader->num_triangles*sizeof(IQMTriangle)); //fseek(iqmFile, iqmHeader->ofs_triangles, SEEK_SET); - //fread(tri, iqmHeader->num_triangles*sizeof(IQMTriangle), 1, iqmFile); + //fread(tri, sizeof(IQMTriangle), iqmHeader->num_triangles, iqmFile); memcpy(tri, fileDataPtr + iqmHeader->ofs_triangles, iqmHeader->num_triangles*sizeof(IQMTriangle)); for (int m = 0; m < model.meshCount; m++) @@ -4276,7 +4276,7 @@ static Model LoadIQM(const char *fileName) // Vertex arrays data processing va = RL_MALLOC(iqmHeader->num_vertexarrays*sizeof(IQMVertexArray)); //fseek(iqmFile, iqmHeader->ofs_vertexarrays, SEEK_SET); - //fread(va, iqmHeader->num_vertexarrays*sizeof(IQMVertexArray), 1, iqmFile); + //fread(va, sizeof(IQMVertexArray), iqmHeader->num_vertexarrays, iqmFile); memcpy(va, fileDataPtr + iqmHeader->ofs_vertexarrays, iqmHeader->num_vertexarrays*sizeof(IQMVertexArray)); for (unsigned int i = 0; i < iqmHeader->num_vertexarrays; i++) @@ -4395,7 +4395,7 @@ static Model LoadIQM(const char *fileName) // Bones (joints) data processing ijoint = RL_MALLOC(iqmHeader->num_joints*sizeof(IQMJoint)); //fseek(iqmFile, iqmHeader->ofs_joints, SEEK_SET); - //fread(ijoint, iqmHeader->num_joints*sizeof(IQMJoint), 1, iqmFile); + //fread(ijoint, sizeof(IQMJoint), iqmHeader->num_joints, iqmFile); memcpy(ijoint, fileDataPtr + iqmHeader->ofs_joints, iqmHeader->num_joints*sizeof(IQMJoint)); model.boneCount = iqmHeader->num_joints; @@ -4407,7 +4407,7 @@ static Model LoadIQM(const char *fileName) // Bones model.bones[i].parent = ijoint[i].parent; //fseek(iqmFile, iqmHeader->ofs_text + ijoint[i].name, SEEK_SET); - //fread(model.bones[i].name, BONE_NAME_LENGTH*sizeof(char), 1, iqmFile); + //fread(model.bones[i].name, sizeof(char), BONE_NAME_LENGTH, iqmFile); memcpy(model.bones[i].name, fileDataPtr + iqmHeader->ofs_text + ijoint[i].name, BONE_NAME_LENGTH*sizeof(char)); // Bind pose (base pose) @@ -4511,14 +4511,14 @@ static ModelAnimation *LoadModelAnimationsIQM(const char *fileName, unsigned int // Get bones data IQMPose *poses = RL_MALLOC(iqmHeader->num_poses*sizeof(IQMPose)); //fseek(iqmFile, iqmHeader->ofs_poses, SEEK_SET); - //fread(poses, iqmHeader->num_poses*sizeof(IQMPose), 1, iqmFile); + //fread(poses, sizeof(IQMPose), iqmHeader->num_poses, iqmFile); memcpy(poses, fileDataPtr + iqmHeader->ofs_poses, iqmHeader->num_poses*sizeof(IQMPose)); // Get animations data *animCount = iqmHeader->num_anims; IQMAnim *anim = RL_MALLOC(iqmHeader->num_anims*sizeof(IQMAnim)); //fseek(iqmFile, iqmHeader->ofs_anims, SEEK_SET); - //fread(anim, iqmHeader->num_anims*sizeof(IQMAnim), 1, iqmFile); + //fread(anim, sizeof(IQMAnim), iqmHeader->num_anims, iqmFile); memcpy(anim, fileDataPtr + iqmHeader->ofs_anims, iqmHeader->num_anims*sizeof(IQMAnim)); ModelAnimation *animations = RL_MALLOC(iqmHeader->num_anims*sizeof(ModelAnimation)); @@ -4526,7 +4526,7 @@ static ModelAnimation *LoadModelAnimationsIQM(const char *fileName, unsigned int // frameposes unsigned short *framedata = RL_MALLOC(iqmHeader->num_frames*iqmHeader->num_framechannels*sizeof(unsigned short)); //fseek(iqmFile, iqmHeader->ofs_frames, SEEK_SET); - //fread(framedata, iqmHeader->num_frames*iqmHeader->num_framechannels*sizeof(unsigned short), 1, iqmFile); + //fread(framedata, sizeof(unsigned short), iqmHeader->num_frames*iqmHeader->num_framechannels, iqmFile); memcpy(framedata, fileDataPtr + iqmHeader->ofs_frames, iqmHeader->num_frames*iqmHeader->num_framechannels*sizeof(unsigned short)); // joints From 73c9f72c5229808fc564c878bd876d0f693f757d Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 25 Feb 2023 22:32:50 +0100 Subject: [PATCH 128/192] Update rtextures.c --- src/rtextures.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/rtextures.c b/src/rtextures.c index 7ae96c67f37f..f9b5c862dfff 100644 --- a/src/rtextures.c +++ b/src/rtextures.c @@ -296,7 +296,7 @@ Image LoadImageRaw(const char *fileName, int width, int height, int format, int Image LoadImageAnim(const char *fileName, int *frames) { Image image = { 0 }; - int frameCount = 1; + int frameCount = 0; #if defined(SUPPORT_FILEFORMAT_GIF) if (IsFileExtension(fileName, ".gif")) @@ -320,7 +320,11 @@ Image LoadImageAnim(const char *fileName, int *frames) #else if (false) { } #endif - else image = LoadImage(fileName); + else + { + image = LoadImage(fileName); + frameCount = 1; + } // TODO: Support APNG animated images From 394b31faffa0a1557f4860c31bc1168be0fc3022 Mon Sep 17 00:00:00 2001 From: Antonis Geralis <43617260+planetis-m@users.noreply.github.com> Date: Sun, 26 Feb 2023 13:01:42 +0200 Subject: [PATCH 129/192] Add GL_MIN GL_MAX blending equations (#2945) --- src/rlgl.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/rlgl.h b/src/rlgl.h index 7e9fee68a6cf..66a34964524f 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -298,6 +298,8 @@ // GL blending functions/equations #define RL_FUNC_ADD 0x8006 // GL_FUNC_ADD +#define RL_MIN 0x8007 // GL_MIN +#define RL_MAX 0x8008 // GL_MAX #define RL_FUNC_SUBTRACT 0x800A // GL_FUNC_SUBTRACT #define RL_FUNC_REVERSE_SUBTRACT 0x800B // GL_FUNC_REVERSE_SUBTRACT #define RL_BLEND_EQUATION 0x8009 // GL_BLEND_EQUATION From 6897b4359922ba5862eaaba159b24e734ff655ee Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 3 Mar 2023 20:13:35 +0100 Subject: [PATCH 130/192] REVIEWED: `core_drop_files` #2943 --- examples/core/core_drop_files.c | 44 ++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/examples/core/core_drop_files.c b/examples/core/core_drop_files.c index cfe03e1968bc..b591cdea7eb8 100644 --- a/examples/core/core_drop_files.c +++ b/examples/core/core_drop_files.c @@ -15,6 +15,11 @@ #include "raylib.h" +#include // Required for: calloc(), free() + +#define MAX_FILEPATH_RECORDED 4096 +#define MAX_FILEPATH_SIZE 2048 + //------------------------------------------------------------------------------------ // Program main entry point //------------------------------------------------------------------------------------ @@ -27,7 +32,14 @@ int main(void) InitWindow(screenWidth, screenHeight, "raylib [core] example - drop files"); - FilePathList droppedFiles = { 0 }; + int filePathCounter = 0; + char *filePaths[MAX_FILEPATH_RECORDED] = { 0 }; // We will register a maximum of filepaths + + // Allocate space for the required file paths + for (int i = 0; i < MAX_FILEPATH_RECORDED; i++) + { + filePaths[i] = (char *)RL_CALLOC(MAX_FILEPATH_SIZE, 1); + } SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- @@ -39,11 +51,18 @@ int main(void) //---------------------------------------------------------------------------------- if (IsFileDropped()) { - // Is some files have been previously loaded, unload them - if (droppedFiles.count > 0) UnloadDroppedFiles(droppedFiles); - - // Load new dropped files - droppedFiles = LoadDroppedFiles(); + FilePathList droppedFiles = LoadDroppedFiles(); + + for (int i = 0, offset = filePathCounter; i < droppedFiles.count; i++) + { + if (filePathCounter < (MAX_FILEPATH_RECORDED - 1)) + { + TextCopy(filePaths[offset + i], droppedFiles.paths[i]); + filePathCounter++; + } + } + + UnloadDroppedFiles(droppedFiles); // Unload filepaths from memory } //---------------------------------------------------------------------------------- @@ -53,20 +72,20 @@ int main(void) ClearBackground(RAYWHITE); - if (droppedFiles.count == 0) DrawText("Drop your files to this window!", 100, 40, 20, DARKGRAY); + if (filePathCounter == 0) DrawText("Drop your files to this window!", 100, 40, 20, DARKGRAY); else { DrawText("Dropped files:", 100, 40, 20, DARKGRAY); - for (unsigned int i = 0; i < droppedFiles.count; i++) + for (unsigned int i = 0; i < filePathCounter; i++) { if (i%2 == 0) DrawRectangle(0, 85 + 40*i, screenWidth, 40, Fade(LIGHTGRAY, 0.5f)); else DrawRectangle(0, 85 + 40*i, screenWidth, 40, Fade(LIGHTGRAY, 0.3f)); - DrawText(droppedFiles.paths[i], 120, 100 + 40*i, 10, GRAY); + DrawText(filePaths[i], 120, 100 + 40*i, 10, GRAY); } - DrawText("Drop new files...", 100, 110 + 40*droppedFiles.count, 20, DARKGRAY); + DrawText("Drop new files...", 100, 110 + 40*filePathCounter, 20, DARKGRAY); } EndDrawing(); @@ -75,7 +94,10 @@ int main(void) // De-Initialization //-------------------------------------------------------------------------------------- - UnloadDroppedFiles(droppedFiles); // Unload files memory + for (int i = 0; i < MAX_FILEPATH_RECORDED; i++) + { + RL_FREE(filePaths[i]); // Free allocated memory for all filepaths + } CloseWindow(); // Close window and OpenGL context //-------------------------------------------------------------------------------------- From 1611cd54e7f9a17bab14902ebe37bd8b2945449d Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 4 Mar 2023 18:56:04 +0100 Subject: [PATCH 131/192] REVIEWED: `GetWindowHandle()` #2938 --- src/rcore.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/rcore.c b/src/rcore.c index 443ef8e3a14f..6f4fa2951488 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -1718,7 +1718,8 @@ void *GetWindowHandle(void) // typedef unsigned long XID; // typedef XID Window; //unsigned long id = (unsigned long)glfwGetX11Window(window); - return NULL; // TODO: Find a way to return value... cast to void *? + //return NULL; // TODO: Find a way to return value... cast to void *? + return (void *)CORE.Window.handle; #endif #if defined(__APPLE__) // NOTE: Returned handle is: (objc_object *) From 5492f52adccbde94db221c1a5c7351deea1dfeec Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 5 Mar 2023 00:09:56 +0100 Subject: [PATCH 132/192] Change default threading model for COM objects It shouldn't matter much but it could avoid some conflicts with other libraries in the future (like `tinyfiledialogs`). --- src/raudio.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/raudio.c b/src/raudio.c index 04386167d5b9..b4b8b64e307b 100644 --- a/src/raudio.c +++ b/src/raudio.c @@ -168,6 +168,10 @@ typedef struct tagBITMAPINFOHEADER { #define MA_NO_WAV #define MA_NO_FLAC #define MA_NO_MP3 + +// Threading model: Default: [0] COINIT_MULTITHREADED: COM calls objects on any thread (free threading) +#define MA_COINIT_VALUE 2 // [2] COINIT_APARTMENTTHREADED: Each object has its own thread (apartment model) + #define MINIAUDIO_IMPLEMENTATION //#define MA_DEBUG_OUTPUT #include "external/miniaudio.h" // Audio device initialization and management From 0eeb499288b7c8f948588695e5927bfd07eabe07 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 5 Mar 2023 11:17:47 +0100 Subject: [PATCH 133/192] Update qoa.h --- src/external/qoa.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/external/qoa.h b/src/external/qoa.h index 65752d1b7c7a..59d90adedb60 100644 --- a/src/external/qoa.h +++ b/src/external/qoa.h @@ -22,12 +22,12 @@ not in the file header. A decoder may peek into the first frame of the file to find these values. In a valid QOA file all frames have the same number of channels and the same -samplerate. These restriction may be releaxed for streaming. This remains to +samplerate. These restrictions may be relaxed for streaming. This remains to be decided. All values in a QOA file are BIG ENDIAN. Luckily, EVERYTHING in a QOA file, including the headers, is 64 bit aligned, so it's possible to read files with -just a read_u64() that does the byte swapping if neccessary. +just a read_u64() that does the byte swapping if necessary. In pseudocode, the file layout is as follows: @@ -66,7 +66,7 @@ Wheras the 64bit qoa_slice_t is defined as follows: `sf_index` defines the scalefactor to use for this slice as an index into the qoa_scalefactor_tab[16] -`r00`--`r19` are the residuals for the individiual samples, divided by the +`r00`--`r19` are the residuals for the individual samples, divided by the scalefactor and quantized by the qoa_quant_tab[]. In the decoder, a prediction of the next sample is computed by multiplying the @@ -153,7 +153,7 @@ typedef unsigned long long qoa_uint64_t; /* The quant_tab provides an index into the dequant_tab for residuals in the -range of -8 .. 8. It maps this range to just 3bits and becommes less accurate at +range of -8 .. 8. It maps this range to just 3bits and becomes less accurate at the higher end. Note that the residual zero is identical to the lowest positive value. This is mostly fine, since the qoa_div() function always rounds away from zero. */ @@ -169,7 +169,7 @@ static int qoa_quant_tab[17] = { less accurate at the higher end. In theory, the highest scalefactor that we would need to encode the highest 16bit residual is (2**16)/8 = 8192. However we rely on the LMS filter to predict samples accurately enough that a maximum -residual of one quarter of the 16 bit range is high sufficent. I.e. with the +residual of one quarter of the 16 bit range is high sufficient. I.e. with the scalefactor 2048 times the quant range of 8 we can encode residuals up to 2**14. The scalefactor values are computed as: @@ -230,7 +230,7 @@ The next sample is predicted as the sum of (weight[i] * history[i]). The adjustment of the weights is done with a "Sign-Sign-LMS" that adds or subtracts the residual to each weight, based on the corresponding sample from -the history. This, suprisingly, is sufficent to get worthwhile predictions. +the history. This, surprisingly, is sufficient to get worthwhile predictions. This is all done with fixed point integers. Hence the right-shifts when updating the weights and calculating the prediction. */ @@ -369,7 +369,7 @@ unsigned int qoa_encode_frame(const short *sample_data, qoa_desc *qoa, unsigned int dequantized = qoa_dequant_tab[scalefactor][quantized]; int reconstructed = qoa_clamp(predicted + dequantized, -32768, 32767); - int error = (sample - reconstructed); + long long error = (sample - reconstructed); current_error += error * error; if (current_error > best_error) { break; From ab14ad5d754f7bbccbf8845b8062c8ece018b3e0 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 5 Mar 2023 11:26:37 +0100 Subject: [PATCH 134/192] Close issue #2949 --- src/rcore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rcore.c b/src/rcore.c index 6f4fa2951488..4efb20179b63 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -1713,7 +1713,7 @@ void *GetWindowHandle(void) // NOTE: Returned handle is: void *HWND (windows.h) return glfwGetWin32Window(CORE.Window.handle); #endif -#if defined(__linux__) +#if defined(__linux__) && !defined(PLATFORM_DRM) // NOTE: Returned handle is: unsigned long Window (X.h) // typedef unsigned long XID; // typedef XID Window; From 9614d3353b81b95adcfd01392c62326a8c512aee Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 5 Mar 2023 13:49:18 +0100 Subject: [PATCH 135/192] REVIEWED: QOA audio file export --- src/raudio.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/raudio.c b/src/raudio.c index b4b8b64e307b..207c0c490d99 100644 --- a/src/raudio.c +++ b/src/raudio.c @@ -1003,13 +1003,17 @@ bool ExportWave(Wave wave, const char *fileName) #if defined(SUPPORT_FILEFORMAT_QOA) else if (IsFileExtension(fileName, ".qoa")) { - qoa_desc qoa = { 0 }; - qoa.channels = wave.channels; - qoa.samplerate = wave.sampleRate; - qoa.samples = wave.frameCount; + if (wave.sampleSize == 16) + { + qoa_desc qoa = { 0 }; + qoa.channels = wave.channels; + qoa.samplerate = wave.sampleRate; + qoa.samples = wave.frameCount; - // TODO: Review wave.data format required for export - success = qoa_write(fileName, wave.data, &qoa); + int bytesWritten = qoa_write(fileName, 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"); } #endif else if (IsFileExtension(fileName, ".raw")) From f4f6e25340080e149deea5f640976dd8f7452d33 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 5 Mar 2023 14:07:02 +0100 Subject: [PATCH 136/192] Support QOA audio file format by default --- examples/audio/resources/target.qoa | Bin 0 -> 35648 bytes src/config.h | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 examples/audio/resources/target.qoa diff --git a/examples/audio/resources/target.qoa b/examples/audio/resources/target.qoa new file mode 100644 index 0000000000000000000000000000000000000000..d48c4f9f057083be25e82f944e6b08f5c6ffb5e6 GIT binary patch literal 35648 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 Oa$vL^7%d0LF9!e{3+BQA literal 0 HcmV?d00001 diff --git a/src/config.h b/src/config.h index d5f8e486cdeb..de9f4641a563 100644 --- a/src/config.h +++ b/src/config.h @@ -214,7 +214,7 @@ #define SUPPORT_FILEFORMAT_WAV 1 #define SUPPORT_FILEFORMAT_OGG 1 #define SUPPORT_FILEFORMAT_MP3 1 -//#define SUPPORT_FILEFORMAT_QOA 1 +#define SUPPORT_FILEFORMAT_QOA 1 //#define SUPPORT_FILEFORMAT_FLAC 1 #define SUPPORT_FILEFORMAT_XM 1 #define SUPPORT_FILEFORMAT_MOD 1 From d3f5bc40436ef45aee2cc353f985d4ad5fc57bbd Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 5 Mar 2023 20:06:45 +0100 Subject: [PATCH 137/192] REVIEWED: `GetWindowHandle()` #2950 --- src/rcore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rcore.c b/src/rcore.c index 4efb20179b63..4f3d98b0fa41 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -1713,7 +1713,7 @@ void *GetWindowHandle(void) // NOTE: Returned handle is: void *HWND (windows.h) return glfwGetWin32Window(CORE.Window.handle); #endif -#if defined(__linux__) && !defined(PLATFORM_DRM) +#if defined(PLATFORM_DESKTOP) && defined(__linux__) // NOTE: Returned handle is: unsigned long Window (X.h) // typedef unsigned long XID; // typedef XID Window; From 68ee0bb8dd43074574dab08d836eaeba58bd0351 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 6 Mar 2023 12:33:49 +0100 Subject: [PATCH 138/192] ADDED: QOA music streaming (with auxiliar lib) Some format tweaks --- src/external/qoaplay.c | 278 +++++++++++++++++++++++++++++++++++++++++ src/raudio.c | 157 +++++++++++------------ 2 files changed, 357 insertions(+), 78 deletions(-) create mode 100644 src/external/qoaplay.c diff --git a/src/external/qoaplay.c b/src/external/qoaplay.c new file mode 100644 index 000000000000..b4dc09c7e424 --- /dev/null +++ b/src/external/qoaplay.c @@ -0,0 +1,278 @@ +/******************************************************************************************* +* +* qoaplay - QOA stream playing helper functions +* +* qoaplay is a tiny abstraction to read and decode a QOA file "on the fly". +* It reads and decodes one frame at a time with minimal memory requirements. +* qoaplay also provides some functions to seek to a specific frame. +* +* LICENSE: MIT License +* +* Copyright (c) 2023 Dominic Szablewski (@phoboslab), 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. +* +**********************************************************************************************/ + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- +// QOA streaming data descriptor +typedef struct { + qoa_desc info; // QOA descriptor data + + FILE *file; // QOA file to read, if NULL, using memory buffer -> file_data + unsigned char *file_data; // QOA file data on memory + unsigned int file_data_size; // QOA file data on memory size + unsigned int file_data_offset; // QOA file data on memory offset for next read + + unsigned int first_frame_pos; // First frame position (after QOA header, required for offset) + unsigned int sample_position; // Current streaming sample position + + unsigned char *buffer; // Buffer used to read samples from file/memory (used on decoding) + unsigned int buffer_len; // Buffer length to read samples for streaming + + short *sample_data; // Sample data decoded + unsigned int sample_data_len; // Sample data decoded length + unsigned int sample_data_pos; // Sample data decoded position + +} qoaplay_desc; + +//---------------------------------------------------------------------------------- +// Module Functions Declaration +//---------------------------------------------------------------------------------- + +#if defined(__cplusplus) +extern "C" { // Prevents name mangling of functions +#endif + +qoaplay_desc *qoaplay_open(char *path); +qoaplay_desc *qoaplay_open_memory(const unsigned char *data, int data_size); +void qoaplay_close(qoaplay_desc *qoa_ctx); + +void qoaplay_rewind(qoaplay_desc *qoa_ctx); +void qoaplay_seek_frame(qoaplay_desc *qoa_ctx, int frame); +unsigned int qoaplay_decode(qoaplay_desc *qoa_ctx, float *sample_data, int num_samples); +unsigned int qoaplay_decode_frame(qoaplay_desc *qoa_ctx); +double qoaplay_get_duration(qoaplay_desc *qoa_ctx); +double qoaplay_get_time(qoaplay_desc *qoa_ctx); +int qoaplay_get_frame(qoaplay_desc *qoa_ctx); + +#if defined(__cplusplus) +} // Prevents name mangling of functions +#endif + +//---------------------------------------------------------------------------------- +// Module Functions Definition +//---------------------------------------------------------------------------------- + +// Open QOA file, keep FILE pointer to keep reading from file +qoaplay_desc *qoaplay_open(char *path) +{ + FILE *file = fopen(path, "rb"); + if (!file) return NULL; + + // Read and decode the file header + unsigned char header[QOA_MIN_FILESIZE]; + int read = fread(header, QOA_MIN_FILESIZE, 1, file); + if (!read) return NULL; + + qoa_desc qoa; + unsigned int first_frame_pos = qoa_decode_header(header, QOA_MIN_FILESIZE, &qoa); + if (!first_frame_pos) return NULL; + + // Rewind the file back to beginning of the first frame + fseek(file, first_frame_pos, SEEK_SET); + + // Allocate one chunk of memory for the qoaplay_desc struct + // + the sample data for one frame + // + 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); + memset(qoa_ctx, 0, sizeof(qoaplay_desc)); + + qoa_ctx->file = file; + qoa_ctx->file_data = NULL; + qoa_ctx->file_data_size = 0; + qoa_ctx->file_data_offset = 0; + qoa_ctx->first_frame_pos = first_frame_pos; + + // Setup data pointers to previously allocated data + qoa_ctx->buffer = ((unsigned char *)qoa_ctx) + sizeof(qoaplay_desc); + qoa_ctx->sample_data = (short *)(((unsigned char *)qoa_ctx) + sizeof(qoaplay_desc) + buffer_size); + + qoa_ctx->info.channels = qoa.channels; + qoa_ctx->info.samplerate = qoa.samplerate; + qoa_ctx->info.samples = qoa.samples; + + return qoa_ctx; +} + +// Open QOA file from memory, no FILE pointer required +qoaplay_desc *qoaplay_open_memory(const unsigned char *data, int data_size) +{ + // Read and decode the file header + unsigned char header[QOA_MIN_FILESIZE]; + memcpy(header, data, QOA_MIN_FILESIZE); + + qoa_desc qoa; + unsigned int first_frame_pos = qoa_decode_header(header, QOA_MIN_FILESIZE, &qoa); + if (!first_frame_pos) return NULL; + + // Allocate one chunk of memory for the qoaplay_desc struct + // + the sample data for one frame + // + 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); + memset(qoa_ctx, 0, sizeof(qoaplay_desc)); + + qoa_ctx->file = NULL; + + // Keep a copy of file data provided to be managed internally + qoa_ctx->file_data = (unsigned char *)QOA_MALLOC(data_size); + memcpy(qoa_ctx->file_data, data, data_size); + qoa_ctx->file_data_size = data_size; + qoa_ctx->file_data_offset = 0; + qoa_ctx->first_frame_pos = first_frame_pos; + + // Setup data pointers to previously allocated data + qoa_ctx->buffer = ((unsigned char *)qoa_ctx) + sizeof(qoaplay_desc); + qoa_ctx->sample_data = (short *)(((unsigned char *)qoa_ctx) + sizeof(qoaplay_desc) + buffer_size); + + qoa_ctx->info.channels = qoa.channels; + qoa_ctx->info.samplerate = qoa.samplerate; + qoa_ctx->info.samples = qoa.samples; + + return qoa_ctx; +} + +// Close QOA file (if open) and free internal memory +void qoaplay_close(qoaplay_desc *qoa_ctx) +{ + if (qoa_ctx->file) fclose(qoa_ctx->file); + + if ((qoa_ctx->file_data) && (qoa_ctx->file_data_size > 0)) + { + QOA_FREE(qoa_ctx->file_data); + qoa_ctx->file_data_size = 0; + } + + QOA_FREE(qoa_ctx); +} + +// Decode one frame from QOA data +unsigned int qoaplay_decode_frame(qoaplay_desc *qoa_ctx) +{ + if (qoa_ctx->file) qoa_ctx->buffer_len = fread(qoa_ctx->buffer, 1, qoa_max_frame_size(&qoa_ctx->info), qoa_ctx->file); + else + { + qoa_ctx->buffer_len = qoa_max_frame_size(&qoa_ctx->info); + memcpy(qoa_ctx->buffer, qoa_ctx->file_data + qoa_ctx->file_data_offset, qoa_ctx->buffer_len); + qoa_ctx->file_data_offset += qoa_ctx->buffer_len; + } + + unsigned int frame_len; + qoa_decode_frame(qoa_ctx->buffer, qoa_ctx->buffer_len, &qoa_ctx->info, qoa_ctx->sample_data, &frame_len); + qoa_ctx->sample_data_pos = 0; + qoa_ctx->sample_data_len = frame_len; + + return frame_len; +} + +// Rewind QOA file or memory pointer to beginning +void qoaplay_rewind(qoaplay_desc *qoa_ctx) +{ + if (qoa_ctx->file) fseek(qoa_ctx->file, qoa_ctx->first_frame_pos, SEEK_SET); + else qoa_ctx->file_data_offset = 0; + + qoa_ctx->sample_position = 0; + qoa_ctx->sample_data_len = 0; + qoa_ctx->sample_data_pos = 0; +} + +// Decode required QOA frames +unsigned int qoaplay_decode(qoaplay_desc *qoa_ctx, float *sample_data, int num_samples) +{ + int src_index = qoa_ctx->sample_data_pos*qoa_ctx->info.channels; + int dst_index = 0; + + for (int i = 0; i < num_samples; i++) + { + // Do we have to decode more samples? + if (qoa_ctx->sample_data_len - qoa_ctx->sample_data_pos == 0) + { + if (!qoaplay_decode_frame(qoa_ctx)) + { + // Loop to the beginning + qoaplay_rewind(qoa_ctx); + qoaplay_decode_frame(qoa_ctx); + } + + src_index = 0; + } + + // Normalize to -1..1 floats and write to dest + for (int c = 0; c < qoa_ctx->info.channels; c++) + { + sample_data[dst_index++] = qoa_ctx->sample_data[src_index++]/32768.0; + } + + qoa_ctx->sample_data_pos++; + qoa_ctx->sample_position++; + } + + return num_samples; +} + +// Get QOA total time duration in seconds +double qoaplay_get_duration(qoaplay_desc *qoa_ctx) +{ + return (double)qoa_ctx->info.samples/(double)qoa_ctx->info.samplerate; +} + +// Get QOA current time position in seconds +double qoaplay_get_time(qoaplay_desc *qoa_ctx) +{ + return (double)qoa_ctx->sample_position/(double)qoa_ctx->info.samplerate; +} + +// Get QOA current audio frame +int qoaplay_get_frame(qoaplay_desc *qoa_ctx) +{ + return qoa_ctx->sample_position/QOA_FRAME_LEN; +} + +// Seek QOA audio frame +void qoaplay_seek_frame(qoaplay_desc *qoa_ctx, int frame) +{ + if (frame < 0) frame = 0; + + if (frame > qoa_ctx->info.samples/QOA_FRAME_LEN) frame = qoa_ctx->info.samples/QOA_FRAME_LEN; + + qoa_ctx->sample_position = frame*QOA_FRAME_LEN; + qoa_ctx->sample_data_len = 0; + qoa_ctx->sample_data_pos = 0; + + unsigned int offset = qoa_ctx->first_frame_pos + frame*qoa_max_frame_size(&qoa_ctx->info); + + if (qoa_ctx->file) fseek(qoa_ctx->file, offset, SEEK_SET); + else qoa_ctx->file_data_offset = offset; +} diff --git a/src/raudio.c b/src/raudio.c index 207c0c490d99..03e4bcbaa867 100644 --- a/src/raudio.c +++ b/src/raudio.c @@ -230,6 +230,7 @@ typedef struct tagBITMAPINFOHEADER { #define QOA_IMPLEMENTATION #include "external/qoa.h" // QOA loading and saving functions + #include "external/qoaplay.c" // QOA stream playing helper functions #endif #if defined(SUPPORT_FILEFORMAT_FLAC) @@ -287,21 +288,6 @@ typedef struct tagBITMAPINFOHEADER { //---------------------------------------------------------------------------------- // Types and Structures Definition //---------------------------------------------------------------------------------- - -// Music context type -// NOTE: Depends on data structure provided by the library -// in charge of reading the different file types -typedef enum { - MUSIC_AUDIO_NONE = 0, // No audio context loaded - MUSIC_AUDIO_WAV, // WAV audio context - MUSIC_AUDIO_OGG, // OGG audio context - MUSIC_AUDIO_FLAC, // FLAC audio context - MUSIC_AUDIO_MP3, // MP3 audio context - MUSIC_AUDIO_QOA, // QOA audio context - MUSIC_MODULE_XM, // XM module audio context - MUSIC_MODULE_MOD // MOD module audio context -} MusicContextType; - #if defined(RAUDIO_STANDALONE) // Trace log level // NOTE: Organized by priority level @@ -317,6 +303,20 @@ typedef enum { } TraceLogLevel; #endif +// Music context type +// NOTE: Depends on data structure provided by the library +// in charge of reading the different file types +typedef enum { + MUSIC_AUDIO_NONE = 0, // No audio context loaded + MUSIC_AUDIO_WAV, // WAV audio context + MUSIC_AUDIO_OGG, // OGG audio context + MUSIC_AUDIO_FLAC, // FLAC audio context + MUSIC_AUDIO_MP3, // MP3 audio context + MUSIC_AUDIO_QOA, // QOA audio context + MUSIC_MODULE_XM, // XM module audio context + MUSIC_MODULE_MOD // MOD module audio context +} MusicContextType; + // NOTE: Different logic is used when feeding data to the playback device // depending on whether data is streamed (Music vs Sound) typedef enum { @@ -1322,7 +1322,7 @@ void UnloadWaveSamples(float *samples) } //---------------------------------------------------------------------------------- -// Module Functions Definition - Music loading and stream playing (.OGG) +// Module Functions Definition - Music loading and stream playing //---------------------------------------------------------------------------------- // Load music stream from file @@ -1395,21 +1395,16 @@ Music LoadMusicStream(const char *fileName) #if defined(SUPPORT_FILEFORMAT_QOA) else if (IsFileExtension(fileName, ".qoa")) { - qoa_desc *ctxQoa = RL_CALLOC(1, sizeof(qoa_desc)); - - // TODO: QOA stream support: Init context from file - int result = 0; - + qoaplay_desc *ctxQoa = qoaplay_open(fileName); music.ctxType = MUSIC_AUDIO_QOA; music.ctxData = ctxQoa; - if (result > 0) + if (ctxQoa->file != NULL) { - music.stream = LoadAudioStream(ctxQoa->samplerate, 16, ctxQoa->channels); - - // TODO: Read next frame(s) from QOA stream - //music.frameCount = qoa_decode_frame(const unsigned char *bytes, unsigned int size, ctxQoa, short *sample_data, unsigned int *frame_len); - + // NOTE: We are loading samples are 32bit float normalized data, so, + // we configure the output audio stream to also use float 32bit + music.stream = LoadAudioStream(ctxQoa->info.samplerate, 32, ctxQoa->info.channels); + music.frameCount = ctxQoa->info.samples; music.looping = true; // Looping enabled by default musicLoaded = true; } @@ -1594,21 +1589,16 @@ Music LoadMusicStreamFromMemory(const char *fileType, const unsigned char *data, #if defined(SUPPORT_FILEFORMAT_QOA) else if (strcmp(fileType, ".qoa") == 0) { - qoa_desc *ctxQoa = RL_CALLOC(1, sizeof(qoa_desc)); - - // TODO: Init QOA context data - int result = 0; - + qoaplay_desc *ctxQoa = qoaplay_open_memory(data, dataSize); music.ctxType = MUSIC_AUDIO_QOA; music.ctxData = ctxQoa; - if (result > 0) + if ((ctxQoa->file_data != NULL) && (ctxQoa->file_data_size != 0)) { - music.stream = LoadAudioStream(ctxQoa->samplerate, 16, ctxQoa->channels); - - // TODO: Read next frame(s) from QOA stream - //music.frameCount = qoa_decode_frame(const unsigned char *bytes, unsigned int size, ctxQoa, short *sample_data, unsigned int *frame_len); - + // NOTE: We are loading samples are 32bit float normalized data, so, + // we configure the output audio stream to also use float 32bit + music.stream = LoadAudioStream(ctxQoa->info.samplerate, 32, ctxQoa->info.channels); + music.frameCount = ctxQoa->info.samples; music.looping = true; // Looping enabled by default musicLoaded = true; } @@ -1697,27 +1687,27 @@ Music LoadMusicStreamFromMemory(const char *fileType, const unsigned char *data, if (!musicLoaded) { if (false) { } - #if defined(SUPPORT_FILEFORMAT_WAV) +#if defined(SUPPORT_FILEFORMAT_WAV) else if (music.ctxType == MUSIC_AUDIO_WAV) drwav_uninit((drwav *)music.ctxData); - #endif - #if defined(SUPPORT_FILEFORMAT_OGG) +#endif +#if defined(SUPPORT_FILEFORMAT_OGG) else if (music.ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close((stb_vorbis *)music.ctxData); - #endif - #if defined(SUPPORT_FILEFORMAT_MP3) +#endif +#if defined(SUPPORT_FILEFORMAT_MP3) else if (music.ctxType == MUSIC_AUDIO_MP3) { drmp3_uninit((drmp3 *)music.ctxData); RL_FREE(music.ctxData); } - #endif - #if defined(SUPPORT_FILEFORMAT_QOA) - else if (music.ctxType == MUSIC_AUDIO_QOA) { /*TODO: Release QOA context*/ RL_FREE(music.ctxData); } - #endif - #if defined(SUPPORT_FILEFORMAT_FLAC) +#endif +#if defined(SUPPORT_FILEFORMAT_QOA) + else if (music.ctxType == MUSIC_AUDIO_QOA) qoaplay_close((qoaplay_desc *)music.ctxData); +#endif +#if defined(SUPPORT_FILEFORMAT_FLAC) else if (music.ctxType == MUSIC_AUDIO_FLAC) drflac_free((drflac *)music.ctxData, NULL); - #endif - #if defined(SUPPORT_FILEFORMAT_XM) +#endif +#if defined(SUPPORT_FILEFORMAT_XM) else if (music.ctxType == MUSIC_MODULE_XM) jar_xm_free_context((jar_xm_context_t *)music.ctxData); - #endif - #if defined(SUPPORT_FILEFORMAT_MOD) +#endif +#if defined(SUPPORT_FILEFORMAT_MOD) else if (music.ctxType == MUSIC_MODULE_MOD) { jar_mod_unload((jar_mod_context_t *)music.ctxData); RL_FREE(music.ctxData); } - #endif +#endif music.ctxData = NULL; TRACELOG(LOG_WARNING, "FILEIO: Music data could not be loaded"); @@ -1763,7 +1753,7 @@ void UnloadMusicStream(Music music) else if (music.ctxType == MUSIC_AUDIO_MP3) { drmp3_uninit((drmp3 *)music.ctxData); RL_FREE(music.ctxData); } #endif #if defined(SUPPORT_FILEFORMAT_QOA) - else if (music.ctxType == MUSIC_AUDIO_QOA) { /*TODO: Release QOA context*/ RL_FREE(music.ctxData); } + else if (music.ctxType == MUSIC_AUDIO_QOA) qoaplay_close((qoaplay_desc *)music.ctxData); #endif #if defined(SUPPORT_FILEFORMAT_FLAC) else if (music.ctxType == MUSIC_AUDIO_FLAC) drflac_free((drflac *)music.ctxData, NULL); @@ -1821,7 +1811,7 @@ void StopMusicStream(Music music) case MUSIC_AUDIO_MP3: drmp3_seek_to_start_of_stream((drmp3 *)music.ctxData); break; #endif #if defined(SUPPORT_FILEFORMAT_QOA) - case MUSIC_AUDIO_QOA: /*TODO: Restart QOA context to beginning*/ break; + case MUSIC_AUDIO_QOA: qoaplay_rewind((qoaplay_desc *)music.ctxData); break; #endif #if defined(SUPPORT_FILEFORMAT_FLAC) case MUSIC_AUDIO_FLAC: drflac__seek_to_first_frame((drflac *)music.ctxData); break; @@ -1856,7 +1846,7 @@ void SeekMusicStream(Music music, float position) case MUSIC_AUDIO_MP3: drmp3_seek_to_pcm_frame((drmp3 *)music.ctxData, positionInFrames); break; #endif #if defined(SUPPORT_FILEFORMAT_QOA) - case MUSIC_AUDIO_QOA: /*TODO: Seek to specific QOA frame*/ break; + case MUSIC_AUDIO_QOA: qoaplay_seek_frame((qoaplay_desc *)music.ctxData, positionInFrames); break; #endif #if defined(SUPPORT_FILEFORMAT_FLAC) case MUSIC_AUDIO_FLAC: drflac_seek_to_pcm_frame((drflac *)music.ctxData, positionInFrames); break; @@ -1892,11 +1882,13 @@ void UpdateMusicStream(Music music) unsigned int framesLeft = music.frameCount - music.stream.buffer->framesProcessed; // Frames left to be processed unsigned int framesToStream = 0; // Total frames to be streamed + if ((framesLeft >= subBufferSizeInFrames) || music.looping) framesToStream = subBufferSizeInFrames; else framesToStream = framesLeft; int frameCountStillNeeded = framesToStream; - int frameCountRedTotal = 0; + int frameCountReadTotal = 0; + switch (music.ctxType) { #if defined(SUPPORT_FILEFORMAT_WAV) @@ -1906,8 +1898,8 @@ void UpdateMusicStream(Music music) { while (true) { - int frameCountRed = (int)drwav_read_pcm_frames_s16((drwav *)music.ctxData, frameCountStillNeeded, (short *)((char *)AUDIO.System.pcmBuffer + frameCountRedTotal*frameSize)); - frameCountRedTotal += frameCountRed; + int frameCountRed = (int)drwav_read_pcm_frames_s16((drwav *)music.ctxData, frameCountStillNeeded, (short *)((char *)AUDIO.System.pcmBuffer + frameCountReadTotal*frameSize)); + frameCountReadTotal += frameCountRed; frameCountStillNeeded -= frameCountRed; if (frameCountStillNeeded == 0) break; else drwav_seek_to_first_pcm_frame((drwav *)music.ctxData); @@ -1917,8 +1909,8 @@ void UpdateMusicStream(Music music) { while (true) { - int frameCountRed = (int)drwav_read_pcm_frames_f32((drwav *)music.ctxData, frameCountStillNeeded, (float *)((char *)AUDIO.System.pcmBuffer + frameCountRedTotal*frameSize)); - frameCountRedTotal += frameCountRed; + int frameCountRed = (int)drwav_read_pcm_frames_f32((drwav *)music.ctxData, frameCountStillNeeded, (float *)((char *)AUDIO.System.pcmBuffer + frameCountReadTotal*frameSize)); + frameCountReadTotal += frameCountRed; frameCountStillNeeded -= frameCountRed; if (frameCountStillNeeded == 0) break; else drwav_seek_to_first_pcm_frame((drwav *)music.ctxData); @@ -1931,8 +1923,8 @@ void UpdateMusicStream(Music music) { while (true) { - int frameCountRed = stb_vorbis_get_samples_short_interleaved((stb_vorbis *)music.ctxData, music.stream.channels, (short *)((char *)AUDIO.System.pcmBuffer + frameCountRedTotal*frameSize), frameCountStillNeeded*music.stream.channels); - frameCountRedTotal += frameCountRed; + int frameCountRed = stb_vorbis_get_samples_short_interleaved((stb_vorbis *)music.ctxData, music.stream.channels, (short *)((char *)AUDIO.System.pcmBuffer + frameCountReadTotal*frameSize), frameCountStillNeeded*music.stream.channels); + frameCountReadTotal += frameCountRed; frameCountStillNeeded -= frameCountRed; if (frameCountStillNeeded == 0) break; else stb_vorbis_seek_start((stb_vorbis *)music.ctxData); @@ -1944,9 +1936,9 @@ void UpdateMusicStream(Music music) { while (true) { - int frameCountRed = (int)drmp3_read_pcm_frames_f32((drmp3 *)music.ctxData, frameCountStillNeeded, (float *)((char *)AUDIO.System.pcmBuffer + frameCountRedTotal*frameSize)); - frameCountRedTotal += frameCountRed; - frameCountStillNeeded -= frameCountRed; + int frameCountRead = (int)drmp3_read_pcm_frames_f32((drmp3 *)music.ctxData, frameCountStillNeeded, (float *)((char *)AUDIO.System.pcmBuffer + frameCountReadTotal*frameSize)); + frameCountReadTotal += frameCountRead; + frameCountStillNeeded -= frameCountRead; if (frameCountStillNeeded == 0) break; else drmp3_seek_to_start_of_stream((drmp3 *)music.ctxData); } @@ -1955,7 +1947,18 @@ void UpdateMusicStream(Music music) #if defined(SUPPORT_FILEFORMAT_QOA) case MUSIC_AUDIO_QOA: { - // TODO: Read QOA required framecount to fill buffer to keep music playing + unsigned int frameCountRead = qoaplay_decode((qoaplay_desc *)music.ctxData, (float *)AUDIO.System.pcmBuffer, framesToStream); + frameCountReadTotal += frameCountRead; + /* + while (true) + { + int frameCountRead = (int)qoaplay_decode((qoaplay_desc *)music.ctxData, (float *)((char *)AUDIO.System.pcmBuffer + frameCountReadTotal*frameSize), frameCountStillNeeded); + frameCountReadTotal += frameCountRead; + frameCountStillNeeded -= frameCountRead; + if (frameCountStillNeeded == 0) break; + else qoaplay_rewind((qoaplay_desc *)music.ctxData); + } + */ } break; #endif #if defined(SUPPORT_FILEFORMAT_FLAC) @@ -1964,8 +1967,8 @@ void UpdateMusicStream(Music music) while (true) { int frameCountRed = drflac_read_pcm_frames_s16((drflac *)music.ctxData, frameCountStillNeeded, (short *)((char *)AUDIO.System.pcmBuffer + frameCountRedTotal*frameSize)); - frameCountRedTotal += frameCountRed; - frameCountStillNeeded -= frameCountRed; + frameCountReadTotal += frameCountRead; + frameCountStillNeeded -= frameCountRead; if (frameCountStillNeeded == 0) break; else drflac__seek_to_first_frame((drflac *)music.ctxData); } @@ -1978,7 +1981,6 @@ void UpdateMusicStream(Music music) if (AUDIO_DEVICE_FORMAT == ma_format_f32) jar_xm_generate_samples((jar_xm_context_t *)music.ctxData, (float *)AUDIO.System.pcmBuffer, framesToStream); else if (AUDIO_DEVICE_FORMAT == ma_format_s16) jar_xm_generate_samples_16bit((jar_xm_context_t *)music.ctxData, (short *)AUDIO.System.pcmBuffer, framesToStream); else if (AUDIO_DEVICE_FORMAT == ma_format_u8) jar_xm_generate_samples_8bit((jar_xm_context_t *)music.ctxData, (char *)AUDIO.System.pcmBuffer, framesToStream); - //jar_xm_reset((jar_xm_context_t *)music.ctxData); } break; @@ -1988,7 +1990,6 @@ void UpdateMusicStream(Music music) { // NOTE: 3rd parameter (nbsample) specify the number of stereo 16bits samples you want, so sampleCount/2 jar_mod_fillbuffer((jar_mod_context_t *)music.ctxData, (short *)AUDIO.System.pcmBuffer, framesToStream, 0); - //jar_mod_seek_start((jar_mod_context_t *)music.ctxData); } break; @@ -2056,7 +2057,7 @@ float GetMusicTimePlayed(Music music) float secondsPlayed = 0.0f; if (music.stream.buffer != NULL) { - #if defined(SUPPORT_FILEFORMAT_XM) +#if defined(SUPPORT_FILEFORMAT_XM) if (music.ctxType == MUSIC_MODULE_XM) { uint64_t framesPlayed = 0; @@ -2065,7 +2066,7 @@ float GetMusicTimePlayed(Music music) secondsPlayed = (float)framesPlayed/music.stream.sampleRate; } else - #endif +#endif { //ma_uint32 frameSizeInBytes = ma_get_bytes_per_sample(music.stream.buffer->dsp.formatConverterIn.config.formatIn)*music.stream.buffer->dsp.formatConverterIn.config.channels; int framesProcessed = (int)music.stream.buffer->framesProcessed; @@ -2115,7 +2116,7 @@ AudioStream LoadAudioStream(unsigned int sampleRate, unsigned int sampleSize, un } // Checks if an audio stream is ready -RLAPI bool IsAudioStreamReady(AudioStream stream) +bool IsAudioStreamReady(AudioStream stream) { return ((stream.buffer != NULL) && // Validate stream buffer (stream.sampleRate > 0) && // Validate sample rate is supported @@ -2277,6 +2278,7 @@ void AttachAudioStreamProcessor(AudioStream stream, AudioCallback process) ma_mutex_unlock(&AUDIO.System.lock); } +// Remove processor from audio stream void DetachAudioStreamProcessor(AudioStream stream, AudioCallback process) { ma_mutex_lock(&AUDIO.System.lock); @@ -2304,9 +2306,8 @@ void DetachAudioStreamProcessor(AudioStream stream, AudioCallback process) } // Add processor to audio pipeline. Order of processors is important -// Works the same way as {Attach,Detach}AudioStreamProcessor functions, except -// these two work on the already mixed output just before sending it to the -// sound hardware. +// Works the same way as {Attach,Detach}AudioStreamProcessor() functions, except +// these two work on the already mixed output just before sending it to the sound hardware void AttachAudioMixedProcessor(AudioCallback process) { ma_mutex_lock(&AUDIO.System.lock); @@ -2330,6 +2331,7 @@ void AttachAudioMixedProcessor(AudioCallback process) ma_mutex_unlock(&AUDIO.System.lock); } +// Remove processor from audio pipeline void DetachAudioMixedProcessor(AudioCallback process) { ma_mutex_lock(&AUDIO.System.lock); @@ -2508,7 +2510,6 @@ static ma_uint32 ReadAudioBufferFramesInMixingFormat(AudioBuffer *audioBuffer, f return totalOutputFramesProcessed; } - // Sending audio data to device callback function // This function will be called when miniaudio needs more data // NOTE: All the mixing takes place here From aae7ab64c7a6b4e7e040b21736710843086b35a0 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 6 Mar 2023 13:00:30 +0100 Subject: [PATCH 139/192] Update raudio.c --- src/raudio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/raudio.c b/src/raudio.c index 03e4bcbaa867..8bd9052c2ee3 100644 --- a/src/raudio.c +++ b/src/raudio.c @@ -1966,7 +1966,7 @@ void UpdateMusicStream(Music music) { while (true) { - int frameCountRed = drflac_read_pcm_frames_s16((drflac *)music.ctxData, frameCountStillNeeded, (short *)((char *)AUDIO.System.pcmBuffer + frameCountRedTotal*frameSize)); + int frameCountRead = drflac_read_pcm_frames_s16((drflac *)music.ctxData, frameCountStillNeeded, (short *)((char *)AUDIO.System.pcmBuffer + frameCountReadTotal*frameSize)); frameCountReadTotal += frameCountRead; frameCountStillNeeded -= frameCountRead; if (frameCountStillNeeded == 0) break; From cf1ebada0e0c18a02d48f091091418ce7b020b1e Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 6 Mar 2023 13:15:13 +0100 Subject: [PATCH 140/192] Tweak `WindowDropCallback()` #2943 --- src/rcore.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/src/rcore.c b/src/rcore.c index 4f3d98b0fa41..071915cf787d 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -5598,25 +5598,28 @@ static void CursorEnterCallback(GLFWwindow *window, int enter) // GLFW3 Window Drop Callback, runs when drop files into window static void WindowDropCallback(GLFWwindow *window, int count, const char **paths) { - // In case previous dropped filepaths have not been freed, we free them - if (CORE.Window.dropFileCount > 0) + if (count > 0) { - for (unsigned int i = 0; i < CORE.Window.dropFileCount; i++) RL_FREE(CORE.Window.dropFilepaths[i]); + // In case previous dropped filepaths have not been freed, we free them + if (CORE.Window.dropFileCount > 0) + { + for (unsigned int i = 0; i < CORE.Window.dropFileCount; i++) RL_FREE(CORE.Window.dropFilepaths[i]); - RL_FREE(CORE.Window.dropFilepaths); + RL_FREE(CORE.Window.dropFilepaths); - CORE.Window.dropFileCount = 0; - CORE.Window.dropFilepaths = NULL; - } + CORE.Window.dropFileCount = 0; + CORE.Window.dropFilepaths = NULL; + } - // WARNING: Paths are freed by GLFW when the callback returns, we must keep an internal copy - CORE.Window.dropFileCount = count; - CORE.Window.dropFilepaths = (char **)RL_CALLOC(CORE.Window.dropFileCount, sizeof(char *)); + // WARNING: Paths are freed by GLFW when the callback returns, we must keep an internal copy + CORE.Window.dropFileCount = count; + CORE.Window.dropFilepaths = (char **)RL_CALLOC(CORE.Window.dropFileCount, sizeof(char *)); - for (unsigned int i = 0; i < CORE.Window.dropFileCount; i++) - { - CORE.Window.dropFilepaths[i] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char)); - strcpy(CORE.Window.dropFilepaths[i], paths[i]); + for (unsigned int i = 0; i < CORE.Window.dropFileCount; i++) + { + CORE.Window.dropFilepaths[i] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char)); + strcpy(CORE.Window.dropFilepaths[i], paths[i]); + } } } #endif From 614e0518a7740bb900539e8c92517acaf052232c Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 6 Mar 2023 14:58:58 +0100 Subject: [PATCH 141/192] Remove trailing spaces --- examples/Makefile | 10 +++++----- examples/core/core_drop_files.c | 4 ++-- src/external/qoaplay.c | 32 ++++++++++++++++---------------- src/rcamera.h | 12 ++++++------ src/rcore.c | 6 +++--- src/rtextures.c | 10 +++++----- 6 files changed, 37 insertions(+), 37 deletions(-) diff --git a/examples/Makefile b/examples/Makefile index 574975d231ea..0b524015ff14 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -297,17 +297,17 @@ ifeq ($(PLATFORM),PLATFORM_WEB) # --preload-file resources # specify a resources folder for data compilation # --source-map-base # allow debugging in browser with source map LDFLAGS += -s USE_GLFW=3 -s TOTAL_MEMORY=$(BUILD_WEB_HEAP_SIZE) -s FORCE_FILESYSTEM=1 - + # Build using asyncify ifeq ($(BUILD_WEB_ASYNCIFY),TRUE) LDFLAGS += -s ASYNCIFY endif - + # Add resources building if required ifeq ($(BUILD_WEB_RESOURCES),TRUE) LDFLAGS += --preload-file $(BUILD_WEB_RESOURCES_PATH) endif - + # Add debug mode flags if required ifeq ($(BUILD_MODE),DEBUG) LDFLAGS += -s ASSERTIONS=1 --profiling @@ -316,7 +316,7 @@ ifeq ($(PLATFORM),PLATFORM_WEB) # Define a custom shell .html and output extension LDFLAGS += --shell-file $(BUILD_WEB_SHELL) EXT = .html - + # NOTE: Simple raylib examples are compiled to be interpreter with asyncify, that way, # we can compile same code for ALL platforms with no change required, but, working on bigger # projects, code needs to be refactored to avoid a blocking while() loop, moving Update and Draw @@ -354,7 +354,7 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP) ifeq ($(RAYLIB_LIBTYPE),SHARED) LDLIBS += -lc endif - + # NOTE: On ARM 32bit arch, miniaudio requires atomics library LDLIBS += -latomic endif diff --git a/examples/core/core_drop_files.c b/examples/core/core_drop_files.c index b591cdea7eb8..9f62203932cd 100644 --- a/examples/core/core_drop_files.c +++ b/examples/core/core_drop_files.c @@ -34,7 +34,7 @@ int main(void) int filePathCounter = 0; char *filePaths[MAX_FILEPATH_RECORDED] = { 0 }; // We will register a maximum of filepaths - + // Allocate space for the required file paths for (int i = 0; i < MAX_FILEPATH_RECORDED; i++) { @@ -94,7 +94,7 @@ int main(void) // De-Initialization //-------------------------------------------------------------------------------------- - for (int i = 0; i < MAX_FILEPATH_RECORDED; i++) + for (int i = 0; i < MAX_FILEPATH_RECORDED; i++) { RL_FREE(filePaths[i]); // Free allocated memory for all filepaths } diff --git a/src/external/qoaplay.c b/src/external/qoaplay.c index b4dc09c7e424..466d13319269 100644 --- a/src/external/qoaplay.c +++ b/src/external/qoaplay.c @@ -7,19 +7,19 @@ * qoaplay also provides some functions to seek to a specific frame. * * LICENSE: MIT License -* +* * Copyright (c) 2023 Dominic Szablewski (@phoboslab), 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 @@ -121,7 +121,7 @@ qoaplay_desc *qoaplay_open(char *path) qoa_ctx->info.channels = qoa.channels; qoa_ctx->info.samplerate = qoa.samplerate; qoa_ctx->info.samples = qoa.samples; - + return qoa_ctx; } @@ -174,15 +174,15 @@ void qoaplay_close(qoaplay_desc *qoa_ctx) QOA_FREE(qoa_ctx->file_data); qoa_ctx->file_data_size = 0; } - + QOA_FREE(qoa_ctx); } // Decode one frame from QOA data unsigned int qoaplay_decode_frame(qoaplay_desc *qoa_ctx) -{ +{ if (qoa_ctx->file) qoa_ctx->buffer_len = fread(qoa_ctx->buffer, 1, qoa_max_frame_size(&qoa_ctx->info), qoa_ctx->file); - else + else { qoa_ctx->buffer_len = qoa_max_frame_size(&qoa_ctx->info); memcpy(qoa_ctx->buffer, qoa_ctx->file_data + qoa_ctx->file_data_offset, qoa_ctx->buffer_len); @@ -193,14 +193,14 @@ unsigned int qoaplay_decode_frame(qoaplay_desc *qoa_ctx) qoa_decode_frame(qoa_ctx->buffer, qoa_ctx->buffer_len, &qoa_ctx->info, qoa_ctx->sample_data, &frame_len); qoa_ctx->sample_data_pos = 0; qoa_ctx->sample_data_len = frame_len; - + return frame_len; } // Rewind QOA file or memory pointer to beginning void qoaplay_rewind(qoaplay_desc *qoa_ctx) { - if (qoa_ctx->file) fseek(qoa_ctx->file, qoa_ctx->first_frame_pos, SEEK_SET); + if (qoa_ctx->file) fseek(qoa_ctx->file, qoa_ctx->first_frame_pos, SEEK_SET); else qoa_ctx->file_data_offset = 0; qoa_ctx->sample_position = 0; @@ -213,7 +213,7 @@ unsigned int qoaplay_decode(qoaplay_desc *qoa_ctx, float *sample_data, int num_s { int src_index = qoa_ctx->sample_data_pos*qoa_ctx->info.channels; int dst_index = 0; - + for (int i = 0; i < num_samples; i++) { // Do we have to decode more samples? @@ -225,20 +225,20 @@ unsigned int qoaplay_decode(qoaplay_desc *qoa_ctx, float *sample_data, int num_s qoaplay_rewind(qoa_ctx); qoaplay_decode_frame(qoa_ctx); } - + src_index = 0; } // Normalize to -1..1 floats and write to dest - for (int c = 0; c < qoa_ctx->info.channels; c++) + for (int c = 0; c < qoa_ctx->info.channels; c++) { sample_data[dst_index++] = qoa_ctx->sample_data[src_index++]/32768.0; } - + qoa_ctx->sample_data_pos++; qoa_ctx->sample_position++; } - + return num_samples; } @@ -272,7 +272,7 @@ void qoaplay_seek_frame(qoaplay_desc *qoa_ctx, int frame) qoa_ctx->sample_data_pos = 0; unsigned int offset = qoa_ctx->first_frame_pos + frame*qoa_max_frame_size(&qoa_ctx->info); - + if (qoa_ctx->file) fseek(qoa_ctx->file, offset, SEEK_SET); else qoa_ctx->file_data_offset = offset; } diff --git a/src/rcamera.h b/src/rcamera.h index 6aee26f385b9..c3a101f0b0ff 100644 --- a/src/rcamera.h +++ b/src/rcamera.h @@ -160,7 +160,7 @@ Matrix GetCameraProjectionMatrix(Camera* camera, float aspect); // MatrixOrtho() // MatrixIdentity() -// raylib required functionality: +// raylib required functionality: // GetMouseDelta() // GetMouseWheelMove() // IsKeyDown() @@ -223,7 +223,7 @@ Vector3 GetCameraRight(Camera *camera) { Vector3 forward = GetCameraForward(camera); Vector3 up = GetCameraUp(camera); - + return Vector3CrossProduct(forward, up); } @@ -251,7 +251,7 @@ void CameraMoveForward(Camera *camera, float distance, bool moveInWorldPlane) void CameraMoveUp(Camera *camera, float distance) { Vector3 up = GetCameraUp(camera); - + // Scale by distance up = Vector3Scale(up, distance); @@ -410,7 +410,7 @@ Matrix GetCameraProjectionMatrix(Camera *camera, float aspect) return MatrixOrtho(-right, right, -top, top, CAMERA_CULL_DISTANCE_NEAR, CAMERA_CULL_DISTANCE_FAR); } - + return MatrixIdentity(); } @@ -425,7 +425,7 @@ void UpdateCamera(Camera *camera, int mode) bool rotateAroundTarget = ((mode == CAMERA_THIRD_PERSON) || (mode == CAMERA_ORBITAL)); bool lockView = ((mode == CAMERA_FIRST_PERSON) || (mode == CAMERA_THIRD_PERSON) || (mode == CAMERA_ORBITAL)); bool rotateUp = (mode == CAMERA_FREE); - + if (mode == CAMERA_ORBITAL) { // Orbital can just orbit @@ -446,7 +446,7 @@ void UpdateCamera(Camera *camera, int mode) CameraYaw(camera, -mousePositionDelta.x*CAMERA_MOUSE_MOVE_SENSITIVITY, rotateAroundTarget); CameraPitch(camera, -mousePositionDelta.y*CAMERA_MOUSE_MOVE_SENSITIVITY, lockView, rotateAroundTarget, rotateUp); - + // Camera movement if (IsKeyDown(KEY_W)) CameraMoveForward(camera, CAMERA_MOVE_SPEED, moveInWorldPlane); if (IsKeyDown(KEY_A)) CameraMoveRight(camera, -CAMERA_MOVE_SPEED, moveInWorldPlane); diff --git a/src/rcore.c b/src/rcore.c index 071915cf787d..f24ae012c814 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -1555,7 +1555,7 @@ void ClearWindowState(unsigned int flags) // Set icon for window (only PLATFORM_DESKTOP) // NOTE 1: Image must be in RGBA format, 8bit per channel -// NOTE 2: Image is scaled by the OS for all required sizes +// NOTE 2: Image is scaled by the OS for all required sizes void SetWindowIcon(Image image) { #if defined(PLATFORM_DESKTOP) @@ -1586,7 +1586,7 @@ void SetWindowIcon(Image image) // Set icon for window (multiple images, only PLATFORM_DESKTOP) // NOTE 1: Images must be in RGBA format, 8bit per channel // NOTE 2: The multiple images are used depending on provided sizes -// Standard Windows icon sizes: 256, 128, 96, 64, 48, 32, 24, 16 +// Standard Windows icon sizes: 256, 128, 96, 64, 48, 32, 24, 16 void SetWindowIcons(Image *images, int count) { #if defined(PLATFORM_DESKTOP) @@ -2580,7 +2580,7 @@ bool IsShaderReady(Shader shader) // The following locations are tried to be set automatically (locs[i] >= 0), // any of them can be checked for validation but the only mandatory one is, afaik, SHADER_LOC_VERTEX_POSITION // NOTE: Users can also setup manually their own attributes/uniforms and do not used the default raylib ones - + // Vertex shader attribute locations (default) // shader.locs[SHADER_LOC_VERTEX_POSITION] // Set by default internal shader // shader.locs[SHADER_LOC_VERTEX_TEXCOORD01] // Set by default internal shader diff --git a/src/rtextures.c b/src/rtextures.c index f9b5c862dfff..56b200ce8505 100644 --- a/src/rtextures.c +++ b/src/rtextures.c @@ -320,7 +320,7 @@ Image LoadImageAnim(const char *fileName, int *frames) #else if (false) { } #endif - else + else { image = LoadImage(fileName); frameCount = 1; @@ -507,7 +507,7 @@ Image LoadImageFromScreen(void) bool IsImageReady(Image image) { return ((image.data != NULL) && // Validate pixel data available - (image.width > 0) && + (image.width > 0) && (image.height > 0) && // Validate image size (image.format > 0) && // Validate image format (image.mipmaps > 0)); // Validate image mipmaps (at least 1 for basic mipmap level) @@ -3340,10 +3340,10 @@ RenderTexture2D LoadRenderTexture(int width, int height) bool IsTextureReady(Texture2D texture) { // TODO: Validate maximum texture size supported by GPU? - + return ((texture.id > 0) && // Validate OpenGL id - (texture.width > 0) && - (texture.height > 0) && // Validate texture size + (texture.width > 0) && + (texture.height > 0) && // Validate texture size (texture.format > 0) && // Validate texture pixel format (texture.mipmaps > 0)); // Validate texture mipmaps (at least 1 for basic mipmap level) } From 8f7e2cd1791414f55e8442186b1b32557704f1b5 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 6 Mar 2023 15:05:57 +0100 Subject: [PATCH 142/192] Replace TABS by 4 spaces --- src/external/qoaplay.c | 242 ++++++++++++++++++++--------------------- 1 file changed, 121 insertions(+), 121 deletions(-) diff --git a/src/external/qoaplay.c b/src/external/qoaplay.c index 466d13319269..549e9f778b8d 100644 --- a/src/external/qoaplay.c +++ b/src/external/qoaplay.c @@ -35,22 +35,22 @@ //---------------------------------------------------------------------------------- // QOA streaming data descriptor typedef struct { - qoa_desc info; // QOA descriptor data - + qoa_desc info; // QOA descriptor data + FILE *file; // QOA file to read, if NULL, using memory buffer -> file_data unsigned char *file_data; // QOA file data on memory unsigned int file_data_size; // QOA file data on memory size unsigned int file_data_offset; // QOA file data on memory offset for next read - unsigned int first_frame_pos; // First frame position (after QOA header, required for offset) - unsigned int sample_position; // Current streaming sample position + unsigned int first_frame_pos; // First frame position (after QOA header, required for offset) + unsigned int sample_position; // Current streaming sample position - unsigned char *buffer; // Buffer used to read samples from file/memory (used on decoding) - unsigned int buffer_len; // Buffer length to read samples for streaming + unsigned char *buffer; // Buffer used to read samples from file/memory (used on decoding) + unsigned int buffer_len; // Buffer length to read samples for streaming - short *sample_data; // Sample data decoded - unsigned int sample_data_len; // Sample data decoded length - unsigned int sample_data_pos; // Sample data decoded position + short *sample_data; // Sample data decoded + unsigned int sample_data_len; // Sample data decoded length + unsigned int sample_data_pos; // Sample data decoded position } qoaplay_desc; @@ -85,97 +85,97 @@ int qoaplay_get_frame(qoaplay_desc *qoa_ctx); // Open QOA file, keep FILE pointer to keep reading from file qoaplay_desc *qoaplay_open(char *path) { - FILE *file = fopen(path, "rb"); - if (!file) return NULL; + FILE *file = fopen(path, "rb"); + if (!file) return NULL; - // Read and decode the file header - unsigned char header[QOA_MIN_FILESIZE]; - int read = fread(header, QOA_MIN_FILESIZE, 1, file); - if (!read) return NULL; + // Read and decode the file header + unsigned char header[QOA_MIN_FILESIZE]; + int read = fread(header, QOA_MIN_FILESIZE, 1, file); + if (!read) return NULL; - qoa_desc qoa; - unsigned int first_frame_pos = qoa_decode_header(header, QOA_MIN_FILESIZE, &qoa); - if (!first_frame_pos) return NULL; + qoa_desc qoa; + unsigned int first_frame_pos = qoa_decode_header(header, QOA_MIN_FILESIZE, &qoa); + if (!first_frame_pos) return NULL; - // Rewind the file back to beginning of the first frame - fseek(file, first_frame_pos, SEEK_SET); + // Rewind the file back to beginning of the first frame + fseek(file, first_frame_pos, SEEK_SET); - // Allocate one chunk of memory for the qoaplay_desc struct + // Allocate one chunk of memory for the qoaplay_desc struct // + the sample data for one frame // + 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); - memset(qoa_ctx, 0, sizeof(qoaplay_desc)); - - qoa_ctx->file = file; - qoa_ctx->file_data = NULL; - qoa_ctx->file_data_size = 0; - qoa_ctx->file_data_offset = 0; - qoa_ctx->first_frame_pos = first_frame_pos; - - // Setup data pointers to previously allocated data - qoa_ctx->buffer = ((unsigned char *)qoa_ctx) + sizeof(qoaplay_desc); - qoa_ctx->sample_data = (short *)(((unsigned char *)qoa_ctx) + sizeof(qoaplay_desc) + buffer_size); - - qoa_ctx->info.channels = qoa.channels; - qoa_ctx->info.samplerate = qoa.samplerate; - qoa_ctx->info.samples = qoa.samples; - - return qoa_ctx; + 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); + memset(qoa_ctx, 0, sizeof(qoaplay_desc)); + + qoa_ctx->file = file; + qoa_ctx->file_data = NULL; + qoa_ctx->file_data_size = 0; + qoa_ctx->file_data_offset = 0; + qoa_ctx->first_frame_pos = first_frame_pos; + + // Setup data pointers to previously allocated data + qoa_ctx->buffer = ((unsigned char *)qoa_ctx) + sizeof(qoaplay_desc); + qoa_ctx->sample_data = (short *)(((unsigned char *)qoa_ctx) + sizeof(qoaplay_desc) + buffer_size); + + qoa_ctx->info.channels = qoa.channels; + qoa_ctx->info.samplerate = qoa.samplerate; + qoa_ctx->info.samples = qoa.samples; + + return qoa_ctx; } // Open QOA file from memory, no FILE pointer required qoaplay_desc *qoaplay_open_memory(const unsigned char *data, int data_size) { - // Read and decode the file header - unsigned char header[QOA_MIN_FILESIZE]; - memcpy(header, data, QOA_MIN_FILESIZE); - - qoa_desc qoa; - unsigned int first_frame_pos = qoa_decode_header(header, QOA_MIN_FILESIZE, &qoa); - if (!first_frame_pos) return NULL; - - // Allocate one chunk of memory for the qoaplay_desc struct - // + the sample data for one frame - // + 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); - memset(qoa_ctx, 0, sizeof(qoaplay_desc)); - - qoa_ctx->file = NULL; - - // Keep a copy of file data provided to be managed internally - qoa_ctx->file_data = (unsigned char *)QOA_MALLOC(data_size); - memcpy(qoa_ctx->file_data, data, data_size); - qoa_ctx->file_data_size = data_size; - qoa_ctx->file_data_offset = 0; - qoa_ctx->first_frame_pos = first_frame_pos; - - // Setup data pointers to previously allocated data - qoa_ctx->buffer = ((unsigned char *)qoa_ctx) + sizeof(qoaplay_desc); - qoa_ctx->sample_data = (short *)(((unsigned char *)qoa_ctx) + sizeof(qoaplay_desc) + buffer_size); - - qoa_ctx->info.channels = qoa.channels; - qoa_ctx->info.samplerate = qoa.samplerate; - qoa_ctx->info.samples = qoa.samples; - - return qoa_ctx; + // Read and decode the file header + unsigned char header[QOA_MIN_FILESIZE]; + memcpy(header, data, QOA_MIN_FILESIZE); + + qoa_desc qoa; + unsigned int first_frame_pos = qoa_decode_header(header, QOA_MIN_FILESIZE, &qoa); + if (!first_frame_pos) return NULL; + + // Allocate one chunk of memory for the qoaplay_desc struct + // + the sample data for one frame + // + 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); + memset(qoa_ctx, 0, sizeof(qoaplay_desc)); + + qoa_ctx->file = NULL; + + // Keep a copy of file data provided to be managed internally + qoa_ctx->file_data = (unsigned char *)QOA_MALLOC(data_size); + memcpy(qoa_ctx->file_data, data, data_size); + qoa_ctx->file_data_size = data_size; + qoa_ctx->file_data_offset = 0; + qoa_ctx->first_frame_pos = first_frame_pos; + + // Setup data pointers to previously allocated data + qoa_ctx->buffer = ((unsigned char *)qoa_ctx) + sizeof(qoaplay_desc); + qoa_ctx->sample_data = (short *)(((unsigned char *)qoa_ctx) + sizeof(qoaplay_desc) + buffer_size); + + qoa_ctx->info.channels = qoa.channels; + qoa_ctx->info.samplerate = qoa.samplerate; + qoa_ctx->info.samples = qoa.samples; + + return qoa_ctx; } // Close QOA file (if open) and free internal memory void qoaplay_close(qoaplay_desc *qoa_ctx) { - if (qoa_ctx->file) fclose(qoa_ctx->file); + if (qoa_ctx->file) fclose(qoa_ctx->file); - if ((qoa_ctx->file_data) && (qoa_ctx->file_data_size > 0)) - { - QOA_FREE(qoa_ctx->file_data); - qoa_ctx->file_data_size = 0; - } + if ((qoa_ctx->file_data) && (qoa_ctx->file_data_size > 0)) + { + QOA_FREE(qoa_ctx->file_data); + qoa_ctx->file_data_size = 0; + } - QOA_FREE(qoa_ctx); + QOA_FREE(qoa_ctx); } // Decode one frame from QOA data @@ -189,90 +189,90 @@ unsigned int qoaplay_decode_frame(qoaplay_desc *qoa_ctx) qoa_ctx->file_data_offset += qoa_ctx->buffer_len; } - unsigned int frame_len; - qoa_decode_frame(qoa_ctx->buffer, qoa_ctx->buffer_len, &qoa_ctx->info, qoa_ctx->sample_data, &frame_len); - qoa_ctx->sample_data_pos = 0; - qoa_ctx->sample_data_len = frame_len; + unsigned int frame_len; + qoa_decode_frame(qoa_ctx->buffer, qoa_ctx->buffer_len, &qoa_ctx->info, qoa_ctx->sample_data, &frame_len); + qoa_ctx->sample_data_pos = 0; + qoa_ctx->sample_data_len = frame_len; - return frame_len; + return frame_len; } // Rewind QOA file or memory pointer to beginning void qoaplay_rewind(qoaplay_desc *qoa_ctx) { - if (qoa_ctx->file) fseek(qoa_ctx->file, qoa_ctx->first_frame_pos, SEEK_SET); + if (qoa_ctx->file) fseek(qoa_ctx->file, qoa_ctx->first_frame_pos, SEEK_SET); else qoa_ctx->file_data_offset = 0; - qoa_ctx->sample_position = 0; - qoa_ctx->sample_data_len = 0; - qoa_ctx->sample_data_pos = 0; + qoa_ctx->sample_position = 0; + qoa_ctx->sample_data_len = 0; + qoa_ctx->sample_data_pos = 0; } // Decode required QOA frames unsigned int qoaplay_decode(qoaplay_desc *qoa_ctx, float *sample_data, int num_samples) { - int src_index = qoa_ctx->sample_data_pos*qoa_ctx->info.channels; - int dst_index = 0; + int src_index = qoa_ctx->sample_data_pos*qoa_ctx->info.channels; + int dst_index = 0; - for (int i = 0; i < num_samples; i++) + for (int i = 0; i < num_samples; i++) { - // Do we have to decode more samples? - if (qoa_ctx->sample_data_len - qoa_ctx->sample_data_pos == 0) + // Do we have to decode more samples? + if (qoa_ctx->sample_data_len - qoa_ctx->sample_data_pos == 0) { - if (!qoaplay_decode_frame(qoa_ctx)) + if (!qoaplay_decode_frame(qoa_ctx)) { - // Loop to the beginning - qoaplay_rewind(qoa_ctx); - qoaplay_decode_frame(qoa_ctx); - } + // Loop to the beginning + qoaplay_rewind(qoa_ctx); + qoaplay_decode_frame(qoa_ctx); + } - src_index = 0; - } + src_index = 0; + } - // Normalize to -1..1 floats and write to dest - for (int c = 0; c < qoa_ctx->info.channels; c++) + // Normalize to -1..1 floats and write to dest + for (int c = 0; c < qoa_ctx->info.channels; c++) { - sample_data[dst_index++] = qoa_ctx->sample_data[src_index++]/32768.0; - } + sample_data[dst_index++] = qoa_ctx->sample_data[src_index++]/32768.0; + } - qoa_ctx->sample_data_pos++; - qoa_ctx->sample_position++; - } + qoa_ctx->sample_data_pos++; + qoa_ctx->sample_position++; + } - return num_samples; + return num_samples; } // Get QOA total time duration in seconds double qoaplay_get_duration(qoaplay_desc *qoa_ctx) { - return (double)qoa_ctx->info.samples/(double)qoa_ctx->info.samplerate; + return (double)qoa_ctx->info.samples/(double)qoa_ctx->info.samplerate; } // Get QOA current time position in seconds double qoaplay_get_time(qoaplay_desc *qoa_ctx) { - return (double)qoa_ctx->sample_position/(double)qoa_ctx->info.samplerate; + return (double)qoa_ctx->sample_position/(double)qoa_ctx->info.samplerate; } // Get QOA current audio frame int qoaplay_get_frame(qoaplay_desc *qoa_ctx) { - return qoa_ctx->sample_position/QOA_FRAME_LEN; + return qoa_ctx->sample_position/QOA_FRAME_LEN; } // Seek QOA audio frame void qoaplay_seek_frame(qoaplay_desc *qoa_ctx, int frame) { - if (frame < 0) frame = 0; + if (frame < 0) frame = 0; - if (frame > qoa_ctx->info.samples/QOA_FRAME_LEN) frame = qoa_ctx->info.samples/QOA_FRAME_LEN; + if (frame > qoa_ctx->info.samples/QOA_FRAME_LEN) frame = qoa_ctx->info.samples/QOA_FRAME_LEN; - qoa_ctx->sample_position = frame*QOA_FRAME_LEN; - qoa_ctx->sample_data_len = 0; - qoa_ctx->sample_data_pos = 0; + qoa_ctx->sample_position = frame*QOA_FRAME_LEN; + qoa_ctx->sample_data_len = 0; + qoa_ctx->sample_data_pos = 0; - unsigned int offset = qoa_ctx->first_frame_pos + frame*qoa_max_frame_size(&qoa_ctx->info); + unsigned int offset = qoa_ctx->first_frame_pos + frame*qoa_max_frame_size(&qoa_ctx->info); - if (qoa_ctx->file) fseek(qoa_ctx->file, offset, SEEK_SET); + if (qoa_ctx->file) fseek(qoa_ctx->file, offset, SEEK_SET); else qoa_ctx->file_data_offset = offset; } From 0b18882a949fb763f03e87d8139d702107223ee0 Mon Sep 17 00:00:00 2001 From: Sid K <58383260+Skaytacium@users.noreply.github.com> Date: Tue, 7 Mar 2023 01:40:18 +0530 Subject: [PATCH 143/192] fix(build): Fix DLL build on Windows (#2951) Changes the DLL export condition to apply to platform WIN32 instead of compiler MSVC --- src/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 690f970a45c4..9087f8eea5d8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -62,7 +62,7 @@ if (NOT BUILD_SHARED_LIBS) add_library(raylib_static ALIAS raylib) else() MESSAGE(STATUS "Building raylib shared library") - if (MSVC) + if (WIN32) target_compile_definitions(raylib PRIVATE $ INTERFACE $ From 3a332d241c1c675c8b581fe3a29e328983642fe4 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 7 Mar 2023 11:32:37 +0100 Subject: [PATCH 144/192] Update CHANGELOG --- CHANGELOG | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 8cbbaa2b1928..091425582f8c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -9,10 +9,11 @@ Release: raylib 4.5 (xx February 2023) -WIP- KEY CHANGES: - ADDED: M3D model format support with animations - ADDED: GLTF animation support - - ADDED: QOA audio format support (import/export) -WIP- - - rlgl redesign to avoid render batch triangles limits pre-check: rlCheckRenderBatchLimit() - - rshapes simplification to minimize the requirement of rlgl functionality, now it only depends on 6 functions - - rl_gputex.h: Compressed textures loading, required by rtextures module, has been moved to a separate self-contained library + - ADDED: QOA audio format support (import/export) + - REDESIGNED: rcamera module, new implementation from scratch, simpler and more extendable + - REDESIGNED: rlgl module to avoid render batch triangles limits pre-check: rlCheckRenderBatchLimit() + - REDESIGNED: rshapes module to minimize the rlgl dependency, now only 6 low-level functions required! + - ADDED: rl_gputex self-contained module for compressed textures loading, used by rtextures module - raygui 3.5: New version of the immediate-mode gui system for tools development with raylib Detailed changes: @@ -20,6 +21,7 @@ Detailed changes: [core] ADDED: Basic gamepad support for Android (#2709) by @deniska [core] ADDED: Support CAPS/NUM lock keys registering if locked [core] ADDED: _GNU_SOURCE define on Linux (#2729) +[core] ADDED: SetWindowIcons() to set multiple icon image sizes [core] `WARNING`: RENAMED: Exported raylib version symbol to raylib_version #2671 [core] REMOVED: Touch points on touch up events on Android (#2711) by @deniska [core] REVIEWED: Window position setup on InitWindow() (#2732) by @RandomErrorMessage @@ -43,6 +45,14 @@ Detailed changes: [core] REVIEWED: Initial window position for display-sized fullscreen (#2742) by @daipom [core] REVIEWED: Sticky touches input (#2857) by @ImazighenGhost [core] REVIEWED: Enable GetWindowHandle() on macOS (#2915) by @Not-Nik +[core] REVIEWED: Window position always inits centered in current monitor +[core] REVIEWED: IsWindowFocused() to consider Android App state (#2935) +[core] REVIEWED: GetMonitorWidth() and GetMonitorHeight() (#2934) +[core] REVIEWED: GetWindowHandle() to return Linux window (#2938) +[core] REVIEWED: WindowDropCallback(), additional security check (#2943) +[rcamera] REDESIGNED: New implementation from scratch (#2563) by @Crydsch +[rcamera] REVIEWED: Make orbital camera work as expected (#2926) by @JeffM2501 +[rcamera] REVIEWED: Multiple reviews on the new implementation [rlgl] ADDED: OpenGL ES 2.0 support on PLATFORM_DESKTOP (#2840) by @wtnbgo [rlgl] ADDED: Separate blending modes for color and alpha, BLEND_CUSTOM_SEPARATE (#2741) [rlgl] ADDED: rlSetBlendFactorsSeparate and custom blend mode modification checks (#2741) by @pure01fx @@ -58,6 +68,7 @@ Detailed changes: [rlgl] REVIEWED: rlMultMatrixf(), use const pointer (#2807) by @planetis-m [rlgl] REVIEWED: Expose OpenGL blending mode factors and functions/equations [rlgl] REVIEWED: rLoadTextureDepth(), issue with depth textures on WebGL (#2824) +[rlgl] REVIEWED: rlUnloadFramebuffer() (#2937) [raymath] ADDED: Vector2LineAngle() (#2887) [raymath] REVIEWED: Vector2Angle() (#2829, #2832) by @AlxHnr, @planetis-m [shapes] ADDED: CheckCollisionPointPoly() (#2685) by @acejacek @@ -95,10 +106,14 @@ Detailed changes: [models] REVIEWED: LoadIQM() (#2676) [models] REVIEWED: Simplify .vox signature check (#2752) by @CrezyDud [models] REVIEWED: LoadIQM(), support bone names loading if available (#2882) by @PencilAmazing +[models] REVIEWED: GenMeshTangents(), avoid crash on missing texcoords data (#2927) [models] `WARNING`: REMOVED: DrawCubeTexture(), DrawCubeTextureRec(), functions moved to new example: `models_draw_cube_texture` +[audio] ADDED: Full support for QOA audio file format +[audio] ADDED: Mixed audio processor (#2929) by @hatkidchan [audio] ADDED: IsWaveReady()`, IsSoundReady(), IsMusicReady() (#2892) by @RobLoach [audio] REVIEWED: Clear PCM buffer state when closing audio device (#2736) by @veins1 [audio] REVIEWED: Android backend selected (#2118, #2875) by @planetis-m +[audio] REVIEWED: Change default threading model for COM objects in miniaudio [multi] ADDED: IsShaderReady(), IsImageReady(), IsFontReady() (#2892) by @RobLoach [multi] ADDED: IsModelReady(), IsMaterialReady(), IsTextureReady(), IsRenderTextureReady() (#2895) by @RobLoach [multi] REVIEWED: Multiple code/comment typos by @sDos280 @@ -113,6 +128,7 @@ Detailed changes: [examples] REVIEWED: core_camera_2d_platformer (#2687) by @skylar779 [examples] REVIEWED: core_input_gamepad.c (#2903) by @planetis-m [examples] REVIEWED: core_custom_frame_control +[examples] REVIEWED: core_drop_files (#2943) [examples] REVIEWED: text_rectangle_bounds (#2746) by @SzieberthAdam [examples] REVIEWED: textures_image_processing, added gaussian blurring (#2775) by @nobytesgiven [examples] REVIEWED: models_billboard, highlighting rotation and draw order (#2779) by @nobytesgiven @@ -124,6 +140,7 @@ Detailed changes: [build] ADDED: Linkage library -latomic on Linux (only required for ARM32) [build] ADDED: Required frameworks on macOS (#2793) by @SpexGuy [build] ADDED: WASM support for Zig build (#2901) by @Not-Nik +[build] ADDED: New raylib examples as VS2022 project (to raylib solution) [build] REVIEWED: config.h format and inconsistencies [build] REVIEWED: Zig build to latest master, avoid deprecated functions (#2910) by @star-tek-mb [build] REVIEWED: CMake project template to easily target raylib version (#2700) by @RobLoach @@ -137,6 +154,7 @@ Detailed changes: [build] REVIEWED: Several compilation warnings (for strict rules) [build] REVIEWED: All github workflows using deprecated actions [build] REVIEWED: CMake when compiling for web (#2820) by @object71 +[build] REVIEWED: DLL build on Windows (#2951) by @Skaytacium [build] REVIEWED: Avoid MSVC warnings in raylib project (#2871) by @JeffM2501 [build] REVIEWED: Paths in .bat files to build examples (#2870) by @masoudd [build] REVIEWED: CMake, use GLVND for old cmake versions (#2826) by @simendsjo @@ -153,6 +171,7 @@ Detailed changes: [bindings] ADDED: TurboRaylib (Object Pascal) by @turborium [bindings] ADDED: Kaylib (Kotlin/Native) by @Its-Kenta [bindings] ADDED: Raylib-Nelua (Nelua) by @Its-Kenta +[bindings] ADDED: Cyber binding by @fubark [misc] REVIEWED: Update external libraries to latest versions ------------------------------------------------------------------------- From 1b873b028f18486d31bb5c75f6b04a4de4c8d9fa Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 7 Mar 2023 19:48:47 +0100 Subject: [PATCH 145/192] WARNING: REMOVED: Multichannel audio support API It was quite restrictive and hacky implementation, just load multiple types same sound to play multiple instances. --- examples/Makefile | 1 - examples/Makefile.Web | 6 - examples/README.md | 1 - examples/audio/audio_multichannel_sound.c | 78 ---- examples/audio/audio_multichannel_sound.png | Bin 16088 -> 0 bytes .../examples/audio_multichannel_sound.vcxproj | 390 ------------------ projects/VS2022/raylib.sln | 2 - src/raudio.c | 87 ---- src/raylib.h | 3 - 9 files changed, 568 deletions(-) delete mode 100644 examples/audio/audio_multichannel_sound.c delete mode 100644 examples/audio/audio_multichannel_sound.png delete mode 100644 projects/VS2022/examples/audio_multichannel_sound.vcxproj diff --git a/examples/Makefile b/examples/Makefile index 0b524015ff14..6b0b4a848ea5 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -531,7 +531,6 @@ AUDIO = \ audio/audio_music_stream \ audio/audio_raw_stream \ audio/audio_sound_loading \ - audio/audio_multichannel_sound \ audio/audio_stream_effects CURRENT_MAKEFILE = $(lastword $(MAKEFILE_LIST)) diff --git a/examples/Makefile.Web b/examples/Makefile.Web index a55a76b8c7cb..063530fb3707 100644 --- a/examples/Makefile.Web +++ b/examples/Makefile.Web @@ -503,7 +503,6 @@ AUDIO = \ audio/audio_music_stream \ audio/audio_raw_stream \ audio/audio_sound_loading \ - audio/audio_multichannel_sound \ audio/audio_stream_effects CURRENT_MAKEFILE = $(lastword $(MAKEFILE_LIST)) @@ -1006,11 +1005,6 @@ audio/audio_sound_loading: audio/audio_sound_loading.c --preload-file audio/resources/sound.wav@resources/sound.wav \ --preload-file audio/resources/target.ogg@resources/target.ogg -audio/audio_multichannel_sound: audio/audio_multichannel_sound.c - $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \ - --preload-file audio/resources/sound.wav@resources/sound.wav \ - --preload-file audio/resources/target.ogg@resources/target.ogg - audio/audio_stream_effects: audio/audio_stream_effects.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) -s TOTAL_MEMORY=67108864 \ --preload-file audio/resources/country.mp3@resources/country.mp3 diff --git a/examples/README.md b/examples/README.md index 7a3e72f8717c..8399d677dfb9 100644 --- a/examples/README.md +++ b/examples/README.md @@ -186,7 +186,6 @@ Examples using raylib audio functionality, including sound/music loading and pla | 118 | [audio_music_stream](audio/audio_music_stream.c) | audio_music_stream | ⭐️☆☆☆ | 1.3 | **4.2** | [Ray](https://github.com/raysan5) | | 119 | [audio_raw_stream](audio/audio_raw_stream.c) | audio_raw_stream | ⭐️⭐️⭐️☆ | 1.6 | **4.2** | [Ray](https://github.com/raysan5) | | 120 | [audio_sound_loading](audio/audio_sound_loading.c) | audio_sound_loading | ⭐️☆☆☆ | 1.1 | 3.5 | [Ray](https://github.com/raysan5) | -| 121 | [audio_multichannel_sound](audio/audio_multichannel_sound.c) | audio_multichannel_sound | ⭐️☆☆☆ | 3.0 | 3.5 | [Chris Camacho](https://github.com/codifies) | ### category: others diff --git a/examples/audio/audio_multichannel_sound.c b/examples/audio/audio_multichannel_sound.c deleted file mode 100644 index 1d549a055a02..000000000000 --- a/examples/audio/audio_multichannel_sound.c +++ /dev/null @@ -1,78 +0,0 @@ -/******************************************************************************************* -* -* raylib [audio] example - Multichannel sound playing -* -* Example originally created with raylib 3.0, last time updated with raylib 3.5 -* -* Example contributed by Chris Camacho (@chriscamacho) 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) 2019-2023 Chris Camacho (@chriscamacho) and Ramon Santamaria (@raysan5) -* -********************************************************************************************/ - -#include "raylib.h" - -//------------------------------------------------------------------------------------ -// Program main entry point -//------------------------------------------------------------------------------------ -int main(void) -{ - // Initialization - //-------------------------------------------------------------------------------------- - const int screenWidth = 800; - const int screenHeight = 450; - - InitWindow(screenWidth, screenHeight, "raylib [audio] example - Multichannel sound playing"); - - InitAudioDevice(); // Initialize audio device - - Sound fxWav = LoadSound("resources/sound.wav"); // Load WAV audio file - Sound fxOgg = LoadSound("resources/target.ogg"); // Load OGG audio file - - SetSoundVolume(fxWav, 0.2f); - - 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_ENTER)) PlaySoundMulti(fxWav); // Play a new wav sound instance - if (IsKeyPressed(KEY_SPACE)) PlaySoundMulti(fxOgg); // Play a new ogg sound instance - //---------------------------------------------------------------------------------- - - // Draw - //---------------------------------------------------------------------------------- - BeginDrawing(); - - ClearBackground(RAYWHITE); - - DrawText("MULTICHANNEL SOUND PLAYING", 20, 20, 20, GRAY); - DrawText("Press SPACE to play new ogg instance!", 200, 120, 20, LIGHTGRAY); - DrawText("Press ENTER to play new wav instance!", 200, 180, 20, LIGHTGRAY); - - DrawText(TextFormat("CONCURRENT SOUNDS PLAYING: %02i", GetSoundsPlaying()), 220, 280, 20, RED); - - EndDrawing(); - //---------------------------------------------------------------------------------- - } - - // De-Initialization - //-------------------------------------------------------------------------------------- - StopSoundMulti(); // We must stop the buffer pool before unloading - - UnloadSound(fxWav); // Unload sound data - UnloadSound(fxOgg); // Unload sound data - - CloseAudioDevice(); // Close audio device - - CloseWindow(); // Close window and OpenGL context - //-------------------------------------------------------------------------------------- - - return 0; -} diff --git a/examples/audio/audio_multichannel_sound.png b/examples/audio/audio_multichannel_sound.png deleted file mode 100644 index 4b98b26e0a05f517b5f157d7cf50ba2424866446..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16088 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 B{|Ep8 diff --git a/projects/VS2022/examples/audio_multichannel_sound.vcxproj b/projects/VS2022/examples/audio_multichannel_sound.vcxproj deleted file mode 100644 index 91ab9095df33..000000000000 --- a/projects/VS2022/examples/audio_multichannel_sound.vcxproj +++ /dev/null @@ -1,390 +0,0 @@ - - - - - Debug.DLL - Win32 - - - Debug.DLL - x64 - - - Debug - Win32 - - - Debug - x64 - - - Release.DLL - Win32 - - - Release.DLL - x64 - - - Release - Win32 - - - Release - x64 - - - - {9875B0C8-3893-43F8-88B2-4BAAAE3E8E6F} - Win32Proj - audio_multichannel_sound - 10.0 - audio_multichannel_sound - - - - 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 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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)\ - - - $(SolutionDir)..\..\examples\audio - WindowsLocalDebugger - - - $(SolutionDir)..\..\examples\audio - WindowsLocalDebugger - - - $(SolutionDir)..\..\examples\audio - WindowsLocalDebugger - - - $(SolutionDir)..\..\examples\audio - WindowsLocalDebugger - - - $(SolutionDir)..\..\examples\audio - WindowsLocalDebugger - - - $(SolutionDir)..\..\examples\audio - WindowsLocalDebugger - - - $(SolutionDir)..\..\examples\audio - WindowsLocalDebugger - - - $(SolutionDir)..\..\examples\audio - 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) - - - 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)\ - - - 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 06166cdd0240..673ccb4b3f79 100644 --- a/projects/VS2022/raylib.sln +++ b/projects/VS2022/raylib.sln @@ -17,8 +17,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "textures_image_drawing", "e EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "audio_module_playing", "examples\audio_module_playing.vcxproj", "{E6784F91-4E4E-4956-A079-73FAB1AC7BE6}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "audio_multichannel_sound", "examples\audio_multichannel_sound.vcxproj", "{9875B0C8-3893-43F8-88B2-4BAAAE3E8E6F}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "audio_music_stream", "examples\audio_music_stream.vcxproj", "{BFB22AB2-041B-4A1B-80C0-1D4BE410C8A9}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "audio_raw_stream", "examples\audio_raw_stream.vcxproj", "{93A1F656-0D29-4C5E-B140-11F23FF5D6AB}" diff --git a/src/raudio.c b/src/raudio.c index 8bd9052c2ee3..c86ea0bb49f1 100644 --- a/src/raudio.c +++ b/src/raudio.c @@ -377,11 +377,6 @@ typedef struct AudioData { int defaultSize; // Default audio buffer size for audio streams } Buffer; rAudioProcessor *mixedProcessor; - struct { - unsigned int poolCounter; // AudioBuffer pointers pool counter - AudioBuffer *pool[MAX_AUDIO_BUFFER_POOL_CHANNELS]; // Multichannel AudioBuffer pointers pool - unsigned int channels[MAX_AUDIO_BUFFER_POOL_CHANNELS]; // AudioBuffer pool channels - } MultiChannel; } AudioData; //---------------------------------------------------------------------------------- @@ -1100,88 +1095,6 @@ void PlaySound(Sound sound) PlayAudioBuffer(sound.stream.buffer); } -// Play a sound in the multichannel buffer pool -void PlaySoundMulti(Sound sound) -{ - int index = -1; - unsigned int oldAge = 0; - int oldIndex = -1; - - // find the first non-playing pool entry - for (int i = 0; i < MAX_AUDIO_BUFFER_POOL_CHANNELS; i++) - { - if (AUDIO.MultiChannel.channels[i] > oldAge) - { - oldAge = AUDIO.MultiChannel.channels[i]; - oldIndex = i; - } - - if (!IsAudioBufferPlaying(AUDIO.MultiChannel.pool[i])) - { - index = i; - break; - } - } - - // If no none playing pool members can be indexed choose the oldest - if (index == -1) - { - TRACELOG(LOG_WARNING, "SOUND: Buffer pool is already full, count: %i", AUDIO.MultiChannel.poolCounter); - - if (oldIndex == -1) - { - // Shouldn't be able to get here... but just in case something odd happens! - TRACELOG(LOG_WARNING, "SOUND: Buffer pool could not determine the oldest buffer not playing sound"); - return; - } - - index = oldIndex; - - // Just in case... - StopAudioBuffer(AUDIO.MultiChannel.pool[index]); - } - - // Experimentally mutex lock doesn't seem to be needed this makes sense - // as pool[index] isn't playing and the only stuff we're copying - // shouldn't be changing... - - AUDIO.MultiChannel.channels[index] = AUDIO.MultiChannel.poolCounter; - AUDIO.MultiChannel.poolCounter++; - - SetAudioBufferVolume(AUDIO.MultiChannel.pool[index], sound.stream.buffer->volume); - SetAudioBufferPitch(AUDIO.MultiChannel.pool[index], sound.stream.buffer->pitch); - SetAudioBufferPan(AUDIO.MultiChannel.pool[index], sound.stream.buffer->pan); - - AUDIO.MultiChannel.pool[index]->looping = sound.stream.buffer->looping; - AUDIO.MultiChannel.pool[index]->usage = sound.stream.buffer->usage; - AUDIO.MultiChannel.pool[index]->isSubBufferProcessed[0] = false; - AUDIO.MultiChannel.pool[index]->isSubBufferProcessed[1] = false; - AUDIO.MultiChannel.pool[index]->sizeInFrames = sound.stream.buffer->sizeInFrames; - - AUDIO.MultiChannel.pool[index]->data = sound.stream.buffer->data; // Fill dummy track with data for playing - - PlayAudioBuffer(AUDIO.MultiChannel.pool[index]); -} - -// Stop any sound played with PlaySoundMulti() -void StopSoundMulti(void) -{ - for (int i = 0; i < MAX_AUDIO_BUFFER_POOL_CHANNELS; i++) StopAudioBuffer(AUDIO.MultiChannel.pool[i]); -} - -// Get number of sounds playing in the multichannel buffer pool -int GetSoundsPlaying(void) -{ - int counter = 0; - - for (int i = 0; i < MAX_AUDIO_BUFFER_POOL_CHANNELS; i++) - { - if (IsAudioBufferPlaying(AUDIO.MultiChannel.pool[i])) counter++; - } - - return counter; -} - // Pause a sound void PauseSound(Sound sound) { diff --git a/src/raylib.h b/src/raylib.h index 6bc81fe75f59..9fcece6f02c3 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1530,9 +1530,6 @@ RLAPI void PlaySound(Sound sound); // Play a RLAPI void StopSound(Sound sound); // Stop playing a sound RLAPI void PauseSound(Sound sound); // Pause a sound RLAPI void ResumeSound(Sound sound); // Resume a paused sound -RLAPI void PlaySoundMulti(Sound sound); // Play a sound (using multichannel buffer pool) -RLAPI void StopSoundMulti(void); // Stop any sound playing (using multichannel buffer pool) -RLAPI int GetSoundsPlaying(void); // Get number of sounds playing in the multichannel RLAPI bool IsSoundPlaying(Sound sound); // Check if a sound is currently playing RLAPI void SetSoundVolume(Sound sound, float volume); // Set volume for a sound (1.0 is max level) RLAPI void SetSoundPitch(Sound sound, float pitch); // Set pitch for a sound (1.0 is base level) From 57f0015a08144aa215789f2536f46e67c426a00e Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 7 Mar 2023 19:51:17 +0100 Subject: [PATCH 146/192] Update CHANGELOG --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index 091425582f8c..b7abe8b68f62 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -111,6 +111,7 @@ Detailed changes: [audio] ADDED: Full support for QOA audio file format [audio] ADDED: Mixed audio processor (#2929) by @hatkidchan [audio] ADDED: IsWaveReady()`, IsSoundReady(), IsMusicReady() (#2892) by @RobLoach +[audio] `WARNING`: REMOVED: Multichannel audio API: PlaySoundMulti(), StopSoundMulti() [audio] REVIEWED: Clear PCM buffer state when closing audio device (#2736) by @veins1 [audio] REVIEWED: Android backend selected (#2118, #2875) by @planetis-m [audio] REVIEWED: Change default threading model for COM objects in miniaudio From ae53600d31c9f8502524a2c9d51bdd4068e7ebf8 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 7 Mar 2023 19:54:53 +0100 Subject: [PATCH 147/192] WARNING: REMOVED: Multichannel audio support API --- src/raudio.c | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/src/raudio.c b/src/raudio.c index c86ea0bb49f1..8ac09b2f329c 100644 --- a/src/raudio.c +++ b/src/raudio.c @@ -485,13 +485,6 @@ void InitAudioDevice(void) return; } - // Init dummy audio buffers pool for multichannel sound playing - for (int i = 0; i < MAX_AUDIO_BUFFER_POOL_CHANNELS; i++) - { - // WARNING: An empty audio buffer is created (data = 0) and added to list, AudioBuffer data is filled on PlaySoundMulti() - AUDIO.MultiChannel.pool[i] = LoadAudioBuffer(AUDIO_DEVICE_FORMAT, AUDIO_DEVICE_CHANNELS, AUDIO.System.device.sampleRate, 0, AUDIO_BUFFER_USAGE_STATIC); - } - TRACELOG(LOG_INFO, "AUDIO: Device initialized successfully"); TRACELOG(LOG_INFO, " > Backend: miniaudio / %s", ma_get_backend_name(AUDIO.System.context.backend)); TRACELOG(LOG_INFO, " > Format: %s -> %s", ma_get_format_name(AUDIO.System.device.playback.format), ma_get_format_name(AUDIO.System.device.playback.internalFormat)); @@ -507,20 +500,6 @@ void CloseAudioDevice(void) { if (AUDIO.System.isReady) { - // Unload dummy audio buffers pool - // WARNING: They can be pointing to already unloaded data - for (int i = 0; i < MAX_AUDIO_BUFFER_POOL_CHANNELS; i++) - { - //UnloadAudioBuffer(AUDIO.MultiChannel.pool[i]); - if (AUDIO.MultiChannel.pool[i] != NULL) - { - ma_data_converter_uninit(&AUDIO.MultiChannel.pool[i]->converter, NULL); - UntrackAudioBuffer(AUDIO.MultiChannel.pool[i]); - //RL_FREE(buffer->data); // Already unloaded by UnloadSound() - RL_FREE(AUDIO.MultiChannel.pool[i]); - } - } - ma_mutex_uninit(&AUDIO.System.lock); ma_device_uninit(&AUDIO.System.device); ma_context_uninit(&AUDIO.System.context); From 15716e59dc1fddbf6efce18a359448fe6d53a908 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 7 Mar 2023 20:07:54 +0100 Subject: [PATCH 148/192] Update CHANGELOG --- CHANGELOG | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index b7abe8b68f62..dfd6b28633e9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -4,7 +4,7 @@ changelog Current Release: raylib 4.2.0 (11 August 2022) ------------------------------------------------------------------------- -Release: raylib 4.5 (xx February 2023) -WIP- +Release: raylib 4.5 (xx March 2023) -WIP- ------------------------------------------------------------------------- KEY CHANGES: - ADDED: M3D model format support with animations From ab1e246367973c4d2ef74843a5f9588010889466 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 7 Mar 2023 20:33:45 +0100 Subject: [PATCH 149/192] REVIEWED: Data types validation --- src/raudio.c | 10 +++++----- src/rmodels.c | 11 +++++++++-- src/rtext.c | 9 ++++++++- src/rtextures.c | 4 +++- 4 files changed, 25 insertions(+), 9 deletions(-) diff --git a/src/raudio.c b/src/raudio.c index 8ac09b2f329c..4bdbede9ebe0 100644 --- a/src/raudio.c +++ b/src/raudio.c @@ -912,11 +912,11 @@ Sound LoadSoundFromWave(Wave wave) // Checks if a sound is ready bool IsSoundReady(Sound sound) { - return ((sound.frameCount > 0) && // Validate frame count - (sound.stream.buffer != NULL) && // Validate stream buffer - (sound.stream.sampleRate > 0) && // Validate sample rate is supported - (sound.stream.sampleSize > 0) && // Validate sample size is supported - (sound.stream.channels > 0)); // Validate number of channels supported + return ((sound.frameCount > 0) && // Validate frame count + (sound.stream.buffer != NULL) && // Validate stream buffer + (sound.stream.sampleRate > 0) && // Validate sample rate is supported + (sound.stream.sampleSize > 0) && // Validate sample size is supported + (sound.stream.channels > 0)); // Validate number of channels supported } // Unload wave data diff --git a/src/rmodels.c b/src/rmodels.c index b28e14dc1ad4..a2b5dd888839 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -1112,7 +1112,13 @@ Model LoadModelFromMesh(Mesh mesh) // Check if a model is ready bool IsModelReady(Model model) { - return model.meshes != NULL && model.materials != NULL && model.meshMaterial != NULL && model.meshCount > 0 && model.materialCount > 0; + return ((model.meshes != NULL) && // Validate model contains some mesh + (model.materials != NULL) && // Validate model contains some material (at least default one) + (model.meshMaterial != NULL) && // Validate mesh-material linkage + (model.meshCount > 0) && // Validate mesh count + (model.materialCount > 0)); // Validate material count + + // NOTE: This is a very general model validation, many elements could be validated from a model... } // Unload model (meshes/materials) from memory (RAM and/or VRAM) @@ -1959,7 +1965,8 @@ Material LoadMaterialDefault(void) // Check if a material is ready bool IsMaterialReady(Material material) { - return material.maps != NULL; + return ((material.maps != NULL) && // Validate material contain some map + (material.shader.id > 0)); // Validate material shader is valid } // Unload material from memory diff --git a/src/rtext.c b/src/rtext.c index f07261121d38..2d47bdf6c836 100644 --- a/src/rtext.c +++ b/src/rtext.c @@ -538,7 +538,14 @@ Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int // Check if a font is ready bool IsFontReady(Font font) { - return font.glyphs != NULL; + return ((font.texture.id > 0) && // Validate OpenGL id fot font texture atlas + (font.baseSize > 0) && // Validate font size + (font.glyphCount > 0) && // Validate font contains some glyph + (font.recs != NULL) && // Validate font recs defining glyphs on texture atlas + (font.glyphs != NULL)); // Validate glyph data is loaded + + // NOTE: Further validations could be done to verify if recs count and glyphs count + // match glyphCount and to verify that data contained is valid (glyphs values, metrics...) } // Load font data for further use diff --git a/src/rtextures.c b/src/rtextures.c index 56b200ce8505..12bca8a8e48f 100644 --- a/src/rtextures.c +++ b/src/rtextures.c @@ -3362,7 +3362,9 @@ void UnloadTexture(Texture2D texture) // Check if a render texture is ready bool IsRenderTextureReady(RenderTexture2D target) { - return target.id > 0 && IsTextureReady(target.depth) && IsTextureReady(target.texture); + return ((target.id > 0) && // Validate OpenGL id + IsTextureReady(target.depth) && // Validate FBO depth texture/renderbuffer + IsTextureReady(target.texture)); // Validate FBO texture } // Unload render texture from GPU memory (VRAM) From 4f7b5ff59f821dfcc62e73fc75753093200d7e97 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 7 Mar 2023 20:40:45 +0100 Subject: [PATCH 150/192] `WARNING`: REMOVED: `UnloadModelKeepMeshes()` --- src/raylib.h | 1 - src/rmodels.c | 21 --------------------- 2 files changed, 22 deletions(-) diff --git a/src/raylib.h b/src/raylib.h index 9fcece6f02c3..a6c1a49d6f50 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1440,7 +1440,6 @@ RLAPI Model LoadModel(const char *fileName); RLAPI Model LoadModelFromMesh(Mesh mesh); // Load model from generated mesh (default material) RLAPI bool IsModelReady(Model model); // Check if a model is ready RLAPI void UnloadModel(Model model); // Unload model (including meshes) from memory (RAM and/or VRAM) -RLAPI void UnloadModelKeepMeshes(Model model); // Unload model (but not meshes) from memory (RAM and/or VRAM) RLAPI BoundingBox GetModelBoundingBox(Model model); // Compute model bounding box limits (considers all meshes) // Model drawing functions diff --git a/src/rmodels.c b/src/rmodels.c index a2b5dd888839..8ab923421323 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -1147,27 +1147,6 @@ void UnloadModel(Model model) TRACELOG(LOG_INFO, "MODEL: Unloaded model (and meshes) from RAM and VRAM"); } -// Unload model (but not meshes) from memory (RAM and/or VRAM) -void UnloadModelKeepMeshes(Model model) -{ - // Unload materials maps - // NOTE: As the user could be sharing shaders and textures between models, - // we don't unload the material but just free its maps, - // the user is responsible for freeing models shaders and textures - for (int i = 0; i < model.materialCount; i++) RL_FREE(model.materials[i].maps); - - // Unload arrays - RL_FREE(model.meshes); - RL_FREE(model.materials); - RL_FREE(model.meshMaterial); - - // Unload animation data - RL_FREE(model.bones); - RL_FREE(model.bindPose); - - TRACELOG(LOG_INFO, "MODEL: Unloaded model (but not meshes) from RAM and VRAM"); -} - // Compute model bounding box limits (considers all meshes) BoundingBox GetModelBoundingBox(Model model) { From 4fd1e04e706bdf290377b7b29d2706fa5954afb1 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 7 Mar 2023 21:03:44 +0100 Subject: [PATCH 151/192] Update CHANGELOG --- CHANGELOG | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index dfd6b28633e9..76fd13ce598b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -100,6 +100,8 @@ Detailed changes: [models] ADDED: GLTF animation support (#2844) by @charles-l [models] ADDED: DrawCapsule() and DrawCapsuleWires() (#2761) by @IanBand [models] ADDED: LoadMaterials(), MTL files loading, same code as OBJ loader (#2872) by @JeffM2501 +[models] `WARNING`: REMOVED: UnloadModelKeepMeshes() +[models] `WARNING`: REMOVED: DrawCubeTexture(), DrawCubeTextureRec(), functions moved to new example: `models_draw_cube_texture` [models] REVIEWED: DrawMesh(), using SHADER_LOC_COLOR_SPECULAR as a material map (#2908) by @haved [models] REVIEWED: LoadM3D() vertex color support (#2878) by @GithubPrankster, @bztsrc [models] REVIEWED: GenMeshHeightmap() (#2716) @@ -107,7 +109,6 @@ Detailed changes: [models] REVIEWED: Simplify .vox signature check (#2752) by @CrezyDud [models] REVIEWED: LoadIQM(), support bone names loading if available (#2882) by @PencilAmazing [models] REVIEWED: GenMeshTangents(), avoid crash on missing texcoords data (#2927) -[models] `WARNING`: REMOVED: DrawCubeTexture(), DrawCubeTextureRec(), functions moved to new example: `models_draw_cube_texture` [audio] ADDED: Full support for QOA audio file format [audio] ADDED: Mixed audio processor (#2929) by @hatkidchan [audio] ADDED: IsWaveReady()`, IsSoundReady(), IsMusicReady() (#2892) by @RobLoach From ee3e40c663e138473fffb9abc58214f6be130f03 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 12 Mar 2023 13:47:02 +0100 Subject: [PATCH 152/192] Update rcore.c --- src/rcore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rcore.c b/src/rcore.c index f24ae012c814..d6c8325eaabb 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -1717,7 +1717,7 @@ void *GetWindowHandle(void) // NOTE: Returned handle is: unsigned long Window (X.h) // typedef unsigned long XID; // typedef XID Window; - //unsigned long id = (unsigned long)glfwGetX11Window(window); + //unsigned long id = (unsigned long)glfwGetX11Window(CORE.Window.handle); //return NULL; // TODO: Find a way to return value... cast to void *? return (void *)CORE.Window.handle; #endif From b436c8d7e5346a241b00511a11585936895d959d Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 12 Mar 2023 13:48:11 +0100 Subject: [PATCH 153/192] ADDED: Security check for `emscripten_run_script()` #2954 --- src/rcore.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/rcore.c b/src/rcore.c index d6c8325eaabb..eae49515fcd4 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -1994,7 +1994,9 @@ void SetClipboardText(const char *text) glfwSetClipboardString(CORE.Window.handle, text); #endif #if defined(PLATFORM_WEB) - emscripten_run_script(TextFormat("navigator.clipboard.writeText('%s')", text)); + // Security check to (partially) avoid malicious code + if (strchr(text, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided Clipboard could be potentially malicious, avoid [\'] character"); + else emscripten_run_script(TextFormat("navigator.clipboard.writeText('%s')", text)); #endif } @@ -2006,6 +2008,7 @@ const char *GetClipboardText(void) return glfwGetClipboardString(CORE.Window.handle); #endif #if defined(PLATFORM_WEB) +/* // Accessing clipboard data from browser is tricky due to security reasons // The method to use is navigator.clipboard.readText() but this is an asynchronous method // that will return at some moment after the function is called with the required data @@ -2019,7 +2022,7 @@ const char *GetClipboardText(void) // Another approach could be just copy the data in a HTML text field and try to retrieve it // later on if available... and clean it for future accesses - +*/ return NULL; #endif return NULL; @@ -2910,6 +2913,9 @@ void SetConfigFlags(unsigned int flags) void TakeScreenshot(const char *fileName) { #if defined(SUPPORT_MODULE_RTEXTURES) + // Security check to (partially) avoid malicious code on PLATFORM_WEB + if (strchr(fileName, '\'') != NULL) { TRACELOG(LOG_WARNING, "SYSTEM: Provided fileName could be potentially malicious, avoid [\'] character"); return; } + Vector2 scale = GetWindowScaleDPI(); unsigned char *imgData = rlReadScreenPixels((int)((float)CORE.Window.render.width*scale.x), (int)((float)CORE.Window.render.height*scale.y)); Image image = { imgData, (int)((float)CORE.Window.render.width*scale.x), (int)((float)CORE.Window.render.height*scale.y), 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 }; @@ -3536,12 +3542,8 @@ unsigned char *DecodeDataBase64(const unsigned char *data, int *outputSize) // Ref: https://github.com/raysan5/raylib/issues/686 void OpenURL(const char *url) { - // Small security check trying to avoid (partially) malicious code... - // sorry for the inconvenience when you hit this point... - if (strchr(url, '\'') != NULL) - { - TRACELOG(LOG_WARNING, "SYSTEM: Provided URL is not valid"); - } + // Security check to (aprtially) avoid malicious code on PLATFORM_WEB + if (strchr(url, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'] character"); else { #if defined(PLATFORM_DESKTOP) From f9c4cc2040aa014292b02fcf10918ca930341e3b Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 12 Mar 2023 19:28:42 +0100 Subject: [PATCH 154/192] ADDED: `UpdateCameraPro()` -Experimental- REVIEWED: rcamera module formating REVIEWED: `core_3d_camera_example` --- examples/core/core_3d_camera_first_person.c | 19 +++ src/rcamera.h | 144 ++++++++++++-------- 2 files changed, 104 insertions(+), 59 deletions(-) diff --git a/examples/core/core_3d_camera_first_person.c b/examples/core/core_3d_camera_first_person.c index 0fc784fa65f1..de0a43c33063 100644 --- a/examples/core/core_3d_camera_first_person.c +++ b/examples/core/core_3d_camera_first_person.c @@ -113,7 +113,26 @@ int main(void) } } + // Update camera computes movement internally depending on the camera mode + // Some default standard keyboard/mouse inputs are hardcoded to simplify use + // For advance camera controls, it's reecommended 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 + // as input parameters, with this approach, rcamera module is internally independent of raylib inputs + UpdateCameraPro(&camera, + (IsKeyDown(KEY_W) || IsKeyDown(KEY_UP))*0.1f - // Move forward-backward + (IsKeyDown(KEY_S) || IsKeyDown(KEY_DOWN))*0.1f, + (IsKeyDown(KEY_D) || IsKeyDown(KEY_RIGHT))*0.1f - // Move right-left + (IsKeyDown(KEY_A) || IsKeyDown(KEY_LEFT))*0.1f, + 0.0f, // Move up-down + GetMouseWheelMove()*2.0f, // Move to target (zoom) + GetMouseDelta().x*0.05f, // Rotation: yaw + GetMouseDelta().y*0.05f, // Rotation: pitch + 0.0f); // Rotation: roll +*/ //---------------------------------------------------------------------------------- // Draw diff --git a/src/rcamera.h b/src/rcamera.h index c3a101f0b0ff..172237588a11 100644 --- a/src/rcamera.h +++ b/src/rcamera.h @@ -46,32 +46,35 @@ //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- -//... +// Function specifiers definition +#ifndef RLAPI + #define RLAPI // Functions defined as 'extern' by default (implicit specifiers) +#endif + #if defined(CAMERA_STANDALONE) -#define CAMERA_CULL_DISTANCE_NEAR 0.01 -#define CAMERA_CULL_DISTANCE_FAR 1000.0 + #define CAMERA_CULL_DISTANCE_NEAR 0.01 + #define CAMERA_CULL_DISTANCE_FAR 1000.0 #else -#define CAMERA_CULL_DISTANCE_NEAR RL_CULL_DISTANCE_NEAR -#define CAMERA_CULL_DISTANCE_FAR RL_CULL_DISTANCE_FAR + #define CAMERA_CULL_DISTANCE_NEAR RL_CULL_DISTANCE_NEAR + #define CAMERA_CULL_DISTANCE_FAR RL_CULL_DISTANCE_FAR #endif //---------------------------------------------------------------------------------- // Types and Structures Definition // NOTE: Below types are required for CAMERA_STANDALONE usage //---------------------------------------------------------------------------------- -// TODO review #if defined(CAMERA_STANDALONE) - // Vector2 type + // Vector2, 2 components typedef struct Vector2 { - float x; - float y; + float x; // Vector x component + float y; // Vector y component } Vector2; - // Vector3 type + // Vector3, 3 components typedef struct Vector3 { - float x; - float y; - float z; + float x; // Vector x component + float y; // Vector y component + float z; // Vector z component } Vector3; // Camera type, defines a camera position/orientation in 3d space @@ -80,31 +83,31 @@ Vector3 target; // Camera target it looks-at Vector3 up; // Camera up vector (rotation over its axis) float fovy; // Camera field-of-view apperture in Y (degrees) in perspective, used as near plane width in orthographic - int projection; // Camera type, defines projection type: CAMERA_PERSPECTIVE or CAMERA_ORTHOGRAPHIC + int projection; // Camera projection type: CAMERA_PERSPECTIVE or CAMERA_ORTHOGRAPHIC } Camera3D; typedef Camera3D Camera; // Camera type fallback, defaults to Camera3D - // Camera system modes + // Camera projection typedef enum { - CAMERA_CUSTOM = 0, - CAMERA_FREE, - CAMERA_ORBITAL, - CAMERA_FIRST_PERSON, - CAMERA_THIRD_PERSON - } CameraMode; + CAMERA_PERSPECTIVE = 0, // Perspective projection + CAMERA_ORTHOGRAPHIC // Orthographic projection + } CameraProjection; - // Camera projection modes + // Camera system modes typedef enum { - CAMERA_PERSPECTIVE = 0, - CAMERA_ORTHOGRAPHIC - } CameraProjection; + CAMERA_CUSTOM = 0, // Camera custom, controlled by user (UpdateCamera() does nothing) + CAMERA_FREE, // Camera free mode + CAMERA_ORBITAL, // Camera orbital, around target, zoom supported + CAMERA_FIRST_PERSON, // Camera first person + CAMERA_THIRD_PERSON // Camera third person + } CameraMode; #endif //---------------------------------------------------------------------------------- // Global Variables Definition //---------------------------------------------------------------------------------- - +//... //---------------------------------------------------------------------------------- // Module Functions Declaration @@ -114,21 +117,23 @@ extern "C" { // Prevents name mangling of functions #endif -Vector3 GetCameraForward(Camera *camera); -Vector3 GetCameraUp(Camera *camera); -Vector3 GetCameraRight(Camera *camera); +RLAPI Vector3 GetCameraForward(Camera *camera); +RLAPI Vector3 GetCameraUp(Camera *camera); +RLAPI Vector3 GetCameraRight(Camera *camera); -void CameraMoveForward(Camera *camera, float distance, bool moveInWorldPlane); -void CameraMoveUp(Camera *camera, float distance); -void CameraMoveRight(Camera *camera, float distance, bool moveInWorldPlane); -void CameraMoveToTarget(Camera *camera, float delta); +// Camera movement +RLAPI void CameraMoveForward(Camera *camera, float distance, bool moveInWorldPlane); +RLAPI void CameraMoveUp(Camera *camera, float distance); +RLAPI void CameraMoveRight(Camera *camera, float distance, bool moveInWorldPlane); +RLAPI void CameraMoveToTarget(Camera *camera, float delta); -void CameraYaw(Camera *camera, float angle, bool rotateAroundTarget); -void CameraPitch(Camera *camera, float angle, bool lockView, bool rotateAroundTarget, bool rotateUp); -void CameraRoll(Camera *camera, float angle); +// Camera rotation +RLAPI void CameraYaw(Camera *camera, float angle, bool rotateAroundTarget); +RLAPI void CameraPitch(Camera *camera, float angle, bool lockView, bool rotateAroundTarget, bool rotateUp); +RLAPI void CameraRoll(Camera *camera, float angle); -Matrix GetCameraViewMatrix(Camera *camera); -Matrix GetCameraProjectionMatrix(Camera* camera, float aspect); +RLAPI Matrix GetCameraViewMatrix(Camera *camera); +RLAPI Matrix GetCameraProjectionMatrix(Camera* camera, float aspect); #if defined(__cplusplus) } @@ -306,36 +311,35 @@ void CameraYaw(Camera *camera, float angle, bool rotateAroundTarget) Vector3 up = GetCameraUp(camera); // View vector - Vector3 target_position = Vector3Subtract(camera->target, camera->position); + Vector3 targetPosition = Vector3Subtract(camera->target, camera->position); // Rotate view vector around up axis - target_position = Vector3RotateByAxisAngle(target_position, up, angle); + targetPosition = Vector3RotateByAxisAngle(targetPosition, up, angle); if (rotateAroundTarget) { // Move position relative to target - camera->position = Vector3Subtract(camera->target, target_position); + camera->position = Vector3Subtract(camera->target, targetPosition); } else // rotate around camera.position { // Move target relative to position - camera->target = Vector3Add(camera->position, target_position); + camera->target = Vector3Add(camera->position, targetPosition); } } -// Rotates the camera around its right vector -// Pitch is "looking up and down" -// lockView prevents camera overrotation (aka "somersaults") -// If rotateAroundTarget is false, the camera rotates around its position -// rotateUp rotates the up direction as well (typically only usefull in CAMERA_FREE) -// Note: angle must be provided in radians +// Rotates the camera around its right vector, pitch is "looking up and down" +// - lockView prevents camera overrotation (aka "somersaults") +// - rotateAroundTarget defines if rotation is around target or around its position +// - rotateUp rotates the up direction as well (typically only usefull in CAMERA_FREE) +// NOTE: angle must be provided in radians void CameraPitch(Camera *camera, float angle, bool lockView, bool rotateAroundTarget, bool rotateUp) { // Up direction Vector3 up = GetCameraUp(camera); // View vector - Vector3 target_position = Vector3Subtract(camera->target, camera->position); + Vector3 targetPosition = Vector3Subtract(camera->target, camera->position); if (lockView) { @@ -343,32 +347,32 @@ void CameraPitch(Camera *camera, float angle, bool lockView, bool rotateAroundTa // to allow only viewing straight up or down. // Clamp view up - float max_angle_up = Vector3Angle(up, target_position); - max_angle_up -= 0.001f; // avoid numerical errors - if (angle > max_angle_up) angle = max_angle_up; + float maxAngleUp = Vector3Angle(up, targetPosition); + maxAngleUp -= 0.001f; // avoid numerical errors + if (angle > maxAngleUp) angle = maxAngleUp; // Clamp view down - float max_angle_down = Vector3Angle(Vector3Negate(up), target_position); - max_angle_down *= -1.0f; // downwards angle is negative - max_angle_down += 0.001f; // avoid numerical errors - if (angle < max_angle_down) angle = max_angle_down; + float maxAngleDown = Vector3Angle(Vector3Negate(up), targetPosition); + maxAngleDown *= -1.0f; // downwards angle is negative + maxAngleDown += 0.001f; // avoid numerical errors + if (angle < maxAngleDown) angle = maxAngleDown; } // Rotation axis Vector3 right = GetCameraRight(camera); // Rotate view vector around right axis - target_position = Vector3RotateByAxisAngle(target_position, right, angle); + targetPosition = Vector3RotateByAxisAngle(targetPosition, right, angle); if (rotateAroundTarget) { // Move position relative to target - camera->position = Vector3Subtract(camera->target, target_position); + camera->position = Vector3Subtract(camera->target, targetPosition); } else // rotate around camera.position { // Move target relative to position - camera->target = Vector3Add(camera->position, target_position); + camera->target = Vector3Add(camera->position, targetPosition); } if (rotateUp) @@ -466,4 +470,26 @@ void UpdateCamera(Camera *camera, int mode) } #endif // !CAMERA_STANDALONE +// Update camera movement, movement/rotation values should be provided by user +void UpdateCameraPro(Camera *camera, float moveForward, float moveRightLeft, float moveUpDown, float moveToTarget, float yaw, float pitch, float roll) +{ + bool lockView = true; + bool rotateAroundTarget = false; + bool rotateUp = false; + bool moveInWorldPlane = true; + + // Camera rotation + CameraPitch(camera, -pitch*DEG2RAD, lockView, rotateAroundTarget, rotateUp); + CameraYaw(camera, -yaw*DEG2RAD, rotateAroundTarget); + CameraRoll(camera, roll*DEG2RAD); + + // Camera movement + CameraMoveForward(camera, moveForward, moveInWorldPlane); + CameraMoveRight(camera, moveRightLeft, moveInWorldPlane); + CameraMoveUp(camera, moveUpDown); + + // Zoom target distance + CameraMoveToTarget(camera, moveToTarget); +} + #endif // CAMERA_IMPLEMENTATION From 8ca32127013be61110b72eddc19dda16520ac704 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 12 Mar 2023 19:40:43 +0100 Subject: [PATCH 155/192] REVIEWED: `UpdateCameraPro()` to use `Vector3` --- examples/core/core_3d_camera_first_person.c | 22 ++++++++++-------- src/rcamera.h | 25 ++++++++++++++------- 2 files changed, 30 insertions(+), 17 deletions(-) diff --git a/examples/core/core_3d_camera_first_person.c b/examples/core/core_3d_camera_first_person.c index de0a43c33063..6a2a115a7db0 100644 --- a/examples/core/core_3d_camera_first_person.c +++ b/examples/core/core_3d_camera_first_person.c @@ -123,15 +123,19 @@ int main(void) // This new camera function allows custom movement/rotation values to be directly provided // as input parameters, with this approach, rcamera module is internally independent of raylib inputs UpdateCameraPro(&camera, - (IsKeyDown(KEY_W) || IsKeyDown(KEY_UP))*0.1f - // Move forward-backward - (IsKeyDown(KEY_S) || IsKeyDown(KEY_DOWN))*0.1f, - (IsKeyDown(KEY_D) || IsKeyDown(KEY_RIGHT))*0.1f - // Move right-left - (IsKeyDown(KEY_A) || IsKeyDown(KEY_LEFT))*0.1f, - 0.0f, // Move up-down - GetMouseWheelMove()*2.0f, // Move to target (zoom) - GetMouseDelta().x*0.05f, // Rotation: yaw - GetMouseDelta().y*0.05f, // Rotation: pitch - 0.0f); // Rotation: roll + (Vector3){ + (IsKeyDown(KEY_W) || IsKeyDown(KEY_UP))*0.1f - // Move forward-backward + (IsKeyDown(KEY_S) || IsKeyDown(KEY_DOWN))*0.1f, + (IsKeyDown(KEY_D) || IsKeyDown(KEY_RIGHT))*0.1f - // Move right-left + (IsKeyDown(KEY_A) || IsKeyDown(KEY_LEFT))*0.1f, + 0.0f // Move up-down + }, + (Vector3){ + GetMouseDelta().x*0.05f, // Rotation: yaw + GetMouseDelta().y*0.05f, // Rotation: pitch + 0.0f // Rotation: roll + }, + GetMouseWheelMove()*2.0f); // Move to target (zoom) */ //---------------------------------------------------------------------------------- diff --git a/src/rcamera.h b/src/rcamera.h index 172237588a11..8b37ff7ba42d 100644 --- a/src/rcamera.h +++ b/src/rcamera.h @@ -471,25 +471,34 @@ void UpdateCamera(Camera *camera, int mode) #endif // !CAMERA_STANDALONE // Update camera movement, movement/rotation values should be provided by user -void UpdateCameraPro(Camera *camera, float moveForward, float moveRightLeft, float moveUpDown, float moveToTarget, float yaw, float pitch, float roll) +void UpdateCameraPro(Camera *camera, Vector3 movement, Vector3 rotation, float zoom) { + // Required values + // movement.x - Move forward/backward + // movement.y - Move right/left + // movement.z - Move up/down + // rotation.x - yaw + // rotation.y - pitch + // rotation.z - roll + // zoom - Move towards target + bool lockView = true; bool rotateAroundTarget = false; bool rotateUp = false; bool moveInWorldPlane = true; // Camera rotation - CameraPitch(camera, -pitch*DEG2RAD, lockView, rotateAroundTarget, rotateUp); - CameraYaw(camera, -yaw*DEG2RAD, rotateAroundTarget); - CameraRoll(camera, roll*DEG2RAD); + CameraPitch(camera, -rotation.y*DEG2RAD, lockView, rotateAroundTarget, rotateUp); + CameraYaw(camera, -rotation.x*DEG2RAD, rotateAroundTarget); + CameraRoll(camera, rotation.z*DEG2RAD); // Camera movement - CameraMoveForward(camera, moveForward, moveInWorldPlane); - CameraMoveRight(camera, moveRightLeft, moveInWorldPlane); - CameraMoveUp(camera, moveUpDown); + CameraMoveForward(camera, movement.x, moveInWorldPlane); + CameraMoveRight(camera, movement.y, moveInWorldPlane); + CameraMoveUp(camera, movement.z); // Zoom target distance - CameraMoveToTarget(camera, moveToTarget); + CameraMoveToTarget(camera, zoom); } #endif // CAMERA_IMPLEMENTATION From 520ea94de8fdf85af987d9b291fb4bc24259494a Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 12 Mar 2023 19:52:24 +0100 Subject: [PATCH 156/192] Update version to `raylib 4.5` --- src/raylib.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/raylib.h b/src/raylib.h index a6c1a49d6f50..9c68807b9fca 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1,6 +1,6 @@ /********************************************************************************************** * -* raylib v4.5-dev - A simple and easy-to-use library to enjoy videogames programming (www.raylib.com) +* raylib v4.5 - A simple and easy-to-use library to enjoy videogames programming (www.raylib.com) * * FEATURES: * - NO external dependencies, all required libraries included with raylib @@ -84,7 +84,7 @@ #define RAYLIB_VERSION_MAJOR 4 #define RAYLIB_VERSION_MINOR 5 #define RAYLIB_VERSION_PATCH 0 -#define RAYLIB_VERSION "4.5-dev" +#define RAYLIB_VERSION "4.5" // 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 From 4f38830058ab65a86bc23e30efeb1f5730acbd56 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 12 Mar 2023 20:14:32 +0100 Subject: [PATCH 157/192] Some tweaks --- examples/models/models_loading_m3d.c | 2 +- examples/textures/textures_textured_curve.c | 2 +- src/raylib.dll.rc.data | Bin 11246 -> 11246 bytes src/raylib.h | 1 + src/raylib.rc.data | Bin 11182 -> 11182 bytes 5 files changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/models/models_loading_m3d.c b/examples/models/models_loading_m3d.c index 42d3416deab0..18c8e1afcb05 100644 --- a/examples/models/models_loading_m3d.c +++ b/examples/models/models_loading_m3d.c @@ -2,7 +2,7 @@ * * raylib [models] example - Load models M3D * -* Example originally created with raylib 4.5-dev, last time updated with raylib 4.5-dev +* Example originally created with raylib 4.5, last time updated with raylib 4.5 * * Example contributed by bzt (@bztsrc) and reviewed by Ramon Santamaria (@raysan5) * diff --git a/examples/textures/textures_textured_curve.c b/examples/textures/textures_textured_curve.c index 7945d8e32cbe..3c2f0606aa8e 100644 --- a/examples/textures/textures_textured_curve.c +++ b/examples/textures/textures_textured_curve.c @@ -2,7 +2,7 @@ * * raylib [textures] example - Draw a texture along a segmented curve * -* Example originally created with raylib 4.5-dev +* Example originally created with raylib 4.5, last time updated with raylib 4.5 * * Example contributed by Jeffery Myers and reviewed by Ramon Santamaria (@raysan5) * diff --git a/src/raylib.dll.rc.data b/src/raylib.dll.rc.data index 729c45ddfb017ca51ecd873c24d166c84cd494ea..d506b8d28651d7d7e17519bcc0a382a161b688f1 100644 GIT binary patch delta 48 zcmaDC{w{pO9Sv?)1{MYo0Me5`YKTwL@wN|X+) delta 48 ycmZ1%zAk*j9Sv?K1{MYo0Me5`YKTwL Date: Sun, 12 Mar 2023 20:48:49 +0100 Subject: [PATCH 158/192] Update CHANGELOG --- CHANGELOG | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 76fd13ce598b..d7207d7082cb 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -50,9 +50,11 @@ Detailed changes: [core] REVIEWED: GetMonitorWidth() and GetMonitorHeight() (#2934) [core] REVIEWED: GetWindowHandle() to return Linux window (#2938) [core] REVIEWED: WindowDropCallback(), additional security check (#2943) +[core] REVIEWED: Security checks for emscripten_run_script() (#2954) [rcamera] REDESIGNED: New implementation from scratch (#2563) by @Crydsch [rcamera] REVIEWED: Make orbital camera work as expected (#2926) by @JeffM2501 [rcamera] REVIEWED: Multiple reviews on the new implementation +[rcamera] ADDED: UpdateCameraPro(), supporting custom user inputs [rlgl] ADDED: OpenGL ES 2.0 support on PLATFORM_DESKTOP (#2840) by @wtnbgo [rlgl] ADDED: Separate blending modes for color and alpha, BLEND_CUSTOM_SEPARATE (#2741) [rlgl] ADDED: rlSetBlendFactorsSeparate and custom blend mode modification checks (#2741) by @pure01fx From 54f01e151cebca517ef31870d6d5f03c4c68b64a Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 12 Mar 2023 20:50:19 +0100 Subject: [PATCH 159/192] Update CHANGELOG --- CHANGELOG | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index d7207d7082cb..118d5782187a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -4,7 +4,7 @@ changelog Current Release: raylib 4.2.0 (11 August 2022) ------------------------------------------------------------------------- -Release: raylib 4.5 (xx March 2023) -WIP- +Release: raylib 4.5 (16 March 2023) ------------------------------------------------------------------------- KEY CHANGES: - ADDED: M3D model format support with animations @@ -14,7 +14,6 @@ KEY CHANGES: - REDESIGNED: rlgl module to avoid render batch triangles limits pre-check: rlCheckRenderBatchLimit() - REDESIGNED: rshapes module to minimize the rlgl dependency, now only 6 low-level functions required! - ADDED: rl_gputex self-contained module for compressed textures loading, used by rtextures module - - raygui 3.5: New version of the immediate-mode gui system for tools development with raylib Detailed changes: [core] ADDED: RAYLIB_VERSION_* values to raylib.h (#2856) by @RobLoach From e4bc2c643ee3fa3fa3360d46afe8b03bb21deadb Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 12 Mar 2023 20:52:24 +0100 Subject: [PATCH 160/192] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c66eed75e317..05ba5ccf08f8 100644 --- a/README.md +++ b/README.md @@ -38,10 +38,10 @@ features -------- - **NO external dependencies**, all required libraries are [bundled into raylib](https://github.com/raysan5/raylib/tree/master/src/external) - Multiple platforms supported: **Windows, Linux, MacOS, RPI, Android, HTML5... and more!** - - Written in plain C code (C99) in PascalCase/camelCase notation + - Written in plain C code (C99) using PascalCase/camelCase notation - Hardware accelerated with OpenGL (**1.1, 2.1, 3.3, 4.3 or ES 2.0**) - **Unique OpenGL abstraction layer** (usable as standalone module): [rlgl](https://github.com/raysan5/raylib/blob/master/src/rlgl.h) - - Multiple **Fonts** formats supported (TTF, XNA fonts, AngelCode fonts) + - Multiple **Fonts** formats supported (TTF, Image fonts, AngelCode fonts) - Multiple texture formats supported, including **compressed formats** (DXT, ETC, ASTC) - **Full 3D support**, including 3D Shapes, Models, Billboards, Heightmaps and more! - Flexible Materials system, supporting classic maps and **PBR maps** @@ -51,7 +51,7 @@ features - Audio loading and playing with streaming support (WAV, OGG, MP3, FLAC, XM, MOD) - **VR stereo rendering** support with configurable HMD device parameters - Huge examples collection with [+120 code examples](https://github.com/raysan5/raylib/tree/master/examples)! - - Bindings to [+50 programming languages](https://github.com/raysan5/raylib/blob/master/BINDINGS.md)! + - Bindings to [+60 programming languages](https://github.com/raysan5/raylib/blob/master/BINDINGS.md)! - **Free and open source**. basic example From ce28dfbdeb8c00d3ee389eb2204db9c43480d1f4 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 12 Mar 2023 21:03:21 +0100 Subject: [PATCH 161/192] Update CHANGELOG --- CHANGELOG | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 118d5782187a..3a5c43759e2a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -93,7 +93,6 @@ Detailed changes: [text] `WARNING`: RENAMED: TextCodepointsToUTF8() to LoadUTF8() [text] `WARNING`: RENAMED: GetCodepoint() -> GetCodepointNext() [text] REDESIGNED: GetCodepointNext() -[text] REVIEWED text_codepoints_loading.c [text] REVIEWED: MeasureTextEx(), avoid crash on bad data [text] REVIEWED: UnloadFontData(), avoid crash on invalid font data [models] ADDED: Support M3D model file format (meshes and materials) (#2648) by @bztsrc @@ -138,6 +137,7 @@ Detailed changes: [examples] REVIEWED: core_loading_thread, join thread on completion (#2845) by @planetis-m [examples] REVIEWED: models_loading_gltf [examples] REVIEWED: Shader lighting.fs for GLSL120 (#2651) +[examples] REVIEWED: text_codepoints_loading.c [parser] REVIEWED: raylib-parser Makefile (#2765) by @Peter0x44 [build] ADDED: Packaging for distros with deb-based and rpm-based packages (#2877) by @KOLANICH [build] ADDED: Linkage library -latomic on Linux (only required for ARM32) From 8873aca268fdd6ecea657b91a9ea0e2910b3430c Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 12 Mar 2023 21:09:50 +0100 Subject: [PATCH 162/192] Update CHANGELOG --- CHANGELOG | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 3a5c43759e2a..36c8bd2820af 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,7 +1,7 @@ changelog --------- -Current Release: raylib 4.2.0 (11 August 2022) +Current Release: raylib 4.5.0 (16 March 2023) ------------------------------------------------------------------------- Release: raylib 4.5 (16 March 2023) From 90e36d188386181e9bb0bf5de7ef087d4033c66b Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 13 Mar 2023 10:54:06 +0100 Subject: [PATCH 163/192] Update ROADMAP.md --- ROADMAP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ROADMAP.md b/ROADMAP.md index f25f83459dc9..0d126c86f62a 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -9,7 +9,7 @@ Here it is a wishlist with features and ideas to improve the library. Note that _Current version of raylib is complete and functional but there is always room for improvements._ **raylib 4.x** - - [ ] Redesign camera module (more flexible) ([#1143](https://github.com/raysan5/raylib/issues/1143), https://github.com/raysan5/raylib/discussions/2507) + - [x] Redesign camera module (more flexible) ([#1143](https://github.com/raysan5/raylib/issues/1143), https://github.com/raysan5/raylib/discussions/2507) - [ ] Redesign gestures system, improve touch inputs management - [ ] Redesign raudio module, implement miniaudio high-level provided features - [x] Better documentation and improved examples From dad0e64aa81c6f53773d3a8d52394ae1147dd386 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 13 Mar 2023 11:44:02 +0100 Subject: [PATCH 164/192] Update HISTORY.md --- HISTORY.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/HISTORY.md b/HISTORY.md index cebac5362225..0b722b1a3a32 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -395,3 +395,18 @@ Highlights for `raylib 4.2`: As always, there are more improvements than the key features listed, make sure to check raylib [CHANGELOG](CHANGELOG) for the detailed list of changes; for this release a `WARNING` flag has been added to all the changes that could affect bindings or productivity code. **raylib keeps improving one more version** and a special focus on maintainability has been put on the library for the future. Specific/advance functionality will be provided through **raylib-extras** repos and raylib main repo devlelopment will be focused on what made raylib popular: being a simple and easy-to-use library to **enjoy videogames programming**. **Enjoy gamedev/tools/graphics programming!** :) + +notes on raylib 4.5 +------------------- + +It's been **7 months** since latest raylib release. As usual, **many parts of the library have been reviewed and improved** along those months. Many issues have been closed, staying under 10 open issues at the moment of this writting and also many PRs from contributors have been received, reviewed and merged into raylib library. Some new functions have been added and some others have been removed to improve library coherence and avoid moving too high level, giving the users the tools to implement advance functionality themselfs over raylib. Again, this is a big release with a considerable amount of changes and improvements. Here it is a small summary highlighting this new **rayib 4.5**. + +Some numbers for this release: + + - **+100** closed issues (for a TOTAL of **+1340**!) + - **+350** commits since previous RELEASE (for a TOTAL of **+6350**!) + - **+25** functions ADDED to raylib API (for a TOTAL of **516**!) + - **+40** functions REVIEWED/REDESIGNED + - **+40** new contributors (for a TOTAL of **405**!) + +-WIP- From a3b7bd0891a7c4a211d75745e51908cc90de7c4a Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 13 Mar 2023 11:44:49 +0100 Subject: [PATCH 165/192] Update webassembly.yml --- .github/workflows/webassembly.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/webassembly.yml b/.github/workflows/webassembly.yml index 198e88802248..b50cd8c4675b 100644 --- a/.github/workflows/webassembly.yml +++ b/.github/workflows/webassembly.yml @@ -29,7 +29,7 @@ jobs: - name: Setup emsdk uses: mymindstorm/setup-emsdk@v11 with: - version: 3.0.0 + version: 3.1.30 actions-cache-folder: 'emsdk-cache' - name: Setup Release Version From 9a115106b4692031a99222cefcea372261d2ab75 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 13 Mar 2023 11:48:34 +0100 Subject: [PATCH 166/192] Update miniaudio.h --- src/external/miniaudio.h | 3360 +++++++++++++++++++++++++++----------- 1 file changed, 2380 insertions(+), 980 deletions(-) diff --git a/src/external/miniaudio.h b/src/external/miniaudio.h index ad3651503150..74d584153097 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.11 - 2022-11-04 +miniaudio - v0.11.12 - TBD David Reid - mackron@gmail.com @@ -38,7 +38,7 @@ A config/init pattern is used throughout the entire library. The idea is that yo object and pass that into the initialization routine. The advantage to this system is that the config object can be initialized with logical defaults and new properties added to it without breaking the API. The config object can be allocated on the stack and does not need to be -maintained after initialization of the corresponding object. +maintained after initialization of the corresponding object. 1.1. Low Level API @@ -363,7 +363,7 @@ initialized. The easiest but least flexible way of playing a sound is like so: This plays what miniaudio calls an "inline" sound. It plays the sound once, and then puts the internal sound up for recycling. The last parameter is used to specify which sound group the sound should be associated with which will be explained later. This particular way of playing a sound is -simple, but lacks flexibility and features. A more flexible way of playing a sound is to first +simple, but lacks flexibility and features. A more flexible way of playing a sound is to first initialize a sound: ```c @@ -460,6 +460,8 @@ 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. +Note that GCC and Clang require `-msse2`, `-mavx2`, etc. for SIMD optimizations. + 2.1. Windows ------------ @@ -489,9 +491,10 @@ notarization process. To fix this there are two options. The first is to use the #include "miniaudio.h" ``` -This will require linking with `-framework CoreFoundation -framework CoreAudio -framework AudioUnit`. -Alternatively, if you would rather keep using runtime linking you can add the following to your -entitlements.xcent file: +This will require linking with `-framework CoreFoundation -framework CoreAudio -framework AudioToolbox`. +If you get errors about AudioToolbox, try with `-framework AudioUnit` instead. You may get this when +using older versions of iOS. Alternatively, if you would rather keep using runtime linking you can +add the following to your entitlements.xcent file: ``` com.apple.security.cs.allow-dyld-environment-variables @@ -748,7 +751,7 @@ To read data from a data source: ma_result result; ma_uint64 framesRead; - result = ma_data_source_read_pcm_frames(pDataSource, pFramesOut, frameCount, &framesRead, loop); + result = ma_data_source_read_pcm_frames(pDataSource, pFramesOut, frameCount, &framesRead); if (result != MA_SUCCESS) { return result; // Failed to read data from the data source. } @@ -768,7 +771,7 @@ you could plug in a decoder like so: ma_uint64 framesRead; ma_decoder decoder; // <-- This would be initialized with `ma_decoder_init_*()`. - result = ma_data_source_read_pcm_frames(&decoder, pFramesOut, frameCount, &framesRead, loop); + result = ma_data_source_read_pcm_frames(&decoder, pFramesOut, frameCount, &framesRead); if (result != MA_SUCCESS) { return result; // Failed to read data from the decoder. } @@ -822,7 +825,7 @@ retrieved like so: ma_uint32 channels; ma_uint32 sampleRate; ma_channel channelMap[MA_MAX_CHANNELS]; - + result = ma_data_source_get_data_format(pDataSource, &format, &channels, &sampleRate, channelMap, MA_MAX_CHANNELS); if (result != MA_SUCCESS) { return result; // Failed to retrieve data format. @@ -842,7 +845,9 @@ 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. +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 +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 they reach the end of the data source, but if you need to loop at a specific location, you can do @@ -871,19 +876,19 @@ To do this, you can use chaining: return result; // Failed to set the next data source. } - result = ma_data_source_read_pcm_frames(&decoder1, pFramesOut, frameCount, pFramesRead, MA_FALSE); + result = ma_data_source_read_pcm_frames(&decoder1, pFramesOut, frameCount, pFramesRead); if (result != MA_SUCCESS) { return result; // Failed to read from the decoder. } ``` In the example above we're using decoders. When reading from a chain, you always want to read from -the top level data source in the chain. In the example above, `decoder1` is the top level data +the top level data source in the chain. In the example above, `decoder1` is the top level data source in the chain. When `decoder1` reaches the end, `decoder2` will start seamlessly without any gaps. -Note that the `loop` parameter is set to false in the example above. When this is set to true, only -the current data source will be looped. You can loop the entire chain by linking in a loop like so: +Note that when looping is enabled, only the current data source will be looped. You can loop the +entire chain by linking in a loop like so: ```c ma_data_source_set_next(&decoder1, &decoder2); // decoder1 -> decoder2 @@ -894,9 +899,9 @@ Note that setting up chaining is not thread safe, so care needs to be taken if y changing links while the audio thread is in the middle of reading. Do not use `ma_decoder_seek_to_pcm_frame()` as a means to reuse a data source to play multiple -instances of the same sound simultaneously. Instead, initialize multiple data sources for each -instance. This can be extremely inefficient depending on the data source and can result in -glitching due to subtle changes to the state of internal filters. +instances of the same sound simultaneously. This can be extremely inefficient depending on the type +of data source and can result in glitching due to subtle changes to the state of internal filters. +Instead, initialize multiple data sources for each instance. 4.1. Custom Data Sources @@ -971,7 +976,7 @@ base object (`ma_data_source_base`): void my_data_source_uninit(my_data_source* pMyDataSource) { // ... do the uninitialization of your custom data source here ... - + // You must uninitialize the base data source. ma_data_source_uninit(&pMyDataSource->base); } @@ -1020,7 +1025,7 @@ configure the engine with an engine config: ma_engine_config engineConfig; engineConfig = ma_engine_config_init(); - engineConfig.pPlaybackDevice = &myDevice; + engineConfig.pDevice = &myDevice; result = ma_engine_init(&engineConfig, &engine); if (result != MA_SUCCESS) { @@ -1061,7 +1066,7 @@ Note that when you're not using a device, you must set the channel count and sam config or else miniaudio won't know what to use (miniaudio will use the device to determine this normally). When not using a device, you need to use `ma_engine_read_pcm_frames()` to process audio data from the engine. This kind of setup is useful if you want to do something like offline -processing. +processing or want to use a different audio system for playback such as SDL. When a sound is loaded it goes through a resource manager. By default the engine will initialize a resource manager internally, but you can also specify a pre-initialized resource manager: @@ -1226,7 +1231,7 @@ might be beneficial to pre-decode the sound. You can do this with the `MA_SOUND_ By default, sounds will be loaded synchronously, meaning `ma_sound_init_*()` will not return until the sound has been fully loaded. If this is prohibitive you can instead load sounds asynchronously -by specificying the `MA_SOUND_FLAG_ASYNC` flag: +by specifying the `MA_SOUND_FLAG_ASYNC` flag: ```c ma_sound_init_from_file(&engine, "my_sound.wav", MA_SOUND_FLAG_DECODE | MA_SOUND_FLAG_ASYNC, pGroup, NULL, &sound); @@ -1247,7 +1252,7 @@ counter hit's zero. You can specify a fence like so: ma_sound sounds[4]; result = ma_fence_init(&fence); - if (result != MA_SUCCES) { + if (result != MA_SUCCESS) { return result; } @@ -2028,14 +2033,14 @@ data from the graph: ``` When you read audio data, miniaudio starts at the node graph's endpoint node which then pulls in -data from it's input attachments, which in turn recusively pull in data from their inputs, and so +data from it's input attachments, which in turn recursively pull in data from their inputs, and so on. At the start of the graph there will be some kind of data source node which will have zero inputs and will instead read directly from a data source. The base nodes don't literally need to read from a `ma_data_source` object, but they will always have some kind of underlying object that sources some kind of audio. The `ma_data_source_node` node can be used to read from a `ma_data_source`. Data is always in floating-point format and in the number of channels you specified when the graph was initialized. The sample rate is defined by the underlying data sources. -It's up to you to ensure they use a consistent and appropraite sample rate. +It's up to you to ensure they use a consistent and appropriate sample rate. The `ma_node` API is designed to allow custom nodes to be implemented with relative ease, but miniaudio includes a few stock nodes for common functionality. This is how you would initialize a @@ -2076,7 +2081,7 @@ another, you do not need to detach first. You can just call `ma_node_attach_outp deal with it for you. Less frequently you may want to create a specialized node. This will be a node where you implement -your own processing callback to apply a custom effect of some kind. This is similar to initalizing +your own processing callback to apply a custom effect of some kind. This is similar to initializing one of the stock node types, only this time you need to specify a pointer to a vtable containing a pointer to the processing function and the number of input and output buses. Example: @@ -2115,7 +2120,7 @@ pointer to the processing function and the number of input and output buses. Exa // Each bus needs to have a channel count specified. To do this you need to specify the channel // counts in an array and then pass that into the node config. ma_uint32 inputChannels[2]; // Equal in size to the number of input channels specified in the vtable. - ma_uint32 outputChannels[1]; // Equal in size to the number of output channels specicied in the vtable. + ma_uint32 outputChannels[1]; // Equal in size to the number of output channels specified in the vtable. inputChannels[0] = channelsIn; inputChannels[1] = channelsIn; @@ -2199,10 +2204,19 @@ and include the following: +-----------------------------------------+---------------------------------------------------+ | MA_NODE_FLAG_CONTINUOUS_PROCESSING | Causes the processing callback to be called even | | | when no data is available to be read from input | - | | attachments. This is useful for effects like | + | | attachments. When a node has at least one input | + | | bus, but there are no inputs attached or the | + | | inputs do not deliver any data, the node's | + | | processing callback will not get fired. This flag | + | | will make it so the callback is always fired | + | | regardless of whether or not any input data is | + | | received. This is useful for effects like | | | echos where there will be a tail of audio data | | | that still needs to be processed even when the | - | | original data sources have reached their ends. | + | | original data sources have reached their ends. It | + | | may also be useful for nodes that must always | + | | have their processing callback fired when there | + | | are no inputs attached. | +-----------------------------------------+---------------------------------------------------+ | MA_NODE_FLAG_ALLOW_NULL_INPUT | Used in conjunction with | | | `MA_NODE_FLAG_CONTINUOUS_PROCESSING`. When this | @@ -2393,7 +2407,7 @@ bus and input bus is locked. This locking is specifically for attaching and deta different threads and does not affect `ma_node_graph_read_pcm_frames()` in any way. The locking and unlocking is mostly self-explanatory, but a slightly less intuitive aspect comes into it when considering that iterating over attachments must not break as a result of attaching or detaching a -node while iteration is occuring. +node while iteration is occurring. Attaching and detaching are both quite simple. When an output bus of a node is attached to an input bus of another node, it's added to a linked list. Basically, an input bus is a linked list, where @@ -2459,7 +2473,7 @@ built-in decoders by specifying one or more of the following options before the #define MA_NO_FLAC ``` -Disabling built-in decoding libraries is useful if you use these libraries independantly of the +Disabling built-in decoding libraries is useful if you use these libraries independently of the `ma_decoder` API. A decoder can be initialized from a file with `ma_decoder_init_file()`, a block of memory with @@ -2561,7 +2575,7 @@ The `ma_decoding_backend_vtable` vtable has the following functions: ``` onInit - onInitFile + onInitFile onInitFileW onInitMemory onUninit @@ -2573,11 +2587,11 @@ these are not specified, miniaudio will deal with it for you via a generic imple When you initialize a custom data source (by implementing the `onInit` function in the vtable) you will need to output a pointer to a `ma_data_source` which implements your custom decoder. See the -section about data sources for details on how to implemen this. Alternatively, see the +section about data sources for details on how to implement this. Alternatively, see the "custom_decoders" example in the miniaudio repository. The `onInit` function takes a pointer to some callbacks for the purpose of reading raw audio data -from some abitrary source. You'll use these functions to read from the raw data and perform the +from some arbitrary source. You'll use these functions to read from the raw data and perform the decoding. When you call them, you will pass in the `pReadSeekTellUserData` pointer to the relevant parameter. @@ -2728,7 +2742,7 @@ To perform the conversion simply call `ma_channel_converter_process_pcm_frames() } ``` -It is up to the caller to ensure the output buffer is large enough to accomodate the new PCM +It is up to the caller to ensure the output buffer is large enough to accommodate the new PCM frames. Input and output PCM frames are always interleaved. Deinterleaved layouts are not supported. @@ -3174,7 +3188,7 @@ you can chain first and second order filters together. If you need to change the configuration of the filter, but need to maintain the state of internal registers you can do so with `ma_lpf_reinit()`. This may be useful if you need to change the sample -rate and/or cutoff frequency dynamically while maintaing smooth transitions. Note that changing the +rate and/or cutoff frequency dynamically while maintaining smooth transitions. Note that changing the format or channel count after initialization is invalid and will result in an error. The `ma_lpf` object supports a configurable order, but if you only need a first order filter you @@ -3347,8 +3361,8 @@ The noise API uses simple LCG random number generation. It supports a custom see for things like automated testing requiring reproducibility. Setting the seed to zero will default to `MA_DEFAULT_LCG_SEED`. -The amplitude, seed, and type can be changed dynamically with `ma_noise_set_amplitude()`, -`ma_noise_set_seed()`, and `ma_noise_set_type()` respectively. +The amplitude and seed can be changed dynamically with `ma_noise_set_amplitude()` and +`ma_noise_set_seed()` respectively. By default, the noise API will use different values for different channels. So, for example, the left side in a stereo stream will be different to the right side. To instead have each channel use @@ -3496,7 +3510,7 @@ you will want to use. To initialize a ring buffer, do something like the followi ``` The `ma_pcm_rb_init()` function takes the sample format and channel count as parameters because -it's the PCM varient of the ring buffer API. For the regular ring buffer that operates on bytes you +it's the PCM variant of the ring buffer API. For the regular ring buffer that operates on bytes you would call `ma_rb_init()` which leaves these out and just takes the size of the buffer in bytes instead of frames. The fourth parameter is an optional pre-allocated buffer and the fifth parameter is a pointer to a `ma_allocation_callbacks` structure for custom memory allocation routines. @@ -3555,7 +3569,7 @@ example, ALSA, which is specific to Linux, will not be included in the Windows b +-------------+-----------------------+--------------------------------------------------------+ | WASAPI | ma_backend_wasapi | Windows Vista+ | | DirectSound | ma_backend_dsound | Windows XP+ | - | WinMM | ma_backend_winmm | Windows XP+ (may work on older versions, but untested) | + | WinMM | ma_backend_winmm | Windows 95+ | | Core Audio | ma_backend_coreaudio | macOS, iOS | | sndio | ma_backend_sndio | OpenBSD | | audio(4) | ma_backend_audio4 | NetBSD, OpenBSD | @@ -3601,6 +3615,12 @@ Some backends have some nuance details you may want to be aware of. miniaudio's built-in resampler is to take advantage of any potential device-specific optimizations the driver may implement. +BSD +--- +- The sndio backend is currently only enabled on OpenBSD builds. +- The audio(4) backend is supported on OpenBSD, but you may need to disable sndiod before you can + use it. + 15.4. UWP --------- - UWP only supports default playback and capture devices. @@ -3631,14 +3651,28 @@ Some backends have some nuance details you may want to be aware of. 16. Optimization Tips ===================== +See below for some tips on improving performance. -16.1. High Level API +16.1. Low Level API +------------------- +- In the data callback, if your data is already clipped prior to copying it into the output buffer, + set the `noClip` config option in the device config to true. This will disable miniaudio's built + in clipping function. +- By default, miniaudio will pre-silence the data callback's output buffer. If you know that you + will always write valid data to the output buffer you can disable pre-silencing by setting the + `noPreSilence` config option in the device config to true. + +16.2. High Level API -------------------- - If a sound does not require doppler or pitch shifting, consider disabling pitching by initializing the sound with the `MA_SOUND_FLAG_NO_PITCH` flag. -- If a sound does not require spatialization, disable it by initialzing the sound with the - `MA_SOUND_FLAG_NO_SPATIALIZATION` flag. It can be renabled again post-initialization with +- If a sound does not require spatialization, disable it by initializing the sound with the + `MA_SOUND_FLAG_NO_SPATIALIZATION` flag. It can be re-enabled again post-initialization with `ma_sound_set_spatialization_enabled()`. +- If you know all of your sounds will always be the same sample rate, set the engine's sample + rate to match that of the sounds. Likewise, if you're using a self-managed resource manager, + consider setting the decoded sample rate to match your sounds. By configuring everything to + use a consistent sample rate, sample rate conversion can be avoided. @@ -3647,17 +3681,6 @@ Some backends have some nuance details you may want to be aware of. - Automatic stream routing is enabled on a per-backend basis. Support is explicitly enabled for WASAPI and Core Audio, however other backends such as PulseAudio may naturally support it, though not all have been tested. -- The contents of the output buffer passed into the data callback will always be pre-initialized to - silence unless the `noPreSilencedOutputBuffer` config variable in `ma_device_config` is set to - true, in which case it'll be undefined which will require you to write something to the entire - buffer. -- By default miniaudio will automatically clip samples. This only applies when the playback sample - format is configured as `ma_format_f32`. If you are doing clipping yourself, you can disable this - overhead by setting `noClip` to true in the device config. -- Note that GCC and Clang requires `-msse2`, `-mavx2`, etc. for SIMD optimizations. -- The sndio backend is currently only enabled on OpenBSD builds. -- The audio(4) backend is supported on OpenBSD, but you may need to disable sndiod before you can - use it. - When compiling with VC6 and earlier, decoding is restricted to files less than 2GB in size. This is due to 64-bit file APIs not being available. */ @@ -3674,7 +3697,7 @@ extern "C" { #define MA_VERSION_MAJOR 0 #define MA_VERSION_MINOR 11 -#define MA_VERSION_REVISION 11 +#define MA_VERSION_REVISION 12 #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__) @@ -3689,7 +3712,7 @@ extern "C" { #pragma GCC diagnostic ignored "-Wc11-extensions" /* anonymous unions are a C11 extension */ #endif #endif - + #if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined(_M_IA64) || defined(__aarch64__) || defined(_M_ARM64) || defined(__powerpc64__) @@ -3748,6 +3771,10 @@ typedef ma_uint32 ma_bool32; #define MA_TRUE 1 #define MA_FALSE 0 +/* These float types are not used universally by miniaudio. It's to simplify some macro expansion for atomic types. */ +typedef float ma_float; +typedef double ma_double; + typedef void* ma_handle; typedef void* ma_ptr; typedef void (* ma_proc)(void); @@ -3801,7 +3828,11 @@ typedef ma_uint16 wchar_t; #ifdef __unix__ #define MA_UNIX - #if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) + #ifdef __ORBIS__ + #define MA_ORBIS + #elif defined(__PROSPERO__) + #define MA_PROSPERO + #elif defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) #define MA_BSD #endif #endif @@ -3817,8 +3848,24 @@ typedef ma_uint16 wchar_t; #ifdef __EMSCRIPTEN__ #define MA_EMSCRIPTEN #endif + #if defined(__NX__) + #define MA_NX + #endif #endif +#if defined(__has_c_attribute) + #if __has_c_attribute(fallthrough) + #define MA_FALLTHROUGH [[fallthrough]] + #endif +#endif +#if !defined(MA_FALLTHROUGH) && defined(__has_attribute) && (defined(__clang__) || defined(__GNUC__)) + #if __has_attribute(fallthrough) + #define MA_FALLTHROUGH __attribute__((fallthrough)) + #endif +#endif +#if !defined(MA_FALLTHROUGH) + #define MA_FALLTHROUGH ((void)0) +#endif #ifdef _MSC_VER #define MA_INLINE __forceinline @@ -4068,6 +4115,7 @@ typedef enum MA_API_NOT_FOUND = -105, MA_INVALID_DEVICE_CONFIG = -106, MA_LOOP = -107, + MA_BACKEND_NOT_ENABLED = -108, /* State errors. */ MA_DEVICE_NOT_INITIALIZED = -200, @@ -4084,7 +4132,7 @@ typedef enum #define MA_MIN_CHANNELS 1 -#ifndef MA_MAX_CHANNELS +#ifndef MA_MAX_CHANNELS #define MA_MAX_CHANNELS 254 #endif @@ -4195,6 +4243,63 @@ typedef struct } ma_lcg; +/* +Atomics. + +These are typesafe structures to prevent errors as a result of forgetting to reference variables atomically. It's too +easy to introduce subtle bugs where you accidentally do a regular assignment instead of an atomic load/store, etc. By +using a struct we can enforce the use of atomics at compile time. + +These types are declared in the header section because we need to reference them in structs below, but functions for +using them are only exposed in the implementation section. I do not want these to be part of the public API. + +There's a few downsides to this system. The first is that you need to declare a new struct for each type. Below are +some macros to help with the declarations. They will be named like so: + + ma_atomic_uint32 - atomic ma_uint32 + ma_atomic_int32 - atomic ma_int32 + ma_atomic_uint64 - atomic ma_uint64 + ma_atomic_float - atomic float + ma_atomic_bool32 - atomic ma_bool32 + +The other downside is that atomic pointers are extremely messy. You need to declare a new struct for each specific +type of pointer you need to make atomic. For example, an atomic ma_node* will look like this: + + MA_ATOMIC_SAFE_TYPE_IMPL_PTR(node) + +Which will declare a type struct that's named like so: + + ma_atomic_ptr_node + +Functions to use the atomic types are declared in the implementation section. All atomic functions are prefixed with +the name of the struct. For example: + + ma_atomic_uint32_set() - Atomic store of ma_uint32 + ma_atomic_uint32_get() - Atomic load of ma_uint32 + etc. + +For pointer types it's the same, which makes them a bit messy to use due to the length of each function name, but in +return you get type safety and enforcement of atomic operations. +*/ +#define MA_ATOMIC_SAFE_TYPE_DECL(c89TypeExtension, typeSize, type) \ + typedef struct \ + { \ + MA_ATOMIC(typeSize, ma_##type) value; \ + } ma_atomic_##type; \ + +#define MA_ATOMIC_SAFE_TYPE_DECL_PTR(type) \ + typedef struct \ + { \ + MA_ATOMIC(MA_SIZEOF_PTR, ma_##type*) value; \ + } ma_atomic_ptr_##type; \ + +MA_ATOMIC_SAFE_TYPE_DECL(32, 4, uint32) +MA_ATOMIC_SAFE_TYPE_DECL(i32, 4, int32) +MA_ATOMIC_SAFE_TYPE_DECL(64, 8, uint64) +MA_ATOMIC_SAFE_TYPE_DECL(f32, 4, float) +MA_ATOMIC_SAFE_TYPE_DECL(32, 4, bool32) + + /* Spinlocks are 32-bit for compatibility reasons. */ typedef ma_uint32 ma_spinlock; @@ -4281,7 +4386,7 @@ Logging #endif #endif #ifndef MA_ATTRIBUTE_FORMAT -#define MA_ATTRIBUTE_FORMAT(fmt,va) +#define MA_ATTRIBUTE_FORMAT(fmt, va) #endif #ifndef MA_MAX_LOG_CALLBACKS @@ -4312,11 +4417,6 @@ logLevel (in) pMessage (in) The log message. - - -Remarks -------- -Do not modify the state of the device from inside the callback. */ typedef void (* ma_log_callback_proc)(void* pUserData, ma_uint32 level, const char* pMessage); @@ -4811,6 +4911,7 @@ typedef struct { ma_gainer_config config; ma_uint32 t; + float masterVolume; float* pOldGains; float* pNewGains; @@ -4826,6 +4927,8 @@ MA_API void ma_gainer_uninit(ma_gainer* pGainer, const ma_allocation_callbacks* MA_API ma_result ma_gainer_process_pcm_frames(ma_gainer* pGainer, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount); MA_API ma_result ma_gainer_set_gain(ma_gainer* pGainer, float newGain); MA_API ma_result ma_gainer_set_gains(ma_gainer* pGainer, float* pNewGains); +MA_API ma_result ma_gainer_set_master_volume(ma_gainer* pGainer, float volume); +MA_API ma_result ma_gainer_get_master_volume(const ma_gainer* pGainer, float* pVolume); @@ -4887,7 +4990,7 @@ MA_API ma_result ma_fader_init(const ma_fader_config* pConfig, ma_fader* pFader) MA_API ma_result ma_fader_process_pcm_frames(ma_fader* pFader, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount); MA_API void ma_fader_get_data_format(const ma_fader* pFader, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate); MA_API void ma_fader_set_fade(ma_fader* pFader, float volumeBeg, float volumeEnd, ma_uint64 lengthInFrames); -MA_API float ma_fader_get_current_volume(ma_fader* pFader); +MA_API float ma_fader_get_current_volume(const ma_fader* pFader); @@ -4899,6 +5002,12 @@ typedef struct float z; } ma_vec3f; +typedef struct +{ + ma_vec3f v; + ma_spinlock lock; +} ma_atomic_vec3f; + typedef enum { ma_attenuation_model_none, /* No distance attenuation and no spatialization. */ @@ -4938,9 +5047,9 @@ MA_API ma_spatializer_listener_config ma_spatializer_listener_config_init(ma_uin typedef struct { ma_spatializer_listener_config config; - ma_vec3f position; /* The absolute position of the listener. */ - ma_vec3f direction; /* The direction the listener is facing. The world up vector is config.worldUp. */ - ma_vec3f velocity; + ma_atomic_vec3f position; /* The absolute position of the listener. */ + ma_atomic_vec3f direction; /* The direction the listener is facing. The world up vector is config.worldUp. */ + ma_atomic_vec3f velocity; ma_bool32 isEnabled; /* Memory management. */ @@ -5012,9 +5121,9 @@ typedef struct float dopplerFactor; /* Set to 0 to disable doppler effect. */ float directionalAttenuationFactor; /* Set to 0 to disable directional attenuation. */ ma_uint32 gainSmoothTimeInFrames; /* When the gain of a channel changes during spatialization, the transition will be linearly interpolated over this number of frames. */ - ma_vec3f position; - ma_vec3f direction; - ma_vec3f velocity; /* For doppler effect. */ + ma_atomic_vec3f position; + ma_atomic_vec3f direction; + ma_atomic_vec3f velocity; /* For doppler effect. */ float dopplerPitch; /* Will be updated by ma_spatializer_process_pcm_frames() and can be used by higher level functions to apply a pitch shift for doppler effect. */ ma_gainer gainer; /* For smooth gain transitions. */ float* pNewChannelGainsOut; /* An offset of _pHeap. Used by ma_spatializer_process_pcm_frames() to store new channel gains. The number of elements in this array is equal to config.channelsOut. */ @@ -5029,6 +5138,8 @@ MA_API ma_result ma_spatializer_init_preallocated(const ma_spatializer_config* p MA_API ma_result ma_spatializer_init(const ma_spatializer_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_spatializer* pSpatializer); MA_API void ma_spatializer_uninit(ma_spatializer* pSpatializer, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_result ma_spatializer_process_pcm_frames(ma_spatializer* pSpatializer, ma_spatializer_listener* pListener, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount); +MA_API ma_result ma_spatializer_set_master_volume(ma_spatializer* pSpatializer, float volume); +MA_API ma_result ma_spatializer_get_master_volume(const ma_spatializer* pSpatializer, float* pVolume); MA_API ma_uint32 ma_spatializer_get_input_channels(const ma_spatializer* pSpatializer); MA_API ma_uint32 ma_spatializer_get_output_channels(const ma_spatializer* pSpatializer); MA_API void ma_spatializer_set_attenuation_model(ma_spatializer* pSpatializer, ma_attenuation_model attenuationModel); @@ -5225,7 +5336,7 @@ MA_API ma_result ma_resampler_process_pcm_frames(ma_resampler* pResampler, const /* -Sets the input and output sample sample rate. +Sets the input and output sample rate. */ MA_API ma_result ma_resampler_set_rate(ma_resampler* pResampler, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut); @@ -6151,7 +6262,7 @@ This section contains the APIs for device playback and capture. Here is where yo #define MA_SUPPORT_JACK /* JACK is technically supported on Windows, but I don't know how many people use it in practice... */ #endif #endif -#if defined(MA_UNIX) +#if defined(MA_UNIX) && !defined(MA_ORBIS) && !defined(MA_PROSPERO) #if defined(MA_LINUX) #if !defined(MA_ANDROID) /* ALSA is not supported on Android. */ #define MA_SUPPORT_ALSA @@ -6246,6 +6357,9 @@ typedef enum ma_device_state_stopping = 4 /* Transitioning from a started state to stopped. */ } ma_device_state; +MA_ATOMIC_SAFE_TYPE_DECL(i32, 4, device_state) + + #ifdef MA_SUPPORT_WASAPI /* We need a IMMNotificationClient object for WASAPI. */ typedef struct @@ -6438,7 +6552,7 @@ DEPRECATED. Use ma_device_notification_proc instead. The callback for when the device has been stopped. This will be called when the device is stopped explicitly with `ma_device_stop()` and also called implicitly when the device is stopped through external forces -such as being unplugged or an internal error occuring. +such as being unplugged or an internal error occurring. Parameters @@ -6567,6 +6681,13 @@ typedef enum ma_aaudio_input_preset_voice_performance /* AAUDIO_INPUT_PRESET_VOICE_PERFORMANCE */ } ma_aaudio_input_preset; +typedef enum +{ + ma_aaudio_allow_capture_default = 0, /* Leaves the allowed capture policy unset. */ + ma_aaudio_allow_capture_by_all, /* AAUDIO_ALLOW_CAPTURE_BY_ALL */ + ma_aaudio_allow_capture_by_system, /* AAUDIO_ALLOW_CAPTURE_BY_SYSTEM */ + ma_aaudio_allow_capture_by_none /* AAUDIO_ALLOW_CAPTURE_BY_NONE */ +} ma_aaudio_allowed_capture_policy; typedef union { @@ -6694,13 +6815,16 @@ struct ma_device_config { ma_opensl_stream_type streamType; ma_opensl_recording_preset recordingPreset; + ma_bool32 enableCompatibilityWorkarounds; } opensl; struct { ma_aaudio_usage usage; ma_aaudio_content_type contentType; ma_aaudio_input_preset inputPreset; + ma_aaudio_allowed_capture_policy allowedCapturePolicy; ma_bool32 noAutoStartAfterReroute; + ma_bool32 enableCompatibilityWorkarounds; } aaudio; }; @@ -6801,7 +6925,7 @@ If the backend requires absolute flexibility with it's data delivery, it can opt which will allow it to implement the logic that will run on the audio thread. This is much more advanced and is completely optional. The audio thread should run data delivery logic in a loop while `ma_device_get_state() == ma_device_state_started` and no errors have been -encounted. Do not start or stop the device here. That will be handled from outside the `onDeviceDataLoop()` callback. +encountered. Do not start or stop the device here. That will be handled from outside the `onDeviceDataLoop()` callback. The invocation of the `onDeviceDataLoop()` callback will be handled by miniaudio. When you start the device, miniaudio will fire this callback. When the device is stopped, the `ma_device_get_state() == ma_device_state_started` condition will fail and the loop will be terminated @@ -7214,6 +7338,7 @@ struct ma_context ma_proc AAudioStreamBuilder_setUsage; ma_proc AAudioStreamBuilder_setContentType; ma_proc AAudioStreamBuilder_setInputPreset; + ma_proc AAudioStreamBuilder_setAllowedCapturePolicy; ma_proc AAudioStreamBuilder_openStream; ma_proc AAudioStream_close; ma_proc AAudioStream_getState; @@ -7263,6 +7388,7 @@ struct ma_context struct { /*HMODULE*/ ma_handle hOle32DLL; + ma_proc CoInitialize; ma_proc CoInitializeEx; ma_proc CoUninitialize; ma_proc CoCreateInstance; @@ -7283,22 +7409,7 @@ struct ma_context #ifdef MA_POSIX struct { - ma_handle pthreadSO; - ma_proc pthread_create; - ma_proc pthread_join; - ma_proc pthread_mutex_init; - ma_proc pthread_mutex_destroy; - ma_proc pthread_mutex_lock; - ma_proc pthread_mutex_unlock; - ma_proc pthread_cond_init; - ma_proc pthread_cond_destroy; - ma_proc pthread_cond_wait; - ma_proc pthread_cond_signal; - ma_proc pthread_attr_init; - ma_proc pthread_attr_destroy; - ma_proc pthread_attr_setschedpolicy; - ma_proc pthread_attr_getschedparam; - ma_proc pthread_attr_setschedparam; + int _unused; } posix; #endif int _unused; @@ -7310,7 +7421,7 @@ struct ma_device ma_context* pContext; ma_device_type type; ma_uint32 sampleRate; - MA_ATOMIC(4, ma_device_state) state; /* The state of the device is variable and can change at any time on any thread. Must be used atomically. */ + ma_atomic_device_state state; /* The state of the device is variable and can change at any time on any thread. Must be used atomically. */ ma_device_data_proc onData; /* Set once at initialization time and should not be changed after. */ ma_device_notification_proc onNotification; /* Set once at initialization time and should not be changed after. */ ma_stop_proc onStop; /* DEPRECATED. Use the notification callback instead. Set once at initialization time and should not be changed after. */ @@ -7326,7 +7437,7 @@ struct ma_device ma_bool8 noClip; ma_bool8 noDisableDenormals; ma_bool8 noFixedSizedCallback; - MA_ATOMIC(4, float) masterVolumeFactor; /* Linear 0..1. Can be read and written simultaneously by different threads. Must be used atomically. */ + ma_atomic_float masterVolumeFactor; /* Linear 0..1. Can be read and written simultaneously by different threads. Must be used atomically. */ ma_duplex_rb duplexRB; /* Intermediary buffer for duplex device on asynchronous backends. */ struct { @@ -7414,8 +7525,8 @@ struct ma_device void* pMappedBufferPlayback; ma_uint32 mappedBufferPlaybackCap; ma_uint32 mappedBufferPlaybackLen; - MA_ATOMIC(4, ma_bool32) isStartedCapture; /* Can be read and written simultaneously across different threads. Must be used atomically, and must be 32-bit. */ - MA_ATOMIC(4, ma_bool32) isStartedPlayback; /* Can be read and written simultaneously across different threads. Must be used atomically, and must be 32-bit. */ + ma_atomic_bool32 isStartedCapture; /* Can be read and written simultaneously across different threads. Must be used atomically, and must be 32-bit. */ + ma_atomic_bool32 isStartedPlayback; /* Can be read and written simultaneously across different threads. Must be used atomically, and must be 32-bit. */ ma_uint32 loopbackProcessID; ma_bool8 loopbackProcessExclude; ma_bool8 noAutoConvertSRC; /* When set to true, disables the use of AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM. */ @@ -7426,7 +7537,8 @@ struct ma_device ma_bool8 isDetachedPlayback; ma_bool8 isDetachedCapture; ma_wasapi_usage usage; - void *hAvrtHandle; + void* hAvrtHandle; + ma_mutex rerouteLock; } wasapi; #endif #ifdef MA_SUPPORT_DSOUND @@ -7544,6 +7656,7 @@ struct ma_device ma_aaudio_usage usage; ma_aaudio_content_type contentType; ma_aaudio_input_preset inputPreset; + ma_aaudio_allowed_capture_policy allowedCapturePolicy; ma_bool32 noAutoStartAfterReroute; } aaudio; #endif @@ -7569,6 +7682,20 @@ struct ma_device #ifdef MA_SUPPORT_WEBAUDIO struct { + /* AudioWorklets path. */ + /* EMSCRIPTEN_WEBAUDIO_T */ int audioContextPlayback; + /* EMSCRIPTEN_WEBAUDIO_T */ int audioContextCapture; + /* EMSCRIPTEN_AUDIO_WORKLET_NODE_T */ int workletNodePlayback; + /* EMSCRIPTEN_AUDIO_WORKLET_NODE_T */ int workletNodeCapture; + size_t intermediaryBufferSizeInFramesPlayback; + size_t intermediaryBufferSizeInFramesCapture; + float* pIntermediaryBufferPlayback; + float* pIntermediaryBufferCapture; + void* pStackBufferPlayback; + void* pStackBufferCapture; + ma_bool32 isInitialized; + + /* ScriptProcessorNode path. */ int indexPlayback; /* We use a factory on the JavaScript side to manage devices and use an index for JS/C interop. */ int indexCapture; } webaudio; @@ -7588,7 +7715,7 @@ struct ma_device ma_uint32 currentPeriodFramesRemainingCapture; ma_uint64 lastProcessedFramePlayback; ma_uint64 lastProcessedFrameCapture; - MA_ATOMIC(4, ma_bool32) isStarted; /* Read and written by multiple threads. Must be used atomically, and must be 32-bit for compiler compatibility. */ + ma_atomic_bool32 isStarted; /* Read and written by multiple threads. Must be used atomically, and must be 32-bit for compiler compatibility. */ } null_device; #endif }; @@ -8252,7 +8379,7 @@ then be set directly on the structure. Below are the members of the `ma_device_c A pointer that will passed to callbacks in pBackendVTable. resampling.linear.lpfOrder - The linear resampler applies a low-pass filter as part of it's procesing for anti-aliasing. This setting controls the order of the filter. The higher + The linear resampler applies a low-pass filter as part of it's processing for anti-aliasing. This setting controls the order of the filter. The higher the value, the better the quality, in general. Setting this to 0 will disable low-pass filtering altogether. The maximum value is `MA_MAX_FILTER_ORDER`. The default value is `min(4, MA_MAX_FILTER_ORDER)`. @@ -9170,6 +9297,11 @@ Retrieves a friendly name for a backend. */ MA_API const char* ma_get_backend_name(ma_backend backend); +/* +Retrieves the backend enum from the given name. +*/ +MA_API ma_result ma_get_backend_from_name(const char* pBackendName, ma_backend* pBackend); + /* Determines whether or not the given backend is available by the compilation environment. */ @@ -9259,7 +9391,7 @@ MA_API ma_bool32 ma_is_loopback_supported(ma_backend backend); /************************************************************************************************************************************************************ -Utiltities +Utilities ************************************************************************************************************************************************************/ @@ -9361,6 +9493,12 @@ Helper for converting gain in decibels to a linear factor. MA_API float ma_volume_db_to_linear(float gain); +/* +Mixes the specified number of frames in floating point format with a volume factor. + +This will run on an optimized path when the volume is equal to 1. +*/ +MA_API ma_result ma_mix_pcm_frames_f32(float* pDst, const float* pSrc, ma_uint64 frameCount, ma_uint32 channels, float volume); /************************************************************************************************** @@ -10118,7 +10256,7 @@ struct ma_resource_manager_data_buffer ma_bool32 seekToCursorOnNextRead; /* On the next read we need to seek to the frame cursor. */ MA_ATOMIC(4, ma_result) result; /* Keeps track of a result of decoding. Set to MA_BUSY while the buffer is still loading. Set to MA_SUCCESS when loading is finished successfully. Otherwise set to some other code. */ MA_ATOMIC(4, ma_bool32) isLooping; /* Can be read and written by different threads at the same time. Must be used atomically. */ - ma_bool32 isConnectorInitialized; /* Used for asynchronous loading to ensure we don't try to initialize the connector multiple times while waiting for the node to fully load. */ + ma_atomic_bool32 isConnectorInitialized; /* Used for asynchronous loading to ensure we don't try to initialize the connector multiple times while waiting for the node to fully load. */ union { ma_decoder decoder; /* Supply type is ma_resource_manager_data_supply_type_encoded */ @@ -10384,7 +10522,7 @@ struct ma_node_output_bus ma_uint8 channels; /* The number of channels in the audio stream for this bus. */ /* Mutable via multiple threads. Must be used atomically. The weird ordering here is for packing reasons. */ - MA_ATOMIC(1, ma_uint8) inputNodeInputBusIndex; /* The index of the input bus on the input. Required for detaching. */ + ma_uint8 inputNodeInputBusIndex; /* The index of the input bus on the input. Required for detaching. Will only be used within the spinlock so does not need to be atomic. */ MA_ATOMIC(4, ma_uint32) flags; /* Some state flags for tracking the read state of the output buffer. A combination of MA_NODE_OUTPUT_BUS_FLAG_*. */ MA_ATOMIC(4, ma_uint32) refCount; /* Reference count for some thread-safety when detaching. */ MA_ATOMIC(4, ma_bool32) isAttached; /* This is used to prevent iteration of nodes that are in the middle of being detached. Used for thread safety. */ @@ -10408,7 +10546,7 @@ struct ma_node_input_bus MA_ATOMIC(4, ma_spinlock) lock; /* Unfortunate lock, but significantly simplifies the implementation. Required for thread-safe attaching and detaching. */ /* Set once at startup. */ - ma_uint8 channels; /* The number of channels in the audio stream for this bus. */ + ma_uint8 channels; /* The number of channels in the audio stream for this bus. */ }; @@ -10416,7 +10554,7 @@ typedef struct ma_node_base ma_node_base; struct ma_node_base { /* These variables are set once at startup. */ - ma_node_graph* pNodeGraph; /* The graph this node belongs to. */ + ma_node_graph* pNodeGraph; /* The graph this node belongs to. */ const ma_node_vtable* vtable; float* pCachedData; /* Allocated on the heap. Fixed size. Needs to be stored on the heap because reading from output buses is done in separate function calls. */ ma_uint16 cachedDataCapInFramesPerBus; /* The capacity of the input data cache in frames, per bus. */ @@ -10518,7 +10656,7 @@ MA_API ma_result ma_data_source_node_set_looping(ma_data_source_node* pDataSourc MA_API ma_bool32 ma_data_source_node_is_looping(ma_data_source_node* pDataSourceNode); -/* Splitter Node. 1 input, 2 outputs. Used for splitting/copying a stream so it can be as input into two separate output nodes. */ +/* Splitter Node. 1 input, many outputs. Used for splitting/copying a stream so it can be as input into two separate output nodes. */ typedef struct { ma_node_config nodeConfig; @@ -10791,7 +10929,7 @@ typedef struct ma_uint32 channelsOut; ma_uint32 sampleRate; /* Only used when the type is set to ma_engine_node_type_sound. */ ma_mono_expansion_mode monoExpansionMode; - ma_bool8 isPitchDisabled; /* Pitching can be explicitly disable with MA_SOUND_FLAG_NO_PITCH to optimize processing. */ + ma_bool8 isPitchDisabled; /* Pitching can be explicitly disabled with MA_SOUND_FLAG_NO_PITCH to optimize processing. */ ma_bool8 isSpatializationDisabled; /* Spatialization can be explicitly disabled with MA_SOUND_FLAG_NO_SPATIALIZATION. */ ma_uint8 pinnedListenerIndex; /* The index of the listener this node should always use for spatialization. If set to MA_LISTENER_INDEX_CLOSEST the engine will use the closest listener. */ } ma_engine_node_config; @@ -10847,7 +10985,8 @@ typedef struct ma_uint64 loopPointBegInPCMFrames; ma_uint64 loopPointEndInPCMFrames; ma_bool32 isLooping; - ma_fence* pDoneFence; /* Released when the resource manager has finished decoding the entire sound. Not used with streams. */ + ma_resource_manager_pipeline_notifications initNotifications; + ma_fence* pDoneFence; /* Deprecated. Use initNotifications instead. Released when the resource manager has finished decoding the entire sound. Not used with streams. */ } ma_sound_config; MA_API ma_sound_config ma_sound_config_init(void); /* Deprecated. Will be removed in version 0.12. Use ma_sound_config_2() instead. */ @@ -11032,7 +11171,7 @@ MA_API void ma_sound_set_directional_attenuation_factor(ma_sound* pSound, float MA_API float ma_sound_get_directional_attenuation_factor(const ma_sound* pSound); MA_API void ma_sound_set_fade_in_pcm_frames(ma_sound* pSound, float volumeBeg, float volumeEnd, ma_uint64 fadeLengthInFrames); MA_API void ma_sound_set_fade_in_milliseconds(ma_sound* pSound, float volumeBeg, float volumeEnd, ma_uint64 fadeLengthInMilliseconds); -MA_API float ma_sound_get_current_fade_volume(ma_sound* pSound); +MA_API float ma_sound_get_current_fade_volume(const ma_sound* pSound); MA_API void ma_sound_set_start_time_in_pcm_frames(ma_sound* pSound, ma_uint64 absoluteGlobalTimeInFrames); MA_API void ma_sound_set_start_time_in_milliseconds(ma_sound* pSound, ma_uint64 absoluteGlobalTimeInMilliseconds); MA_API void ma_sound_set_stop_time_in_pcm_frames(ma_sound* pSound, ma_uint64 absoluteGlobalTimeInFrames); @@ -11155,6 +11294,10 @@ IMPLEMENTATION #include #endif +#ifdef MA_NX +#include /* For nanosleep() */ +#endif + #include /* For fstat(), etc. */ #ifdef MA_EMSCRIPTEN @@ -11436,23 +11579,6 @@ static MA_INLINE ma_bool32 ma_has_neon(void) #endif } -#define MA_SIMD_NONE 0 -#define MA_SIMD_SSE2 1 -#define MA_SIMD_AVX2 2 -#define MA_SIMD_NEON 3 - -#ifndef MA_PREFERRED_SIMD - # if defined(MA_SUPPORT_SSE2) && defined(MA_PREFER_SSE2) - #define MA_PREFERRED_SIMD MA_SIMD_SSE2 - #elif defined(MA_SUPPORT_AVX2) && defined(MA_PREFER_AVX2) - #define MA_PREFERRED_SIMD MA_SIMD_AVX2 - #elif defined(MA_SUPPORT_NEON) && defined(MA_PREFER_NEON) - #define MA_PREFERRED_SIMD MA_SIMD_NEON - #else - #define MA_PREFERRED_SIMD MA_SIMD_NONE - #endif -#endif - #if defined(__has_builtin) #define MA_COMPILER_HAS_BUILTIN(x) __has_builtin(x) #else @@ -11566,7 +11692,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 + #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; @@ -11714,6 +11840,20 @@ static MA_INLINE void ma_restore_denormals(unsigned int prevState) } +#ifdef MA_ANDROID +#include + +int ma_android_sdk_version() +{ + char sdkVersion[PROP_VALUE_MAX + 1] = {0, }; + if (__system_property_get("ro.build.version.sdk", sdkVersion)) { + return atoi(sdkVersion); + } + + return 0; +} +#endif + #ifndef MA_COINIT_VALUE #define MA_COINIT_VALUE 0 /* 0 = COINIT_MULTITHREADED */ @@ -11867,6 +12007,14 @@ MA_API const char* ma_version_string(void) Standard Library Stuff ******************************************************************************/ +#ifndef MA_ASSERT +#ifdef MA_WIN32 +#define MA_ASSERT(condition) assert(condition) +#else +#define MA_ASSERT(condition) assert(condition) +#endif +#endif + #ifndef MA_MALLOC #ifdef MA_WIN32 #define MA_MALLOC(sz) HeapAlloc(GetProcessHeap(), 0, (sz)) @@ -11893,6 +12041,11 @@ Standard Library Stuff static MA_INLINE void ma_zero_memory_default(void* p, size_t sz) { + if (p == NULL) { + MA_ASSERT(sz == 0); /* If this is triggered there's an error with the calling code. */ + return; + } + #ifdef MA_WIN32 ZeroMemory(p, sz); #else @@ -11922,14 +12075,6 @@ static MA_INLINE void ma_zero_memory_default(void* p, size_t sz) #endif #endif -#ifndef MA_ASSERT -#ifdef MA_WIN32 -#define MA_ASSERT(condition) assert(condition) -#else -#define MA_ASSERT(condition) assert(condition) -#endif -#endif - #define MA_ZERO_OBJECT(p) MA_ZERO_MEMORY((p), sizeof(*(p))) #define ma_countof(x) (sizeof(x) / sizeof(x[0])) @@ -11974,6 +12119,40 @@ static MA_INLINE double ma_sqrtd(double x) } +static MA_INLINE float ma_rsqrtf(float x) +{ + #if defined(MA_SUPPORT_SSE2) && !defined(MA_NO_SSE2) && (defined(MA_X64) || (defined(_M_IX86_FP) && _M_IX86_FP == 2) || defined(__SSE2__)) + { + /* + For SSE we can use RSQRTSS. + + This Stack Overflow post suggests that compilers don't necessarily generate optimal code + when using intrinsics: + + https://web.archive.org/web/20221211012522/https://stackoverflow.com/questions/32687079/getting-fewest-instructions-for-rsqrtss-wrapper + + I'm going to do something similar here, but a bit simpler. + */ + #if defined(__GNUC__) || defined(__clang__) + { + float result; + __asm__ __volatile__("rsqrtss %1, %0" : "=x"(result) : "x"(x)); + return result; + } + #else + { + return _mm_cvtss_f32(_mm_rsqrt_ss(_mm_set_ps1(x))); + } + #endif + } + #else + { + return 1 / (float)ma_sqrtd(x); + } + #endif +} + + static MA_INLINE float ma_sinf(float x) { return (float)ma_sind((float)x); @@ -13069,6 +13248,9 @@ MA_API const char* ma_log_level_to_string(ma_uint32 logLevel) } #if defined(MA_DEBUG_OUTPUT) +#if defined(MA_ANDROID) + #include +#endif /* Customize this to use a specific tag in __android_log_print() for debug output messages. */ #ifndef MA_ANDROID_LOG_TAG @@ -13733,11 +13915,17 @@ typedef unsigned char c89atomic_bool; #define C89ATOMIC_32BIT #endif #endif +#if defined(__arm__) || defined(_M_ARM) +#define C89ATOMIC_ARM32 +#endif +#if defined(__arm64) || defined(__arm64__) || defined(__aarch64__) || defined(_M_ARM64) +#define C89ATOMIC_ARM64 +#endif #if defined(__x86_64__) || defined(_M_X64) #define C89ATOMIC_X64 #elif defined(__i386) || defined(_M_IX86) #define C89ATOMIC_X86 -#elif defined(__arm__) || defined(_M_ARM) || defined(__arm64) || defined(__arm64__) || defined(__aarch64__) || defined(_M_ARM64) +#elif defined(C89ATOMIC_ARM32) || defined(C89ATOMIC_ARM64) #define C89ATOMIC_ARM #endif #if defined(_MSC_VER) @@ -13758,6 +13946,56 @@ typedef unsigned char c89atomic_bool; #define C89ATOMIC_HAS_32 #define C89ATOMIC_HAS_64 #if (defined(_MSC_VER) ) || defined(__WATCOMC__) || defined(__DMC__) + #define C89ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, intrin, c89atomicType, msvcType) \ + c89atomicType result; \ + switch (order) \ + { \ + case c89atomic_memory_order_relaxed: \ + { \ + result = (c89atomicType)intrin##_nf((volatile msvcType*)dst, (msvcType)src); \ + } break; \ + case c89atomic_memory_order_consume: \ + case c89atomic_memory_order_acquire: \ + { \ + result = (c89atomicType)intrin##_acq((volatile msvcType*)dst, (msvcType)src); \ + } break; \ + case c89atomic_memory_order_release: \ + { \ + result = (c89atomicType)intrin##_rel((volatile msvcType*)dst, (msvcType)src); \ + } break; \ + case c89atomic_memory_order_acq_rel: \ + case c89atomic_memory_order_seq_cst: \ + default: \ + { \ + result = (c89atomicType)intrin((volatile msvcType*)dst, (msvcType)src); \ + } break; \ + } \ + return result; + #define C89ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, expected, desired, order, intrin, c89atomicType, msvcType) \ + c89atomicType result; \ + switch (order) \ + { \ + case c89atomic_memory_order_relaxed: \ + { \ + result = (c89atomicType)intrin##_nf((volatile msvcType*)ptr, (msvcType)expected, (msvcType)desired); \ + } break; \ + case c89atomic_memory_order_consume: \ + case c89atomic_memory_order_acquire: \ + { \ + result = (c89atomicType)intrin##_acq((volatile msvcType*)ptr, (msvcType)expected, (msvcType)desired); \ + } break; \ + case c89atomic_memory_order_release: \ + { \ + result = (c89atomicType)intrin##_rel((volatile msvcType*)ptr, (msvcType)expected, (msvcType)desired); \ + } break; \ + case c89atomic_memory_order_acq_rel: \ + case c89atomic_memory_order_seq_cst: \ + default: \ + { \ + result = (c89atomicType)intrin((volatile msvcType*)ptr, (msvcType)expected, (msvcType)desired); \ + } break; \ + } \ + return result; #define c89atomic_memory_order_relaxed 0 #define c89atomic_memory_order_consume 1 #define c89atomic_memory_order_acquire 2 @@ -13896,29 +14134,45 @@ typedef unsigned char c89atomic_bool; #if defined(C89ATOMIC_HAS_8) static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_exchange_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order) { + #if defined(C89ATOMIC_ARM) + C89ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchange8, c89atomic_uint8, char); + #else (void)order; return (c89atomic_uint8)_InterlockedExchange8((volatile char*)dst, (char)src); + #endif } #endif #if defined(C89ATOMIC_HAS_16) static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_exchange_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order) { + #if defined(C89ATOMIC_ARM) + C89ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchange16, c89atomic_uint16, short); + #else (void)order; return (c89atomic_uint16)_InterlockedExchange16((volatile short*)dst, (short)src); + #endif } #endif #if defined(C89ATOMIC_HAS_32) static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_exchange_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order) { + #if defined(C89ATOMIC_ARM) + C89ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchange, c89atomic_uint32, long); + #else (void)order; return (c89atomic_uint32)_InterlockedExchange((volatile long*)dst, (long)src); + #endif } #endif #if defined(C89ATOMIC_HAS_64) && defined(C89ATOMIC_64BIT) static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_exchange_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order) { + #if defined(C89ATOMIC_ARM) + C89ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchange64, c89atomic_uint64, long long); + #else (void)order; return (c89atomic_uint64)_InterlockedExchange64((volatile long long*)dst, (long long)src); + #endif } #else #endif @@ -13981,29 +14235,45 @@ typedef unsigned char c89atomic_bool; #if defined(C89ATOMIC_HAS_8) static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_fetch_add_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order) { + #if defined(C89ATOMIC_ARM) + C89ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchangeAdd8, c89atomic_uint8, char); + #else (void)order; return (c89atomic_uint8)_InterlockedExchangeAdd8((volatile char*)dst, (char)src); + #endif } #endif #if defined(C89ATOMIC_HAS_16) static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_fetch_add_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order) { + #if defined(C89ATOMIC_ARM) + C89ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchangeAdd16, c89atomic_uint16, short); + #else (void)order; return (c89atomic_uint16)_InterlockedExchangeAdd16((volatile short*)dst, (short)src); + #endif } #endif #if defined(C89ATOMIC_HAS_32) static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_fetch_add_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order) { + #if defined(C89ATOMIC_ARM) + C89ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchangeAdd, c89atomic_uint32, long); + #else (void)order; return (c89atomic_uint32)_InterlockedExchangeAdd((volatile long*)dst, (long)src); + #endif } #endif #if defined(C89ATOMIC_HAS_64) && defined(C89ATOMIC_64BIT) static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_fetch_add_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order) { + #if defined(C89ATOMIC_ARM) + C89ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedExchangeAdd64, c89atomic_uint64, long long); + #else (void)order; return (c89atomic_uint64)_InterlockedExchangeAdd64((volatile long long*)dst, (long long)src); + #endif } #else #endif @@ -14032,6 +14302,8 @@ typedef unsigned char c89atomic_bool; #else #if defined(C89ATOMIC_X64) #define c89atomic_thread_fence(order) __faststorefence(), (void)order + #elif defined(C89ATOMIC_ARM64) + #define c89atomic_thread_fence(order) __dmb(_ARM64_BARRIER_ISH), (void)order #else static C89ATOMIC_INLINE void c89atomic_thread_fence(c89atomic_memory_order order) { @@ -14045,29 +14317,45 @@ typedef unsigned char c89atomic_bool; #if defined(C89ATOMIC_HAS_8) static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_load_explicit_8(volatile const c89atomic_uint8* ptr, c89atomic_memory_order order) { + #if defined(C89ATOMIC_ARM) + C89ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, 0, 0, order, _InterlockedCompareExchange8, c89atomic_uint8, char); + #else (void)order; return c89atomic_compare_and_swap_8((volatile c89atomic_uint8*)ptr, 0, 0); + #endif } #endif #if defined(C89ATOMIC_HAS_16) static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_load_explicit_16(volatile const c89atomic_uint16* ptr, c89atomic_memory_order order) { + #if defined(C89ATOMIC_ARM) + C89ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, 0, 0, order, _InterlockedCompareExchange16, c89atomic_uint16, short); + #else (void)order; return c89atomic_compare_and_swap_16((volatile c89atomic_uint16*)ptr, 0, 0); + #endif } #endif #if defined(C89ATOMIC_HAS_32) static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_load_explicit_32(volatile const c89atomic_uint32* ptr, c89atomic_memory_order order) { + #if defined(C89ATOMIC_ARM) + C89ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, 0, 0, order, _InterlockedCompareExchange, c89atomic_uint32, long); + #else (void)order; return c89atomic_compare_and_swap_32((volatile c89atomic_uint32*)ptr, 0, 0); + #endif } #endif #if defined(C89ATOMIC_HAS_64) static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_load_explicit_64(volatile const c89atomic_uint64* ptr, c89atomic_memory_order order) { + #if defined(C89ATOMIC_ARM) + C89ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr, 0, 0, order, _InterlockedCompareExchange64, c89atomic_uint64, long long); + #else (void)order; return c89atomic_compare_and_swap_64((volatile c89atomic_uint64*)ptr, 0, 0); + #endif } #endif #if defined(C89ATOMIC_HAS_8) @@ -14137,6 +14425,9 @@ typedef unsigned char c89atomic_bool; #if defined(C89ATOMIC_HAS_8) static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_fetch_and_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order) { + #if defined(C89ATOMIC_ARM) + C89ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedAnd8, c89atomic_uint8, char); + #else c89atomic_uint8 oldValue; c89atomic_uint8 newValue; do { @@ -14145,11 +14436,15 @@ typedef unsigned char c89atomic_bool; } while (c89atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; + #endif } #endif #if defined(C89ATOMIC_HAS_16) static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_fetch_and_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order) { + #if defined(C89ATOMIC_ARM) + C89ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedAnd16, c89atomic_uint16, short); + #else c89atomic_uint16 oldValue; c89atomic_uint16 newValue; do { @@ -14158,11 +14453,15 @@ typedef unsigned char c89atomic_bool; } while (c89atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; + #endif } #endif #if defined(C89ATOMIC_HAS_32) static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_fetch_and_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order) { + #if defined(C89ATOMIC_ARM) + C89ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedAnd, c89atomic_uint32, long); + #else c89atomic_uint32 oldValue; c89atomic_uint32 newValue; do { @@ -14171,11 +14470,15 @@ typedef unsigned char c89atomic_bool; } while (c89atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; + #endif } #endif #if defined(C89ATOMIC_HAS_64) static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_fetch_and_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order) { + #if defined(C89ATOMIC_ARM) + C89ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedAnd64, c89atomic_uint64, long long); + #else c89atomic_uint64 oldValue; c89atomic_uint64 newValue; do { @@ -14184,11 +14487,15 @@ typedef unsigned char c89atomic_bool; } while (c89atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; + #endif } #endif #if defined(C89ATOMIC_HAS_8) static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_fetch_xor_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order) { + #if defined(C89ATOMIC_ARM) + C89ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedXor8, c89atomic_uint8, char); + #else c89atomic_uint8 oldValue; c89atomic_uint8 newValue; do { @@ -14197,11 +14504,15 @@ typedef unsigned char c89atomic_bool; } while (c89atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; + #endif } #endif #if defined(C89ATOMIC_HAS_16) static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_fetch_xor_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order) { + #if defined(C89ATOMIC_ARM) + C89ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedXor16, c89atomic_uint16, short); + #else c89atomic_uint16 oldValue; c89atomic_uint16 newValue; do { @@ -14210,11 +14521,15 @@ typedef unsigned char c89atomic_bool; } while (c89atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; + #endif } #endif #if defined(C89ATOMIC_HAS_32) static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_fetch_xor_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order) { + #if defined(C89ATOMIC_ARM) + C89ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedXor, c89atomic_uint32, long); + #else c89atomic_uint32 oldValue; c89atomic_uint32 newValue; do { @@ -14223,11 +14538,15 @@ typedef unsigned char c89atomic_bool; } while (c89atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; + #endif } #endif #if defined(C89ATOMIC_HAS_64) static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_fetch_xor_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order) { + #if defined(C89ATOMIC_ARM) + C89ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedXor64, c89atomic_uint64, long long); + #else c89atomic_uint64 oldValue; c89atomic_uint64 newValue; do { @@ -14236,11 +14555,15 @@ typedef unsigned char c89atomic_bool; } while (c89atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; + #endif } #endif #if defined(C89ATOMIC_HAS_8) static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_fetch_or_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order) { + #if defined(C89ATOMIC_ARM) + C89ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedOr8, c89atomic_uint8, char); + #else c89atomic_uint8 oldValue; c89atomic_uint8 newValue; do { @@ -14249,11 +14572,15 @@ typedef unsigned char c89atomic_bool; } while (c89atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; + #endif } #endif #if defined(C89ATOMIC_HAS_16) static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_fetch_or_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order) { + #if defined(C89ATOMIC_ARM) + C89ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedOr16, c89atomic_uint16, short); + #else c89atomic_uint16 oldValue; c89atomic_uint16 newValue; do { @@ -14262,11 +14589,15 @@ typedef unsigned char c89atomic_bool; } while (c89atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; + #endif } #endif #if defined(C89ATOMIC_HAS_32) static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_fetch_or_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order) { + #if defined(C89ATOMIC_ARM) + C89ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedOr, c89atomic_uint32, long); + #else c89atomic_uint32 oldValue; c89atomic_uint32 newValue; do { @@ -14275,11 +14606,15 @@ typedef unsigned char c89atomic_bool; } while (c89atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; + #endif } #endif #if defined(C89ATOMIC_HAS_64) static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_fetch_or_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order) { + #if defined(C89ATOMIC_ARM) + C89ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedOr64, c89atomic_uint64, long long); + #else c89atomic_uint64 oldValue; c89atomic_uint64 newValue; do { @@ -14288,6 +14623,7 @@ typedef unsigned char c89atomic_bool; } while (c89atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); (void)order; return oldValue; + #endif } #endif #if defined(C89ATOMIC_HAS_8) @@ -15140,10 +15476,10 @@ typedef unsigned char c89atomic_bool; #define c89atomic_clear_explicit_i16(ptr, order) c89atomic_clear_explicit_16((c89atomic_uint16*)ptr, order) #define c89atomic_clear_explicit_i32(ptr, order) c89atomic_clear_explicit_32((c89atomic_uint32*)ptr, order) #define c89atomic_clear_explicit_i64(ptr, order) c89atomic_clear_explicit_64((c89atomic_uint64*)ptr, order) -#define c89atomic_store_explicit_i8( dst, src, order) (c89atomic_int8 )c89atomic_store_explicit_8( (c89atomic_uint8* )dst, (c89atomic_uint8 )src, order) -#define c89atomic_store_explicit_i16(dst, src, order) (c89atomic_int16)c89atomic_store_explicit_16((c89atomic_uint16*)dst, (c89atomic_uint16)src, order) -#define c89atomic_store_explicit_i32(dst, src, order) (c89atomic_int32)c89atomic_store_explicit_32((c89atomic_uint32*)dst, (c89atomic_uint32)src, order) -#define c89atomic_store_explicit_i64(dst, src, order) (c89atomic_int64)c89atomic_store_explicit_64((c89atomic_uint64*)dst, (c89atomic_uint64)src, order) +#define c89atomic_store_explicit_i8( dst, src, order) c89atomic_store_explicit_8( (c89atomic_uint8* )dst, (c89atomic_uint8 )src, order) +#define c89atomic_store_explicit_i16(dst, src, order) c89atomic_store_explicit_16((c89atomic_uint16*)dst, (c89atomic_uint16)src, order) +#define c89atomic_store_explicit_i32(dst, src, order) c89atomic_store_explicit_32((c89atomic_uint32*)dst, (c89atomic_uint32)src, order) +#define c89atomic_store_explicit_i64(dst, src, order) c89atomic_store_explicit_64((c89atomic_uint64*)dst, (c89atomic_uint64)src, order) #define c89atomic_load_explicit_i8( ptr, order) (c89atomic_int8 )c89atomic_load_explicit_8( (c89atomic_uint8* )ptr, order) #define c89atomic_load_explicit_i16(ptr, order) (c89atomic_int16)c89atomic_load_explicit_16((c89atomic_uint16*)ptr, order) #define c89atomic_load_explicit_i32(ptr, order) (c89atomic_int32)c89atomic_load_explicit_32((c89atomic_uint32*)ptr, order) @@ -15284,6 +15620,110 @@ static C89ATOMIC_INLINE double c89atomic_exchange_explicit_f64(volatile double* r.i = c89atomic_exchange_explicit_64((volatile c89atomic_uint64*)dst, x.i, order); return r.f; } +static C89ATOMIC_INLINE c89atomic_bool c89atomic_compare_exchange_strong_explicit_f32(volatile float* dst, float* expected, float desired, c89atomic_memory_order successOrder, c89atomic_memory_order failureOrder) +{ + c89atomic_if32 d; + d.f = desired; + return c89atomic_compare_exchange_strong_explicit_32((volatile c89atomic_uint32*)dst, (c89atomic_uint32*)expected, d.i, successOrder, failureOrder); +} +static C89ATOMIC_INLINE c89atomic_bool c89atomic_compare_exchange_strong_explicit_f64(volatile double* dst, double* expected, double desired, c89atomic_memory_order successOrder, c89atomic_memory_order failureOrder) +{ + c89atomic_if64 d; + d.f = desired; + return c89atomic_compare_exchange_strong_explicit_64((volatile c89atomic_uint64*)dst, (c89atomic_uint64*)expected, d.i, successOrder, failureOrder); +} +static C89ATOMIC_INLINE c89atomic_bool c89atomic_compare_exchange_weak_explicit_f32(volatile float* dst, float* expected, float desired, c89atomic_memory_order successOrder, c89atomic_memory_order failureOrder) +{ + c89atomic_if32 d; + d.f = desired; + return c89atomic_compare_exchange_weak_explicit_32((volatile c89atomic_uint32*)dst, (c89atomic_uint32*)expected, d.i, successOrder, failureOrder); +} +static C89ATOMIC_INLINE c89atomic_bool c89atomic_compare_exchange_weak_explicit_f64(volatile double* dst, double* expected, double desired, c89atomic_memory_order successOrder, c89atomic_memory_order failureOrder) +{ + c89atomic_if64 d; + d.f = desired; + return c89atomic_compare_exchange_weak_explicit_64((volatile c89atomic_uint64*)dst, (c89atomic_uint64*)expected, d.i, successOrder, failureOrder); +} +static C89ATOMIC_INLINE float c89atomic_fetch_add_explicit_f32(volatile float* dst, float src, c89atomic_memory_order order) +{ + c89atomic_if32 r; + c89atomic_if32 x; + x.f = src; + r.i = c89atomic_fetch_add_explicit_32((volatile c89atomic_uint32*)dst, x.i, order); + return r.f; +} +static C89ATOMIC_INLINE double c89atomic_fetch_add_explicit_f64(volatile double* dst, double src, c89atomic_memory_order order) +{ + c89atomic_if64 r; + c89atomic_if64 x; + x.f = src; + r.i = c89atomic_fetch_add_explicit_64((volatile c89atomic_uint64*)dst, x.i, order); + return r.f; +} +static C89ATOMIC_INLINE float c89atomic_fetch_sub_explicit_f32(volatile float* dst, float src, c89atomic_memory_order order) +{ + c89atomic_if32 r; + c89atomic_if32 x; + x.f = src; + r.i = c89atomic_fetch_sub_explicit_32((volatile c89atomic_uint32*)dst, x.i, order); + return r.f; +} +static C89ATOMIC_INLINE double c89atomic_fetch_sub_explicit_f64(volatile double* dst, double src, c89atomic_memory_order order) +{ + c89atomic_if64 r; + c89atomic_if64 x; + x.f = src; + r.i = c89atomic_fetch_sub_explicit_64((volatile c89atomic_uint64*)dst, x.i, order); + return r.f; +} +static C89ATOMIC_INLINE float c89atomic_fetch_or_explicit_f32(volatile float* dst, float src, c89atomic_memory_order order) +{ + c89atomic_if32 r; + c89atomic_if32 x; + x.f = src; + r.i = c89atomic_fetch_or_explicit_32((volatile c89atomic_uint32*)dst, x.i, order); + return r.f; +} +static C89ATOMIC_INLINE double c89atomic_fetch_or_explicit_f64(volatile double* dst, double src, c89atomic_memory_order order) +{ + c89atomic_if64 r; + c89atomic_if64 x; + x.f = src; + r.i = c89atomic_fetch_or_explicit_64((volatile c89atomic_uint64*)dst, x.i, order); + return r.f; +} +static C89ATOMIC_INLINE float c89atomic_fetch_xor_explicit_f32(volatile float* dst, float src, c89atomic_memory_order order) +{ + c89atomic_if32 r; + c89atomic_if32 x; + x.f = src; + r.i = c89atomic_fetch_xor_explicit_32((volatile c89atomic_uint32*)dst, x.i, order); + return r.f; +} +static C89ATOMIC_INLINE double c89atomic_fetch_xor_explicit_f64(volatile double* dst, double src, c89atomic_memory_order order) +{ + c89atomic_if64 r; + c89atomic_if64 x; + x.f = src; + r.i = c89atomic_fetch_xor_explicit_64((volatile c89atomic_uint64*)dst, x.i, order); + return r.f; +} +static C89ATOMIC_INLINE float c89atomic_fetch_and_explicit_f32(volatile float* dst, float src, c89atomic_memory_order order) +{ + c89atomic_if32 r; + c89atomic_if32 x; + x.f = src; + r.i = c89atomic_fetch_and_explicit_32((volatile c89atomic_uint32*)dst, x.i, order); + return r.f; +} +static C89ATOMIC_INLINE double c89atomic_fetch_and_explicit_f64(volatile double* dst, double src, c89atomic_memory_order order) +{ + c89atomic_if64 r; + c89atomic_if64 x; + x.f = src; + r.i = c89atomic_fetch_and_explicit_64((volatile c89atomic_uint64*)dst, x.i, order); + return r.f; +} #define c89atomic_clear_f32(ptr) (float )c89atomic_clear_explicit_f32(ptr, c89atomic_memory_order_seq_cst) #define c89atomic_clear_f64(ptr) (double)c89atomic_clear_explicit_f64(ptr, c89atomic_memory_order_seq_cst) #define c89atomic_store_f32(dst, src) c89atomic_store_explicit_f32(dst, src, c89atomic_memory_order_seq_cst) @@ -15292,6 +15732,38 @@ static C89ATOMIC_INLINE double c89atomic_exchange_explicit_f64(volatile double* #define c89atomic_load_f64(ptr) (double)c89atomic_load_explicit_f64(ptr, c89atomic_memory_order_seq_cst) #define c89atomic_exchange_f32(dst, src) (float )c89atomic_exchange_explicit_f32(dst, src, c89atomic_memory_order_seq_cst) #define c89atomic_exchange_f64(dst, src) (double)c89atomic_exchange_explicit_f64(dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_compare_exchange_strong_f32(dst, expected, desired) c89atomic_compare_exchange_strong_explicit_f32(dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst) +#define c89atomic_compare_exchange_strong_f64(dst, expected, desired) c89atomic_compare_exchange_strong_explicit_f64(dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst) +#define c89atomic_compare_exchange_weak_f32(dst, expected, desired) c89atomic_compare_exchange_weak_explicit_f32(dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst) +#define c89atomic_compare_exchange_weak_f64(dst, expected, desired) c89atomic_compare_exchange_weak_explicit_f64(dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst) +#define c89atomic_fetch_add_f32(dst, src) c89atomic_fetch_add_explicit_f32(dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_fetch_add_f64(dst, src) c89atomic_fetch_add_explicit_f64(dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_fetch_sub_f32(dst, src) c89atomic_fetch_sub_explicit_f32(dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_fetch_sub_f64(dst, src) c89atomic_fetch_sub_explicit_f64(dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_fetch_or_f32(dst, src) c89atomic_fetch_or_explicit_f32(dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_fetch_or_f64(dst, src) c89atomic_fetch_or_explicit_f64(dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_fetch_xor_f32(dst, src) c89atomic_fetch_xor_explicit_f32(dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_fetch_xor_f64(dst, src) c89atomic_fetch_xor_explicit_f64(dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_fetch_and_f32(dst, src) c89atomic_fetch_and_explicit_f32(dst, src, c89atomic_memory_order_seq_cst) +#define c89atomic_fetch_and_f64(dst, src) c89atomic_fetch_and_explicit_f64(dst, src, c89atomic_memory_order_seq_cst) +static C89ATOMIC_INLINE float c89atomic_compare_and_swap_f32(volatile float* dst, float expected, float desired) +{ + c89atomic_if32 r; + c89atomic_if32 e, d; + e.f = expected; + d.f = desired; + r.i = c89atomic_compare_and_swap_32((volatile c89atomic_uint32*)dst, e.i, d.i); + return r.f; +} +static C89ATOMIC_INLINE double c89atomic_compare_and_swap_f64(volatile double* dst, double expected, double desired) +{ + c89atomic_if64 r; + c89atomic_if64 e, d; + e.f = expected; + d.f = desired; + r.i = c89atomic_compare_and_swap_64((volatile c89atomic_uint64*)dst, e.i, d.i); + return r.f; +} typedef c89atomic_flag c89atomic_spinlock; static C89ATOMIC_INLINE void c89atomic_spinlock_lock(volatile c89atomic_spinlock* pSpinlock) { @@ -15313,6 +15785,76 @@ static C89ATOMIC_INLINE void c89atomic_spinlock_unlock(volatile c89atomic_spinlo #endif /* c89atomic.h end */ +#define MA_ATOMIC_SAFE_TYPE_IMPL(c89TypeExtension, type) \ + static MA_INLINE ma_##type ma_atomic_##type##_get(ma_atomic_##type* x) \ + { \ + return (ma_##type)c89atomic_load_##c89TypeExtension(&x->value); \ + } \ + static MA_INLINE void ma_atomic_##type##_set(ma_atomic_##type* x, ma_##type value) \ + { \ + c89atomic_store_##c89TypeExtension(&x->value, value); \ + } \ + static MA_INLINE ma_##type ma_atomic_##type##_exchange(ma_atomic_##type* x, ma_##type value) \ + { \ + return (ma_##type)c89atomic_exchange_##c89TypeExtension(&x->value, value); \ + } \ + static MA_INLINE ma_bool32 ma_atomic_##type##_compare_exchange(ma_atomic_##type* x, ma_##type* expected, ma_##type desired) \ + { \ + return c89atomic_compare_exchange_weak_##c89TypeExtension(&x->value, expected, desired); \ + } \ + static MA_INLINE ma_##type ma_atomic_##type##_fetch_add(ma_atomic_##type* x, ma_##type y) \ + { \ + return (ma_##type)c89atomic_fetch_add_##c89TypeExtension(&x->value, y); \ + } \ + static MA_INLINE ma_##type ma_atomic_##type##_fetch_sub(ma_atomic_##type* x, ma_##type y) \ + { \ + return (ma_##type)c89atomic_fetch_sub_##c89TypeExtension(&x->value, y); \ + } \ + static MA_INLINE ma_##type ma_atomic_##type##_fetch_or(ma_atomic_##type* x, ma_##type y) \ + { \ + return (ma_##type)c89atomic_fetch_or_##c89TypeExtension(&x->value, y); \ + } \ + static MA_INLINE ma_##type ma_atomic_##type##_fetch_xor(ma_atomic_##type* x, ma_##type y) \ + { \ + return (ma_##type)c89atomic_fetch_xor_##c89TypeExtension(&x->value, y); \ + } \ + static MA_INLINE ma_##type ma_atomic_##type##_fetch_and(ma_atomic_##type* x, ma_##type y) \ + { \ + return (ma_##type)c89atomic_fetch_and_##c89TypeExtension(&x->value, y); \ + } \ + static MA_INLINE ma_##type ma_atomic_##type##_compare_and_swap(ma_atomic_##type* x, ma_##type expected, ma_##type desired) \ + { \ + return (ma_##type)c89atomic_compare_and_swap_##c89TypeExtension(&x->value, expected, desired); \ + } \ + +#define MA_ATOMIC_SAFE_TYPE_IMPL_PTR(type) \ + static MA_INLINE ma_##type* ma_atomic_ptr_##type##_get(ma_atomic_ptr_##type* x) \ + { \ + return c89atomic_load_ptr((void**)&x->value); \ + } \ + static MA_INLINE void ma_atomic_ptr_##type##_set(ma_atomic_ptr_##type* x, ma_##type* value) \ + { \ + c89atomic_store_ptr((void**)&x->value, (void*)value); \ + } \ + static MA_INLINE ma_##type* ma_atomic_ptr_##type##_exchange(ma_atomic_ptr_##type* x, ma_##type* value) \ + { \ + return c89atomic_exchange_ptr((void**)&x->value, (void*)value); \ + } \ + static MA_INLINE ma_bool32 ma_atomic_ptr_##type##_compare_exchange(ma_atomic_ptr_##type* x, ma_##type** expected, ma_##type* desired) \ + { \ + return c89atomic_compare_exchange_weak_ptr((void**)&x->value, (void*)expected, (void*)desired); \ + } \ + static MA_INLINE ma_##type* ma_atomic_ptr_##type##_compare_and_swap(ma_atomic_ptr_##type* x, ma_##type* expected, ma_##type* desired) \ + { \ + return (ma_##type*)c89atomic_compare_and_swap_ptr((void**)&x->value, (void*)expected, (void*)desired); \ + } \ + +MA_ATOMIC_SAFE_TYPE_IMPL(32, uint32) +MA_ATOMIC_SAFE_TYPE_IMPL(i32, int32) +MA_ATOMIC_SAFE_TYPE_IMPL(64, uint64) +MA_ATOMIC_SAFE_TYPE_IMPL(f32, float) +MA_ATOMIC_SAFE_TYPE_IMPL(32, bool32) +MA_ATOMIC_SAFE_TYPE_IMPL(i32, device_state) MA_API ma_uint64 ma_calculate_frame_count_after_resampling(ma_uint32 sampleRateOut, ma_uint32 sampleRateIn, ma_uint64 frameCountIn) @@ -15446,7 +15988,9 @@ static int ma_thread_priority_to_win32(ma_thread_priority priority) static ma_result ma_thread_create__win32(ma_thread* pThread, ma_thread_priority priority, size_t stackSize, ma_thread_entry_proc entryProc, void* pData) { - *pThread = CreateThread(NULL, stackSize, entryProc, pData, 0, NULL); + DWORD threadID; /* Not used. Only used for passing into CreateThread() so it doesn't fail on Windows 98. */ + + *pThread = CreateThread(NULL, stackSize, entryProc, pData, 0, &threadID); if (*pThread == NULL) { return ma_result_from_GetLastError(GetLastError()); } @@ -15465,7 +16009,7 @@ static void ma_thread_wait__win32(ma_thread* pThread) static ma_result ma_mutex_init__win32(ma_mutex* pMutex) { - *pMutex = CreateEventW(NULL, FALSE, TRUE, NULL); + *pMutex = CreateEventA(NULL, FALSE, TRUE, NULL); if (*pMutex == NULL) { return ma_result_from_GetLastError(GetLastError()); } @@ -15491,7 +16035,7 @@ static void ma_mutex_unlock__win32(ma_mutex* pMutex) static ma_result ma_event_init__win32(ma_event* pEvent) { - *pEvent = CreateEventW(NULL, FALSE, FALSE, NULL); + *pEvent = CreateEventA(NULL, FALSE, FALSE, NULL); if (*pEvent == NULL) { return ma_result_from_GetLastError(GetLastError()); } @@ -15581,6 +16125,10 @@ static ma_result ma_thread_create__posix(ma_thread* pThread, ma_thread_priority pthread_attr_t attr; if (pthread_attr_init(&attr) == 0) { int scheduler = -1; + + /* We successfully initialized our attributes object so we can assign the pointer so it's passed into pthread_create(). */ + pAttr = &attr; + if (priority == ma_thread_priority_idle) { #ifdef SCHED_IDLE if (pthread_attr_setschedpolicy(&attr, SCHED_IDLE) == 0) { @@ -15624,9 +16172,8 @@ static ma_result ma_thread_create__posix(ma_thread* pThread, ma_thread_priority } } - if (pthread_attr_setschedparam(&attr, &sched) == 0) { - pAttr = &attr; - } + /* I'm not treating a failure of setting the priority as a critical error so not checking the return value here. */ + pthread_attr_setschedparam(&attr, &sched); } } } @@ -16748,7 +17295,7 @@ MA_API ma_result ma_job_process(ma_job* pJob) return MA_INVALID_ARGS; } - if (pJob->toc.breakup.code > MA_JOB_TYPE_COUNT) { + if (pJob->toc.breakup.code >= MA_JOB_TYPE_COUNT) { return MA_INVALID_OPERATION; } @@ -17141,6 +17688,14 @@ 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 + #ifndef MA_NO_DEVICE_IO #ifdef MA_WIN32 #include @@ -17152,33 +17707,18 @@ DEVICE I/O #include /* For mach_absolute_time() */ #endif -#ifdef MA_ANDROID - #include -#endif - #ifdef MA_POSIX #include #include - #include -#endif - -/* -Unfortunately using runtime linking for pthreads causes problems. This has occurred for me when testing on FreeBSD. When -using runtime linking, deadlocks can occur (for me it happens when loading data from fread()). It turns out that doing -compile-time linking fixes this. I'm not sure why this happens, but the safest way I can think of to fix this is to simply -disable runtime linking by default. To enable runtime linking, #define this before the implementation of this file. I am -not officially supporting this, but I'm leaving it here in case it's useful for somebody, somewhere. -*/ -/*#define MA_USE_RUNTIME_LINKING_FOR_PTHREAD*/ -/* Disable run-time linking on certain backends. */ -#ifndef MA_NO_RUNTIME_LINKING - #if defined(MA_EMSCRIPTEN) - #define MA_NO_RUNTIME_LINKING + /* No need for dlfcn.h if we're not using runtime linking. */ + #ifndef MA_NO_RUNTIME_LINKING + #include #endif #endif + MA_API void ma_device_info_add_native_data_format(ma_device_info* pDeviceInfo, ma_format format, ma_uint32 channels, ma_uint32 sampleRate, ma_uint32 flags) { if (pDeviceInfo == NULL) { @@ -17195,27 +17735,60 @@ MA_API void ma_device_info_add_native_data_format(ma_device_info* pDeviceInfo, m } +typedef struct +{ + ma_backend backend; + const char* pName; +} ma_backend_info; + +static ma_backend_info gBackendInfo[] = /* Indexed by the backend enum. Must be in the order backends are declared in the ma_backend enum. */ +{ + {ma_backend_wasapi, "WASAPI"}, + {ma_backend_dsound, "DirectSound"}, + {ma_backend_winmm, "WinMM"}, + {ma_backend_coreaudio, "Core Audio"}, + {ma_backend_sndio, "sndio"}, + {ma_backend_audio4, "audio(4)"}, + {ma_backend_oss, "OSS"}, + {ma_backend_pulseaudio, "PulseAudio"}, + {ma_backend_alsa, "ALSA"}, + {ma_backend_jack, "JACK"}, + {ma_backend_aaudio, "AAudio"}, + {ma_backend_opensl, "OpenSL|ES"}, + {ma_backend_webaudio, "Web Audio"}, + {ma_backend_custom, "Custom"}, + {ma_backend_null, "Null"} +}; + MA_API const char* ma_get_backend_name(ma_backend backend) { - switch (backend) - { - case ma_backend_wasapi: return "WASAPI"; - case ma_backend_dsound: return "DirectSound"; - case ma_backend_winmm: return "WinMM"; - case ma_backend_coreaudio: return "Core Audio"; - case ma_backend_sndio: return "sndio"; - case ma_backend_audio4: return "audio(4)"; - case ma_backend_oss: return "OSS"; - case ma_backend_pulseaudio: return "PulseAudio"; - case ma_backend_alsa: return "ALSA"; - case ma_backend_jack: return "JACK"; - case ma_backend_aaudio: return "AAudio"; - case ma_backend_opensl: return "OpenSL|ES"; - case ma_backend_webaudio: return "Web Audio"; - case ma_backend_custom: return "Custom"; - case ma_backend_null: return "Null"; - default: return "Unknown"; + if (backend < 0 || backend >= (int)ma_countof(gBackendInfo)) { + return "Unknown"; + } + + return gBackendInfo[backend].pName; +} + +MA_API ma_result ma_get_backend_from_name(const char* pBackendName, ma_backend* pBackend) +{ + size_t iBackend; + + if (pBackendName == NULL) { + return MA_INVALID_ARGS; } + + for (iBackend = 0; iBackend < ma_countof(gBackendInfo); iBackend += 1) { + if (ma_strcmp(pBackendName, gBackendInfo[iBackend].pName) == 0) { + if (pBackend != NULL) { + *pBackend = gBackendInfo[iBackend].backend; + } + + return MA_SUCCESS; + } + } + + /* Getting here means the backend name is unknown. */ + return MA_INVALID_ARGS; } MA_API ma_bool32 ma_is_backend_enabled(ma_backend backend) @@ -17290,16 +17863,7 @@ MA_API ma_bool32 ma_is_backend_enabled(ma_backend backend) #if defined(MA_HAS_AAUDIO) #if defined(MA_ANDROID) { - char sdkVersion[PROP_VALUE_MAX + 1] = {0, }; - if (__system_property_get("ro.build.version.sdk", sdkVersion)) { - if (atoi(sdkVersion) >= 26) { - return MA_TRUE; - } else { - return MA_FALSE; - } - } else { - return MA_FALSE; - } + return ma_android_sdk_version() >= 26; } #else return MA_FALSE; @@ -17311,16 +17875,7 @@ MA_API ma_bool32 ma_is_backend_enabled(ma_backend backend) #if defined(MA_HAS_OPENSL) #if defined(MA_ANDROID) { - char sdkVersion[PROP_VALUE_MAX + 1] = {0, }; - if (__system_property_get("ro.build.version.sdk", sdkVersion)) { - if (atoi(sdkVersion) >= 9) { - return MA_TRUE; - } else { - return MA_FALSE; - } - } else { - return MA_FALSE; - } + return ma_android_sdk_version() >= 9; } #else return MA_TRUE; @@ -17570,6 +18125,7 @@ static ma_result ma_result_from_HRESULT(HRESULT hr) } } +typedef HRESULT (WINAPI * MA_PFN_CoInitialize)(LPVOID pvReserved); typedef HRESULT (WINAPI * MA_PFN_CoInitializeEx)(LPVOID pvReserved, DWORD dwCoInit); typedef void (WINAPI * MA_PFN_CoUninitialize)(void); typedef HRESULT (WINAPI * MA_PFN_CoCreateInstance)(REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID riid, LPVOID *ppv); @@ -17713,6 +18269,7 @@ Dynamic Linking *******************************************************************************/ MA_API ma_handle ma_dlopen(ma_context* pContext, const char* filename) { +#ifndef MA_NO_RUNTIME_LINKING ma_handle handle; ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "Loading library: %s\n", filename); @@ -17744,10 +18301,17 @@ MA_API ma_handle ma_dlopen(ma_context* pContext, const char* filename) (void)pContext; /* It's possible for pContext to be unused. */ return handle; +#else + /* Runtime linking is disabled. */ + (void)pContext; + (void)filename; + return NULL; +#endif } MA_API void ma_dlclose(ma_context* pContext, ma_handle handle) { +#ifndef MA_NO_RUNTIME_LINKING #ifdef _WIN32 FreeLibrary((HMODULE)handle); #else @@ -17755,10 +18319,16 @@ MA_API void ma_dlclose(ma_context* pContext, ma_handle handle) #endif (void)pContext; +#else + /* Runtime linking is disabled. */ + (void)pContext; + (void)handle; +#endif } MA_API ma_proc ma_dlsym(ma_context* pContext, ma_handle handle, const char* symbol) { +#ifndef MA_NO_RUNTIME_LINKING ma_proc proc; ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "Loading symbol: %s\n", symbol); @@ -17782,6 +18352,13 @@ MA_API ma_proc ma_dlsym(ma_context* pContext, ma_handle handle, const char* symb (void)pContext; /* It's possible for pContext to be unused. */ return proc; +#else + /* Runtime linking is disabled. */ + (void)pContext; + (void)handle; + (void)symbol; + return NULL; +#endif } @@ -17986,7 +18563,7 @@ static void ma_device__on_data(ma_device* pDevice, void* pFramesOut, const void* /* The intermediary buffer has just been filled. */ pDevice->playback.intermediaryBufferLen = pDevice->playback.intermediaryBufferCap; } - } + } } /* If we're in duplex mode we might need to do a refill of the data. */ @@ -18338,7 +18915,7 @@ static ma_result ma_device__handle_duplex_callback_playback(ma_device* pDevice, /* A helper for changing the state of the device. */ static MA_INLINE void ma_device__set_state(ma_device* pDevice, ma_device_state newState) { - c89atomic_exchange_i32((ma_int32*)&pDevice->state, (ma_int32)newState); + ma_atomic_device_state_set(&pDevice->state, newState); } @@ -18849,7 +19426,7 @@ static ma_result ma_device_start__null(ma_device* pDevice) ma_device_do_operation__null(pDevice, MA_DEVICE_OP_START__NULL); - c89atomic_exchange_32(&pDevice->null_device.isStarted, MA_TRUE); + ma_atomic_bool32_set(&pDevice->null_device.isStarted, MA_TRUE); return MA_SUCCESS; } @@ -18859,10 +19436,17 @@ static ma_result ma_device_stop__null(ma_device* pDevice) ma_device_do_operation__null(pDevice, MA_DEVICE_OP_SUSPEND__NULL); - c89atomic_exchange_32(&pDevice->null_device.isStarted, MA_FALSE); + ma_atomic_bool32_set(&pDevice->null_device.isStarted, MA_FALSE); return MA_SUCCESS; } +static ma_bool32 ma_device_is_started__null(ma_device* pDevice) +{ + MA_ASSERT(pDevice != NULL); + + return ma_atomic_bool32_get(&pDevice->null_device.isStarted); +} + static ma_result ma_device_write__null(ma_device* pDevice, const void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesWritten) { ma_result result = MA_SUCCESS; @@ -18873,7 +19457,7 @@ static ma_result ma_device_write__null(ma_device* pDevice, const void* pPCMFrame *pFramesWritten = 0; } - wasStartedOnEntry = c89atomic_load_32(&pDevice->null_device.isStarted); + wasStartedOnEntry = ma_device_is_started__null(pDevice); /* Keep going until everything has been read. */ totalPCMFramesProcessed = 0; @@ -18899,7 +19483,7 @@ static ma_result ma_device_write__null(ma_device* pDevice, const void* pPCMFrame if (pDevice->null_device.currentPeriodFramesRemainingPlayback == 0) { pDevice->null_device.currentPeriodFramesRemainingPlayback = 0; - if (!c89atomic_load_32(&pDevice->null_device.isStarted) && !wasStartedOnEntry) { + if (!ma_device_is_started__null(pDevice) && !wasStartedOnEntry) { result = ma_device_start__null(pDevice); if (result != MA_SUCCESS) { break; @@ -18919,7 +19503,7 @@ static ma_result ma_device_write__null(ma_device* pDevice, const void* pPCMFrame ma_uint64 currentFrame; /* Stop waiting if the device has been stopped. */ - if (!c89atomic_load_32(&pDevice->null_device.isStarted)) { + if (!ma_device_is_started__null(pDevice)) { break; } @@ -18990,7 +19574,7 @@ static ma_result ma_device_read__null(ma_device* pDevice, void* pPCMFrames, ma_u ma_uint64 currentFrame; /* Stop waiting if the device has been stopped. */ - if (!c89atomic_load_32(&pDevice->null_device.isStarted)) { + if (!ma_device_is_started__null(pDevice)) { break; } @@ -19056,7 +19640,7 @@ WIN32 COMMON *******************************************************************************/ #if defined(MA_WIN32) #if defined(MA_WIN32_DESKTOP) - #define ma_CoInitializeEx(pContext, pvReserved, dwCoInit) ((MA_PFN_CoInitializeEx)pContext->win32.CoInitializeEx)(pvReserved, dwCoInit) + #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)() #define ma_CoCreateInstance(pContext, rclsid, pUnkOuter, dwClsContext, riid, ppv) ((MA_PFN_CoCreateInstance)pContext->win32.CoCreateInstance)(rclsid, pUnkOuter, dwClsContext, riid, ppv) #define ma_CoTaskMemFree(pContext, pv) ((MA_PFN_CoTaskMemFree)pContext->win32.CoTaskMemFree)(pv) @@ -19917,7 +20501,7 @@ static ma_result ma_completion_handler_uwp_init(ma_completion_handler_uwp* pHand pHandler->lpVtbl = &g_maCompletionHandlerVtblInstance; pHandler->counter = 1; - pHandler->hEvent = CreateEventW(NULL, FALSE, FALSE, NULL); + pHandler->hEvent = CreateEventA(NULL, FALSE, FALSE, NULL); if (pHandler->hEvent == NULL) { return ma_result_from_GetLastError(GetLastError()); } @@ -20093,12 +20677,18 @@ static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnDefaultDeviceChanged } /* We only care about devices with the same data flow and role as the current device. */ - if ((pThis->pDevice->type == ma_device_type_playback && dataFlow != ma_eRender) || - (pThis->pDevice->type == ma_device_type_capture && dataFlow != ma_eCapture)) { + if ((pThis->pDevice->type == ma_device_type_playback && dataFlow != ma_eRender) || + (pThis->pDevice->type == ma_device_type_capture && dataFlow != ma_eCapture) || + (pThis->pDevice->type == ma_device_type_loopback && dataFlow != ma_eRender)) { ma_log_postf(ma_device_get_log(pThis->pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Stream rerouting abandoned because dataFlow does match device type.\n"); return S_OK; } + /* We need to consider dataFlow as ma_eCapture if device is ma_device_type_loopback */ + if (pThis->pDevice->type == ma_device_type_loopback) { + dataFlow = ma_eCapture; + } + /* Don't do automatic stream routing if we're not allowed. */ if ((dataFlow == ma_eRender && pThis->pDevice->wasapi.allowPlaybackAutoStreamRouting == MA_FALSE) || (dataFlow == ma_eCapture && pThis->pDevice->wasapi.allowCaptureAutoStreamRouting == MA_FALSE)) { @@ -20119,7 +20709,6 @@ static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnDefaultDeviceChanged - /* Second attempt at device rerouting. We're going to retrieve the device's state at the time of the route change. We're then going to stop the device, reinitialize the device, and then start @@ -20129,37 +20718,49 @@ static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnDefaultDeviceChanged ma_uint32 previousState = ma_device_get_state(pThis->pDevice); ma_bool8 restartDevice = MA_FALSE; + if (previousState == ma_device_state_uninitialized || previousState == ma_device_state_starting) { + ma_log_postf(ma_device_get_log(pThis->pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Stream rerouting abandoned because the device is in the process of starting.\n"); + return S_OK; + } + if (previousState == ma_device_state_started) { ma_device_stop(pThis->pDevice); restartDevice = MA_TRUE; } if (pDefaultDeviceID != NULL) { /* <-- The input device ID will be null if there's no other device available. */ - if (dataFlow == ma_eRender) { - ma_device_reroute__wasapi(pThis->pDevice, ma_device_type_playback); + ma_mutex_lock(&pThis->pDevice->wasapi.rerouteLock); + { + if (dataFlow == ma_eRender) { + ma_device_reroute__wasapi(pThis->pDevice, ma_device_type_playback); - if (pThis->pDevice->wasapi.isDetachedPlayback) { - pThis->pDevice->wasapi.isDetachedPlayback = MA_FALSE; + if (pThis->pDevice->wasapi.isDetachedPlayback) { + pThis->pDevice->wasapi.isDetachedPlayback = MA_FALSE; - if (pThis->pDevice->type == ma_device_type_duplex && pThis->pDevice->wasapi.isDetachedCapture) { - restartDevice = MA_FALSE; /* It's a duplex device and the capture side is detached. We cannot be restarting the device just yet. */ - } else { - restartDevice = MA_TRUE; /* It's not a duplex device, or the capture side is also attached so we can go ahead and restart the device. */ + if (pThis->pDevice->type == ma_device_type_duplex && pThis->pDevice->wasapi.isDetachedCapture) { + restartDevice = MA_FALSE; /* It's a duplex device and the capture side is detached. We cannot be restarting the device just yet. */ + } + else { + restartDevice = MA_TRUE; /* It's not a duplex device, or the capture side is also attached so we can go ahead and restart the device. */ + } } } - } else { - ma_device_reroute__wasapi(pThis->pDevice, (pThis->pDevice->type == ma_device_type_loopback) ? ma_device_type_loopback : ma_device_type_capture); + else { + ma_device_reroute__wasapi(pThis->pDevice, (pThis->pDevice->type == ma_device_type_loopback) ? ma_device_type_loopback : ma_device_type_capture); - if (pThis->pDevice->wasapi.isDetachedCapture) { - pThis->pDevice->wasapi.isDetachedCapture = MA_FALSE; + if (pThis->pDevice->wasapi.isDetachedCapture) { + pThis->pDevice->wasapi.isDetachedCapture = MA_FALSE; - if (pThis->pDevice->type == ma_device_type_duplex && pThis->pDevice->wasapi.isDetachedPlayback) { - restartDevice = MA_FALSE; /* It's a duplex device and the playback side is detached. We cannot be restarting the device just yet. */ - } else { - restartDevice = MA_TRUE; /* It's not a duplex device, or the playback side is also attached so we can go ahead and restart the device. */ + if (pThis->pDevice->type == ma_device_type_duplex && pThis->pDevice->wasapi.isDetachedPlayback) { + restartDevice = MA_FALSE; /* It's a duplex device and the playback side is detached. We cannot be restarting the device just yet. */ + } + else { + restartDevice = MA_TRUE; /* It's not a duplex device, or the playback side is also attached so we can go ahead and restart the device. */ + } } } } + ma_mutex_unlock(&pThis->pDevice->wasapi.rerouteLock); if (restartDevice) { ma_device_start(pThis->pDevice); @@ -21797,7 +22398,7 @@ static ma_result ma_device_init__wasapi(ma_device* pDevice, const ma_device_conf The event for capture needs to be manual reset for the same reason as playback. We keep the initial state set to unsignaled, however, because we want to block until we actually have something for the first call to ma_device_read(). */ - pDevice->wasapi.hEventCapture = CreateEventW(NULL, FALSE, FALSE, NULL); /* Auto reset, unsignaled by default. */ + pDevice->wasapi.hEventCapture = CreateEventA(NULL, FALSE, FALSE, NULL); /* Auto reset, unsignaled by default. */ if (pDevice->wasapi.hEventCapture == NULL) { result = ma_result_from_GetLastError(GetLastError()); @@ -21879,7 +22480,7 @@ static ma_result ma_device_init__wasapi(ma_device* pDevice, const ma_device_conf The playback event also needs to be initially set to a signaled state so that the first call to ma_device_write() is able to get passed WaitForMultipleObjects(). */ - pDevice->wasapi.hEventPlayback = CreateEventW(NULL, FALSE, TRUE, NULL); /* Auto reset, signaled by default. */ + pDevice->wasapi.hEventPlayback = CreateEventA(NULL, FALSE, TRUE, NULL); /* Auto reset, signaled by default. */ if (pDevice->wasapi.hEventPlayback == NULL) { result = ma_result_from_GetLastError(GetLastError()); @@ -21933,7 +22534,7 @@ static ma_result ma_device_init__wasapi(ma_device* pDevice, const ma_device_conf */ #if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) if (pConfig->wasapi.noAutoStreamRouting == MA_FALSE) { - if ((pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) && pConfig->capture.pDeviceID == NULL) { + if ((pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex || pConfig->deviceType == ma_device_type_loopback) && pConfig->capture.pDeviceID == NULL) { pDevice->wasapi.allowCaptureAutoStreamRouting = MA_TRUE; } if ((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pConfig->playback.pDeviceID == NULL) { @@ -21941,6 +22542,8 @@ static ma_result ma_device_init__wasapi(ma_device* pDevice, const ma_device_conf } } + ma_mutex_init(&pDevice->wasapi.rerouteLock); + hr = ma_CoCreateInstance(pDevice->pContext, MA_CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, MA_IID_IMMDeviceEnumerator, (void**)&pDeviceEnumerator); if (FAILED(hr)) { ma_device_uninit__wasapi(pDevice); @@ -21961,8 +22564,8 @@ static ma_result ma_device_init__wasapi(ma_device* pDevice, const ma_device_conf } #endif - c89atomic_exchange_32(&pDevice->wasapi.isStartedCapture, MA_FALSE); - c89atomic_exchange_32(&pDevice->wasapi.isStartedPlayback, MA_FALSE); + ma_atomic_bool32_set(&pDevice->wasapi.isStartedCapture, MA_FALSE); + ma_atomic_bool32_set(&pDevice->wasapi.isStartedPlayback, MA_FALSE); return MA_SUCCESS; } @@ -22040,18 +22643,17 @@ static ma_result ma_device_reroute__wasapi(ma_device* pDevice, ma_device_type de } ma_device__post_init_setup(pDevice, deviceType); - ma_device__on_notification_rerouted(pDevice); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "=== DEVICE CHANGED ===\n"); + return MA_SUCCESS; } -static ma_result ma_device_start__wasapi(ma_device* pDevice) +static ma_result ma_device_start__wasapi_nolock(ma_device* pDevice) { HRESULT hr; - MA_ASSERT(pDevice != NULL); - if (pDevice->pContext->wasapi.hAvrt) { LPCWSTR pTaskName = ma_to_usage_string__wasapi(pDevice->wasapi.usage); if (pTaskName) { @@ -22067,7 +22669,7 @@ static ma_result ma_device_start__wasapi(ma_device* pDevice) return ma_result_from_HRESULT(hr); } - c89atomic_exchange_32(&pDevice->wasapi.isStartedCapture, MA_TRUE); + ma_atomic_bool32_set(&pDevice->wasapi.isStartedCapture, MA_TRUE); } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { @@ -22077,13 +22679,29 @@ static ma_result ma_device_start__wasapi(ma_device* pDevice) return ma_result_from_HRESULT(hr); } - c89atomic_exchange_32(&pDevice->wasapi.isStartedPlayback, MA_TRUE); + ma_atomic_bool32_set(&pDevice->wasapi.isStartedPlayback, MA_TRUE); } return MA_SUCCESS; } -static ma_result ma_device_stop__wasapi(ma_device* pDevice) +static ma_result ma_device_start__wasapi(ma_device* pDevice) +{ + ma_result result; + + MA_ASSERT(pDevice != NULL); + + /* Wait for any rerouting to finish before attempting to start the device. */ + ma_mutex_lock(&pDevice->wasapi.rerouteLock); + { + result = ma_device_start__wasapi_nolock(pDevice); + } + ma_mutex_unlock(&pDevice->wasapi.rerouteLock); + + return result; +} + +static ma_result ma_device_stop__wasapi_nolock(ma_device* pDevice) { ma_result result; HRESULT hr; @@ -22112,12 +22730,12 @@ static ma_result ma_device_stop__wasapi(ma_device* pDevice) /* If we have a mapped buffer we need to release it. */ if (pDevice->wasapi.pMappedBufferCapture != NULL) { ma_IAudioCaptureClient_ReleaseBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, pDevice->wasapi.mappedBufferCaptureCap); - pDevice->wasapi.pMappedBufferCapture = NULL; + pDevice->wasapi.pMappedBufferCapture = NULL; pDevice->wasapi.mappedBufferCaptureCap = 0; pDevice->wasapi.mappedBufferCaptureLen = 0; } - c89atomic_exchange_32(&pDevice->wasapi.isStartedCapture, MA_FALSE); + ma_atomic_bool32_set(&pDevice->wasapi.isStartedCapture, MA_FALSE); } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { @@ -22125,13 +22743,14 @@ static ma_result ma_device_stop__wasapi(ma_device* pDevice) The buffer needs to be drained before stopping the device. Not doing this will result in the last few frames not getting output to the speakers. This is a problem for very short sounds because it'll result in a significant portion of it not getting played. */ - if (c89atomic_load_32(&pDevice->wasapi.isStartedPlayback)) { + if (ma_atomic_bool32_get(&pDevice->wasapi.isStartedPlayback)) { /* We need to make sure we put a timeout here or else we'll risk getting stuck in a deadlock in some cases. */ DWORD waitTime = pDevice->wasapi.actualBufferSizeInFramesPlayback / pDevice->playback.internalSampleRate; if (pDevice->playback.shareMode == ma_share_mode_exclusive) { WaitForSingleObject(pDevice->wasapi.hEventPlayback, waitTime); - } else { + } + else { ma_uint32 prevFramesAvaialablePlayback = (ma_uint32)-1; ma_uint32 framesAvailablePlayback; for (;;) { @@ -22174,17 +22793,33 @@ static ma_result ma_device_stop__wasapi(ma_device* pDevice) if (pDevice->wasapi.pMappedBufferPlayback != NULL) { ma_IAudioRenderClient_ReleaseBuffer((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient, pDevice->wasapi.mappedBufferPlaybackCap, 0); - pDevice->wasapi.pMappedBufferPlayback = NULL; + pDevice->wasapi.pMappedBufferPlayback = NULL; pDevice->wasapi.mappedBufferPlaybackCap = 0; pDevice->wasapi.mappedBufferPlaybackLen = 0; } - c89atomic_exchange_32(&pDevice->wasapi.isStartedPlayback, MA_FALSE); + ma_atomic_bool32_set(&pDevice->wasapi.isStartedPlayback, MA_FALSE); } return MA_SUCCESS; } +static ma_result ma_device_stop__wasapi(ma_device* pDevice) +{ + ma_result result; + + MA_ASSERT(pDevice != NULL); + + /* Wait for any rerouting to finish before attempting to stop the device. */ + ma_mutex_lock(&pDevice->wasapi.rerouteLock); + { + result = ma_device_stop__wasapi_nolock(pDevice); + } + ma_mutex_unlock(&pDevice->wasapi.rerouteLock); + + return result; +} + #ifndef MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS #define MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS 5000 @@ -22291,7 +22926,7 @@ static ma_result ma_device_read__wasapi(ma_device* pDevice, void* pFrames, ma_ui for (i = 0; i < iterationCount; i += 1) { hr = ma_IAudioCaptureClient_ReleaseBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, pDevice->wasapi.mappedBufferCaptureCap); if (FAILED(hr)) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Data discontinuity recovery: IAudioCaptureClient_ReleaseBuffer() failed with %d.\n", hr); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Data discontinuity recovery: IAudioCaptureClient_ReleaseBuffer() failed with %ld.\n", hr); break; } @@ -22316,7 +22951,7 @@ static ma_result ma_device_read__wasapi(ma_device* pDevice, void* pFrames, ma_ui } if (FAILED(hr)) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Data discontinuity recovery: IAudioCaptureClient_GetBuffer() failed with %d.\n", hr); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Data discontinuity recovery: IAudioCaptureClient_GetBuffer() failed with %ld.\n", hr); } break; @@ -23708,6 +24343,8 @@ static ma_result ma_device_init__dsound(ma_device* pDevice, const ma_device_conf ma_uint32 periodSizeInFrames; ma_uint32 periodCount; MA_DSBUFFERDESC descDS; + WORD nativeChannelCount; + DWORD nativeChannelMask = 0; result = ma_config_to_WAVEFORMATEXTENSIBLE(pDescriptorPlayback->format, pDescriptorPlayback->channels, pDescriptorPlayback->sampleRate, pDescriptorPlayback->channelMap, &wf); if (result != MA_SUCCESS) { @@ -23741,21 +24378,25 @@ static ma_result ma_device_init__dsound(ma_device* pDevice, const ma_device_conf return ma_result_from_HRESULT(hr); } - if (pDescriptorPlayback->channels == 0) { - if ((caps.dwFlags & MA_DSCAPS_PRIMARYSTEREO) != 0) { - DWORD speakerConfig; + if ((caps.dwFlags & MA_DSCAPS_PRIMARYSTEREO) != 0) { + DWORD speakerConfig; - /* It supports at least stereo, but could support more. */ - wf.Format.nChannels = 2; + /* It supports at least stereo, but could support more. */ + nativeChannelCount = 2; - /* Look at the speaker configuration to get a better idea on the channel count. */ - if (SUCCEEDED(ma_IDirectSound_GetSpeakerConfig((ma_IDirectSound*)pDevice->dsound.pPlayback, &speakerConfig))) { - ma_get_channels_from_speaker_config__dsound(speakerConfig, &wf.Format.nChannels, &wf.dwChannelMask); - } - } else { - /* It does not support stereo, which means we are stuck with mono. */ - wf.Format.nChannels = 1; + /* Look at the speaker configuration to get a better idea on the channel count. */ + if (SUCCEEDED(ma_IDirectSound_GetSpeakerConfig((ma_IDirectSound*)pDevice->dsound.pPlayback, &speakerConfig))) { + ma_get_channels_from_speaker_config__dsound(speakerConfig, &nativeChannelCount, &nativeChannelMask); } + } else { + /* It does not support stereo, which means we are stuck with mono. */ + nativeChannelCount = 1; + nativeChannelMask = 0x00000001; + } + + if (pDescriptorPlayback->channels == 0) { + wf.Format.nChannels = nativeChannelCount; + wf.dwChannelMask = nativeChannelMask; } if (pDescriptorPlayback->sampleRate == 0) { @@ -23777,11 +24418,28 @@ static ma_result ma_device_init__dsound(ma_device* pDevice, const ma_device_conf supported format. To determine whether this has happened, an application can call the GetFormat method for the primary buffer and compare the result with the format that was requested with the SetFormat method. */ - hr = ma_IDirectSoundBuffer_SetFormat((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackPrimaryBuffer, (WAVEFORMATEX*)&wf); + hr = ma_IDirectSoundBuffer_SetFormat((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackPrimaryBuffer, &wf.Format); if (FAILED(hr)) { - ma_device_uninit__dsound(pDevice); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to set format of playback device's primary buffer."); - return ma_result_from_HRESULT(hr); + /* + If setting of the format failed we'll try again with some fallback settings. On Windows 98 I have + observed that IEEE_FLOAT does not work. We'll therefore enforce PCM. I also had issues where a + sample rate of 48000 did not work correctly. Not sure if it was a driver issue or not, but will + use 44100 for the sample rate. + */ + wf.Format.cbSize = sizeof(wf.Format); + wf.Format.wFormatTag = WAVE_FORMAT_PCM; + wf.Format.wBitsPerSample = 16; + wf.Format.nChannels = nativeChannelCount; + wf.Format.nSamplesPerSec = 44100; + wf.Format.nBlockAlign = wf.Format.nChannels * (wf.Format.wBitsPerSample / 8); + wf.Format.nAvgBytesPerSec = wf.Format.nSamplesPerSec * wf.Format.nBlockAlign; + + hr = ma_IDirectSoundBuffer_SetFormat((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackPrimaryBuffer, &wf.Format); + if (FAILED(hr)) { + ma_device_uninit__dsound(pDevice); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to set format of playback device's primary buffer."); + return ma_result_from_HRESULT(hr); + } } /* Get the _actual_ properties of the buffer. */ @@ -23828,7 +24486,7 @@ static ma_result ma_device_init__dsound(ma_device* pDevice, const ma_device_conf descDS.dwSize = sizeof(descDS); descDS.dwFlags = MA_DSBCAPS_CTRLPOSITIONNOTIFY | MA_DSBCAPS_GLOBALFOCUS | MA_DSBCAPS_GETCURRENTPOSITION2; descDS.dwBufferBytes = periodSizeInFrames * periodCount * ma_get_bytes_per_frame(pDescriptorPlayback->format, pDescriptorPlayback->channels); - descDS.lpwfxFormat = (WAVEFORMATEX*)&wf; + descDS.lpwfxFormat = &pActualFormat->Format; hr = ma_IDirectSound_CreateSoundBuffer((ma_IDirectSound*)pDevice->dsound.pPlayback, &descDS, (ma_IDirectSoundBuffer**)&pDevice->dsound.pPlaybackBuffer, NULL); if (FAILED(hr)) { ma_device_uninit__dsound(pDevice); @@ -24385,6 +25043,18 @@ static ma_result ma_context_init__dsound(ma_context* pContext, const ma_context_ pContext->dsound.DirectSoundCaptureCreate = ma_dlsym(pContext, pContext->dsound.hDSoundDLL, "DirectSoundCaptureCreate"); pContext->dsound.DirectSoundCaptureEnumerateA = ma_dlsym(pContext, pContext->dsound.hDSoundDLL, "DirectSoundCaptureEnumerateA"); + /* + We need to support all functions or nothing. DirectSound with Windows 95 seems to not work too + well in my testing. For example, it's missing DirectSoundCaptureEnumerateA(). This is a convenient + place to just disable the DirectSound backend for Windows 95. + */ + if (pContext->dsound.DirectSoundCreate == NULL || + pContext->dsound.DirectSoundEnumerateA == NULL || + pContext->dsound.DirectSoundCaptureCreate == NULL || + pContext->dsound.DirectSoundCaptureEnumerateA == NULL) { + return MA_API_NOT_FOUND; + } + pCallbacks->onContextInit = ma_context_init__dsound; pCallbacks->onContextUninit = ma_context_uninit__dsound; pCallbacks->onContextEnumerateDevices = ma_context_enumerate_devices__dsound; @@ -24934,7 +25604,7 @@ static ma_result ma_device_init__winmm(ma_device* pDevice, const ma_device_confi MMRESULT resultMM; /* We use an event to know when a new fragment needs to be enqueued. */ - pDevice->winmm.hEventCapture = (ma_handle)CreateEventW(NULL, TRUE, TRUE, NULL); + pDevice->winmm.hEventCapture = (ma_handle)CreateEventA(NULL, TRUE, TRUE, NULL); if (pDevice->winmm.hEventCapture == NULL) { errorMsg = "[WinMM] Failed to create event for fragment enqueing for the capture device.", errorCode = ma_result_from_GetLastError(GetLastError()); goto on_error; @@ -24972,7 +25642,7 @@ static ma_result ma_device_init__winmm(ma_device* pDevice, const ma_device_confi MMRESULT resultMM; /* We use an event to know when a new fragment needs to be enqueued. */ - pDevice->winmm.hEventPlayback = (ma_handle)CreateEventW(NULL, TRUE, TRUE, NULL); + pDevice->winmm.hEventPlayback = (ma_handle)CreateEventA(NULL, TRUE, TRUE, NULL); if (pDevice->winmm.hEventPlayback == NULL) { errorMsg = "[WinMM] Failed to create event for fragment enqueing for the playback device.", errorCode = ma_result_from_GetLastError(GetLastError()); goto on_error; @@ -26617,7 +27287,7 @@ static ma_result ma_device_init_by_type__alsa(ma_device* pDevice, const ma_devic isUsingMMap = MA_FALSE; #if 0 /* NOTE: MMAP mode temporarily disabled. */ if (deviceType != ma_device_type_capture) { /* <-- Disabling MMAP mode for capture devices because I apparently do not have a device that supports it which means I can't test it... Contributions welcome. */ - if (!pConfig->alsa.noMMap && ma_device__is_async(pDevice)) { + if (!pConfig->alsa.noMMap) { if (((ma_snd_pcm_hw_params_set_access_proc)pDevice->pContext->alsa.snd_pcm_hw_params_set_access)(pPCM, pHWParams, MA_SND_PCM_ACCESS_MMAP_INTERLEAVED) == 0) { pDevice->alsa.isUsingMMap = MA_TRUE; } @@ -29300,7 +29970,7 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi sampleRate = pDescriptorCapture->sampleRate; } - + result = ma_init_pa_mainloop_and_pa_context__pulse(pDevice->pContext, pDevice->pContext->pulse.pApplicationName, pDevice->pContext->pulse.pServerName, MA_FALSE, &pDevice->pulse.pMainLoop, &pDevice->pulse.pPulseContext); if (result != MA_SUCCESS) { @@ -31092,15 +31762,15 @@ static ma_result ma_get_channel_map_from_AudioChannelLayout(AudioChannelLayout* { pChannelMap[7] = MA_CHANNEL_SIDE_RIGHT; pChannelMap[6] = MA_CHANNEL_SIDE_LEFT; - } /* Intentional fallthrough. */ + } MA_FALLTHROUGH; /* Intentional fallthrough. */ case kAudioChannelLayoutTag_Hexagonal: { pChannelMap[5] = MA_CHANNEL_BACK_CENTER; - } /* Intentional fallthrough. */ + } MA_FALLTHROUGH; /* Intentional fallthrough. */ case kAudioChannelLayoutTag_Pentagonal: { pChannelMap[4] = MA_CHANNEL_FRONT_CENTER; - } /* Intentional fallghrough. */ + } MA_FALLTHROUGH; /* Intentional fallthrough. */ case kAudioChannelLayoutTag_Quadraphonic: { pChannelMap[3] = MA_CHANNEL_BACK_RIGHT; @@ -32438,7 +33108,7 @@ static OSStatus ma_on_input__coreaudio(void* pUserData, AudioUnitRenderActionFla ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "Failed to allocate AudioBufferList for capture.\n"); return noErr; } - + pRenderedBufferList = (AudioBufferList*)pDevice->coreaudio.pAudioBufferList; MA_ASSERT(pRenderedBufferList); @@ -32876,7 +33546,7 @@ static ma_result ma_device__untrack__coreaudio(ma_device* pDevice) */ ma_device__on_notification_interruption_began(m_pDevice); } break; - + case AVAudioSessionInterruptionTypeEnded: { ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_INFO, "[Core Audio] Interruption: AVAudioSessionInterruptionTypeEnded\n"); @@ -32930,7 +33600,7 @@ static ma_result ma_device__untrack__coreaudio(ma_device* pDevice) } ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_DEBUG, "[Core Audio] Changing Route. inputNumberChannels=%d; outputNumberOfChannels=%d\n", (int)pSession.inputNumberOfChannels, (int)pSession.outputNumberOfChannels); - + /* Let the application know about the route change. */ ma_device__on_notification_rerouted(m_pDevice); } @@ -33303,7 +33973,7 @@ static ma_result ma_device_init_internal__coreaudio(ma_context* pContext, ma_dev @autoreleasepool { AVAudioSession* pAudioSession = [AVAudioSession sharedInstance]; MA_ASSERT(pAudioSession != NULL); - + [pAudioSession setPreferredIOBufferDuration:((float)actualPeriodSizeInFrames / pAudioSession.sampleRate) error:nil]; actualPeriodSizeInFrames = ma_next_power_of_2((ma_uint32)(pAudioSession.IOBufferDuration * pAudioSession.sampleRate)); } @@ -33544,7 +34214,7 @@ static ma_result ma_device_init__coreaudio(ma_device* pDevice, const ma_device_c #if defined(MA_APPLE_DESKTOP) ma_get_AudioObject_uid(pDevice->pContext, pDevice->coreaudio.deviceObjectIDCapture, sizeof(pDevice->capture.id.coreaudio), pDevice->capture.id.coreaudio); - + /* If we are using the default device we'll need to listen for changes to the system's default device so we can seemlessly switch the device in the background. @@ -33608,7 +34278,7 @@ static ma_result ma_device_init__coreaudio(ma_device* pDevice, const ma_device_c #if defined(MA_APPLE_DESKTOP) ma_get_AudioObject_uid(pDevice->pContext, pDevice->coreaudio.deviceObjectIDPlayback, sizeof(pDevice->playback.id.coreaudio), pDevice->playback.id.coreaudio); - + /* If we are using the default device we'll need to listen for changes to the system's default device so we can seemlessly switch the device in the background. @@ -36255,6 +36925,9 @@ static ma_result ma_context_init__oss(ma_context* pContext, const ma_context_con #endif /* OSS */ + + + /****************************************************************************** AAudio Backend @@ -36273,6 +36946,7 @@ typedef int32_t ma_aaudio_performance_mo typedef int32_t ma_aaudio_usage_t; typedef int32_t ma_aaudio_content_type_t; typedef int32_t ma_aaudio_input_preset_t; +typedef int32_t ma_aaudio_allowed_capture_policy_t; typedef int32_t ma_aaudio_data_callback_result_t; typedef struct ma_AAudioStreamBuilder_t* ma_AAudioStreamBuilder; typedef struct ma_AAudioStream_t* ma_AAudioStream; @@ -36347,6 +37021,11 @@ typedef struct ma_AAudioStream_t* ma_AAudioStream; #define MA_AAUDIO_INPUT_PRESET_UNPROCESSED 9 #define MA_AAUDIO_INPUT_PRESET_VOICE_PERFORMANCE 10 +/* Allowed Capture Policies */ +#define MA_AAUDIO_ALLOW_CAPTURE_BY_ALL 1 +#define MA_AAUDIO_ALLOW_CAPTURE_BY_SYSTEM 2 +#define MA_AAUDIO_ALLOW_CAPTURE_BY_NONE 3 + /* Callback results. */ #define MA_AAUDIO_CALLBACK_RESULT_CONTINUE 0 #define MA_AAUDIO_CALLBACK_RESULT_STOP 1 @@ -36371,6 +37050,7 @@ typedef void (* MA_PFN_AAudioStreamBuilder_setPerformanceMod typedef void (* MA_PFN_AAudioStreamBuilder_setUsage) (ma_AAudioStreamBuilder* pBuilder, ma_aaudio_usage_t contentType); typedef void (* MA_PFN_AAudioStreamBuilder_setContentType) (ma_AAudioStreamBuilder* pBuilder, ma_aaudio_content_type_t contentType); typedef void (* MA_PFN_AAudioStreamBuilder_setInputPreset) (ma_AAudioStreamBuilder* pBuilder, ma_aaudio_input_preset_t inputPreset); +typedef void (* MA_PFN_AAudioStreamBuilder_setAllowedCapturePolicy) (ma_AAudioStreamBuilder* pBuilder, ma_aaudio_allowed_capture_policy_t policy); typedef ma_aaudio_result_t (* MA_PFN_AAudioStreamBuilder_openStream) (ma_AAudioStreamBuilder* pBuilder, ma_AAudioStream** ppStream); typedef ma_aaudio_result_t (* MA_PFN_AAudioStream_close) (ma_AAudioStream* pStream); typedef ma_aaudio_stream_state_t (* MA_PFN_AAudioStream_getState) (ma_AAudioStream* pStream); @@ -36448,8 +37128,22 @@ static ma_aaudio_input_preset_t ma_to_input_preset__aaudio(ma_aaudio_input_prese return MA_AAUDIO_INPUT_PRESET_GENERIC; } +static ma_aaudio_allowed_capture_policy_t ma_to_allowed_capture_policy__aaudio(ma_aaudio_allowed_capture_policy allowedCapturePolicy) +{ + switch (allowedCapturePolicy) { + case ma_aaudio_allow_capture_by_all: return MA_AAUDIO_ALLOW_CAPTURE_BY_ALL; + case ma_aaudio_allow_capture_by_system: return MA_AAUDIO_ALLOW_CAPTURE_BY_SYSTEM; + case ma_aaudio_allow_capture_by_none: return MA_AAUDIO_ALLOW_CAPTURE_BY_NONE; + default: break; + } + + return MA_AAUDIO_ALLOW_CAPTURE_BY_ALL; +} + static void ma_stream_error_callback__aaudio(ma_AAudioStream* pStream, void* pUserData, ma_aaudio_result_t error) { + ma_result result; + ma_job job; ma_device* pDevice = (ma_device*)pUserData; MA_ASSERT(pDevice != NULL); @@ -36458,26 +37152,24 @@ static void ma_stream_error_callback__aaudio(ma_AAudioStream* pStream, void* pUs 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)); /* - From the documentation for AAudio, when a device is disconnected all we can do is stop it. However, we cannot stop it from the callback - we need - to do it from another thread. Therefore we are going to use an event thread for the AAudio backend to do this cleanly and safely. + 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_PFN_AAudioStream_getState)pDevice->pContext->aaudio.AAudioStream_getState)(pStream) == MA_AAUDIO_STREAM_STATE_DISCONNECTED) { - /* We need to post a job to the job thread for processing. This will reroute the device by reinitializing the stream. */ - ma_result result; - ma_job job = ma_job_init(MA_JOB_TYPE_DEVICE_AAUDIO_REROUTE); - job.data.device.aaudio.reroute.pDevice = pDevice; + 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; - } + 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; - } + 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; } } @@ -36507,7 +37199,6 @@ static ma_result ma_create_and_configure_AAudioStreamBuilder__aaudio(ma_context* { ma_AAudioStreamBuilder* pBuilder; ma_aaudio_result_t resultAA; - ma_uint32 bufferCapacityInFrames; /* Safety. */ *ppBuilder = NULL; @@ -36549,17 +37240,26 @@ static ma_result ma_create_and_configure_AAudioStreamBuilder__aaudio(ma_context* } } - /* - AAudio is annoying when it comes to it's buffer calculation stuff because it doesn't let you - retrieve the actual sample rate until after you've opened the stream. But you need to configure - the buffer capacity before you open the stream... :/ - To solve, we're just going to assume MA_DEFAULT_SAMPLE_RATE (48000) and move on. + /* + There have been reports where setting the frames per data callback results in an error + later on from Android. To address this, I'm experimenting with simply not setting it on + anything from Android 11 and earlier. Suggestions welcome on how we might be able to make + this more targetted. */ - bufferCapacityInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptor, pDescriptor->sampleRate, pConfig->performanceProfile) * pDescriptor->periodCount; + if (pConfig->aaudio.enableCompatibilityWorkarounds && ma_android_sdk_version() > 30) { + /* + AAudio is annoying when it comes to it's buffer calculation stuff because it doesn't let you + retrieve the actual sample rate until after you've opened the stream. But you need to configure + the buffer capacity before you open the stream... :/ - ((MA_PFN_AAudioStreamBuilder_setBufferCapacityInFrames)pContext->aaudio.AAudioStreamBuilder_setBufferCapacityInFrames)(pBuilder, bufferCapacityInFrames); - ((MA_PFN_AAudioStreamBuilder_setFramesPerDataCallback)pContext->aaudio.AAudioStreamBuilder_setFramesPerDataCallback)(pBuilder, bufferCapacityInFrames / pDescriptor->periodCount); + To solve, we're just going to assume MA_DEFAULT_SAMPLE_RATE (48000) and move on. + */ + ma_uint32 bufferCapacityInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptor, pDescriptor->sampleRate, pConfig->performanceProfile) * pDescriptor->periodCount; + + ((MA_PFN_AAudioStreamBuilder_setBufferCapacityInFrames)pContext->aaudio.AAudioStreamBuilder_setBufferCapacityInFrames)(pBuilder, bufferCapacityInFrames); + ((MA_PFN_AAudioStreamBuilder_setFramesPerDataCallback)pContext->aaudio.AAudioStreamBuilder_setFramesPerDataCallback)(pBuilder, bufferCapacityInFrames / pDescriptor->periodCount); + } if (deviceType == ma_device_type_capture) { if (pConfig->aaudio.inputPreset != ma_aaudio_input_preset_default && pContext->aaudio.AAudioStreamBuilder_setInputPreset != NULL) { @@ -36576,6 +37276,10 @@ static ma_result ma_create_and_configure_AAudioStreamBuilder__aaudio(ma_context* ((MA_PFN_AAudioStreamBuilder_setContentType)pContext->aaudio.AAudioStreamBuilder_setContentType)(pBuilder, ma_to_content_type__aaudio(pConfig->aaudio.contentType)); } + if (pConfig->aaudio.allowedCapturePolicy != ma_aaudio_allow_capture_default && pContext->aaudio.AAudioStreamBuilder_setAllowedCapturePolicy != NULL) { + ((MA_PFN_AAudioStreamBuilder_setAllowedCapturePolicy)pContext->aaudio.AAudioStreamBuilder_setAllowedCapturePolicy)(pBuilder, ma_to_allowed_capture_policy__aaudio(pConfig->aaudio.allowedCapturePolicy)); + } + ((MA_PFN_AAudioStreamBuilder_setDataCallback)pContext->aaudio.AAudioStreamBuilder_setDataCallback)(pBuilder, ma_stream_data_callback_playback__aaudio, (void*)pDevice); } @@ -36843,6 +37547,7 @@ static ma_result ma_device_init__aaudio(ma_device* pDevice, const ma_device_conf pDevice->aaudio.usage = pConfig->aaudio.usage; pDevice->aaudio.contentType = pConfig->aaudio.contentType; pDevice->aaudio.inputPreset = pConfig->aaudio.inputPreset; + pDevice->aaudio.allowedCapturePolicy = pConfig->aaudio.allowedCapturePolicy; pDevice->aaudio.noAutoStartAfterReroute = pConfig->aaudio.noAutoStartAfterReroute; if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) { @@ -37019,6 +37724,7 @@ static ma_result ma_device_reinit__aaudio(ma_device* pDevice, ma_device_type dev deviceConfig.aaudio.usage = pDevice->aaudio.usage; deviceConfig.aaudio.contentType = pDevice->aaudio.contentType; deviceConfig.aaudio.inputPreset = pDevice->aaudio.inputPreset; + deviceConfig.aaudio.allowedCapturePolicy = pDevice->aaudio.allowedCapturePolicy; deviceConfig.aaudio.noAutoStartAfterReroute = pDevice->aaudio.noAutoStartAfterReroute; deviceConfig.periods = 1; @@ -37154,6 +37860,7 @@ static ma_result ma_context_init__aaudio(ma_context* pContext, const ma_context_ pContext->aaudio.AAudioStreamBuilder_setUsage = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setUsage"); pContext->aaudio.AAudioStreamBuilder_setContentType = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setContentType"); pContext->aaudio.AAudioStreamBuilder_setInputPreset = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setInputPreset"); + pContext->aaudio.AAudioStreamBuilder_setAllowedCapturePolicy = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setAllowedCapturePolicy"); pContext->aaudio.AAudioStreamBuilder_openStream = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_openStream"); pContext->aaudio.AAudioStream_close = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_close"); pContext->aaudio.AAudioStream_getState = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_getState"); @@ -37196,7 +37903,7 @@ static ma_result ma_context_init__aaudio(ma_context* pContext, const ma_context_ return result; } } - + (void)pConfig; return MA_SUCCESS; @@ -38495,6 +39202,29 @@ Web Audio Backend #ifdef MA_HAS_WEBAUDIO #include +#if (__EMSCRIPTEN_major__ > 3) || (__EMSCRIPTEN_major__ == 3 && (__EMSCRIPTEN_minor__ > 1 || (__EMSCRIPTEN_minor__ == 1 && __EMSCRIPTEN_tiny__ >= 32))) + #include + #define MA_SUPPORT_AUDIO_WORKLETS +#endif + +/* +TODO: Version 0.12: Swap this logic around so that AudioWorklets are used by default. Add MA_NO_AUDIO_WORKLETS. +*/ +#if defined(MA_ENABLE_AUDIO_WORKLETS) && defined(MA_SUPPORT_AUDIO_WORKLETS) + #define MA_USE_AUDIO_WORKLETS +#endif + +/* The thread stack size must be a multiple of 16. */ +#ifndef MA_AUDIO_WORKLETS_THREAD_STACK_SIZE +#define MA_AUDIO_WORKLETS_THREAD_STACK_SIZE 16384 +#endif + +#if defined(MA_USE_AUDIO_WORKLETS) +#define MA_WEBAUDIO_LATENCY_HINT_BALANCED "balanced" +#define MA_WEBAUDIO_LATENCY_HINT_INTERACTIVE "interactive" +#define MA_WEBAUDIO_LATENCY_HINT_PLAYBACK "playback" +#endif + static ma_bool32 ma_is_capture_supported__webaudio() { return EM_ASM_INT({ @@ -38505,6 +39235,16 @@ static ma_bool32 ma_is_capture_supported__webaudio() #ifdef __cplusplus extern "C" { #endif +void* EMSCRIPTEN_KEEPALIVE ma_malloc_emscripten(size_t sz, const ma_allocation_callbacks* pAllocationCallbacks) +{ + return ma_malloc(sz, pAllocationCallbacks); +} + +void EMSCRIPTEN_KEEPALIVE ma_free_emscripten(void* p, const ma_allocation_callbacks* pAllocationCallbacks) +{ + ma_free(p, pAllocationCallbacks); +} + void EMSCRIPTEN_KEEPALIVE ma_device_process_pcm_frames_capture__webaudio(ma_device* pDevice, int frameCount, float* pFrames) { ma_device_handle_backend_data_callback(pDevice, NULL, pFrames, (ma_uint32)frameCount); @@ -38595,13 +39335,14 @@ static ma_result ma_context_get_device_info__webaudio(ma_context* pContext, ma_d return MA_SUCCESS; } - +#if !defined(MA_USE_AUDIO_WORKLETS) static void ma_device_uninit_by_index__webaudio(ma_device* pDevice, ma_device_type deviceType, int deviceIndex) { MA_ASSERT(pDevice != NULL); EM_ASM({ var device = miniaudio.get_device_by_index($0); + var pAllocationCallbacks = $3; /* Make sure all nodes are disconnected and marked for collection. */ if (device.scriptNode !== undefined) { @@ -38623,7 +39364,7 @@ static void ma_device_uninit_by_index__webaudio(ma_device* pDevice, ma_device_ty /* Can't forget to free the intermediary buffer. This is the buffer that's shared between JavaScript and C. */ if (device.intermediaryBuffer !== undefined) { - Module._free(device.intermediaryBuffer); + _ma_free_emscripten(device.intermediaryBuffer, pAllocationCallbacks); device.intermediaryBuffer = undefined; device.intermediaryBufferView = undefined; device.intermediaryBufferSizeInBytes = undefined; @@ -38631,7 +39372,32 @@ static void ma_device_uninit_by_index__webaudio(ma_device* pDevice, ma_device_ty /* Make sure the device is untracked so the slot can be reused later. */ miniaudio.untrack_device_by_index($0); - }, deviceIndex, deviceType); + }, deviceIndex, deviceType, &pDevice->pContext->allocationCallbacks); +} +#endif + +static void ma_device_uninit_by_type__webaudio(ma_device* pDevice, ma_device_type deviceType) +{ + MA_ASSERT(pDevice != NULL); + MA_ASSERT(deviceType == ma_device_type_capture || deviceType == ma_device_type_playback); + +#if defined(MA_USE_AUDIO_WORKLETS) + if (deviceType == ma_device_type_capture) { + ma_free(pDevice->webaudio.pIntermediaryBufferCapture, &pDevice->pContext->allocationCallbacks); + ma_free(pDevice->webaudio.pStackBufferCapture, &pDevice->pContext->allocationCallbacks); + emscripten_destroy_audio_context(pDevice->webaudio.audioContextCapture); + } else { + ma_free(pDevice->webaudio.pIntermediaryBufferPlayback, &pDevice->pContext->allocationCallbacks); + ma_free(pDevice->webaudio.pStackBufferPlayback, &pDevice->pContext->allocationCallbacks); + emscripten_destroy_audio_context(pDevice->webaudio.audioContextPlayback); + } +#else + if (deviceType == ma_device_type_capture) { + ma_device_uninit_by_index__webaudio(pDevice, ma_device_type_capture, pDevice->webaudio.indexCapture); + } else { + ma_device_uninit_by_index__webaudio(pDevice, ma_device_type_playback, pDevice->webaudio.indexPlayback); + } +#endif } static ma_result ma_device_uninit__webaudio(ma_device* pDevice) @@ -38639,11 +39405,11 @@ static ma_result ma_device_uninit__webaudio(ma_device* pDevice) MA_ASSERT(pDevice != NULL); if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { - ma_device_uninit_by_index__webaudio(pDevice, ma_device_type_capture, pDevice->webaudio.indexCapture); + ma_device_uninit_by_type__webaudio(pDevice, ma_device_type_capture); } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { - ma_device_uninit_by_index__webaudio(pDevice, ma_device_type_playback, pDevice->webaudio.indexPlayback); + ma_device_uninit_by_type__webaudio(pDevice, ma_device_type_playback); } return MA_SUCCESS; @@ -38651,10 +39417,16 @@ static ma_result ma_device_uninit__webaudio(ma_device* pDevice) static ma_uint32 ma_calculate_period_size_in_frames_from_descriptor__webaudio(const ma_device_descriptor* pDescriptor, ma_uint32 nativeSampleRate, ma_performance_profile performanceProfile) { +#if defined(MA_USE_AUDIO_WORKLETS) + (void)pDescriptor; + (void)nativeSampleRate; + (void)performanceProfile; + + return 256; +#else /* - There have been reports of the default buffer size being too small on some browsers. There have been reports of the default buffer - size being too small on some browsers. If we're using default buffer size, we'll make sure the period size is a big biffer than our - standard defaults. + There have been reports of the default buffer size being too small on some browsers. If we're using + the default buffer size, we'll make sure the period size is bigger than our standard defaults. */ ma_uint32 periodSizeInFrames; @@ -38682,11 +39454,177 @@ static ma_uint32 ma_calculate_period_size_in_frames_from_descriptor__webaudio(co } return periodSizeInFrames; +#endif +} + + +#if defined(MA_USE_AUDIO_WORKLETS) +typedef struct +{ + ma_device* pDevice; + const ma_device_config* pConfig; + ma_device_descriptor* pDescriptor; + ma_device_type deviceType; + ma_uint32 channels; +} ma_audio_worklet_thread_initialized_data; + +static EM_BOOL ma_audio_worklet_process_callback__webaudio(int inputCount, const AudioSampleFrame* pInputs, int outputCount, AudioSampleFrame* pOutputs, int paramCount, const AudioParamFrame* pParams, void* pUserData) +{ + ma_device* pDevice = (ma_device*)pUserData; + ma_uint32 frameCount; + ma_uint32 framesProcessed; + + (void)paramCount; + (void)pParams; + + /* + The Emscripten documentation says that it'll always be 128 frames being passed in. Hard coding it like that feels + like a very bad idea to me. Even if it's hard coded in the backend, the API and documentation should always refer + to variables instead of a hard coded number. In any case, will follow along for the time being. + + Unfortunately the audio data is not interleaved so we'll need to convert it before we give the data to miniaudio + for further processing. + */ + frameCount = 128; + + /* Run the conversion logic in a loop for robustness. */ + framesProcessed = 0; + while (framesProcessed < frameCount) { + ma_uint32 framesToProcessThisIteration = frameCount - framesProcessed; + + if (inputCount > 0) { + if (framesToProcessThisIteration > pDevice->webaudio.intermediaryBufferSizeInFramesPlayback) { + framesToProcessThisIteration = pDevice->webaudio.intermediaryBufferSizeInFramesPlayback; + } + + /* Input data needs to be interleaved before we hand it to the client. */ + for (ma_uint32 iFrame = 0; iFrame < framesToProcessThisIteration; iFrame += 1) { + for (ma_uint32 iChannel = 0; iChannel < pDevice->capture.internalChannels; iChannel += 1) { + pDevice->webaudio.pIntermediaryBufferCapture[iFrame*pDevice->capture.internalChannels + iChannel] = pInputs[0].data[frameCount*iChannel + framesProcessed + iFrame]; + } + } + + ma_device_process_pcm_frames_capture__webaudio(pDevice, framesToProcessThisIteration, pDevice->webaudio.pIntermediaryBufferCapture); + } + + if (outputCount > 0) { + ma_device_process_pcm_frames_playback__webaudio(pDevice, framesToProcessThisIteration, pDevice->webaudio.pIntermediaryBufferPlayback); + + /* We've read the data from the client. Now we need to deinterleave the buffer and output to the output buffer. */ + for (ma_uint32 iFrame = 0; iFrame < framesToProcessThisIteration; iFrame += 1) { + for (ma_uint32 iChannel = 0; iChannel < pDevice->playback.internalChannels; iChannel += 1) { + pOutputs[0].data[frameCount*iChannel + framesProcessed + iFrame] = pDevice->webaudio.pIntermediaryBufferPlayback[iFrame*pDevice->playback.internalChannels + iChannel]; + } + } + } + + framesProcessed += framesToProcessThisIteration; + } + + return EM_TRUE; +} + + +static void ma_audio_worklet_processor_created__webaudio(EMSCRIPTEN_WEBAUDIO_T audioContext, EM_BOOL success, void* pUserData) +{ + ma_audio_worklet_thread_initialized_data* pParameters = (ma_audio_worklet_thread_initialized_data*)pUserData; + EmscriptenAudioWorkletNodeCreateOptions workletNodeOptions; + EMSCRIPTEN_AUDIO_WORKLET_NODE_T workletNode; + int outputChannelCount = 0; + + if (success == EM_FALSE) { + pParameters->pDevice->webaudio.isInitialized = MA_TRUE; + return; + } + + MA_ZERO_OBJECT(&workletNodeOptions); + + if (pParameters->deviceType == ma_device_type_capture) { + workletNodeOptions.numberOfInputs = 1; + } else { + outputChannelCount = (int)pParameters->channels; /* Safe cast. */ + + workletNodeOptions.numberOfOutputs = 1; + workletNodeOptions.outputChannelCounts = &outputChannelCount; + } + + /* Here is where we create the node that will do our processing. */ + workletNode = emscripten_create_wasm_audio_worklet_node(audioContext, "miniaudio", &workletNodeOptions, &ma_audio_worklet_process_callback__webaudio, pParameters->pDevice); + + if (pParameters->deviceType == ma_device_type_capture) { + pParameters->pDevice->webaudio.workletNodeCapture = workletNode; + } else { + pParameters->pDevice->webaudio.workletNodePlayback = workletNode; + } + + /* + With the worklet node created we can now attach it to the graph. This is done differently depending on whether or not + it's capture or playback mode. + */ + if (pParameters->deviceType == ma_device_type_capture) { + EM_ASM({ + var workletNode = emscriptenGetAudioObject($0); + var audioContext = emscriptenGetAudioObject($1); + + navigator.mediaDevices.getUserMedia({audio:true, video:false}) + .then(function(stream) { + audioContext.streamNode = audioContext.createMediaStreamSource(stream); + audioContext.streamNode.connect(workletNode); + + /* + Now that the worklet node has been connected, do we need to inspect workletNode.channelCount + to check the actual channel count, or is it safe to assume it's always 2? + */ + }) + .catch(function(error) { + + }); + }, workletNode, audioContext); + } else { + EM_ASM({ + var workletNode = emscriptenGetAudioObject($0); + var audioContext = emscriptenGetAudioObject($1); + workletNode.connect(audioContext.destination); + }, workletNode, audioContext); + } + + pParameters->pDevice->webaudio.isInitialized = MA_TRUE; + + ma_log_postf(ma_device_get_log(pParameters->pDevice), MA_LOG_LEVEL_DEBUG, "AudioWorklets: Created worklet node: %d\n", workletNode); + + /* Our parameter data is no longer needed. */ + ma_free(pParameters, &pParameters->pDevice->pContext->allocationCallbacks); +} + + + +static void ma_audio_worklet_thread_initialized__webaudio(EMSCRIPTEN_WEBAUDIO_T audioContext, EM_BOOL success, void* pUserData) +{ + ma_audio_worklet_thread_initialized_data* pParameters = (ma_audio_worklet_thread_initialized_data*)pUserData; + WebAudioWorkletProcessorCreateOptions workletProcessorOptions; + + MA_ASSERT(pParameters != NULL); + + if (success == EM_FALSE) { + pParameters->pDevice->webaudio.isInitialized = MA_TRUE; + return; + } + + MA_ZERO_OBJECT(&workletProcessorOptions); + workletProcessorOptions.name = "miniaudio"; /* I'm not entirely sure what to call this. Does this need to be globally unique, or does it need only be unique for a given AudioContext? */ + + emscripten_create_wasm_audio_worklet_processor_async(audioContext, &workletProcessorOptions, ma_audio_worklet_processor_created__webaudio, pParameters); } +#endif static ma_result ma_device_init_by_type__webaudio(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptor, ma_device_type deviceType) { - int deviceIndex; +#if defined(MA_USE_AUDIO_WORKLETS) + EMSCRIPTEN_WEBAUDIO_T audioContext; + void* pStackBuffer; + size_t intermediaryBufferSizeInFrames; + float* pIntermediaryBuffer; +#endif ma_uint32 channels; ma_uint32 sampleRate; ma_uint32 periodSizeInFrames; @@ -38706,13 +39644,99 @@ static ma_result ma_device_init_by_type__webaudio(ma_device* pDevice, const ma_d ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "periodSizeInFrames = %d\n", (int)periodSizeInFrames); +#if defined(MA_USE_AUDIO_WORKLETS) + { + ma_audio_worklet_thread_initialized_data* pInitParameters; + EmscriptenWebAudioCreateAttributes audioContextAttributes; + + audioContextAttributes.latencyHint = MA_WEBAUDIO_LATENCY_HINT_INTERACTIVE; + audioContextAttributes.sampleRate = sampleRate; + + /* It's not clear if this can return an error. None of the tests in the Emscripten repository check for this, so neither am I for now. */ + audioContext = emscripten_create_audio_context(&audioContextAttributes); + + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "TRACE: AUDIO CONTEXT CREATED\n"); + + /* + We now need to create a worker thread. This is a bit weird because we need to allocate our + own buffer for the thread's stack. The stack needs to be aligned to 16 bytes. I'm going to + allocate this on the heap to keep it simple. + */ + pStackBuffer = ma_aligned_malloc(MA_AUDIO_WORKLETS_THREAD_STACK_SIZE, 16, &pDevice->pContext->allocationCallbacks); + if (pStackBuffer == NULL) { + emscripten_destroy_audio_context(audioContext); + return MA_OUT_OF_MEMORY; + } + + /* + We need an intermediary buffer for data conversion. WebAudio reports data in uninterleaved + format whereas we require it to be interleaved. We'll do this in chunks of 128 frames. + */ + intermediaryBufferSizeInFrames = 128; + pIntermediaryBuffer = ma_malloc(intermediaryBufferSizeInFrames * channels * sizeof(float), &pDevice->pContext->allocationCallbacks); + if (pIntermediaryBuffer == NULL) { + ma_free(pStackBuffer, &pDevice->pContext->allocationCallbacks); + emscripten_destroy_audio_context(audioContext); + return MA_OUT_OF_MEMORY; + } + + pInitParameters = ma_malloc(sizeof(*pInitParameters), &pDevice->pContext->allocationCallbacks); + if (pInitParameters == NULL) { + ma_free(pIntermediaryBuffer, &pDevice->pContext->allocationCallbacks); + ma_free(pStackBuffer, &pDevice->pContext->allocationCallbacks); + emscripten_destroy_audio_context(audioContext); + return MA_OUT_OF_MEMORY; + } + + pInitParameters->pDevice = pDevice; + pInitParameters->pConfig = pConfig; + pInitParameters->pDescriptor = pDescriptor; + pInitParameters->deviceType = deviceType; + pInitParameters->channels = channels; + + /* + We need to flag the device as not yet initialized so we can wait on it later. Unfortunately all of + the Emscripten WebAudio stuff is asynchronous. + */ + pDevice->webaudio.isInitialized = MA_FALSE; + + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "TRACE: CREATING WORKLET\n"); + + emscripten_start_wasm_audio_worklet_thread_async(audioContext, pStackBuffer, MA_AUDIO_WORKLETS_THREAD_STACK_SIZE, ma_audio_worklet_thread_initialized__webaudio, pInitParameters); + + /* We must wait for initialization to complete. We're just spinning here. The emscripten_sleep() call is why we need to build with `-sASYNCIFY`. */ + while (pDevice->webaudio.isInitialized == MA_FALSE) { + emscripten_sleep(1); + } + + /* + Now that initialization is finished we can go ahead and extract our channel count so that + miniaudio can set up a data converter at a higher level. + */ + if (deviceType == ma_device_type_capture) { + /* + For capture we won't actually know what the channel count is. Everything I've seen seems + to indicate that the default channel count is 2, so I'm sticking with that. + */ + channels = 2; + } else { + /* Get the channel count from the audio context. */ + channels = (ma_uint32)EM_ASM_INT({ + return emscriptenGetAudioObject($0).destination.channelCount; + }, audioContext); + } + + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "TRACE: INITIALIZED. channels = %u\n", channels); + } +#else /* We create the device on the JavaScript side and reference it using an index. We use this to make it possible to reference the device between JavaScript and C. */ - deviceIndex = EM_ASM_INT({ - var channels = $0; - var sampleRate = $1; - var bufferSize = $2; /* In PCM frames. */ - var isCapture = $3; - var pDevice = $4; + int deviceIndex = EM_ASM_INT({ + var channels = $0; + var sampleRate = $1; + var bufferSize = $2; /* In PCM frames. */ + var isCapture = $3; + var pDevice = $4; + var pAllocationCallbacks = $5; if (typeof(window.miniaudio) === 'undefined') { return -1; /* Context not initialized. */ @@ -38725,12 +39749,9 @@ static ma_result ma_device_init_by_type__webaudio(ma_device* pDevice, const ma_d device.webaudio.suspend(); device.state = 1; /* ma_device_state_stopped */ - /* - We need an intermediary buffer which we use for JavaScript and C interop. This buffer stores interleaved f32 PCM data. Because it's passed between - JavaScript and C it needs to be allocated and freed using Module._malloc() and Module._free(). - */ + /* We need an intermediary buffer which we use for JavaScript and C interop. This buffer stores interleaved f32 PCM data. */ device.intermediaryBufferSizeInBytes = channels * bufferSize * 4; - device.intermediaryBuffer = Module._malloc(device.intermediaryBufferSizeInBytes); + device.intermediaryBuffer = _ma_malloc_emscripten(device.intermediaryBufferSizeInBytes, pAllocationCallbacks); device.intermediaryBufferView = new Float32Array(Module.HEAPF32.buffer, device.intermediaryBuffer, device.intermediaryBufferSizeInBytes); /* @@ -38871,25 +39892,45 @@ static ma_result ma_device_init_by_type__webaudio(ma_device* pDevice, const ma_d } return miniaudio.track_device(device); - }, channels, sampleRate, periodSizeInFrames, deviceType == ma_device_type_capture, pDevice); + }, channels, sampleRate, periodSizeInFrames, deviceType == ma_device_type_capture, pDevice, &pDevice->pContext->allocationCallbacks); if (deviceIndex < 0) { return MA_FAILED_TO_OPEN_BACKEND_DEVICE; } +#endif +#if defined(MA_USE_AUDIO_WORKLETS) + if (deviceType == ma_device_type_capture) { + pDevice->webaudio.audioContextCapture = audioContext; + pDevice->webaudio.pStackBufferCapture = pStackBuffer; + pDevice->webaudio.intermediaryBufferSizeInFramesCapture = intermediaryBufferSizeInFrames; + pDevice->webaudio.pIntermediaryBufferCapture = pIntermediaryBuffer; + } else { + pDevice->webaudio.audioContextPlayback = audioContext; + pDevice->webaudio.pStackBufferPlayback = pStackBuffer; + pDevice->webaudio.intermediaryBufferSizeInFramesPlayback = intermediaryBufferSizeInFrames; + pDevice->webaudio.pIntermediaryBufferPlayback = pIntermediaryBuffer; + } +#else if (deviceType == ma_device_type_capture) { pDevice->webaudio.indexCapture = deviceIndex; } else { pDevice->webaudio.indexPlayback = deviceIndex; } +#endif pDescriptor->format = ma_format_f32; pDescriptor->channels = channels; ma_channel_map_init_standard(ma_standard_channel_map_webaudio, pDescriptor->channelMap, ma_countof(pDescriptor->channelMap), pDescriptor->channels); - pDescriptor->sampleRate = EM_ASM_INT({ return miniaudio.get_device_by_index($0).webaudio.sampleRate; }, deviceIndex); pDescriptor->periodSizeInFrames = periodSizeInFrames; pDescriptor->periodCount = 1; +#if defined(MA_USE_AUDIO_WORKLETS) + pDescriptor->sampleRate = sampleRate; /* Is this good enough to be used in the general case? */ +#else + pDescriptor->sampleRate = EM_ASM_INT({ return miniaudio.get_device_by_index($0).webaudio.sampleRate; }, deviceIndex); +#endif + return MA_SUCCESS; } @@ -38918,7 +39959,7 @@ static ma_result ma_device_init__webaudio(ma_device* pDevice, const ma_device_co result = ma_device_init_by_type__webaudio(pDevice, pConfig, pDescriptorPlayback, ma_device_type_playback); if (result != MA_SUCCESS) { if (pConfig->deviceType == ma_device_type_duplex) { - ma_device_uninit_by_index__webaudio(pDevice, ma_device_type_capture, pDevice->webaudio.indexCapture); + ma_device_uninit_by_type__webaudio(pDevice, ma_device_type_capture); } return result; } @@ -38931,6 +39972,15 @@ static ma_result ma_device_start__webaudio(ma_device* pDevice) { MA_ASSERT(pDevice != NULL); +#if defined(MA_USE_AUDIO_WORKLETS) + if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { + emscripten_resume_audio_context_sync(pDevice->webaudio.audioContextCapture); + } + + if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { + emscripten_resume_audio_context_sync(pDevice->webaudio.audioContextPlayback); + } +#else if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { EM_ASM({ var device = miniaudio.get_device_by_index($0); @@ -38946,6 +39996,7 @@ static ma_result ma_device_start__webaudio(ma_device* pDevice) device.state = 2; /* ma_device_state_started */ }, pDevice->webaudio.indexPlayback); } +#endif return MA_SUCCESS; } @@ -38964,6 +40015,20 @@ static ma_result ma_device_stop__webaudio(ma_device* pDevice) do any kind of explicit draining. */ +#if defined(MA_USE_AUDIO_WORKLETS) + /* I can't seem to find a way to suspend an AudioContext via the C Emscripten API. Is this an oversight? */ + if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { + EM_ASM({ + emscriptenGetAudioObject($0).suspend(); + }, pDevice->webaudio.audioContextCapture); + } + + if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { + EM_ASM({ + emscriptenGetAudioObject($0).suspend(); + }, pDevice->webaudio.audioContextPlayback); + } +#else if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { EM_ASM({ var device = miniaudio.get_device_by_index($0); @@ -38979,6 +40044,7 @@ static ma_result ma_device_stop__webaudio(ma_device* pDevice) device.state = 1; /* ma_device_state_stopped */ }, pDevice->webaudio.indexPlayback); } +#endif ma_device__on_notification_stopped(pDevice); @@ -39138,6 +40204,22 @@ static ma_bool32 ma__is_channel_map_valid(const ma_channel* pChannelMap, ma_uint } +static ma_bool32 ma_context_is_backend_asynchronous(ma_context* pContext) +{ + MA_ASSERT(pContext != NULL); + + if (pContext->callbacks.onDeviceRead == NULL && pContext->callbacks.onDeviceWrite == NULL) { + if (pContext->callbacks.onDeviceDataLoop == NULL) { + return MA_TRUE; + } else { + return MA_FALSE; + } + } else { + return MA_FALSE; + } +} + + static ma_result ma_device__post_init_setup(ma_device* pDevice, ma_device_type deviceType) { ma_result result; @@ -39257,8 +40339,23 @@ static ma_result ma_device__post_init_setup(ma_device* pDevice, ma_device_type d /* - In playback mode, if the data converter does not support retrieval of the required number of - input frames given a number of output frames, we need to fall back to a heap-allocated cache. + If the device is doing playback (ma_device_type_playback or ma_device_type_duplex), there's + a couple of situations where we'll need a heap allocated cache. + + The first is a duplex device for backends that use a callback for data delivery. The reason + this is needed is that the input stage needs to have a buffer to place the input data while it + waits for the playback stage, after which the miniaudio data callback will get fired. This is + not needed for backends that use a blocking API because miniaudio manages temporary buffers on + the stack to achieve this. + + The other situation is when the data converter does not have the ability to query the number + of input frames that are required in order to process a given number of output frames. When + performing data conversion, it's useful if miniaudio know exactly how many frames it needs + from the client in order to generate a given number of output frames. This way, only exactly + the number of frames are needed to be read from the client which means no cache is necessary. + On the other hand, if miniaudio doesn't know how many frames to read, it is forced to read + in fixed sized chunks and then cache any residual unused input frames, those of which will be + processed at a later stage. */ if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) { ma_uint64 unused; @@ -39266,7 +40363,9 @@ static ma_result ma_device__post_init_setup(ma_device* pDevice, ma_device_type d pDevice->playback.inputCacheConsumed = 0; pDevice->playback.inputCacheRemaining = 0; - if (deviceType == ma_device_type_duplex || ma_data_converter_get_required_input_frame_count(&pDevice->playback.converter, 1, &unused) != MA_SUCCESS) { + if ((pDevice->type == ma_device_type_duplex && ma_context_is_backend_asynchronous(pDevice->pContext)) || /* Duplex with asynchronous backend. */ + ma_data_converter_get_required_input_frame_count(&pDevice->playback.converter, 1, &unused) != MA_SUCCESS) /* Data conversion required input frame calculation not supported. */ + { /* We need a heap allocated cache. We want to size this based on the period size. */ void* pNewInputCache; ma_uint64 newInputCacheCap; @@ -39282,7 +40381,7 @@ static ma_result ma_device__post_init_setup(ma_device* pDevice, ma_device_type d return MA_OUT_OF_MEMORY; /* Allocation too big. Should never hit this, but makes the cast below safer for 32-bit builds. */ } - pNewInputCache = ma_realloc(pDevice->playback.pInputCache, (size_t)newInputCacheSizeInBytes, &pDevice->pContext->allocationCallbacks); + pNewInputCache = ma_realloc(pDevice->playback.pInputCache, (size_t)newInputCacheSizeInBytes, &pDevice->pContext->allocationCallbacks); if (pNewInputCache == NULL) { ma_free(pDevice->playback.pInputCache, &pDevice->pContext->allocationCallbacks); pDevice->playback.pInputCache = NULL; @@ -39523,6 +40622,7 @@ static ma_result ma_context_init_backend_apis__win32(ma_context* pContext) return MA_FAILED_TO_INIT_BACKEND; } + pContext->win32.CoInitialize = (ma_proc)ma_dlsym(pContext, pContext->win32.hOle32DLL, "CoInitialize"); pContext->win32.CoInitializeEx = (ma_proc)ma_dlsym(pContext, pContext->win32.hOle32DLL, "CoInitializeEx"); pContext->win32.CoUninitialize = (ma_proc)ma_dlsym(pContext, pContext->win32.hOle32DLL, "CoUninitialize"); pContext->win32.CoCreateInstance = (ma_proc)ma_dlsym(pContext, pContext->win32.hOle32DLL, "CoCreateInstance"); @@ -39560,71 +40660,14 @@ static ma_result ma_context_init_backend_apis__win32(ma_context* pContext) #else static ma_result ma_context_uninit_backend_apis__nix(ma_context* pContext) { -#if defined(MA_USE_RUNTIME_LINKING_FOR_PTHREAD) && !defined(MA_NO_RUNTIME_LINKING) - ma_dlclose(pContext, pContext->posix.pthreadSO); -#else (void)pContext; -#endif return MA_SUCCESS; } static ma_result ma_context_init_backend_apis__nix(ma_context* pContext) { - /* pthread */ -#if defined(MA_USE_RUNTIME_LINKING_FOR_PTHREAD) && !defined(MA_NO_RUNTIME_LINKING) - const char* libpthreadFileNames[] = { - "libpthread.so", - "libpthread.so.0", - "libpthread.dylib" - }; - size_t i; - - for (i = 0; i < sizeof(libpthreadFileNames) / sizeof(libpthreadFileNames[0]); ++i) { - pContext->posix.pthreadSO = ma_dlopen(pContext, libpthreadFileNames[i]); - if (pContext->posix.pthreadSO != NULL) { - break; - } - } - - if (pContext->posix.pthreadSO == NULL) { - return MA_FAILED_TO_INIT_BACKEND; - } - - pContext->posix.pthread_create = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_create"); - pContext->posix.pthread_join = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_join"); - pContext->posix.pthread_mutex_init = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_mutex_init"); - pContext->posix.pthread_mutex_destroy = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_mutex_destroy"); - pContext->posix.pthread_mutex_lock = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_mutex_lock"); - pContext->posix.pthread_mutex_unlock = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_mutex_unlock"); - pContext->posix.pthread_cond_init = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_cond_init"); - pContext->posix.pthread_cond_destroy = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_cond_destroy"); - pContext->posix.pthread_cond_wait = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_cond_wait"); - pContext->posix.pthread_cond_signal = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_cond_signal"); - pContext->posix.pthread_attr_init = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_attr_init"); - pContext->posix.pthread_attr_destroy = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_attr_destroy"); - pContext->posix.pthread_attr_setschedpolicy = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_attr_setschedpolicy"); - pContext->posix.pthread_attr_getschedparam = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_attr_getschedparam"); - pContext->posix.pthread_attr_setschedparam = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_attr_setschedparam"); -#else - pContext->posix.pthread_create = (ma_proc)pthread_create; - pContext->posix.pthread_join = (ma_proc)pthread_join; - pContext->posix.pthread_mutex_init = (ma_proc)pthread_mutex_init; - pContext->posix.pthread_mutex_destroy = (ma_proc)pthread_mutex_destroy; - pContext->posix.pthread_mutex_lock = (ma_proc)pthread_mutex_lock; - pContext->posix.pthread_mutex_unlock = (ma_proc)pthread_mutex_unlock; - pContext->posix.pthread_cond_init = (ma_proc)pthread_cond_init; - pContext->posix.pthread_cond_destroy = (ma_proc)pthread_cond_destroy; - pContext->posix.pthread_cond_wait = (ma_proc)pthread_cond_wait; - pContext->posix.pthread_cond_signal = (ma_proc)pthread_cond_signal; - pContext->posix.pthread_attr_init = (ma_proc)pthread_attr_init; - pContext->posix.pthread_attr_destroy = (ma_proc)pthread_attr_destroy; -#if !defined(__EMSCRIPTEN__) - pContext->posix.pthread_attr_setschedpolicy = (ma_proc)pthread_attr_setschedpolicy; - pContext->posix.pthread_attr_getschedparam = (ma_proc)pthread_attr_getschedparam; - pContext->posix.pthread_attr_setschedparam = (ma_proc)pthread_attr_setschedparam; -#endif -#endif + (void)pContext; return MA_SUCCESS; } @@ -39655,22 +40698,6 @@ static ma_result ma_context_uninit_backend_apis(ma_context* pContext) } -static ma_bool32 ma_context_is_backend_asynchronous(ma_context* pContext) -{ - MA_ASSERT(pContext != NULL); - - if (pContext->callbacks.onDeviceRead == NULL && pContext->callbacks.onDeviceWrite == NULL) { - if (pContext->callbacks.onDeviceDataLoop == NULL) { - return MA_TRUE; - } else { - return MA_FALSE; - } - } else { - return MA_FALSE; - } -} - - /* The default capacity doesn't need to be too big. */ #ifndef MA_DEFAULT_DEVICE_JOB_QUEUE_CAPACITY #define MA_DEFAULT_DEVICE_JOB_QUEUE_CAPACITY 32 @@ -39730,7 +40757,7 @@ MA_API ma_result ma_device_job_thread_init(const ma_device_job_thread_config* pC /* Initialize the job queue before the thread to ensure it's in a valid state. */ - jobQueueConfig = ma_job_queue_config_init(pConfig->jobQueueFlags, pConfig->jobQueueCapacity); + jobQueueConfig = ma_job_queue_config_init(pConfig->jobQueueFlags, pConfig->jobQueueCapacity); result = ma_job_queue_init(&jobQueueConfig, pAllocationCallbacks, &pJobThread->jobQueue); if (result != MA_SUCCESS) { @@ -39983,7 +41010,16 @@ MA_API ma_result ma_context_init(const ma_backend backends[], ma_uint32 backendC ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "Attempting to initialize %s backend...\n", ma_get_backend_name(backend)); result = pContext->callbacks.onContextInit(pContext, pConfig, &pContext->callbacks); } else { - result = MA_NO_BACKEND; + /* Getting here means the onContextInit callback is not set which means the backend is not enabled. Special case for the custom backend. */ + if (backend != ma_backend_custom) { + result = MA_BACKEND_NOT_ENABLED; + } else { + #if !defined(MA_HAS_CUSTOM) + result = MA_BACKEND_NOT_ENABLED; + #else + result = MA_NO_BACKEND; + #endif + } } /* If this iteration was successful, return. */ @@ -40007,7 +41043,11 @@ MA_API ma_result ma_context_init(const ma_backend backends[], ma_uint32 backendC pContext->backend = backend; return result; } else { - ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "Failed to initialize %s backend.\n", ma_get_backend_name(backend)); + if (result == MA_BACKEND_NOT_ENABLED) { + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "%s backend is disabled.\n", ma_get_backend_name(backend)); + } else { + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "Failed to initialize %s backend.\n", ma_get_backend_name(backend)); + } } } @@ -40303,7 +41343,7 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC pDevice->noClip = pConfig->noClip; pDevice->noDisableDenormals = pConfig->noDisableDenormals; pDevice->noFixedSizedCallback = pConfig->noFixedSizedCallback; - pDevice->masterVolumeFactor = 1; + ma_atomic_float_set(&pDevice->masterVolumeFactor, 1); pDevice->type = pConfig->deviceType; pDevice->sampleRate = pConfig->sampleRate; @@ -40525,7 +41565,7 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) { ma_uint64 intermediaryBufferSizeInBytes; - + pDevice->playback.intermediaryBufferLen = 0; if (pConfig->deviceType == ma_device_type_duplex) { pDevice->playback.intermediaryBufferCap = pDevice->capture.intermediaryBufferCap; /* In duplex mode, make sure the intermediary buffer is always the same size as the capture side. */ @@ -40537,7 +41577,7 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC } intermediaryBufferSizeInBytes = pDevice->playback.intermediaryBufferCap * ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels); - + pDevice->playback.pIntermediaryBuffer = ma_malloc((size_t)intermediaryBufferSizeInBytes, &pContext->allocationCallbacks); if (pDevice->playback.pIntermediaryBuffer == NULL) { ma_device_uninit(pDevice); @@ -40663,7 +41703,6 @@ MA_API ma_result ma_device_init_ex(const ma_backend backends[], ma_uint32 backen allocationCallbacks = ma_allocation_callbacks_init_default(); } - pContext = (ma_context*)ma_malloc(sizeof(*pContext), &allocationCallbacks); if (pContext == NULL) { return MA_OUT_OF_MEMORY; @@ -41011,7 +42050,7 @@ MA_API ma_device_state ma_device_get_state(const ma_device* pDevice) return ma_device_state_uninitialized; } - return (ma_device_state)c89atomic_load_i32((ma_int32*)&pDevice->state); /* Naughty cast to get rid of a const warning. */ + return ma_atomic_device_state_get((ma_atomic_device_state*)&pDevice->state); /* Naughty cast to get rid of a const warning. */ } MA_API ma_result ma_device_set_master_volume(ma_device* pDevice, float volume) @@ -41024,7 +42063,7 @@ MA_API ma_result ma_device_set_master_volume(ma_device* pDevice, float volume) return MA_INVALID_ARGS; } - c89atomic_exchange_f32(&pDevice->masterVolumeFactor, volume); + ma_atomic_float_set(&pDevice->masterVolumeFactor, volume); return MA_SUCCESS; } @@ -41040,7 +42079,7 @@ MA_API ma_result ma_device_get_master_volume(ma_device* pDevice, float* pVolume) return MA_INVALID_ARGS; } - *pVolume = c89atomic_load_f32(&pDevice->masterVolumeFactor); + *pVolume = ma_atomic_float_get(&pDevice->masterVolumeFactor); return MA_SUCCESS; } @@ -41635,6 +42674,35 @@ MA_API float ma_volume_db_to_linear(float gain) } +MA_API ma_result ma_mix_pcm_frames_f32(float* pDst, const float* pSrc, ma_uint64 frameCount, ma_uint32 channels, float volume) +{ + ma_uint64 iSample; + ma_uint64 sampleCount; + + if (pDst == NULL || pSrc == NULL || channels == 0) { + return MA_INVALID_ARGS; + } + + if (volume == 0) { + return MA_SUCCESS; /* No changes if the volume is 0. */ + } + + sampleCount = frameCount * channels; + + if (volume == 1) { + for (iSample = 0; iSample < sampleCount; iSample += 1) { + pDst[iSample] += pSrc[iSample]; + } + } else { + for (iSample = 0; iSample < sampleCount; iSample += 1) { + pDst[iSample] += ma_apply_volume_unclipped_f32(pSrc[iSample], volume); + } + } + + return MA_SUCCESS; +} + + /************************************************************************************************************************************************************** @@ -41700,12 +42768,6 @@ static MA_INLINE void ma_pcm_u8_to_s16__sse2(void* dst, const void* src, ma_uint ma_pcm_u8_to_s16__optimized(dst, src, count, ditherMode); } #endif -#if defined(MA_SUPPORT_AVX2) -static MA_INLINE void ma_pcm_u8_to_s16__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) -{ - ma_pcm_u8_to_s16__optimized(dst, src, count, ditherMode); -} -#endif #if defined(MA_SUPPORT_NEON) static MA_INLINE void ma_pcm_u8_to_s16__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { @@ -41718,15 +42780,11 @@ MA_API void ma_pcm_u8_to_s16(void* dst, const void* src, ma_uint64 count, ma_dit #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_u8_to_s16__reference(dst, src, count, ditherMode); #else - # if MA_PREFERRED_SIMD == MA_SIMD_AVX2 - if (ma_has_avx2()) { - ma_pcm_u8_to_s16__avx2(dst, src, count, ditherMode); - } else - #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2 + # if defined(MA_SUPPORT_SSE2) if (ma_has_sse2()) { ma_pcm_u8_to_s16__sse2(dst, src, count, ditherMode); } else - #elif MA_PREFERRED_SIMD == MA_SIMD_NEON + #elif defined(MA_SUPPORT_NEON) if (ma_has_neon()) { ma_pcm_u8_to_s16__neon(dst, src, count, ditherMode); } else @@ -41767,12 +42825,6 @@ static MA_INLINE void ma_pcm_u8_to_s24__sse2(void* dst, const void* src, ma_uint ma_pcm_u8_to_s24__optimized(dst, src, count, ditherMode); } #endif -#if defined(MA_SUPPORT_AVX2) -static MA_INLINE void ma_pcm_u8_to_s24__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) -{ - ma_pcm_u8_to_s24__optimized(dst, src, count, ditherMode); -} -#endif #if defined(MA_SUPPORT_NEON) static MA_INLINE void ma_pcm_u8_to_s24__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { @@ -41785,15 +42837,11 @@ MA_API void ma_pcm_u8_to_s24(void* dst, const void* src, ma_uint64 count, ma_dit #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_u8_to_s24__reference(dst, src, count, ditherMode); #else - # if MA_PREFERRED_SIMD == MA_SIMD_AVX2 - if (ma_has_avx2()) { - ma_pcm_u8_to_s24__avx2(dst, src, count, ditherMode); - } else - #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2 + # if defined(MA_SUPPORT_SSE2) if (ma_has_sse2()) { ma_pcm_u8_to_s24__sse2(dst, src, count, ditherMode); } else - #elif MA_PREFERRED_SIMD == MA_SIMD_NEON + #elif defined(MA_SUPPORT_NEON) if (ma_has_neon()) { ma_pcm_u8_to_s24__neon(dst, src, count, ditherMode); } else @@ -41832,12 +42880,6 @@ static MA_INLINE void ma_pcm_u8_to_s32__sse2(void* dst, const void* src, ma_uint ma_pcm_u8_to_s32__optimized(dst, src, count, ditherMode); } #endif -#if defined(MA_SUPPORT_AVX2) -static MA_INLINE void ma_pcm_u8_to_s32__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) -{ - ma_pcm_u8_to_s32__optimized(dst, src, count, ditherMode); -} -#endif #if defined(MA_SUPPORT_NEON) static MA_INLINE void ma_pcm_u8_to_s32__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { @@ -41850,15 +42892,11 @@ MA_API void ma_pcm_u8_to_s32(void* dst, const void* src, ma_uint64 count, ma_dit #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_u8_to_s32__reference(dst, src, count, ditherMode); #else - # if MA_PREFERRED_SIMD == MA_SIMD_AVX2 - if (ma_has_avx2()) { - ma_pcm_u8_to_s32__avx2(dst, src, count, ditherMode); - } else - #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2 + # if defined(MA_SUPPORT_SSE2) if (ma_has_sse2()) { ma_pcm_u8_to_s32__sse2(dst, src, count, ditherMode); } else - #elif MA_PREFERRED_SIMD == MA_SIMD_NEON + #elif defined(MA_SUPPORT_NEON) if (ma_has_neon()) { ma_pcm_u8_to_s32__neon(dst, src, count, ditherMode); } else @@ -41898,12 +42936,6 @@ static MA_INLINE void ma_pcm_u8_to_f32__sse2(void* dst, const void* src, ma_uint ma_pcm_u8_to_f32__optimized(dst, src, count, ditherMode); } #endif -#if defined(MA_SUPPORT_AVX2) -static MA_INLINE void ma_pcm_u8_to_f32__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) -{ - ma_pcm_u8_to_f32__optimized(dst, src, count, ditherMode); -} -#endif #if defined(MA_SUPPORT_NEON) static MA_INLINE void ma_pcm_u8_to_f32__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { @@ -41916,15 +42948,11 @@ MA_API void ma_pcm_u8_to_f32(void* dst, const void* src, ma_uint64 count, ma_dit #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_u8_to_f32__reference(dst, src, count, ditherMode); #else - # if MA_PREFERRED_SIMD == MA_SIMD_AVX2 - if (ma_has_avx2()) { - ma_pcm_u8_to_f32__avx2(dst, src, count, ditherMode); - } else - #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2 + # if defined(MA_SUPPORT_SSE2) if (ma_has_sse2()) { ma_pcm_u8_to_f32__sse2(dst, src, count, ditherMode); } else - #elif MA_PREFERRED_SIMD == MA_SIMD_NEON + #elif defined(MA_SUPPORT_NEON) if (ma_has_neon()) { ma_pcm_u8_to_f32__neon(dst, src, count, ditherMode); } else @@ -42060,12 +43088,6 @@ static MA_INLINE void ma_pcm_s16_to_u8__sse2(void* dst, const void* src, ma_uint ma_pcm_s16_to_u8__optimized(dst, src, count, ditherMode); } #endif -#if defined(MA_SUPPORT_AVX2) -static MA_INLINE void ma_pcm_s16_to_u8__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) -{ - ma_pcm_s16_to_u8__optimized(dst, src, count, ditherMode); -} -#endif #if defined(MA_SUPPORT_NEON) static MA_INLINE void ma_pcm_s16_to_u8__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { @@ -42078,15 +43100,11 @@ MA_API void ma_pcm_s16_to_u8(void* dst, const void* src, ma_uint64 count, ma_dit #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_s16_to_u8__reference(dst, src, count, ditherMode); #else - # if MA_PREFERRED_SIMD == MA_SIMD_AVX2 - if (ma_has_avx2()) { - ma_pcm_s16_to_u8__avx2(dst, src, count, ditherMode); - } else - #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2 + # if defined(MA_SUPPORT_SSE2) if (ma_has_sse2()) { ma_pcm_s16_to_u8__sse2(dst, src, count, ditherMode); } else - #elif MA_PREFERRED_SIMD == MA_SIMD_NEON + #elif defined(MA_SUPPORT_NEON) if (ma_has_neon()) { ma_pcm_s16_to_u8__neon(dst, src, count, ditherMode); } else @@ -42131,12 +43149,6 @@ static MA_INLINE void ma_pcm_s16_to_s24__sse2(void* dst, const void* src, ma_uin ma_pcm_s16_to_s24__optimized(dst, src, count, ditherMode); } #endif -#if defined(MA_SUPPORT_AVX2) -static MA_INLINE void ma_pcm_s16_to_s24__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) -{ - ma_pcm_s16_to_s24__optimized(dst, src, count, ditherMode); -} -#endif #if defined(MA_SUPPORT_NEON) static MA_INLINE void ma_pcm_s16_to_s24__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { @@ -42149,15 +43161,11 @@ MA_API void ma_pcm_s16_to_s24(void* dst, const void* src, ma_uint64 count, ma_di #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_s16_to_s24__reference(dst, src, count, ditherMode); #else - # if MA_PREFERRED_SIMD == MA_SIMD_AVX2 - if (ma_has_avx2()) { - ma_pcm_s16_to_s24__avx2(dst, src, count, ditherMode); - } else - #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2 + # if defined(MA_SUPPORT_SSE2) if (ma_has_sse2()) { ma_pcm_s16_to_s24__sse2(dst, src, count, ditherMode); } else - #elif MA_PREFERRED_SIMD == MA_SIMD_NEON + #elif defined(MA_SUPPORT_NEON) if (ma_has_neon()) { ma_pcm_s16_to_s24__neon(dst, src, count, ditherMode); } else @@ -42193,12 +43201,6 @@ static MA_INLINE void ma_pcm_s16_to_s32__sse2(void* dst, const void* src, ma_uin ma_pcm_s16_to_s32__optimized(dst, src, count, ditherMode); } #endif -#if defined(MA_SUPPORT_AVX2) -static MA_INLINE void ma_pcm_s16_to_s32__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) -{ - ma_pcm_s16_to_s32__optimized(dst, src, count, ditherMode); -} -#endif #if defined(MA_SUPPORT_NEON) static MA_INLINE void ma_pcm_s16_to_s32__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { @@ -42211,15 +43213,11 @@ MA_API void ma_pcm_s16_to_s32(void* dst, const void* src, ma_uint64 count, ma_di #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_s16_to_s32__reference(dst, src, count, ditherMode); #else - # if MA_PREFERRED_SIMD == MA_SIMD_AVX2 - if (ma_has_avx2()) { - ma_pcm_s16_to_s32__avx2(dst, src, count, ditherMode); - } else - #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2 + # if defined(MA_SUPPORT_SSE2) if (ma_has_sse2()) { ma_pcm_s16_to_s32__sse2(dst, src, count, ditherMode); } else - #elif MA_PREFERRED_SIMD == MA_SIMD_NEON + #elif defined(MA_SUPPORT_NEON) if (ma_has_neon()) { ma_pcm_s16_to_s32__neon(dst, src, count, ditherMode); } else @@ -42267,12 +43265,6 @@ static MA_INLINE void ma_pcm_s16_to_f32__sse2(void* dst, const void* src, ma_uin ma_pcm_s16_to_f32__optimized(dst, src, count, ditherMode); } #endif -#if defined(MA_SUPPORT_AVX2) -static MA_INLINE void ma_pcm_s16_to_f32__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) -{ - ma_pcm_s16_to_f32__optimized(dst, src, count, ditherMode); -} -#endif #if defined(MA_SUPPORT_NEON) static MA_INLINE void ma_pcm_s16_to_f32__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { @@ -42285,15 +43277,11 @@ MA_API void ma_pcm_s16_to_f32(void* dst, const void* src, ma_uint64 count, ma_di #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_s16_to_f32__reference(dst, src, count, ditherMode); #else - # if MA_PREFERRED_SIMD == MA_SIMD_AVX2 - if (ma_has_avx2()) { - ma_pcm_s16_to_f32__avx2(dst, src, count, ditherMode); - } else - #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2 + # if defined(MA_SUPPORT_SSE2) if (ma_has_sse2()) { ma_pcm_s16_to_f32__sse2(dst, src, count, ditherMode); } else - #elif MA_PREFERRED_SIMD == MA_SIMD_NEON + #elif defined(MA_SUPPORT_NEON) if (ma_has_neon()) { ma_pcm_s16_to_f32__neon(dst, src, count, ditherMode); } else @@ -42405,12 +43393,6 @@ static MA_INLINE void ma_pcm_s24_to_u8__sse2(void* dst, const void* src, ma_uint ma_pcm_s24_to_u8__optimized(dst, src, count, ditherMode); } #endif -#if defined(MA_SUPPORT_AVX2) -static MA_INLINE void ma_pcm_s24_to_u8__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) -{ - ma_pcm_s24_to_u8__optimized(dst, src, count, ditherMode); -} -#endif #if defined(MA_SUPPORT_NEON) static MA_INLINE void ma_pcm_s24_to_u8__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { @@ -42423,15 +43405,11 @@ MA_API void ma_pcm_s24_to_u8(void* dst, const void* src, ma_uint64 count, ma_dit #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_s24_to_u8__reference(dst, src, count, ditherMode); #else - # if MA_PREFERRED_SIMD == MA_SIMD_AVX2 - if (ma_has_avx2()) { - ma_pcm_s24_to_u8__avx2(dst, src, count, ditherMode); - } else - #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2 + # if defined(MA_SUPPORT_SSE2) if (ma_has_sse2()) { ma_pcm_s24_to_u8__sse2(dst, src, count, ditherMode); } else - #elif MA_PREFERRED_SIMD == MA_SIMD_NEON + #elif defined(MA_SUPPORT_NEON) if (ma_has_neon()) { ma_pcm_s24_to_u8__neon(dst, src, count, ditherMode); } else @@ -42485,12 +43463,6 @@ static MA_INLINE void ma_pcm_s24_to_s16__sse2(void* dst, const void* src, ma_uin ma_pcm_s24_to_s16__optimized(dst, src, count, ditherMode); } #endif -#if defined(MA_SUPPORT_AVX2) -static MA_INLINE void ma_pcm_s24_to_s16__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) -{ - ma_pcm_s24_to_s16__optimized(dst, src, count, ditherMode); -} -#endif #if defined(MA_SUPPORT_NEON) static MA_INLINE void ma_pcm_s24_to_s16__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { @@ -42503,15 +43475,11 @@ MA_API void ma_pcm_s24_to_s16(void* dst, const void* src, ma_uint64 count, ma_di #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_s24_to_s16__reference(dst, src, count, ditherMode); #else - # if MA_PREFERRED_SIMD == MA_SIMD_AVX2 - if (ma_has_avx2()) { - ma_pcm_s24_to_s16__avx2(dst, src, count, ditherMode); - } else - #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2 + # if defined(MA_SUPPORT_SSE2) if (ma_has_sse2()) { ma_pcm_s24_to_s16__sse2(dst, src, count, ditherMode); } else - #elif MA_PREFERRED_SIMD == MA_SIMD_NEON + #elif defined(MA_SUPPORT_NEON) if (ma_has_neon()) { ma_pcm_s24_to_s16__neon(dst, src, count, ditherMode); } else @@ -42555,12 +43523,6 @@ static MA_INLINE void ma_pcm_s24_to_s32__sse2(void* dst, const void* src, ma_uin ma_pcm_s24_to_s32__optimized(dst, src, count, ditherMode); } #endif -#if defined(MA_SUPPORT_AVX2) -static MA_INLINE void ma_pcm_s24_to_s32__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) -{ - ma_pcm_s24_to_s32__optimized(dst, src, count, ditherMode); -} -#endif #if defined(MA_SUPPORT_NEON) static MA_INLINE void ma_pcm_s24_to_s32__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { @@ -42573,15 +43535,11 @@ MA_API void ma_pcm_s24_to_s32(void* dst, const void* src, ma_uint64 count, ma_di #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_s24_to_s32__reference(dst, src, count, ditherMode); #else - # if MA_PREFERRED_SIMD == MA_SIMD_AVX2 - if (ma_has_avx2()) { - ma_pcm_s24_to_s32__avx2(dst, src, count, ditherMode); - } else - #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2 + # if defined(MA_SUPPORT_SSE2) if (ma_has_sse2()) { ma_pcm_s24_to_s32__sse2(dst, src, count, ditherMode); } else - #elif MA_PREFERRED_SIMD == MA_SIMD_NEON + #elif defined(MA_SUPPORT_NEON) if (ma_has_neon()) { ma_pcm_s24_to_s32__neon(dst, src, count, ditherMode); } else @@ -42629,12 +43587,6 @@ static MA_INLINE void ma_pcm_s24_to_f32__sse2(void* dst, const void* src, ma_uin ma_pcm_s24_to_f32__optimized(dst, src, count, ditherMode); } #endif -#if defined(MA_SUPPORT_AVX2) -static MA_INLINE void ma_pcm_s24_to_f32__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) -{ - ma_pcm_s24_to_f32__optimized(dst, src, count, ditherMode); -} -#endif #if defined(MA_SUPPORT_NEON) static MA_INLINE void ma_pcm_s24_to_f32__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { @@ -42647,15 +43599,11 @@ MA_API void ma_pcm_s24_to_f32(void* dst, const void* src, ma_uint64 count, ma_di #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_s24_to_f32__reference(dst, src, count, ditherMode); #else - # if MA_PREFERRED_SIMD == MA_SIMD_AVX2 - if (ma_has_avx2()) { - ma_pcm_s24_to_f32__avx2(dst, src, count, ditherMode); - } else - #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2 + # if defined(MA_SUPPORT_SSE2) if (ma_has_sse2()) { ma_pcm_s24_to_f32__sse2(dst, src, count, ditherMode); } else - #elif MA_PREFERRED_SIMD == MA_SIMD_NEON + #elif defined(MA_SUPPORT_NEON) if (ma_has_neon()) { ma_pcm_s24_to_f32__neon(dst, src, count, ditherMode); } else @@ -42775,12 +43723,6 @@ static MA_INLINE void ma_pcm_s32_to_u8__sse2(void* dst, const void* src, ma_uint ma_pcm_s32_to_u8__optimized(dst, src, count, ditherMode); } #endif -#if defined(MA_SUPPORT_AVX2) -static MA_INLINE void ma_pcm_s32_to_u8__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) -{ - ma_pcm_s32_to_u8__optimized(dst, src, count, ditherMode); -} -#endif #if defined(MA_SUPPORT_NEON) static MA_INLINE void ma_pcm_s32_to_u8__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { @@ -42793,15 +43735,11 @@ MA_API void ma_pcm_s32_to_u8(void* dst, const void* src, ma_uint64 count, ma_dit #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_s32_to_u8__reference(dst, src, count, ditherMode); #else - # if MA_PREFERRED_SIMD == MA_SIMD_AVX2 - if (ma_has_avx2()) { - ma_pcm_s32_to_u8__avx2(dst, src, count, ditherMode); - } else - #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2 + # if defined(MA_SUPPORT_SSE2) if (ma_has_sse2()) { ma_pcm_s32_to_u8__sse2(dst, src, count, ditherMode); } else - #elif MA_PREFERRED_SIMD == MA_SIMD_NEON + #elif defined(MA_SUPPORT_NEON) if (ma_has_neon()) { ma_pcm_s32_to_u8__neon(dst, src, count, ditherMode); } else @@ -42855,12 +43793,6 @@ static MA_INLINE void ma_pcm_s32_to_s16__sse2(void* dst, const void* src, ma_uin ma_pcm_s32_to_s16__optimized(dst, src, count, ditherMode); } #endif -#if defined(MA_SUPPORT_AVX2) -static MA_INLINE void ma_pcm_s32_to_s16__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) -{ - ma_pcm_s32_to_s16__optimized(dst, src, count, ditherMode); -} -#endif #if defined(MA_SUPPORT_NEON) static MA_INLINE void ma_pcm_s32_to_s16__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { @@ -42873,15 +43805,11 @@ MA_API void ma_pcm_s32_to_s16(void* dst, const void* src, ma_uint64 count, ma_di #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_s32_to_s16__reference(dst, src, count, ditherMode); #else - # if MA_PREFERRED_SIMD == MA_SIMD_AVX2 - if (ma_has_avx2()) { - ma_pcm_s32_to_s16__avx2(dst, src, count, ditherMode); - } else - #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2 + # if defined(MA_SUPPORT_SSE2) if (ma_has_sse2()) { ma_pcm_s32_to_s16__sse2(dst, src, count, ditherMode); } else - #elif MA_PREFERRED_SIMD == MA_SIMD_NEON + #elif defined(MA_SUPPORT_NEON) if (ma_has_neon()) { ma_pcm_s32_to_s16__neon(dst, src, count, ditherMode); } else @@ -42920,12 +43848,6 @@ static MA_INLINE void ma_pcm_s32_to_s24__sse2(void* dst, const void* src, ma_uin ma_pcm_s32_to_s24__optimized(dst, src, count, ditherMode); } #endif -#if defined(MA_SUPPORT_AVX2) -static MA_INLINE void ma_pcm_s32_to_s24__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) -{ - ma_pcm_s32_to_s24__optimized(dst, src, count, ditherMode); -} -#endif #if defined(MA_SUPPORT_NEON) static MA_INLINE void ma_pcm_s32_to_s24__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { @@ -42938,15 +43860,11 @@ MA_API void ma_pcm_s32_to_s24(void* dst, const void* src, ma_uint64 count, ma_di #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_s32_to_s24__reference(dst, src, count, ditherMode); #else - # if MA_PREFERRED_SIMD == MA_SIMD_AVX2 - if (ma_has_avx2()) { - ma_pcm_s32_to_s24__avx2(dst, src, count, ditherMode); - } else - #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2 + # if defined(MA_SUPPORT_SSE2) if (ma_has_sse2()) { ma_pcm_s32_to_s24__sse2(dst, src, count, ditherMode); } else - #elif MA_PREFERRED_SIMD == MA_SIMD_NEON + #elif defined(MA_SUPPORT_NEON) if (ma_has_neon()) { ma_pcm_s32_to_s24__neon(dst, src, count, ditherMode); } else @@ -43000,12 +43918,6 @@ static MA_INLINE void ma_pcm_s32_to_f32__sse2(void* dst, const void* src, ma_uin ma_pcm_s32_to_f32__optimized(dst, src, count, ditherMode); } #endif -#if defined(MA_SUPPORT_AVX2) -static MA_INLINE void ma_pcm_s32_to_f32__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) -{ - ma_pcm_s32_to_f32__optimized(dst, src, count, ditherMode); -} -#endif #if defined(MA_SUPPORT_NEON) static MA_INLINE void ma_pcm_s32_to_f32__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { @@ -43018,15 +43930,11 @@ MA_API void ma_pcm_s32_to_f32(void* dst, const void* src, ma_uint64 count, ma_di #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_s32_to_f32__reference(dst, src, count, ditherMode); #else - # if MA_PREFERRED_SIMD == MA_SIMD_AVX2 - if (ma_has_avx2()) { - ma_pcm_s32_to_f32__avx2(dst, src, count, ditherMode); - } else - #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2 + # if defined(MA_SUPPORT_SSE2) if (ma_has_sse2()) { ma_pcm_s32_to_f32__sse2(dst, src, count, ditherMode); } else - #elif MA_PREFERRED_SIMD == MA_SIMD_NEON + #elif defined(MA_SUPPORT_NEON) if (ma_has_neon()) { ma_pcm_s32_to_f32__neon(dst, src, count, ditherMode); } else @@ -43133,12 +44041,6 @@ static MA_INLINE void ma_pcm_f32_to_u8__sse2(void* dst, const void* src, ma_uint ma_pcm_f32_to_u8__optimized(dst, src, count, ditherMode); } #endif -#if defined(MA_SUPPORT_AVX2) -static MA_INLINE void ma_pcm_f32_to_u8__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) -{ - ma_pcm_f32_to_u8__optimized(dst, src, count, ditherMode); -} -#endif #if defined(MA_SUPPORT_NEON) static MA_INLINE void ma_pcm_f32_to_u8__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { @@ -43151,15 +44053,11 @@ MA_API void ma_pcm_f32_to_u8(void* dst, const void* src, ma_uint64 count, ma_dit #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_f32_to_u8__reference(dst, src, count, ditherMode); #else - # if MA_PREFERRED_SIMD == MA_SIMD_AVX2 - if (ma_has_avx2()) { - ma_pcm_f32_to_u8__avx2(dst, src, count, ditherMode); - } else - #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2 + # if defined(MA_SUPPORT_SSE2) if (ma_has_sse2()) { ma_pcm_f32_to_u8__sse2(dst, src, count, ditherMode); } else - #elif MA_PREFERRED_SIMD == MA_SIMD_NEON + #elif defined(MA_SUPPORT_NEON) if (ma_has_neon()) { ma_pcm_f32_to_u8__neon(dst, src, count, ditherMode); } else @@ -43363,129 +44261,6 @@ static MA_INLINE void ma_pcm_f32_to_s16__sse2(void* dst, const void* src, ma_uin } #endif /* SSE2 */ -#if defined(MA_SUPPORT_AVX2) -static MA_INLINE void ma_pcm_f32_to_s16__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) -{ - ma_uint64 i; - ma_uint64 i16; - ma_uint64 count16; - ma_int16* dst_s16; - const float* src_f32; - float ditherMin; - float ditherMax; - - /* Both the input and output buffers need to be aligned to 32 bytes. */ - if ((((ma_uintptr)dst & 31) != 0) || (((ma_uintptr)src & 31) != 0)) { - ma_pcm_f32_to_s16__optimized(dst, src, count, ditherMode); - return; - } - - dst_s16 = (ma_int16*)dst; - src_f32 = (const float*)src; - - ditherMin = 0; - ditherMax = 0; - if (ditherMode != ma_dither_mode_none) { - ditherMin = 1.0f / -32768; - ditherMax = 1.0f / 32767; - } - - i = 0; - - /* AVX2. AVX2 allows us to output 16 s16's at a time which means our loop is unrolled 16 times. */ - count16 = count >> 4; - for (i16 = 0; i16 < count16; i16 += 1) { - __m256 d0; - __m256 d1; - __m256 x0; - __m256 x1; - __m256i i0; - __m256i i1; - __m256i p0; - __m256i p1; - __m256i r; - - if (ditherMode == ma_dither_mode_none) { - d0 = _mm256_set1_ps(0); - d1 = _mm256_set1_ps(0); - } else if (ditherMode == ma_dither_mode_rectangle) { - d0 = _mm256_set_ps( - ma_dither_f32_rectangle(ditherMin, ditherMax), - ma_dither_f32_rectangle(ditherMin, ditherMax), - ma_dither_f32_rectangle(ditherMin, ditherMax), - ma_dither_f32_rectangle(ditherMin, ditherMax), - ma_dither_f32_rectangle(ditherMin, ditherMax), - ma_dither_f32_rectangle(ditherMin, ditherMax), - ma_dither_f32_rectangle(ditherMin, ditherMax), - ma_dither_f32_rectangle(ditherMin, ditherMax) - ); - d1 = _mm256_set_ps( - ma_dither_f32_rectangle(ditherMin, ditherMax), - ma_dither_f32_rectangle(ditherMin, ditherMax), - ma_dither_f32_rectangle(ditherMin, ditherMax), - ma_dither_f32_rectangle(ditherMin, ditherMax), - ma_dither_f32_rectangle(ditherMin, ditherMax), - ma_dither_f32_rectangle(ditherMin, ditherMax), - ma_dither_f32_rectangle(ditherMin, ditherMax), - ma_dither_f32_rectangle(ditherMin, ditherMax) - ); - } else { - d0 = _mm256_set_ps( - ma_dither_f32_triangle(ditherMin, ditherMax), - ma_dither_f32_triangle(ditherMin, ditherMax), - ma_dither_f32_triangle(ditherMin, ditherMax), - ma_dither_f32_triangle(ditherMin, ditherMax), - ma_dither_f32_triangle(ditherMin, ditherMax), - ma_dither_f32_triangle(ditherMin, ditherMax), - ma_dither_f32_triangle(ditherMin, ditherMax), - ma_dither_f32_triangle(ditherMin, ditherMax) - ); - d1 = _mm256_set_ps( - ma_dither_f32_triangle(ditherMin, ditherMax), - ma_dither_f32_triangle(ditherMin, ditherMax), - ma_dither_f32_triangle(ditherMin, ditherMax), - ma_dither_f32_triangle(ditherMin, ditherMax), - ma_dither_f32_triangle(ditherMin, ditherMax), - ma_dither_f32_triangle(ditherMin, ditherMax), - ma_dither_f32_triangle(ditherMin, ditherMax), - ma_dither_f32_triangle(ditherMin, ditherMax) - ); - } - - x0 = *((__m256*)(src_f32 + i) + 0); - x1 = *((__m256*)(src_f32 + i) + 1); - - x0 = _mm256_add_ps(x0, d0); - x1 = _mm256_add_ps(x1, d1); - - x0 = _mm256_mul_ps(x0, _mm256_set1_ps(32767.0f)); - x1 = _mm256_mul_ps(x1, _mm256_set1_ps(32767.0f)); - - /* Computing the final result is a little more complicated for AVX2 than SSE2. */ - i0 = _mm256_cvttps_epi32(x0); - i1 = _mm256_cvttps_epi32(x1); - p0 = _mm256_permute2x128_si256(i0, i1, 0 | 32); - p1 = _mm256_permute2x128_si256(i0, i1, 1 | 48); - r = _mm256_packs_epi32(p0, p1); - - _mm256_stream_si256(((__m256i*)(dst_s16 + i)), r); - - i += 16; - } - - - /* Leftover. */ - for (; i < count; i += 1) { - float x = src_f32[i]; - x = x + ma_dither_f32(ditherMode, ditherMin, ditherMax); - x = ((x < -1) ? -1 : ((x > 1) ? 1 : x)); /* clip */ - x = x * 32767.0f; /* -1..1 to -32767..32767 */ - - dst_s16[i] = (ma_int16)x; - } -} -#endif /* AVX2 */ - #if defined(MA_SUPPORT_NEON) static MA_INLINE void ma_pcm_f32_to_s16__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { @@ -43498,7 +44273,8 @@ static MA_INLINE void ma_pcm_f32_to_s16__neon(void* dst, const void* src, ma_uin float ditherMax; if (!ma_has_neon()) { - return ma_pcm_f32_to_s16__optimized(dst, src, count, ditherMode); + ma_pcm_f32_to_s16__optimized(dst, src, count, ditherMode); + return; } /* Both the input and output buffers need to be aligned to 16 bytes. */ @@ -43597,15 +44373,11 @@ MA_API void ma_pcm_f32_to_s16(void* dst, const void* src, ma_uint64 count, ma_di #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_f32_to_s16__reference(dst, src, count, ditherMode); #else - # if MA_PREFERRED_SIMD == MA_SIMD_AVX2 - if (ma_has_avx2()) { - ma_pcm_f32_to_s16__avx2(dst, src, count, ditherMode); - } else - #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2 + # if defined(MA_SUPPORT_SSE2) if (ma_has_sse2()) { ma_pcm_f32_to_s16__sse2(dst, src, count, ditherMode); } else - #elif MA_PREFERRED_SIMD == MA_SIMD_NEON + #elif defined(MA_SUPPORT_NEON) if (ma_has_neon()) { ma_pcm_f32_to_s16__neon(dst, src, count, ditherMode); } else @@ -43658,12 +44430,6 @@ static MA_INLINE void ma_pcm_f32_to_s24__sse2(void* dst, const void* src, ma_uin ma_pcm_f32_to_s24__optimized(dst, src, count, ditherMode); } #endif -#if defined(MA_SUPPORT_AVX2) -static MA_INLINE void ma_pcm_f32_to_s24__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) -{ - ma_pcm_f32_to_s24__optimized(dst, src, count, ditherMode); -} -#endif #if defined(MA_SUPPORT_NEON) static MA_INLINE void ma_pcm_f32_to_s24__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { @@ -43676,15 +44442,11 @@ MA_API void ma_pcm_f32_to_s24(void* dst, const void* src, ma_uint64 count, ma_di #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_f32_to_s24__reference(dst, src, count, ditherMode); #else - # if MA_PREFERRED_SIMD == MA_SIMD_AVX2 - if (ma_has_avx2()) { - ma_pcm_f32_to_s24__avx2(dst, src, count, ditherMode); - } else - #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2 + # if defined(MA_SUPPORT_SSE2) if (ma_has_sse2()) { ma_pcm_f32_to_s24__sse2(dst, src, count, ditherMode); } else - #elif MA_PREFERRED_SIMD == MA_SIMD_NEON + #elif defined(MA_SUPPORT_NEON) if (ma_has_neon()) { ma_pcm_f32_to_s24__neon(dst, src, count, ditherMode); } else @@ -43733,12 +44495,6 @@ static MA_INLINE void ma_pcm_f32_to_s32__sse2(void* dst, const void* src, ma_uin ma_pcm_f32_to_s32__optimized(dst, src, count, ditherMode); } #endif -#if defined(MA_SUPPORT_AVX2) -static MA_INLINE void ma_pcm_f32_to_s32__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) -{ - ma_pcm_f32_to_s32__optimized(dst, src, count, ditherMode); -} -#endif #if defined(MA_SUPPORT_NEON) static MA_INLINE void ma_pcm_f32_to_s32__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) { @@ -43751,15 +44507,11 @@ MA_API void ma_pcm_f32_to_s32(void* dst, const void* src, ma_uint64 count, ma_di #ifdef MA_USE_REFERENCE_CONVERSION_APIS ma_pcm_f32_to_s32__reference(dst, src, count, ditherMode); #else - # if MA_PREFERRED_SIMD == MA_SIMD_AVX2 - if (ma_has_avx2()) { - ma_pcm_f32_to_s32__avx2(dst, src, count, ditherMode); - } else - #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2 + # if defined(MA_SUPPORT_SSE2) if (ma_has_sse2()) { ma_pcm_f32_to_s32__sse2(dst, src, count, ditherMode); } else - #elif MA_PREFERRED_SIMD == MA_SIMD_NEON + #elif defined(MA_SUPPORT_NEON) if (ma_has_neon()) { ma_pcm_f32_to_s32__neon(dst, src, count, ditherMode); } else @@ -45134,7 +45886,7 @@ static MA_INLINE void ma_lpf_process_pcm_frame_f32(ma_lpf* pLPF, float* pY, cons MA_ASSERT(pLPF->format == ma_format_f32); - MA_COPY_MEMORY(pY, pX, ma_get_bytes_per_frame(pLPF->format, pLPF->channels)); + MA_MOVE_MEMORY(pY, pX, ma_get_bytes_per_frame(pLPF->format, pLPF->channels)); for (ilpf1 = 0; ilpf1 < pLPF->lpf1Count; ilpf1 += 1) { ma_lpf1_process_pcm_frame_f32(&pLPF->pLPF1[ilpf1], pY, pY); @@ -45152,7 +45904,7 @@ static MA_INLINE void ma_lpf_process_pcm_frame_s16(ma_lpf* pLPF, ma_int16* pY, c MA_ASSERT(pLPF->format == ma_format_s16); - MA_COPY_MEMORY(pY, pX, ma_get_bytes_per_frame(pLPF->format, pLPF->channels)); + MA_MOVE_MEMORY(pY, pX, ma_get_bytes_per_frame(pLPF->format, pLPF->channels)); for (ilpf1 = 0; ilpf1 < pLPF->lpf1Count; ilpf1 += 1) { ma_lpf1_process_pcm_frame_s16(&pLPF->pLPF1[ilpf1], pY, pY); @@ -47491,6 +48243,7 @@ MA_API ma_result ma_gainer_init_preallocated(const ma_gainer_config* pConfig, vo pGainer->pOldGains = (float*)ma_offset_ptr(pHeap, heapLayout.oldGainsOffset); pGainer->pNewGains = (float*)ma_offset_ptr(pHeap, heapLayout.newGainsOffset); + pGainer->masterVolume = 1; pGainer->config = *pConfig; pGainer->t = (ma_uint32)-1; /* No interpolation by default. */ @@ -47550,20 +48303,256 @@ static float ma_gainer_calculate_current_gain(const ma_gainer* pGainer, ma_uint3 return ma_mix_f32_fast(pGainer->pOldGains[channel], pGainer->pNewGains[channel], a); } -MA_API ma_result ma_gainer_process_pcm_frames(ma_gainer* pGainer, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount) +static /*__attribute__((noinline))*/ ma_result ma_gainer_process_pcm_frames_internal(ma_gainer * pGainer, void* MA_RESTRICT pFramesOut, const void* MA_RESTRICT pFramesIn, ma_uint64 frameCount) { ma_uint64 iFrame; ma_uint32 iChannel; - float* pFramesOutF32 = (float*)pFramesOut; - const float* pFramesInF32 = (const float*)pFramesIn; + ma_uint64 interpolatedFrameCount; - if (pGainer == NULL) { - return MA_INVALID_ARGS; + MA_ASSERT(pGainer != NULL); + + /* + We don't necessarily need to apply a linear interpolation for the entire frameCount frames. When + linear interpolation is not needed we can do a simple volume adjustment which will be more + efficient than a lerp with an alpha value of 1. + + To do this, all we need to do is determine how many frames need to have a lerp applied. Then we + just process that number of frames with linear interpolation. After that we run on an optimized + path which just applies the new gains without a lerp. + */ + if (pGainer->t >= pGainer->config.smoothTimeInFrames) { + interpolatedFrameCount = 0; + } else { + interpolatedFrameCount = pGainer->t - pGainer->config.smoothTimeInFrames; + if (interpolatedFrameCount > frameCount) { + interpolatedFrameCount = frameCount; + } } + /* + Start off with our interpolated frames. When we do this, we'll adjust frameCount and our pointers + so that the fast path can work naturally without consideration of the interpolated path. + */ + if (interpolatedFrameCount > 0) { + /* We can allow the input and output buffers to be null in which case we'll just update the internal timer. */ + if (pFramesOut != NULL && pFramesIn != NULL) { + /* + All we're really doing here is moving the old gains towards the new gains. We don't want to + be modifying the gains inside the ma_gainer object because that will break things. Instead + we can make a copy here on the stack. For extreme channel counts we can fall back to a slower + implementation which just uses a standard lerp. + */ + float* pFramesOutF32 = (float*)pFramesOut; + const float* pFramesInF32 = (const float*)pFramesIn; + float a = (float)pGainer->t / pGainer->config.smoothTimeInFrames; + float d = 1.0f / pGainer->config.smoothTimeInFrames; + + if (pGainer->config.channels <= 32) { + float pRunningGain[32]; + float pRunningGainDelta[32]; /* Could this be heap-allocated as part of the ma_gainer object? */ + + /* Initialize the running gain. */ + for (iChannel = 0; iChannel < pGainer->config.channels; iChannel += 1) { + float t = (pGainer->pOldGains[iChannel] - pGainer->pNewGains[iChannel]) * pGainer->masterVolume; + pRunningGainDelta[iChannel] = t * d; + pRunningGain[iChannel] = (pGainer->pOldGains[iChannel] * pGainer->masterVolume) + (t * a); + } + + iFrame = 0; + + /* Optimized paths for common channel counts. This is mostly just experimenting with some SIMD ideas. It's not necessarily final. */ + if (pGainer->config.channels == 2) { + #if defined(MA_SUPPORT_SSE2) + if (ma_has_sse2()) { + ma_uint64 unrolledLoopCount = interpolatedFrameCount >> 1; + + /* Expand some arrays so we can have a clean SIMD loop below. */ + __m128 runningGainDelta0 = _mm_set_ps(pRunningGainDelta[1], pRunningGainDelta[0], pRunningGainDelta[1], pRunningGainDelta[0]); + __m128 runningGain0 = _mm_set_ps(pRunningGain[1] + pRunningGainDelta[1], pRunningGain[0] + pRunningGainDelta[0], pRunningGain[1], pRunningGain[0]); + + for (; iFrame < unrolledLoopCount; iFrame += 1) { + _mm_storeu_ps(&pFramesOutF32[iFrame*4 + 0], _mm_mul_ps(_mm_loadu_ps(&pFramesInF32[iFrame*4 + 0]), runningGain0)); + runningGain0 = _mm_add_ps(runningGain0, runningGainDelta0); + } + + iFrame = unrolledLoopCount << 1; + } else + #endif + { + /* + Two different scalar implementations here. Clang (and I assume GCC) will vectorize + both of these, but the bottom version results in a nicer vectorization with less + instructions emitted. The problem, however, is that the bottom version runs slower + when compiled with MSVC. The top version will be partially vectorized by MSVC. + */ + #if defined(_MSC_VER) && !defined(__clang__) + ma_uint64 unrolledLoopCount = interpolatedFrameCount >> 1; + + /* Expand some arrays so we can have a clean 4x SIMD operation in the loop. */ + pRunningGainDelta[2] = pRunningGainDelta[0]; + pRunningGainDelta[3] = pRunningGainDelta[1]; + pRunningGain[2] = pRunningGain[0] + pRunningGainDelta[0]; + pRunningGain[3] = pRunningGain[1] + pRunningGainDelta[1]; + + for (; iFrame < unrolledLoopCount; iFrame += 1) { + pFramesOutF32[iFrame*4 + 0] = pFramesInF32[iFrame*4 + 0] * pRunningGain[0]; + pFramesOutF32[iFrame*4 + 1] = pFramesInF32[iFrame*4 + 1] * pRunningGain[1]; + pFramesOutF32[iFrame*4 + 2] = pFramesInF32[iFrame*4 + 2] * pRunningGain[2]; + pFramesOutF32[iFrame*4 + 3] = pFramesInF32[iFrame*4 + 3] * pRunningGain[3]; + + /* Move the running gain forward towards the new gain. */ + pRunningGain[0] += pRunningGainDelta[0]; + pRunningGain[1] += pRunningGainDelta[1]; + pRunningGain[2] += pRunningGainDelta[2]; + pRunningGain[3] += pRunningGainDelta[3]; + } + + iFrame = unrolledLoopCount << 1; + #else + for (; iFrame < interpolatedFrameCount; iFrame += 1) { + for (iChannel = 0; iChannel < 2; iChannel += 1) { + pFramesOutF32[iFrame*2 + iChannel] = pFramesInF32[iFrame*2 + iChannel] * pRunningGain[iChannel]; + } + + for (iChannel = 0; iChannel < 2; iChannel += 1) { + pRunningGain[iChannel] += pRunningGainDelta[iChannel]; + } + } + #endif + } + } else if (pGainer->config.channels == 6) { + #if defined(MA_SUPPORT_SSE2) + if (ma_has_sse2()) { + /* + For 6 channels things are a bit more complicated because 6 isn't cleanly divisible by 4. We need to do 2 frames + at a time, meaning we'll be doing 12 samples in a group. Like the stereo case we'll need to expand some arrays + so we can do clean 4x SIMD operations. + */ + ma_uint64 unrolledLoopCount = interpolatedFrameCount >> 1; + + /* Expand some arrays so we can have a clean SIMD loop below. */ + __m128 runningGainDelta0 = _mm_set_ps(pRunningGainDelta[3], pRunningGainDelta[2], pRunningGainDelta[1], pRunningGainDelta[0]); + __m128 runningGainDelta1 = _mm_set_ps(pRunningGainDelta[1], pRunningGainDelta[0], pRunningGainDelta[5], pRunningGainDelta[4]); + __m128 runningGainDelta2 = _mm_set_ps(pRunningGainDelta[5], pRunningGainDelta[4], pRunningGainDelta[3], pRunningGainDelta[2]); + + __m128 runningGain0 = _mm_set_ps(pRunningGain[3], pRunningGain[2], pRunningGain[1], pRunningGain[0]); + __m128 runningGain1 = _mm_set_ps(pRunningGain[1] + pRunningGainDelta[1], pRunningGain[0] + pRunningGainDelta[0], pRunningGain[5], pRunningGain[4]); + __m128 runningGain2 = _mm_set_ps(pRunningGain[5] + pRunningGainDelta[5], pRunningGain[4] + pRunningGainDelta[4], pRunningGain[3] + pRunningGainDelta[3], pRunningGain[2] + pRunningGainDelta[2]); + + for (; iFrame < unrolledLoopCount; iFrame += 1) { + _mm_storeu_ps(&pFramesOutF32[iFrame*12 + 0], _mm_mul_ps(_mm_loadu_ps(&pFramesInF32[iFrame*12 + 0]), runningGain0)); + _mm_storeu_ps(&pFramesOutF32[iFrame*12 + 4], _mm_mul_ps(_mm_loadu_ps(&pFramesInF32[iFrame*12 + 4]), runningGain1)); + _mm_storeu_ps(&pFramesOutF32[iFrame*12 + 8], _mm_mul_ps(_mm_loadu_ps(&pFramesInF32[iFrame*12 + 8]), runningGain2)); + + runningGain0 = _mm_add_ps(runningGain0, runningGainDelta0); + runningGain1 = _mm_add_ps(runningGain1, runningGainDelta1); + runningGain2 = _mm_add_ps(runningGain2, runningGainDelta2); + } + + iFrame = unrolledLoopCount << 1; + } else + #endif + { + for (; iFrame < interpolatedFrameCount; iFrame += 1) { + for (iChannel = 0; iChannel < 6; iChannel += 1) { + pFramesOutF32[iFrame*6 + iChannel] = pFramesInF32[iFrame*6 + iChannel] * pRunningGain[iChannel]; + } + + /* Move the running gain forward towards the new gain. */ + for (iChannel = 0; iChannel < 6; iChannel += 1) { + pRunningGain[iChannel] += pRunningGainDelta[iChannel]; + } + } + } + } else if (pGainer->config.channels == 8) { + /* For 8 channels we can just go over frame by frame and do all eight channels as 2 separate 4x SIMD operations. */ + #if defined(MA_SUPPORT_SSE2) + if (ma_has_sse2()) { + __m128 runningGainDelta0 = _mm_loadu_ps(&pRunningGainDelta[0]); + __m128 runningGainDelta1 = _mm_loadu_ps(&pRunningGainDelta[4]); + __m128 runningGain0 = _mm_loadu_ps(&pRunningGain[0]); + __m128 runningGain1 = _mm_loadu_ps(&pRunningGain[4]); + + for (; iFrame < interpolatedFrameCount; iFrame += 1) { + _mm_storeu_ps(&pFramesOutF32[iFrame*8 + 0], _mm_mul_ps(_mm_loadu_ps(&pFramesInF32[iFrame*8 + 0]), runningGain0)); + _mm_storeu_ps(&pFramesOutF32[iFrame*8 + 4], _mm_mul_ps(_mm_loadu_ps(&pFramesInF32[iFrame*8 + 4]), runningGain1)); + + runningGain0 = _mm_add_ps(runningGain0, runningGainDelta0); + runningGain1 = _mm_add_ps(runningGain1, runningGainDelta1); + } + } else + #endif + { + /* This is crafted so that it auto-vectorizes when compiled with Clang. */ + for (; iFrame < interpolatedFrameCount; iFrame += 1) { + for (iChannel = 0; iChannel < 8; iChannel += 1) { + pFramesOutF32[iFrame*8 + iChannel] = pFramesInF32[iFrame*8 + iChannel] * pRunningGain[iChannel]; + } + + /* Move the running gain forward towards the new gain. */ + for (iChannel = 0; iChannel < 8; iChannel += 1) { + pRunningGain[iChannel] += pRunningGainDelta[iChannel]; + } + } + } + } + + for (; iFrame < interpolatedFrameCount; iFrame += 1) { + for (iChannel = 0; iChannel < pGainer->config.channels; iChannel += 1) { + pFramesOutF32[iFrame*pGainer->config.channels + iChannel] = pFramesInF32[iFrame*pGainer->config.channels + iChannel] * pRunningGain[iChannel]; + pRunningGain[iChannel] += pRunningGainDelta[iChannel]; + } + } + } else { + /* Slower path for extreme channel counts where we can't fit enough on the stack. We could also move this to the heap as part of the ma_gainer object which might even be better since it'll only be updated when the gains actually change. */ + for (iFrame = 0; iFrame < interpolatedFrameCount; iFrame += 1) { + for (iChannel = 0; iChannel < pGainer->config.channels; iChannel += 1) { + pFramesOutF32[iFrame*pGainer->config.channels + iChannel] = pFramesInF32[iFrame*pGainer->config.channels + iChannel] * ma_mix_f32_fast(pGainer->pOldGains[iChannel], pGainer->pNewGains[iChannel], a) * pGainer->masterVolume; + } + + a += d; + } + } + } + + /* Make sure the timer is updated. */ + pGainer->t = (ma_uint32)ma_min(pGainer->t + interpolatedFrameCount, pGainer->config.smoothTimeInFrames); + + /* Adjust our arguments so the next part can work normally. */ + frameCount -= interpolatedFrameCount; + pFramesOut = ma_offset_ptr(pFramesOut, interpolatedFrameCount * sizeof(float)); + pFramesIn = ma_offset_ptr(pFramesIn, interpolatedFrameCount * sizeof(float)); + } + + /* All we need to do here is apply the new gains using an optimized path. */ + if (pFramesOut != NULL && pFramesIn != NULL) { + if (pGainer->config.channels <= 32) { + float gains[32]; + for (iChannel = 0; iChannel < pGainer->config.channels; iChannel += 1) { + gains[iChannel] = pGainer->pNewGains[iChannel] * pGainer->masterVolume; + } + + ma_copy_and_apply_volume_factor_per_channel_f32((float*)pFramesOut, (const float*)pFramesIn, frameCount, pGainer->config.channels, gains); + } else { + /* Slow path. Too many channels to fit on the stack. Need to apply a master volume as a separate path. */ + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + for (iChannel = 0; iChannel < pGainer->config.channels; iChannel += 1) { + ((float*)pFramesOut)[iFrame*pGainer->config.channels + iChannel] = ((const float*)pFramesIn)[iFrame*pGainer->config.channels + iChannel] * pGainer->pNewGains[iChannel] * pGainer->masterVolume; + } + } + } + } + + /* Now that some frames have been processed we need to make sure future changes to the gain are interpolated. */ + if (pGainer->t == (ma_uint32)-1) { + pGainer->t = (ma_uint32)ma_min(pGainer->config.smoothTimeInFrames, frameCount); + } + +#if 0 if (pGainer->t >= pGainer->config.smoothTimeInFrames) { /* Fast path. No gain calculation required. */ ma_copy_and_apply_volume_factor_per_channel_f32(pFramesOutF32, pFramesInF32, frameCount, pGainer->config.channels, pGainer->pNewGains); + ma_apply_volume_factor_f32(pFramesOutF32, frameCount * pGainer->config.channels, pGainer->masterVolume); /* Now that some frames have been processed we need to make sure future changes to the gain are interpolated. */ if (pGainer->t == (ma_uint32)-1) { @@ -47580,7 +48569,7 @@ MA_API ma_result ma_gainer_process_pcm_frames(ma_gainer* pGainer, void* pFramesO for (iFrame = 0; iFrame < frameCount; iFrame += 1) { for (iChannel = 0; iChannel < channelCount; iChannel += 1) { - pFramesOutF32[iChannel] = pFramesInF32[iChannel] * ma_mix_f32_fast(pGainer->pOldGains[iChannel], pGainer->pNewGains[iChannel], a); + pFramesOutF32[iChannel] = pFramesInF32[iChannel] * ma_mix_f32_fast(pGainer->pOldGains[iChannel], pGainer->pNewGains[iChannel], a) * pGainer->masterVolume; } pFramesOutF32 += channelCount; @@ -47600,7 +48589,7 @@ MA_API ma_result ma_gainer_process_pcm_frames(ma_gainer* pGainer, void* pFramesO /* We can allow the input and output buffers to be null in which case we'll just update the internal timer. */ if (pFramesOut != NULL && pFramesIn != NULL) { for (iChannel = 0; iChannel < pGainer->config.channels; iChannel += 1) { - pFramesOutF32[iFrame*pGainer->config.channels + iChannel] = pFramesInF32[iFrame*pGainer->config.channels + iChannel] * ma_gainer_calculate_current_gain(pGainer, iChannel); + pFramesOutF32[iFrame * pGainer->config.channels + iChannel] = pFramesInF32[iFrame * pGainer->config.channels + iChannel] * ma_gainer_calculate_current_gain(pGainer, iChannel) * pGainer->masterVolume; } } @@ -47609,10 +48598,24 @@ MA_API ma_result ma_gainer_process_pcm_frames(ma_gainer* pGainer, void* pFramesO } #endif } +#endif return MA_SUCCESS; } +MA_API ma_result ma_gainer_process_pcm_frames(ma_gainer* pGainer, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount) +{ + if (pGainer == NULL) { + return MA_INVALID_ARGS; + } + + /* + ma_gainer_process_pcm_frames_internal() marks pFramesOut and pFramesIn with MA_RESTRICT which + helps with auto-vectorization. + */ + return ma_gainer_process_pcm_frames_internal(pGainer, pFramesOut, pFramesIn, frameCount); +} + static void ma_gainer_set_gain_by_index(ma_gainer* pGainer, float newGain, ma_uint32 iChannel) { pGainer->pOldGains[iChannel] = ma_gainer_calculate_current_gain(pGainer, iChannel); @@ -47664,6 +48667,28 @@ MA_API ma_result ma_gainer_set_gains(ma_gainer* pGainer, float* pNewGains) return MA_SUCCESS; } +MA_API ma_result ma_gainer_set_master_volume(ma_gainer* pGainer, float volume) +{ + if (pGainer == NULL) { + return MA_INVALID_ARGS; + } + + pGainer->masterVolume = volume; + + return MA_SUCCESS; +} + +MA_API ma_result ma_gainer_get_master_volume(const ma_gainer* pGainer, float* pVolume) +{ + if (pGainer == NULL || pVolume == NULL) { + return MA_INVALID_ARGS; + } + + *pVolume = pGainer->masterVolume; + + return MA_SUCCESS; +} + MA_API ma_panner_config ma_panner_config_init(ma_format format, ma_uint32 channels) { @@ -48013,7 +49038,7 @@ MA_API void ma_fader_set_fade(ma_fader* pFader, float volumeBeg, float volumeEnd pFader->cursorInFrames = 0; /* Reset cursor. */ } -MA_API float ma_fader_get_current_volume(ma_fader* pFader) +MA_API float ma_fader_get_current_volume(const ma_fader* pFader) { if (pFader == NULL) { return 0.0f; @@ -48078,6 +49103,8 @@ MA_API float ma_vec3f_len(ma_vec3f v) return (float)ma_sqrtd(ma_vec3f_len2(v)); } + + MA_API float ma_vec3f_dist(ma_vec3f a, ma_vec3f b) { return ma_vec3f_len(ma_vec3f_sub(a, b)); @@ -48085,16 +49112,16 @@ MA_API float ma_vec3f_dist(ma_vec3f a, ma_vec3f b) MA_API ma_vec3f ma_vec3f_normalize(ma_vec3f v) { - float f; - float l = ma_vec3f_len(v); - if (l == 0) { + float invLen; + float len2 = ma_vec3f_len2(v); + if (len2 == 0) { return ma_vec3f_init_3f(0, 0, 0); } - f = 1 / l; - v.x *= f; - v.y *= f; - v.z *= f; + invLen = ma_rsqrtf(len2); + v.x *= invLen; + v.y *= invLen; + v.z *= invLen; return v; } @@ -48109,6 +49136,35 @@ MA_API ma_vec3f ma_vec3f_cross(ma_vec3f a, ma_vec3f b) } +MA_API void ma_atomic_vec3f_init(ma_atomic_vec3f* v, ma_vec3f value) +{ + v->v = value; + v->lock = 0; /* Important this is initialized to 0. */ +} + +MA_API void ma_atomic_vec3f_set(ma_atomic_vec3f* v, ma_vec3f value) +{ + ma_spinlock_lock(&v->lock); + { + v->v = value; + } + ma_spinlock_unlock(&v->lock); +} + +MA_API ma_vec3f ma_atomic_vec3f_get(ma_atomic_vec3f* v) +{ + ma_vec3f r; + + ma_spinlock_lock(&v->lock); + { + r = v->v; + } + ma_spinlock_unlock(&v->lock); + + return r; +} + + static void ma_channel_map_apply_f32(float* pFramesOut, const ma_channel* pChannelMapOut, ma_uint32 channelsOut, const float* pFramesIn, const ma_channel* pChannelMapIn, ma_uint32 channelsIn, ma_uint64 frameCount, ma_channel_mix_mode mode, ma_mono_expansion_mode monoExpansionMode); static ma_bool32 ma_is_spatial_channel_position(ma_channel channelPosition); @@ -48359,14 +49415,15 @@ MA_API ma_result ma_spatializer_listener_init_preallocated(const ma_spatializer_ MA_ZERO_MEMORY(pHeap, heapLayout.sizeInBytes); pListener->config = *pConfig; - pListener->position = ma_vec3f_init_3f(0, 0, 0); - pListener->direction = ma_vec3f_init_3f(0, 0, -1); - pListener->velocity = ma_vec3f_init_3f(0, 0, 0); + ma_atomic_vec3f_init(&pListener->position, ma_vec3f_init_3f(0, 0, 0)); + ma_atomic_vec3f_init(&pListener->direction, ma_vec3f_init_3f(0, 0, -1)); + ma_atomic_vec3f_init(&pListener->velocity, ma_vec3f_init_3f(0, 0, 0)); pListener->isEnabled = MA_TRUE; /* Swap the forward direction if we're left handed (it was initialized based on right handed). */ if (pListener->config.handedness == ma_handedness_left) { - pListener->direction = ma_vec3f_neg(pListener->direction); + ma_vec3f negDir = ma_vec3f_neg(ma_spatializer_listener_get_direction(pListener)); + ma_spatializer_listener_set_direction(pListener, negDir.x, negDir.y, negDir.z); } @@ -48469,7 +49526,7 @@ MA_API void ma_spatializer_listener_set_position(ma_spatializer_listener* pListe return; } - pListener->position = ma_vec3f_init_3f(x, y, z); + ma_atomic_vec3f_set(&pListener->position, ma_vec3f_init_3f(x, y, z)); } MA_API ma_vec3f ma_spatializer_listener_get_position(const ma_spatializer_listener* pListener) @@ -48478,7 +49535,7 @@ MA_API ma_vec3f ma_spatializer_listener_get_position(const ma_spatializer_listen return ma_vec3f_init_3f(0, 0, 0); } - return pListener->position; + return ma_atomic_vec3f_get((ma_atomic_vec3f*)&pListener->position); /* Naughty const-cast. It's just for atomically loading the vec3 which should be safe. */ } MA_API void ma_spatializer_listener_set_direction(ma_spatializer_listener* pListener, float x, float y, float z) @@ -48487,7 +49544,7 @@ MA_API void ma_spatializer_listener_set_direction(ma_spatializer_listener* pList return; } - pListener->direction = ma_vec3f_init_3f(x, y, z); + ma_atomic_vec3f_set(&pListener->direction, ma_vec3f_init_3f(x, y, z)); } MA_API ma_vec3f ma_spatializer_listener_get_direction(const ma_spatializer_listener* pListener) @@ -48496,7 +49553,7 @@ MA_API ma_vec3f ma_spatializer_listener_get_direction(const ma_spatializer_liste return ma_vec3f_init_3f(0, 0, -1); } - return pListener->direction; + return ma_atomic_vec3f_get((ma_atomic_vec3f*)&pListener->direction); /* Naughty const-cast. It's just for atomically loading the vec3 which should be safe. */ } MA_API void ma_spatializer_listener_set_velocity(ma_spatializer_listener* pListener, float x, float y, float z) @@ -48505,7 +49562,7 @@ MA_API void ma_spatializer_listener_set_velocity(ma_spatializer_listener* pListe return; } - pListener->velocity = ma_vec3f_init_3f(x, y, z); + ma_atomic_vec3f_set(&pListener->velocity, ma_vec3f_init_3f(x, y, z)); } MA_API ma_vec3f ma_spatializer_listener_get_velocity(const ma_spatializer_listener* pListener) @@ -48514,7 +49571,7 @@ MA_API ma_vec3f ma_spatializer_listener_get_velocity(const ma_spatializer_listen return ma_vec3f_init_3f(0, 0, 0); } - return pListener->velocity; + return ma_atomic_vec3f_get((ma_atomic_vec3f*)&pListener->velocity); /* Naughty const-cast. It's just for atomically loading the vec3 which should be safe. */ } MA_API void ma_spatializer_listener_set_speed_of_sound(ma_spatializer_listener* pListener, float speedOfSound) @@ -48737,14 +49794,15 @@ MA_API ma_result ma_spatializer_init_preallocated(const ma_spatializer_config* p pSpatializer->dopplerFactor = pConfig->dopplerFactor; pSpatializer->directionalAttenuationFactor = pConfig->directionalAttenuationFactor; pSpatializer->gainSmoothTimeInFrames = pConfig->gainSmoothTimeInFrames; - pSpatializer->position = ma_vec3f_init_3f(0, 0, 0); - pSpatializer->direction = ma_vec3f_init_3f(0, 0, -1); - pSpatializer->velocity = ma_vec3f_init_3f(0, 0, 0); + ma_atomic_vec3f_init(&pSpatializer->position, ma_vec3f_init_3f(0, 0, 0)); + ma_atomic_vec3f_init(&pSpatializer->direction, ma_vec3f_init_3f(0, 0, -1)); + ma_atomic_vec3f_init(&pSpatializer->velocity, ma_vec3f_init_3f(0, 0, 0)); pSpatializer->dopplerPitch = 1; /* Swap the forward direction if we're left handed (it was initialized based on right handed). */ if (pSpatializer->handedness == ma_handedness_left) { - pSpatializer->direction = ma_vec3f_neg(pSpatializer->direction); + ma_vec3f negDir = ma_vec3f_neg(ma_spatializer_get_direction(pSpatializer)); + ma_spatializer_set_direction(pSpatializer, negDir.x, negDir.y, negDir.z); } /* Channel map. This will be on the heap. */ @@ -48909,7 +49967,7 @@ MA_API ma_result ma_spatializer_process_pcm_frames(ma_spatializer* pSpatializer, defined by the listener, so we'll grab that here too. */ if (pListener != NULL) { - listenerVel = pListener->velocity; + listenerVel = ma_spatializer_listener_get_velocity(pListener); speedOfSound = pListener->config.speedOfSound; } else { listenerVel = ma_vec3f_init_3f(0, 0, 0); @@ -48918,8 +49976,8 @@ MA_API ma_result ma_spatializer_process_pcm_frames(ma_spatializer* pSpatializer, if (pListener == NULL || ma_spatializer_get_positioning(pSpatializer) == ma_positioning_relative) { /* There's no listener or we're using relative positioning. */ - relativePos = pSpatializer->position; - relativeDir = pSpatializer->direction; + relativePos = ma_spatializer_get_position(pSpatializer); + relativeDir = ma_spatializer_get_direction(pSpatializer); } else { /* We've found a listener and we're using absolute positioning. We need to transform the @@ -49079,7 +50137,7 @@ MA_API ma_result ma_spatializer_process_pcm_frames(ma_spatializer* pSpatializer, 0, panning will be most extreme and any sounds that are positioned on the opposite side of the speaker will be completely silent from that speaker. Not only does this feel uncomfortable, it doesn't even remotely represent the real world at all because sounds that come from your right side - are still clearly audible from your left side. Setting "dMin" to 1 will result in no panning at + are still clearly audible from your left side. Setting "dMin" to 1 will result in no panning at all, which is also not ideal. By setting it to something greater than 0, the spatialization effect becomes much less dramatic and a lot more bearable. @@ -49148,7 +50206,7 @@ MA_API ma_result ma_spatializer_process_pcm_frames(ma_spatializer* pSpatializer, source. */ if (dopplerFactor > 0) { - pSpatializer->dopplerPitch = ma_doppler_pitch(ma_vec3f_sub(pListener->position, pSpatializer->position), pSpatializer->velocity, listenerVel, speedOfSound, dopplerFactor); + pSpatializer->dopplerPitch = ma_doppler_pitch(ma_vec3f_sub(ma_spatializer_listener_get_position(pListener), ma_spatializer_get_position(pSpatializer)), ma_spatializer_get_velocity(pSpatializer), listenerVel, speedOfSound, dopplerFactor); } else { pSpatializer->dopplerPitch = 1; } @@ -49157,6 +50215,24 @@ MA_API ma_result ma_spatializer_process_pcm_frames(ma_spatializer* pSpatializer, return MA_SUCCESS; } +MA_API ma_result ma_spatializer_set_master_volume(ma_spatializer* pSpatializer, float volume) +{ + if (pSpatializer == NULL) { + return MA_INVALID_ARGS; + } + + return ma_gainer_set_master_volume(&pSpatializer->gainer, volume); +} + +MA_API ma_result ma_spatializer_get_master_volume(const ma_spatializer* pSpatializer, float* pVolume) +{ + if (pSpatializer == NULL) { + return MA_INVALID_ARGS; + } + + return ma_gainer_get_master_volume(&pSpatializer->gainer, pVolume); +} + MA_API ma_uint32 ma_spatializer_get_input_channels(const ma_spatializer* pSpatializer) { if (pSpatializer == NULL) { @@ -49373,7 +50449,7 @@ MA_API void ma_spatializer_set_position(ma_spatializer* pSpatializer, float x, f return; } - pSpatializer->position = ma_vec3f_init_3f(x, y, z); + ma_atomic_vec3f_set(&pSpatializer->position, ma_vec3f_init_3f(x, y, z)); } MA_API ma_vec3f ma_spatializer_get_position(const ma_spatializer* pSpatializer) @@ -49382,7 +50458,7 @@ MA_API ma_vec3f ma_spatializer_get_position(const ma_spatializer* pSpatializer) return ma_vec3f_init_3f(0, 0, 0); } - return pSpatializer->position; + return ma_atomic_vec3f_get((ma_atomic_vec3f*)&pSpatializer->position); /* Naughty const-cast. It's just for atomically loading the vec3 which should be safe. */ } MA_API void ma_spatializer_set_direction(ma_spatializer* pSpatializer, float x, float y, float z) @@ -49391,7 +50467,7 @@ MA_API void ma_spatializer_set_direction(ma_spatializer* pSpatializer, float x, return; } - pSpatializer->direction = ma_vec3f_init_3f(x, y, z); + ma_atomic_vec3f_set(&pSpatializer->direction, ma_vec3f_init_3f(x, y, z)); } MA_API ma_vec3f ma_spatializer_get_direction(const ma_spatializer* pSpatializer) @@ -49400,7 +50476,7 @@ MA_API ma_vec3f ma_spatializer_get_direction(const ma_spatializer* pSpatializer) return ma_vec3f_init_3f(0, 0, -1); } - return pSpatializer->direction; + return ma_atomic_vec3f_get((ma_atomic_vec3f*)&pSpatializer->direction); /* Naughty const-cast. It's just for atomically loading the vec3 which should be safe. */ } MA_API void ma_spatializer_set_velocity(ma_spatializer* pSpatializer, float x, float y, float z) @@ -49409,7 +50485,7 @@ MA_API void ma_spatializer_set_velocity(ma_spatializer* pSpatializer, float x, f return; } - pSpatializer->velocity = ma_vec3f_init_3f(x, y, z); + ma_atomic_vec3f_set(&pSpatializer->velocity, ma_vec3f_init_3f(x, y, z)); } MA_API ma_vec3f ma_spatializer_get_velocity(const ma_spatializer* pSpatializer) @@ -49418,7 +50494,7 @@ MA_API ma_vec3f ma_spatializer_get_velocity(const ma_spatializer* pSpatializer) return ma_vec3f_init_3f(0, 0, 0); } - return pSpatializer->velocity; + return ma_atomic_vec3f_get((ma_atomic_vec3f*)&pSpatializer->velocity); /* Naughty const-cast. It's just for atomically loading the vec3 which should be safe. */ } MA_API void ma_spatializer_get_relative_position_and_direction(const ma_spatializer* pSpatializer, const ma_spatializer_listener* pListener, ma_vec3f* pRelativePos, ma_vec3f* pRelativeDir) @@ -49442,23 +50518,32 @@ MA_API void ma_spatializer_get_relative_position_and_direction(const ma_spatiali if (pListener == NULL || ma_spatializer_get_positioning(pSpatializer) == ma_positioning_relative) { /* There's no listener or we're using relative positioning. */ if (pRelativePos != NULL) { - *pRelativePos = pSpatializer->position; + *pRelativePos = ma_spatializer_get_position(pSpatializer); } if (pRelativeDir != NULL) { - *pRelativeDir = pSpatializer->direction; + *pRelativeDir = ma_spatializer_get_direction(pSpatializer); } } else { + ma_vec3f spatializerPosition; + ma_vec3f spatializerDirection; + ma_vec3f listenerPosition; + ma_vec3f listenerDirection; ma_vec3f v; ma_vec3f axisX; ma_vec3f axisY; ma_vec3f axisZ; float m[4][4]; + spatializerPosition = ma_spatializer_get_position(pSpatializer); + spatializerDirection = ma_spatializer_get_direction(pSpatializer); + listenerPosition = ma_spatializer_listener_get_position(pListener); + listenerDirection = ma_spatializer_listener_get_direction(pListener); + /* We need to calcualte the right vector from our forward and up vectors. This is done with a cross product. */ - axisZ = ma_vec3f_normalize(pListener->direction); /* Normalization required here because we can't trust the caller. */ + axisZ = ma_vec3f_normalize(listenerDirection); /* Normalization required here because we can't trust the caller. */ axisX = ma_vec3f_normalize(ma_vec3f_cross(axisZ, pListener->config.worldUp)); /* Normalization required here because the world up vector may not be perpendicular with the forward vector. */ /* @@ -49483,9 +50568,9 @@ MA_API void ma_spatializer_get_relative_position_and_direction(const ma_spatiali } /* Lookat. */ - m[0][0] = axisX.x; m[1][0] = axisX.y; m[2][0] = axisX.z; m[3][0] = -ma_vec3f_dot(axisX, pListener->position); - m[0][1] = axisY.x; m[1][1] = axisY.y; m[2][1] = axisY.z; m[3][1] = -ma_vec3f_dot(axisY, pListener->position); - m[0][2] = -axisZ.x; m[1][2] = -axisZ.y; m[2][2] = -axisZ.z; m[3][2] = -ma_vec3f_dot(ma_vec3f_neg(axisZ), pListener->position); + m[0][0] = axisX.x; m[1][0] = axisX.y; m[2][0] = axisX.z; m[3][0] = -ma_vec3f_dot(axisX, listenerPosition); + m[0][1] = axisY.x; m[1][1] = axisY.y; m[2][1] = axisY.z; m[3][1] = -ma_vec3f_dot(axisY, listenerPosition); + m[0][2] = -axisZ.x; m[1][2] = -axisZ.y; m[2][2] = -axisZ.z; m[3][2] = -ma_vec3f_dot(ma_vec3f_neg(axisZ), listenerPosition); m[0][3] = 0; m[1][3] = 0; m[2][3] = 0; m[3][3] = 1; /* @@ -49494,7 +50579,7 @@ MA_API void ma_spatializer_get_relative_position_and_direction(const ma_spatiali origin which makes things simpler. */ if (pRelativePos != NULL) { - v = pSpatializer->position; + v = spatializerPosition; pRelativePos->x = m[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z + m[3][0] * 1; pRelativePos->y = m[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z + m[3][1] * 1; pRelativePos->z = m[0][2] * v.x + m[1][2] * v.y + m[2][2] * v.z + m[3][2] * 1; @@ -49505,7 +50590,7 @@ MA_API void ma_spatializer_get_relative_position_and_direction(const ma_spatiali rotation of the listener. */ if (pRelativeDir != NULL) { - v = pSpatializer->direction; + v = spatializerDirection; pRelativeDir->x = m[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z; pRelativeDir->y = m[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z; pRelativeDir->z = m[0][2] * v.x + m[1][2] * v.y + m[2][2] * v.z; @@ -51245,7 +52330,7 @@ static ma_result ma_channel_map_apply_mono_out_f32(float* pFramesOut, const floa return MA_SUCCESS; } -static ma_result ma_channel_map_apply_mono_in_f32(float* pFramesOut, const ma_channel* pChannelMapOut, ma_uint32 channelsOut, const float* pFramesIn, ma_uint64 frameCount, ma_mono_expansion_mode monoExpansionMode) +static ma_result ma_channel_map_apply_mono_in_f32(float* MA_RESTRICT pFramesOut, const ma_channel* pChannelMapOut, ma_uint32 channelsOut, const float* MA_RESTRICT pFramesIn, ma_uint64 frameCount, ma_mono_expansion_mode monoExpansionMode) { ma_uint64 iFrame; ma_uint32 iChannelOut; @@ -51350,16 +52435,123 @@ static ma_result ma_channel_map_apply_mono_in_f32(float* pFramesOut, const ma_ch { default_handler: { - for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + if (channelsOut <= MA_MAX_CHANNELS) { + ma_bool32 hasEmptyChannel = MA_FALSE; + ma_channel channelPositions[MA_MAX_CHANNELS]; for (iChannelOut = 0; iChannelOut < channelsOut; iChannelOut += 1) { - ma_channel channelOut = ma_channel_map_get_channel(pChannelMapOut, channelsOut, iChannelOut); - if (channelOut != MA_CHANNEL_NONE) { - pFramesOut[iChannelOut] = pFramesIn[0]; + channelPositions[iChannelOut] = ma_channel_map_get_channel(pChannelMapOut, channelsOut, iChannelOut); + if (channelPositions[iChannelOut] == MA_CHANNEL_NONE) { + hasEmptyChannel = MA_TRUE; } } - pFramesOut += channelsOut; - pFramesIn += 1; + if (hasEmptyChannel == MA_FALSE) { + /* + Faster path when there's no MA_CHANNEL_NONE channel positions. This should hopefully + help the compiler with auto-vectorization.m + */ + if (channelsOut == 2) { + #if defined(MA_SUPPORT_SSE2) + if (ma_has_sse2()) { + /* We want to do two frames in each iteration. */ + ma_uint64 unrolledFrameCount = frameCount >> 1; + + for (iFrame = 0; iFrame < unrolledFrameCount; iFrame += 1) { + __m128 in0 = _mm_set1_ps(pFramesIn[iFrame*2 + 0]); + __m128 in1 = _mm_set1_ps(pFramesIn[iFrame*2 + 1]); + _mm_storeu_ps(&pFramesOut[iFrame*4 + 0], _mm_shuffle_ps(in1, in0, _MM_SHUFFLE(0, 0, 0, 0))); + } + + /* Tail. */ + iFrame = unrolledFrameCount << 1; + goto generic_on_fastpath; + } else + #endif + { + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + for (iChannelOut = 0; iChannelOut < 2; iChannelOut += 1) { + pFramesOut[iFrame*2 + iChannelOut] = pFramesIn[iFrame]; + } + } + } + } else if (channelsOut == 6) { + #if defined(MA_SUPPORT_SSE2) + if (ma_has_sse2()) { + /* We want to do two frames in each iteration so we can have a multiple of 4 samples. */ + ma_uint64 unrolledFrameCount = frameCount >> 1; + + for (iFrame = 0; iFrame < unrolledFrameCount; iFrame += 1) { + __m128 in0 = _mm_set1_ps(pFramesIn[iFrame*2 + 0]); + __m128 in1 = _mm_set1_ps(pFramesIn[iFrame*2 + 1]); + + _mm_storeu_ps(&pFramesOut[iFrame*12 + 0], in0); + _mm_storeu_ps(&pFramesOut[iFrame*12 + 4], _mm_shuffle_ps(in1, in0, _MM_SHUFFLE(0, 0, 0, 0))); + _mm_storeu_ps(&pFramesOut[iFrame*12 + 8], in1); + } + + /* Tail. */ + iFrame = unrolledFrameCount << 1; + goto generic_on_fastpath; + } else + #endif + { + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + for (iChannelOut = 0; iChannelOut < 6; iChannelOut += 1) { + pFramesOut[iFrame*6 + iChannelOut] = pFramesIn[iFrame]; + } + } + } + } else if (channelsOut == 8) { + #if defined(MA_SUPPORT_SSE2) + if (ma_has_sse2()) { + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + __m128 in = _mm_set1_ps(pFramesIn[iFrame]); + _mm_storeu_ps(&pFramesOut[iFrame*8 + 0], in); + _mm_storeu_ps(&pFramesOut[iFrame*8 + 4], in); + } + } else + #endif + { + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + for (iChannelOut = 0; iChannelOut < 8; iChannelOut += 1) { + pFramesOut[iFrame*8 + iChannelOut] = pFramesIn[iFrame]; + } + } + } + } else { + iFrame = 0; + + #if defined(MA_SUPPORT_SSE2) /* For silencing a warning with non-x86 builds. */ + generic_on_fastpath: + #endif + { + for (; iFrame < frameCount; iFrame += 1) { + for (iChannelOut = 0; iChannelOut < channelsOut; iChannelOut += 1) { + pFramesOut[iFrame*channelsOut + iChannelOut] = pFramesIn[iFrame]; + } + } + } + } + } else { + /* Slow path. Need to handle MA_CHANNEL_NONE. */ + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + for (iChannelOut = 0; iChannelOut < channelsOut; iChannelOut += 1) { + if (channelPositions[iChannelOut] != MA_CHANNEL_NONE) { + pFramesOut[iFrame*channelsOut + iChannelOut] = pFramesIn[iFrame]; + } + } + } + } + } else { + /* Slow path. Too many channels to store on the stack. */ + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + for (iChannelOut = 0; iChannelOut < channelsOut; iChannelOut += 1) { + ma_channel channelOut = ma_channel_map_get_channel(pChannelMapOut, channelsOut, iChannelOut); + if (channelOut != MA_CHANNEL_NONE) { + pFramesOut[iFrame*channelsOut + iChannelOut] = pFramesIn[iFrame]; + } + } + } } } } break; @@ -51426,19 +52618,105 @@ static void ma_channel_map_apply_f32(float* pFramesOut, const ma_channel* pChann } } - for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + iFrame = 0; + + /* Experiment: Try an optimized unroll for some specific cases to see how it improves performance. RESULT: Good gains. */ + if (channelsOut == 8) { + /* Experiment 2: Expand the inner loop to see what kind of different it makes. RESULT: Small, but worthwhile gain. */ + if (channelsIn == 2) { + for (; iFrame < frameCount; iFrame += 1) { + float accumulation[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + + accumulation[0] += pFramesIn[iFrame*2 + 0] * weights[0][0]; + accumulation[1] += pFramesIn[iFrame*2 + 0] * weights[1][0]; + accumulation[2] += pFramesIn[iFrame*2 + 0] * weights[2][0]; + accumulation[3] += pFramesIn[iFrame*2 + 0] * weights[3][0]; + accumulation[4] += pFramesIn[iFrame*2 + 0] * weights[4][0]; + accumulation[5] += pFramesIn[iFrame*2 + 0] * weights[5][0]; + accumulation[6] += pFramesIn[iFrame*2 + 0] * weights[6][0]; + accumulation[7] += pFramesIn[iFrame*2 + 0] * weights[7][0]; + + accumulation[0] += pFramesIn[iFrame*2 + 1] * weights[0][1]; + accumulation[1] += pFramesIn[iFrame*2 + 1] * weights[1][1]; + accumulation[2] += pFramesIn[iFrame*2 + 1] * weights[2][1]; + accumulation[3] += pFramesIn[iFrame*2 + 1] * weights[3][1]; + accumulation[4] += pFramesIn[iFrame*2 + 1] * weights[4][1]; + accumulation[5] += pFramesIn[iFrame*2 + 1] * weights[5][1]; + accumulation[6] += pFramesIn[iFrame*2 + 1] * weights[6][1]; + accumulation[7] += pFramesIn[iFrame*2 + 1] * weights[7][1]; + + pFramesOut[iFrame*8 + 0] = accumulation[0]; + pFramesOut[iFrame*8 + 1] = accumulation[1]; + pFramesOut[iFrame*8 + 2] = accumulation[2]; + pFramesOut[iFrame*8 + 3] = accumulation[3]; + pFramesOut[iFrame*8 + 4] = accumulation[4]; + pFramesOut[iFrame*8 + 5] = accumulation[5]; + pFramesOut[iFrame*8 + 6] = accumulation[6]; + pFramesOut[iFrame*8 + 7] = accumulation[7]; + } + } else { + /* When outputting to 8 channels, we can do everything in groups of two 4x SIMD operations. */ + for (; iFrame < frameCount; iFrame += 1) { + float accumulation[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + + for (iChannelIn = 0; iChannelIn < channelsIn; iChannelIn += 1) { + accumulation[0] += pFramesIn[iFrame*channelsIn + iChannelIn] * weights[0][iChannelIn]; + accumulation[1] += pFramesIn[iFrame*channelsIn + iChannelIn] * weights[1][iChannelIn]; + accumulation[2] += pFramesIn[iFrame*channelsIn + iChannelIn] * weights[2][iChannelIn]; + accumulation[3] += pFramesIn[iFrame*channelsIn + iChannelIn] * weights[3][iChannelIn]; + accumulation[4] += pFramesIn[iFrame*channelsIn + iChannelIn] * weights[4][iChannelIn]; + accumulation[5] += pFramesIn[iFrame*channelsIn + iChannelIn] * weights[5][iChannelIn]; + accumulation[6] += pFramesIn[iFrame*channelsIn + iChannelIn] * weights[6][iChannelIn]; + accumulation[7] += pFramesIn[iFrame*channelsIn + iChannelIn] * weights[7][iChannelIn]; + } + + pFramesOut[iFrame*8 + 0] = accumulation[0]; + pFramesOut[iFrame*8 + 1] = accumulation[1]; + pFramesOut[iFrame*8 + 2] = accumulation[2]; + pFramesOut[iFrame*8 + 3] = accumulation[3]; + pFramesOut[iFrame*8 + 4] = accumulation[4]; + pFramesOut[iFrame*8 + 5] = accumulation[5]; + pFramesOut[iFrame*8 + 6] = accumulation[6]; + pFramesOut[iFrame*8 + 7] = accumulation[7]; + } + } + } else if (channelsOut == 6) { + /* + When outputting to 6 channels we unfortunately don't have a nice multiple of 4 to do 4x SIMD operations. Instead we'll + expand our weights and do two frames at a time. + */ + for (; iFrame < frameCount; iFrame += 1) { + float accumulation[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + for (iChannelIn = 0; iChannelIn < channelsIn; iChannelIn += 1) { + accumulation[0] += pFramesIn[iFrame*channelsIn + iChannelIn] * weights[0][iChannelIn]; + accumulation[1] += pFramesIn[iFrame*channelsIn + iChannelIn] * weights[1][iChannelIn]; + accumulation[2] += pFramesIn[iFrame*channelsIn + iChannelIn] * weights[2][iChannelIn]; + accumulation[3] += pFramesIn[iFrame*channelsIn + iChannelIn] * weights[3][iChannelIn]; + accumulation[4] += pFramesIn[iFrame*channelsIn + iChannelIn] * weights[4][iChannelIn]; + accumulation[5] += pFramesIn[iFrame*channelsIn + iChannelIn] * weights[5][iChannelIn]; + } + + pFramesOut[iFrame*6 + 0] = accumulation[0]; + pFramesOut[iFrame*6 + 1] = accumulation[1]; + pFramesOut[iFrame*6 + 2] = accumulation[2]; + pFramesOut[iFrame*6 + 3] = accumulation[3]; + pFramesOut[iFrame*6 + 4] = accumulation[4]; + pFramesOut[iFrame*6 + 5] = accumulation[5]; + } + } + + /* Leftover frames. */ + for (; iFrame < frameCount; iFrame += 1) { for (iChannelOut = 0; iChannelOut < channelsOut; iChannelOut += 1) { float accumulation = 0; for (iChannelIn = 0; iChannelIn < channelsIn; iChannelIn += 1) { - accumulation += pFramesIn[iChannelIn] * weights[iChannelOut][iChannelIn]; + accumulation += pFramesIn[iFrame*channelsIn + iChannelIn] * weights[iChannelOut][iChannelIn]; } - pFramesOut[iChannelOut] = accumulation; + pFramesOut[iFrame*channelsOut + iChannelOut] = accumulation; } - - pFramesOut += channelsOut; - pFramesIn += channelsIn; } } else { /* Cannot pre-compute weights because not enough room in stack-allocated buffer. */ @@ -51449,14 +52727,11 @@ static void ma_channel_map_apply_f32(float* pFramesOut, const ma_channel* pChann for (iChannelIn = 0; iChannelIn < channelsIn; iChannelIn += 1) { ma_channel channelIn = ma_channel_map_get_channel(pChannelMapIn, channelsIn, iChannelIn); - accumulation += pFramesIn[iChannelIn] * ma_calculate_channel_position_rectangular_weight(channelOut, channelIn); + accumulation += pFramesIn[iFrame*channelsIn + iChannelIn] * ma_calculate_channel_position_rectangular_weight(channelOut, channelIn); } - pFramesOut[iChannelOut] = accumulation; + pFramesOut[iFrame*channelsOut + iChannelOut] = accumulation; } - - pFramesOut += channelsOut; - pFramesIn += channelsIn; } } } @@ -51638,7 +52913,7 @@ MA_API ma_result ma_channel_converter_init_preallocated(const ma_channel_convert /* We now need to fill out our weights table. This is determined by the mixing mode. */ - + /* In all cases we need to make sure all channels that are present in both channel maps have a 1:1 mapping. */ for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) { ma_channel channelPosIn = ma_channel_map_get_channel(pConverter->pChannelMapIn, pConverter->channelsIn, iChannelIn); @@ -55284,6 +56559,11 @@ MA_API ma_uint32 ma_get_bytes_per_sample(ma_format format) +#define MA_DATA_SOURCE_DEFAULT_RANGE_BEG 0 +#define MA_DATA_SOURCE_DEFAULT_RANGE_END ~((ma_uint64)0) +#define MA_DATA_SOURCE_DEFAULT_LOOP_POINT_BEG 0 +#define MA_DATA_SOURCE_DEFAULT_LOOP_POINT_END ~((ma_uint64)0) + MA_API ma_data_source_config ma_data_source_config_init(void) { ma_data_source_config config; @@ -55309,10 +56589,10 @@ MA_API ma_result ma_data_source_init(const ma_data_source_config* pConfig, ma_da } pDataSourceBase->vtable = pConfig->vtable; - pDataSourceBase->rangeBegInFrames = 0; - pDataSourceBase->rangeEndInFrames = ~((ma_uint64)0); - pDataSourceBase->loopBegInFrames = 0; - pDataSourceBase->loopEndInFrames = ~((ma_uint64)0); + pDataSourceBase->rangeBegInFrames = MA_DATA_SOURCE_DEFAULT_RANGE_BEG; + pDataSourceBase->rangeEndInFrames = MA_DATA_SOURCE_DEFAULT_RANGE_END; + pDataSourceBase->loopBegInFrames = MA_DATA_SOURCE_DEFAULT_LOOP_POINT_BEG; + pDataSourceBase->loopEndInFrames = MA_DATA_SOURCE_DEFAULT_LOOP_POINT_END; pDataSourceBase->pCurrent = pDataSource; /* Always read from ourself by default. */ pDataSourceBase->pNext = NULL; pDataSourceBase->onGetNext = NULL; @@ -55378,18 +56658,23 @@ static ma_result ma_data_source_read_pcm_frames_within_range(ma_data_source* pDa result = pDataSourceBase->vtable->onRead(pDataSourceBase, pFramesOut, frameCount, &framesRead); } else { /* Need to clamp to within the range. */ - ma_uint64 cursor; + ma_uint64 relativeCursor; + ma_uint64 absoluteCursor; - result = ma_data_source_get_cursor_in_pcm_frames(pDataSourceBase, &cursor); + result = ma_data_source_get_cursor_in_pcm_frames(pDataSourceBase, &relativeCursor); if (result != MA_SUCCESS) { /* Failed to retrieve the cursor. Cannot read within a range or loop points. Just read like normal - this may happen for things like noise data sources where it doesn't really matter. */ result = pDataSourceBase->vtable->onRead(pDataSourceBase, pFramesOut, frameCount, &framesRead); } else { + ma_uint64 rangeBeg; ma_uint64 rangeEnd; /* We have the cursor. We need to make sure we don't read beyond our range. */ + rangeBeg = pDataSourceBase->rangeBegInFrames; rangeEnd = pDataSourceBase->rangeEndInFrames; + absoluteCursor = rangeBeg + relativeCursor; + /* If looping, make sure we're within range. */ if (loop) { if (pDataSourceBase->loopEndInFrames != ~((ma_uint64)0)) { @@ -55397,8 +56682,8 @@ static ma_result ma_data_source_read_pcm_frames_within_range(ma_data_source* pDa } } - if (frameCount > (rangeEnd - cursor) && rangeEnd != ~((ma_uint64)0)) { - frameCount = (rangeEnd - cursor); + if (frameCount > (rangeEnd - absoluteCursor) && rangeEnd != ~((ma_uint64)0)) { + frameCount = (rangeEnd - absoluteCursor); } /* @@ -55803,9 +57088,9 @@ MA_API ma_result ma_data_source_set_range_in_pcm_frames(ma_data_source* pDataSou { ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource; ma_result result; - ma_uint64 cursor; - ma_uint64 loopBegAbsolute; - ma_uint64 loopEndAbsolute; + ma_uint64 relativeCursor; + ma_uint64 absoluteCursor; + ma_bool32 doSeekAdjustment = MA_FALSE; if (pDataSource == NULL) { return MA_INVALID_ARGS; @@ -55816,51 +57101,51 @@ MA_API ma_result ma_data_source_set_range_in_pcm_frames(ma_data_source* pDataSou } /* - The loop points need to be updated. We'll be storing the loop points relative to the range. We'll update - these so that they maintain their absolute positioning. The loop points will then be clamped to the range. + We may need to adjust the position of the cursor to ensure it's clamped to the range. Grab it now + so we can calculate it's absolute position before we change the range. */ - loopBegAbsolute = pDataSourceBase->loopBegInFrames + pDataSourceBase->rangeBegInFrames; - loopEndAbsolute = pDataSourceBase->loopEndInFrames + ((pDataSourceBase->loopEndInFrames != ~((ma_uint64)0)) ? pDataSourceBase->rangeBegInFrames : 0); - - pDataSourceBase->rangeBegInFrames = rangeBegInFrames; - pDataSourceBase->rangeEndInFrames = rangeEndInFrames; - - /* Make the loop points relative again, and make sure they're clamped to within the range. */ - if (loopBegAbsolute > pDataSourceBase->rangeBegInFrames) { - pDataSourceBase->loopBegInFrames = loopBegAbsolute - pDataSourceBase->rangeBegInFrames; + result = ma_data_source_get_cursor_in_pcm_frames(pDataSource, &relativeCursor); + if (result == MA_SUCCESS) { + doSeekAdjustment = MA_TRUE; + absoluteCursor = relativeCursor + pDataSourceBase->rangeBegInFrames; } else { - pDataSourceBase->loopBegInFrames = 0; - } - - if (pDataSourceBase->loopBegInFrames > pDataSourceBase->rangeEndInFrames) { - pDataSourceBase->loopBegInFrames = pDataSourceBase->rangeEndInFrames; + /* + We couldn't get the position of the cursor. It probably means the data source has no notion + of a cursor. We'll just leave it at position 0. Don't treat this as an error. + */ + doSeekAdjustment = MA_FALSE; + relativeCursor = 0; + absoluteCursor = 0; } - /* Only need to update the loop end point if it's not -1. */ - if (loopEndAbsolute != ~((ma_uint64)0)) { - if (loopEndAbsolute > pDataSourceBase->rangeBegInFrames) { - pDataSourceBase->loopEndInFrames = loopEndAbsolute - pDataSourceBase->rangeBegInFrames; - } else { - pDataSourceBase->loopEndInFrames = 0; - } + pDataSourceBase->rangeBegInFrames = rangeBegInFrames; + pDataSourceBase->rangeEndInFrames = rangeEndInFrames; - if (pDataSourceBase->loopEndInFrames > pDataSourceBase->rangeEndInFrames && pDataSourceBase->loopEndInFrames) { - pDataSourceBase->loopEndInFrames = pDataSourceBase->rangeEndInFrames; - } - } + /* + The commented out logic below was intended to maintain loop points in response to a change in the + range. However, this is not useful because it results in the sound breaking when you move the range + outside of the old loop points. I'm simplifying this by simply resetting the loop points. The + caller is expected to update their loop points if they change the range. + In practice this should be mostly a non-issue because the majority of the time the range will be + set once right after initialization. + */ + pDataSourceBase->loopBegInFrames = 0; + pDataSourceBase->loopEndInFrames = ~((ma_uint64)0); - /* If the new range is past the current cursor position we need to seek to it. */ - result = ma_data_source_get_cursor_in_pcm_frames(pDataSource, &cursor); - if (result == MA_SUCCESS) { - /* Seek to within range. Note that our seek positions here are relative to the new range. */ - if (cursor < rangeBegInFrames) { + + /* + Seek to within range. Note that our seek positions here are relative to the new range. We don't want + do do this if we failed to retrieve the cursor earlier on because it probably means the data source + has no notion of a cursor. In practice the seek would probably fail (which we silently ignore), but + I'm just not even going to attempt it. + */ + if (doSeekAdjustment) { + if (absoluteCursor < rangeBegInFrames) { ma_data_source_seek_to_pcm_frame(pDataSource, 0); - } else if (cursor > rangeEndInFrames) { + } else if (absoluteCursor > rangeEndInFrames) { ma_data_source_seek_to_pcm_frame(pDataSource, rangeEndInFrames - rangeBegInFrames); } - } else { - /* We failed to get the cursor position. Probably means the data source has no notion of a cursor such a noise data source. Just pretend the seeking worked. */ } return MA_SUCCESS; @@ -57870,7 +59155,7 @@ extern "C" { #define DRWAV_XSTRINGIFY(x) DRWAV_STRINGIFY(x) #define DRWAV_VERSION_MAJOR 0 #define DRWAV_VERSION_MINOR 13 -#define DRWAV_VERSION_REVISION 7 +#define DRWAV_VERSION_REVISION 8 #define DRWAV_VERSION_STRING DRWAV_XSTRINGIFY(DRWAV_VERSION_MAJOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_MINOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_REVISION) #include typedef signed char drwav_int8; @@ -61292,6 +62577,7 @@ typedef struct ma_uint8* pData; size_t dataSize; size_t dataCapacity; + size_t audioStartOffsetInBytes; ma_uint32 framesConsumed; /* The number of frames consumed in ppPacketData. */ ma_uint32 framesRemaining; /* The number of frames remaining in ppPacketData. */ float** ppPacketData; @@ -61458,6 +62744,13 @@ MA_API ma_result ma_stbvorbis_init(ma_read_proc onRead, ma_seek_proc onSeek, ma_ */ dataSize -= (size_t)consumedDataSize; /* Consume the data. */ MA_MOVE_MEMORY(pData, ma_offset_ptr(pData, consumedDataSize), dataSize); + + /* + We need to track the start point so we can seek back to the start of the audio + data when seeking. + */ + pVorbis->push.audioStartOffsetInBytes = consumedDataSize; + break; } else { /* Failed to open the decoder. */ @@ -61791,13 +63084,14 @@ MA_API ma_result ma_stbvorbis_seek_to_pcm_frame(ma_stbvorbis* pVorbis, ma_uint64 TODO: Use seeking logic documented for stb_vorbis_flush_pushdata(). */ - /* Seek to the start of the file to begin with. */ - result = pVorbis->onSeek(pVorbis->pReadSeekTellUserData, 0, ma_seek_origin_start); + /* Seek to the start of the audio data in the file to begin with. */ + result = pVorbis->onSeek(pVorbis->pReadSeekTellUserData, pVorbis->push.audioStartOffsetInBytes, ma_seek_origin_start); if (result != MA_SUCCESS) { return result; } stb_vorbis_flush_pushdata(pVorbis->stb); + pVorbis->push.framesConsumed = 0; pVorbis->push.framesRemaining = 0; pVorbis->push.dataSize = 0; @@ -64360,8 +65654,15 @@ MA_API ma_result ma_noise_set_type(ma_noise* pNoise, ma_noise_type type) return MA_INVALID_ARGS; } - pNoise->config.type = type; - return MA_SUCCESS; + /* + This function should never have been implemented in the first place. Changing the type dynamically is not + supported. Instead you need to uninitialize and reinitiailize a fresh `ma_noise` object. This function + will be removed in version 0.12. + */ + MA_ASSERT(MA_FALSE); + (void)type; + + return MA_INVALID_OPERATION; } static MA_INLINE float ma_noise_f32_white(ma_noise* pNoise) @@ -65573,8 +66874,11 @@ MA_API ma_resource_manager_data_source_config ma_resource_manager_data_source_co ma_resource_manager_data_source_config config; MA_ZERO_OBJECT(&config); - config.rangeEndInPCMFrames = ~((ma_uint64)0); - config.loopPointEndInPCMFrames = ~((ma_uint64)0); + config.rangeBegInPCMFrames = MA_DATA_SOURCE_DEFAULT_RANGE_BEG; + config.rangeEndInPCMFrames = MA_DATA_SOURCE_DEFAULT_RANGE_END; + config.loopPointBegInPCMFrames = MA_DATA_SOURCE_DEFAULT_LOOP_POINT_BEG; + config.loopPointEndInPCMFrames = MA_DATA_SOURCE_DEFAULT_LOOP_POINT_END; + config.isLooping = MA_FALSE; return config; } @@ -65623,8 +66927,17 @@ static ma_result ma_resource_manager__init_decoder(ma_resource_manager* pResourc return MA_SUCCESS; } +static ma_bool32 ma_resource_manager_data_buffer_has_connector(ma_resource_manager_data_buffer* pDataBuffer) +{ + return ma_atomic_bool32_get(&pDataBuffer->isConnectorInitialized); +} + static ma_data_source* ma_resource_manager_data_buffer_get_connector(ma_resource_manager_data_buffer* pDataBuffer) { + if (ma_resource_manager_data_buffer_has_connector(pDataBuffer) == MA_FALSE) { + return NULL; /* Connector not yet initialized. */ + } + switch (pDataBuffer->pNode->data.type) { case ma_resource_manager_data_supply_type_encoded: return &pDataBuffer->connector.decoder; @@ -65646,7 +66959,7 @@ static ma_result ma_resource_manager_data_buffer_init_connector(ma_resource_mana MA_ASSERT(pDataBuffer != NULL); MA_ASSERT(pConfig != NULL); - MA_ASSERT(pDataBuffer->isConnectorInitialized == MA_FALSE); + MA_ASSERT(ma_resource_manager_data_buffer_has_connector(pDataBuffer) == MA_FALSE); /* The underlying data buffer must be initialized before we'll be able to know how to initialize the backend. */ result = ma_resource_manager_data_buffer_node_result(pDataBuffer->pNode); @@ -65696,14 +67009,30 @@ static ma_result ma_resource_manager_data_buffer_init_connector(ma_resource_mana */ if (result == MA_SUCCESS) { /* - Make sure the looping state is set before returning in order to handle the case where the - loop state was set on the data buffer before the connector was initialized. + The resource manager supports the ability to set the range and loop settings via a config at + initialization time. This results in an case where the ranges could be set explicitly via + ma_data_source_set_*() before we get to this point here. If this happens, we'll end up + hitting a case where we just override those settings which results in what feels like a bug. + + To address this we only change the relevant properties if they're not equal to defaults. If + they're equal to defaults there's no need to change them anyway. If they're *not* set to the + default values, we can assume the user has set the range and loop settings via the config. If + they're doing their own calls to ma_data_source_set_*() in addition to setting them via the + config, that's entirely on the caller and any synchronization issue becomes their problem. */ - ma_data_source_set_range_in_pcm_frames(pDataBuffer, pConfig->rangeBegInPCMFrames, pConfig->rangeEndInPCMFrames); - ma_data_source_set_loop_point_in_pcm_frames(pDataBuffer, pConfig->loopPointBegInPCMFrames, pConfig->loopPointEndInPCMFrames); - ma_data_source_set_looping(pDataBuffer, pConfig->isLooping); + if (pConfig->rangeBegInPCMFrames != MA_DATA_SOURCE_DEFAULT_RANGE_BEG || pConfig->rangeEndInPCMFrames != MA_DATA_SOURCE_DEFAULT_RANGE_END) { + ma_data_source_set_range_in_pcm_frames(pDataBuffer, pConfig->rangeBegInPCMFrames, pConfig->rangeEndInPCMFrames); + } + + if (pConfig->loopPointBegInPCMFrames != MA_DATA_SOURCE_DEFAULT_LOOP_POINT_BEG || pConfig->loopPointEndInPCMFrames != MA_DATA_SOURCE_DEFAULT_LOOP_POINT_END) { + ma_data_source_set_loop_point_in_pcm_frames(pDataBuffer, pConfig->loopPointBegInPCMFrames, pConfig->loopPointEndInPCMFrames); + } - pDataBuffer->isConnectorInitialized = MA_TRUE; + if (pConfig->isLooping != MA_FALSE) { + ma_data_source_set_looping(pDataBuffer, pConfig->isLooping); + } + + ma_atomic_bool32_set(&pDataBuffer->isConnectorInitialized, MA_TRUE); if (pInitNotification != NULL) { ma_async_notification_signal(pInitNotification); @@ -65723,6 +67052,8 @@ static ma_result ma_resource_manager_data_buffer_uninit_connector(ma_resource_ma MA_ASSERT(pResourceManager != NULL); MA_ASSERT(pDataBuffer != NULL); + (void)pResourceManager; + switch (ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBuffer->pNode)) { case ma_resource_manager_data_supply_type_encoded: /* Connector is a decoder. */ @@ -66708,15 +68039,25 @@ MA_API ma_result ma_resource_manager_data_buffer_read_pcm_frames(ma_resource_man MA_ASSERT(ma_resource_manager_data_buffer_node_result(pDataBuffer->pNode) != MA_UNAVAILABLE); /* If the node is not initialized we need to abort with a busy code. */ - if (ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBuffer->pNode) == ma_resource_manager_data_supply_type_unknown) { + if (ma_resource_manager_data_buffer_has_connector(pDataBuffer) == MA_FALSE) { return MA_BUSY; /* Still loading. */ } + /* + If we've got a seek scheduled we'll want to do that before reading. However, for paged buffers, there's + a chance that the sound hasn't yet been decoded up to the seek point will result in the seek failing. If + this happens, we need to keep the seek scheduled and return MA_BUSY. + */ if (pDataBuffer->seekToCursorOnNextRead) { pDataBuffer->seekToCursorOnNextRead = MA_FALSE; result = ma_data_source_seek_to_pcm_frame(ma_resource_manager_data_buffer_get_connector(pDataBuffer), pDataBuffer->seekTargetInPCMFrames); if (result != MA_SUCCESS) { + if (result == MA_BAD_SEEK && ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBuffer->pNode) == ma_resource_manager_data_supply_type_decoded_paged) { + pDataBuffer->seekToCursorOnNextRead = MA_TRUE; /* Keep the seek scheduled. We just haven't loaded enough data yet to do the seek properly. */ + return MA_BUSY; + } + return result; } } @@ -66789,7 +68130,7 @@ MA_API ma_result ma_resource_manager_data_buffer_seek_to_pcm_frame(ma_resource_m MA_ASSERT(ma_resource_manager_data_buffer_node_result(pDataBuffer->pNode) != MA_UNAVAILABLE); /* If we haven't yet got a connector we need to abort. */ - if (ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBuffer->pNode) == ma_resource_manager_data_supply_type_unknown) { + if (ma_resource_manager_data_buffer_has_connector(pDataBuffer) == MA_FALSE) { pDataBuffer->seekTargetInPCMFrames = frameIndex; pDataBuffer->seekToCursorOnNextRead = MA_TRUE; return MA_BUSY; /* Still loading. */ @@ -67248,6 +68589,14 @@ MA_API ma_result ma_resource_manager_data_stream_init_ex(ma_resource_manager* pR ma_async_notification_signal(notifications.init.pNotification); } + /* + If there was an error during initialization make sure we return that result here. We don't want to do this + if we're not waiting because it will most likely be in a busy state. + */ + if (pDataStream->result != MA_SUCCESS) { + return pDataStream->result; + } + /* NOTE: Do not release pInitFence here. That will be done by the job. */ } @@ -67262,7 +68611,7 @@ MA_API ma_result ma_resource_manager_data_stream_init(ma_resource_manager* pReso config.pFilePath = pFilePath; config.flags = flags; config.pNotifications = pNotifications; - + return ma_resource_manager_data_stream_init_ex(pResourceManager, &config, pDataStream); } @@ -67274,7 +68623,7 @@ MA_API ma_result ma_resource_manager_data_stream_init_w(ma_resource_manager* pRe config.pFilePathW = pFilePath; config.flags = flags; config.pNotifications = pNotifications; - + return ma_resource_manager_data_stream_init_ex(pResourceManager, &config, pDataStream); } @@ -68354,7 +69703,7 @@ static ma_result ma_job_process__resource_manager__load_data_buffer(ma_job* pJob } /* Try initializing the connector if we haven't already. */ - isConnectorInitialized = pDataBuffer->isConnectorInitialized; + isConnectorInitialized = ma_resource_manager_data_buffer_has_connector(pDataBuffer); if (isConnectorInitialized == MA_FALSE) { dataSupplyType = ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBuffer->pNode); @@ -68387,7 +69736,7 @@ static ma_result ma_job_process__resource_manager__load_data_buffer(ma_job* pJob There is a hole between here and the where the data connector is initialized where the data buffer node may have finished initializing. We need to check for this by checking the result of the data buffer node and whether or not we had an unknown data supply type at the time of - trying to initialize the data connector. + trying to initialize the data connector. */ result = ma_resource_manager_data_buffer_node_result(pDataBuffer->pNode); if (result == MA_BUSY || (result == MA_SUCCESS && isConnectorInitialized == MA_FALSE && dataSupplyType == ma_resource_manager_data_supply_type_unknown)) { @@ -68410,7 +69759,7 @@ static ma_result ma_job_process__resource_manager__load_data_buffer(ma_job* pJob If at this point the data buffer has not had it's connector initialized, it means the notification event was never signalled which means we need to signal it here. */ - if (pDataBuffer->isConnectorInitialized == MA_FALSE && result != MA_SUCCESS) { + if (ma_resource_manager_data_buffer_has_connector(pDataBuffer) == MA_FALSE && result != MA_SUCCESS) { if (pJob->data.resourceManager.loadDataBuffer.pInitNotification != NULL) { ma_async_notification_signal(pJob->data.resourceManager.loadDataBuffer.pInitNotification); } @@ -68736,35 +70085,6 @@ MA_API void ma_debug_fill_pcm_frames_with_sine_wave(float* pFramesOut, ma_uint32 -static ma_result ma_mix_pcm_frames_f32(float* pDst, const float* pSrc, ma_uint64 frameCount, ma_uint32 channels, float volume) -{ - ma_uint64 iSample; - ma_uint64 sampleCount; - - if (pDst == NULL || pSrc == NULL || channels == 0) { - return MA_INVALID_ARGS; - } - - if (volume == 0) { - return MA_SUCCESS; /* No changes if the volume is 0. */ - } - - sampleCount = frameCount * channels; - - if (volume == 1) { - for (iSample = 0; iSample < sampleCount; iSample += 1) { - pDst[iSample] += pSrc[iSample]; - } - } else { - for (iSample = 0; iSample < sampleCount; iSample += 1) { - pDst[iSample] += ma_apply_volume_unclipped_f32(pSrc[iSample], volume); - } - } - - return MA_SUCCESS; -} - - MA_API ma_node_graph_config ma_node_graph_config_init(ma_uint32 channels) { ma_node_graph_config config; @@ -69238,7 +70558,7 @@ static void ma_node_input_bus_attach(ma_node_input_bus* pInputBus, ma_node_outpu old input bus has been updated so that pOutputBus will not get iterated again. */ pOutputBus->pInputNode = pNewInputNode; /* No need for an atomic assignment here because modification of this variable always happens within a lock. */ - pOutputBus->inputNodeInputBusIndex = (ma_uint8)inputNodeInputBusIndex; /* As above. */ + pOutputBus->inputNodeInputBusIndex = (ma_uint8)inputNodeInputBusIndex; /* Now we need to attach the output bus to the linked list. This involves updating two pointers on @@ -69336,6 +70656,8 @@ static ma_result ma_node_input_bus_read_pcm_frames(ma_node* pInputNode, ma_node_ ma_uint32 inputChannels; ma_bool32 doesOutputBufferHaveContent = MA_FALSE; + (void)pInputNode; /* Not currently used. */ + /* This will be called from the audio thread which means we can't be doing any locking. Basically, this function will not perfom any locking, whereas attaching and detaching will, but crafted in @@ -69378,6 +70700,7 @@ static ma_result ma_node_input_bus_read_pcm_frames(ma_node* pInputNode, ma_node_ ma_bool32 isSilentOutput = MA_FALSE; MA_ASSERT(pOutputBus->pNode != NULL); + MA_ASSERT(((ma_node_base*)pOutputBus->pNode)->vtable != NULL); isSilentOutput = (((ma_node_base*)pOutputBus->pNode)->vtable->flags & MA_NODE_FLAG_SILENT_OUTPUT) != 0; @@ -69560,8 +70883,8 @@ static ma_result ma_node_translate_bus_counts(const ma_node_config* pConfig, ma_ /* Some special rules for passthrough nodes. */ if ((pConfig->vtable->flags & MA_NODE_FLAG_PASSTHROUGH) != 0) { - if (pConfig->vtable->inputBusCount != 1 || pConfig->vtable->outputBusCount != 1) { - return MA_INVALID_ARGS; /* Passthrough nodes must have exactly 1 input bus and 1 output bus. */ + if ((pConfig->vtable->inputBusCount != 0 && pConfig->vtable->inputBusCount != 1) || pConfig->vtable->outputBusCount != 1) { + return MA_INVALID_ARGS; /* Passthrough nodes must have exactly 1 output bus and either 0 or 1 input bus. */ } if (pConfig->pInputChannels[0] != pConfig->pOutputChannels[0]) { @@ -70250,6 +71573,15 @@ static ma_result ma_node_read_pcm_frames(ma_node* pNode, ma_uint32 outputBusInde frameCountOut = frameCount; /* Just read as much as we can. The callback will return what was actually read. */ ppFramesOut[0] = pFramesOut; + + /* + If it's a passthrough we won't be expecting the callback to output anything, so we'll + need to pre-silence the output buffer. + */ + if ((pNodeBase->vtable->flags & MA_NODE_FLAG_PASSTHROUGH) != 0) { + ma_silence_pcm_frames(pFramesOut, frameCount, ma_format_f32, ma_node_get_output_channels(pNode, outputBusIndex)); + } + ma_node_process_pcm_frames_internal(pNode, NULL, &frameCountIn, ppFramesOut, &frameCountOut); totalFramesRead = frameCountOut; } else { @@ -70502,7 +71834,7 @@ static ma_result ma_node_read_pcm_frames(ma_node* pNode, ma_uint32 outputBusInde ma_node_output_bus_set_has_read(&pNodeBase->pOutputBuses[outputBusIndex], MA_TRUE); } } - + /* Apply volume, if necessary. */ ma_apply_volume_factor_f32(pFramesOut, totalFramesRead * ma_node_get_output_channels(pNodeBase, outputBusIndex), ma_node_output_bus_get_volume(&pNodeBase->pOutputBuses[outputBusIndex])); @@ -70671,8 +72003,7 @@ static void ma_splitter_node_process_pcm_frames(ma_node* pNode, const float** pp ma_uint32 channels; MA_ASSERT(pNodeBase != NULL); - MA_ASSERT(ma_node_get_input_bus_count(pNodeBase) == 1); - MA_ASSERT(ma_node_get_output_bus_count(pNodeBase) >= 2); + MA_ASSERT(ma_node_get_input_bus_count(pNodeBase) == 1); /* We don't need to consider the input frame count - it'll be the same as the output frame count and we process everything. */ (void)pFrameCountIn; @@ -71702,6 +73033,33 @@ static ma_uint64 ma_engine_node_get_required_input_frame_count(const ma_engine_n return inputFrameCount; } +static ma_result ma_engine_node_set_volume(ma_engine_node* pEngineNode, float volume) +{ + if (pEngineNode == NULL) { + return MA_INVALID_ARGS; + } + + /* We should always have an active spatializer because it can be enabled and disabled dynamically. We can just use that for hodling our volume. */ + ma_spatializer_set_master_volume(&pEngineNode->spatializer, volume); + + return MA_SUCCESS; +} + +static ma_result ma_engine_node_get_volume(const ma_engine_node* pEngineNode, float* pVolume) +{ + if (pVolume == NULL) { + return MA_INVALID_ARGS; + } + + *pVolume = 0.0f; + + if (pEngineNode == NULL) { + return MA_INVALID_ARGS; + } + + return ma_spatializer_get_master_volume(&pEngineNode->spatializer, pVolume); +} + static void ma_engine_node_process_pcm_frames__general(ma_engine_node* pEngineNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut) { ma_uint32 frameCountIn; @@ -71822,18 +73180,23 @@ static void ma_engine_node_process_pcm_frames__general(ma_engine_node* pEngineNo if (pEngineNode->pinnedListenerIndex != MA_LISTENER_INDEX_CLOSEST && pEngineNode->pinnedListenerIndex < ma_engine_get_listener_count(pEngineNode->pEngine)) { iListener = pEngineNode->pinnedListenerIndex; } else { - iListener = ma_engine_find_closest_listener(pEngineNode->pEngine, pEngineNode->spatializer.position.x, pEngineNode->spatializer.position.y, pEngineNode->spatializer.position.z); + ma_vec3f spatializerPosition = ma_spatializer_get_position(&pEngineNode->spatializer); + iListener = ma_engine_find_closest_listener(pEngineNode->pEngine, spatializerPosition.x, spatializerPosition.y, spatializerPosition.z); } ma_spatializer_process_pcm_frames(&pEngineNode->spatializer, &pEngineNode->pEngine->listeners[iListener], pRunningFramesOut, pWorkingBuffer, framesJustProcessedOut); } else { - /* No spatialization, but we still need to do channel conversion. */ + /* No spatialization, but we still need to do channel conversion and master volume. */ + float volume; + ma_engine_node_get_volume(pEngineNode, &volume); /* Should never fail. */ + if (channelsIn == channelsOut) { /* No channel conversion required. Just copy straight to the output buffer. */ - ma_copy_pcm_frames(pRunningFramesOut, pWorkingBuffer, framesJustProcessedOut, ma_format_f32, channelsOut); + ma_copy_and_apply_volume_factor_f32(pRunningFramesOut, pWorkingBuffer, framesJustProcessedOut * channelsOut, volume); } else { /* Channel conversion required. TODO: Add support for channel maps here. */ ma_channel_map_apply_f32(pRunningFramesOut, NULL, channelsOut, pWorkingBuffer, NULL, channelsIn, framesJustProcessedOut, ma_channel_mix_mode_simple, pEngineNode->monoExpansionMode); + ma_apply_volume_factor_f32(pRunningFramesOut, framesJustProcessedOut * channelsOut, volume); } } @@ -72068,6 +73431,7 @@ static ma_result ma_engine_node_get_heap_layout(const ma_engine_node_config* pCo ma_spatializer_config spatializerConfig; ma_uint32 channelsIn; ma_uint32 channelsOut; + ma_channel defaultStereoChannelMap[2] = {MA_CHANNEL_SIDE_LEFT, MA_CHANNEL_SIDE_RIGHT}; /* <-- Consistent with the default channel map of a stereo listener. Means channel conversion can run on a fast path. */ MA_ASSERT(pHeapLayout); @@ -72104,7 +73468,7 @@ static ma_result ma_engine_node_get_heap_layout(const ma_engine_node_config* pCo /* Resmapler. */ resamplerConfig = ma_linear_resampler_config_init(ma_format_f32, channelsIn, 1, 1); /* Input and output sample rates don't affect the calculation of the heap size. */ resamplerConfig.lpfOrder = 0; - + result = ma_linear_resampler_get_heap_size(&resamplerConfig, &tempHeapSize); if (result != MA_SUCCESS) { return result; /* Failed to retrieve the size of the heap for the resampler. */ @@ -72117,6 +73481,10 @@ static ma_result ma_engine_node_get_heap_layout(const ma_engine_node_config* pCo /* Spatializer. */ spatializerConfig = ma_engine_node_spatializer_config_init(&baseNodeConfig); + if (spatializerConfig.channelsIn == 2) { + spatializerConfig.pChannelMapIn = defaultStereoChannelMap; + } + result = ma_spatializer_get_heap_size(&spatializerConfig, &tempHeapSize); if (result != MA_SUCCESS) { return result; /* Failed to retrieve the size of the heap for the spatializer. */ @@ -72161,6 +73529,7 @@ MA_API ma_result ma_engine_node_init_preallocated(const ma_engine_node_config* p ma_panner_config pannerConfig; ma_uint32 channelsIn; ma_uint32 channelsOut; + ma_channel defaultStereoChannelMap[2] = {MA_CHANNEL_SIDE_LEFT, MA_CHANNEL_SIDE_RIGHT}; /* <-- Consistent with the default channel map of a stereo listener. Means channel conversion can run on a fast path. */ if (pEngineNode == NULL) { return MA_INVALID_ARGS; @@ -72190,10 +73559,17 @@ MA_API ma_result ma_engine_node_init_preallocated(const ma_engine_node_config* p pEngineNode->isSpatializationDisabled = pConfig->isSpatializationDisabled; pEngineNode->pinnedListenerIndex = pConfig->pinnedListenerIndex; - channelsIn = (pConfig->channelsIn != 0) ? pConfig->channelsIn : ma_engine_get_channels(pConfig->pEngine); channelsOut = (pConfig->channelsOut != 0) ? pConfig->channelsOut : ma_engine_get_channels(pConfig->pEngine); + /* + If the sample rate of the sound is different to the engine, make sure pitching is enabled so that the resampler + is activated. Not doing this will result in the sound not being resampled if MA_SOUND_FLAG_NO_PITCH is used. + */ + if (pEngineNode->sampleRate != ma_engine_get_sample_rate(pEngineNode->pEngine)) { + pEngineNode->isPitchDisabled = MA_FALSE; + } + /* Base node. */ baseNodeConfig = ma_engine_node_base_node_config_init(pConfig); @@ -72240,6 +73616,10 @@ MA_API ma_result ma_engine_node_init_preallocated(const ma_engine_node_config* p spatializerConfig = ma_engine_node_spatializer_config_init(&baseNodeConfig); spatializerConfig.gainSmoothTimeInFrames = pEngineNode->pEngine->gainSmoothTimeInFrames; + if (spatializerConfig.channelsIn == 2) { + spatializerConfig.pChannelMapIn = defaultStereoChannelMap; + } + result = ma_spatializer_init_preallocated(&spatializerConfig, ma_offset_ptr(pHeap, heapLayout.spatializerOffset), &pEngineNode->spatializer); if (result != MA_SUCCESS) { goto error2; @@ -72331,7 +73711,7 @@ MA_API ma_sound_config ma_sound_config_init_2(ma_engine* pEngine) } else { config.monoExpansionMode = ma_mono_expansion_mode_default; } - + config.rangeEndInPCMFrames = ~((ma_uint64)0); config.loopPointEndInPCMFrames = ~((ma_uint64)0); @@ -72439,7 +73819,7 @@ MA_API ma_result ma_engine_init(const ma_engine_config* pConfig, ma_engine* pEng #if !defined(MA_NO_DEVICE_IO) { pEngine->pDevice = engineConfig.pDevice; - + /* If we don't have a device, we need one. */ if (pEngine->pDevice == NULL && engineConfig.noDevice == MA_FALSE) { ma_device_config deviceConfig; @@ -72554,7 +73934,7 @@ MA_API ma_result ma_engine_init(const ma_engine_config* pConfig, ma_engine* pEng Temporarily disabled. There is a subtle bug here where front-left and front-right will be used by the device's channel map, but this is not what we want to use for spatialization. Instead we want to use side-left and side-right. I need to figure - out a better solution for this. For now, disabling the user of device channel maps. + out a better solution for this. For now, disabling the use of device channel maps. */ /*listenerConfig.pChannelMapOut = pEngine->pDevice->playback.channelMap;*/ } @@ -72924,7 +74304,7 @@ MA_API ma_uint32 ma_engine_find_closest_listener(const ma_engine* pEngine, float iListenerClosest = 0; for (iListener = 0; iListener < pEngine->listenerCount; iListener += 1) { if (ma_engine_listener_is_enabled(pEngine, iListener)) { - float len2 = ma_vec3f_len2(ma_vec3f_sub(pEngine->listeners[iListener].position, ma_vec3f_init_3f(absolutePosX, absolutePosY, absolutePosZ))); + float len2 = ma_vec3f_len2(ma_vec3f_sub(ma_spatializer_listener_get_position(&pEngine->listeners[iListener]), ma_vec3f_init_3f(absolutePosX, absolutePosY, absolutePosZ))); if (closestLen2 > len2) { closestLen2 = len2; iListenerClosest = iListener; @@ -73306,8 +74686,11 @@ MA_API ma_result ma_sound_init_from_file_internal(ma_engine* pEngine, const ma_s return MA_OUT_OF_MEMORY; } - notifications = ma_resource_manager_pipeline_notifications_init(); - notifications.done.pFence = pConfig->pDoneFence; + /* Removed in 0.12. Set pDoneFence on the notifications. */ + notifications = pConfig->initNotifications; + if (pConfig->pDoneFence != NULL && notifications.done.pFence == NULL) { + notifications.done.pFence = pConfig->pDoneFence; + } /* We must wrap everything around the fence if one was specified. This ensures ma_fence_wait() does @@ -73355,21 +74738,35 @@ MA_API ma_result ma_sound_init_from_file_internal(ma_engine* pEngine, const ma_s MA_API ma_result ma_sound_init_from_file(ma_engine* pEngine, const char* pFilePath, ma_uint32 flags, ma_sound_group* pGroup, ma_fence* pDoneFence, ma_sound* pSound) { - ma_sound_config config = ma_sound_config_init_2(pEngine); + ma_sound_config config; + + if (pFilePath == NULL) { + return MA_INVALID_ARGS; + } + + config = ma_sound_config_init_2(pEngine); config.pFilePath = pFilePath; config.flags = flags; config.pInitialAttachment = pGroup; config.pDoneFence = pDoneFence; + return ma_sound_init_ex(pEngine, &config, pSound); } MA_API ma_result ma_sound_init_from_file_w(ma_engine* pEngine, const wchar_t* pFilePath, ma_uint32 flags, ma_sound_group* pGroup, ma_fence* pDoneFence, ma_sound* pSound) { - ma_sound_config config = ma_sound_config_init_2(pEngine); + ma_sound_config config; + + if (pFilePath == NULL) { + return MA_INVALID_ARGS; + } + + config = ma_sound_config_init_2(pEngine); config.pFilePathW = pFilePath; config.flags = flags; config.pInitialAttachment = pGroup; config.pDoneFence = pDoneFence; + return ma_sound_init_ex(pEngine, &config, pSound); } @@ -73552,17 +74949,20 @@ MA_API void ma_sound_set_volume(ma_sound* pSound, float volume) return; } - /* The volume is controlled via the output bus. */ - ma_node_set_output_bus_volume(pSound, 0, volume); + ma_engine_node_set_volume(&pSound->engineNode, volume); } MA_API float ma_sound_get_volume(const ma_sound* pSound) { + float volume = 0; + if (pSound == NULL) { return 0; } - return ma_node_get_output_bus_volume(pSound, 0); + ma_engine_node_get_volume(&pSound->engineNode, &volume); + + return volume; } MA_API void ma_sound_set_pan(ma_sound* pSound, float pan) @@ -73956,7 +75356,7 @@ MA_API void ma_sound_set_fade_in_milliseconds(ma_sound* pSound, float volumeBeg, ma_sound_set_fade_in_pcm_frames(pSound, volumeBeg, volumeEnd, (fadeLengthInMilliseconds * pSound->engineNode.fader.config.sampleRate) / 1000); } -MA_API float ma_sound_get_current_fade_volume(ma_sound* pSound) +MA_API float ma_sound_get_current_fade_volume(const ma_sound* pSound) { if (pSound == NULL) { return MA_INVALID_ARGS; @@ -76318,7 +77718,7 @@ DRWAV_PRIVATE size_t drwav__write_or_count_metadata(drwav* pWav, drwav_metadata* bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].playCount); } if (pMetadata->data.smpl.samplerSpecificDataSizeInBytes > 0) { - bytesWritten += drwav__write(pWav, pMetadata->data.smpl.pSamplerSpecificData, pMetadata->data.smpl.samplerSpecificDataSizeInBytes); + bytesWritten += drwav__write_or_count(pWav, pMetadata->data.smpl.pSamplerSpecificData, pMetadata->data.smpl.samplerSpecificDataSizeInBytes); } } break; case drwav_metadata_type_inst: @@ -77235,10 +78635,10 @@ DRWAV_PRIVATE drwav_result drwav_wfopen(FILE** ppFile, const wchar_t* pFilePath, (void)pAllocationCallbacks; } #else - #if defined(__DJGPP__) - { - } - #else + #if defined(__DJGPP__) + { + } + #else { mbstate_t mbs; size_t lenMB; @@ -77271,7 +78671,7 @@ DRWAV_PRIVATE drwav_result drwav_wfopen(FILE** ppFile, const wchar_t* pFilePath, *ppFile = fopen(pFilePathMB, pOpenModeMB); drwav__free_from_callbacks(pFilePathMB, pAllocationCallbacks); } - #endif + #endif if (*ppFile == NULL) { return DRWAV_ERROR; } @@ -85196,10 +86596,10 @@ static drflac_result drflac_wfopen(FILE** ppFile, const wchar_t* pFilePath, cons (void)pAllocationCallbacks; } #else - #if defined(__DJGPP__) - { - } - #else + #if defined(__DJGPP__) + { + } + #else { mbstate_t mbs; size_t lenMB; @@ -85232,7 +86632,7 @@ static drflac_result drflac_wfopen(FILE** ppFile, const wchar_t* pFilePath, cons *ppFile = fopen(pFilePathMB, pOpenModeMB); drflac__free_from_callbacks(pFilePathMB, pAllocationCallbacks); } - #endif + #endif if (*ppFile == NULL) { return DRFLAC_ERROR; } @@ -90532,10 +91932,10 @@ static drmp3_result drmp3_wfopen(FILE** ppFile, const wchar_t* pFilePath, const (void)pAllocationCallbacks; } #else - #if defined(__DJGPP__) - { - } - #else + #if defined(__DJGPP__) + { + } + #else { mbstate_t mbs; size_t lenMB; @@ -90568,7 +91968,7 @@ static drmp3_result drmp3_wfopen(FILE** ppFile, const wchar_t* pFilePath, const *ppFile = fopen(pFilePathMB, pOpenModeMB); drmp3__free_from_callbacks(pFilePathMB, pAllocationCallbacks); } - #endif + #endif if (*ppFile == NULL) { return DRMP3_ERROR; } From 393b0d1a80cee881323e352164071f7bf6def557 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 13 Mar 2023 12:06:54 +0100 Subject: [PATCH 167/192] Delete rcamera.old.h --- src/rcamera.old.h | 567 ---------------------------------------------- 1 file changed, 567 deletions(-) delete mode 100644 src/rcamera.old.h diff --git a/src/rcamera.old.h b/src/rcamera.old.h deleted file mode 100644 index 08c37669049e..000000000000 --- a/src/rcamera.old.h +++ /dev/null @@ -1,567 +0,0 @@ -/******************************************************************************************* -* -* rcamera - Basic camera system for multiple camera modes -* -* NOTE: Memory footprint of this library is aproximately 52 bytes (global variables) -* -* CONFIGURATION: -* -* #define CAMERA_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 CAMERA_STANDALONE -* If defined, the library can be used as standalone as a camera system but some -* functions must be redefined to manage inputs accordingly. -* -* CONTRIBUTORS: -* Ramon Santamaria: Supervision, review, update and maintenance -* Marc Palau: Initial implementation (2014) -* -* -* LICENSE: zlib/libpng -* -* Copyright (c) 2015-2022 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 RCAMERA_H -#define RCAMERA_H - -//---------------------------------------------------------------------------------- -// Defines and Macros -//---------------------------------------------------------------------------------- -//... - -//---------------------------------------------------------------------------------- -// Types and Structures Definition -// NOTE: Below types are required for CAMERA_STANDALONE usage -//---------------------------------------------------------------------------------- -#if defined(CAMERA_STANDALONE) - // Vector2 type - typedef struct Vector2 { - float x; - float y; - } Vector2; - - // Vector3 type - typedef struct Vector3 { - float x; - float y; - float z; - } Vector3; - - // Camera type, defines a camera position/orientation in 3d space - typedef struct Camera3D { - Vector3 position; // Camera position - Vector3 target; // Camera target it looks-at - Vector3 up; // Camera up vector (rotation over its axis) - float fovy; // Camera field-of-view apperture in Y (degrees) in perspective, used as near plane width in orthographic - int type; // Camera type, defines projection type: CAMERA_PERSPECTIVE or CAMERA_ORTHOGRAPHIC - } Camera3D; - - typedef Camera3D Camera; // Camera type fallback, defaults to Camera3D - - // Camera system modes - typedef enum { - CAMERA_CUSTOM = 0, - CAMERA_FREE, - CAMERA_ORBITAL, - CAMERA_FIRST_PERSON, - CAMERA_THIRD_PERSON - } CameraMode; - - // Camera projection modes - typedef enum { - CAMERA_PERSPECTIVE = 0, - CAMERA_ORTHOGRAPHIC - } CameraProjection; -#endif - -//---------------------------------------------------------------------------------- -// Global Variables Definition -//---------------------------------------------------------------------------------- -//... - -//---------------------------------------------------------------------------------- -// Module Functions Declaration -//---------------------------------------------------------------------------------- - -#ifdef __cplusplus -extern "C" { // Prevents name mangling of functions -#endif - -#if defined(CAMERA_STANDALONE) -void SetCameraMode(Camera camera, int mode); // Set camera mode (multiple camera modes available) -void UpdateCamera(Camera *camera); // Update camera position for selected mode - -void SetCameraPanControl(int keyPan); // Set camera pan key to combine with mouse movement (free camera) -void SetCameraAltControl(int keyAlt); // Set camera alt key to combine with mouse movement (free camera) -void SetCameraSmoothZoomControl(int szoomKey); // Set camera smooth zoom key to combine with mouse (free camera) -void SetCameraMoveControls(int keyFront, int keyBack, - int keyRight, int keyLeft, - int keyUp, int keyDown); // Set camera move controls (1st person and 3rd person cameras) -#endif - -#ifdef __cplusplus -} -#endif - -#endif // CAMERA_H - - -/*********************************************************************************** -* -* CAMERA IMPLEMENTATION -* -************************************************************************************/ - -#if defined(CAMERA_IMPLEMENTATION) - -#include // Required for: sinf(), cosf(), sqrtf() - -//---------------------------------------------------------------------------------- -// Defines and Macros -//---------------------------------------------------------------------------------- -#ifndef PI - #define PI 3.14159265358979323846 -#endif -#ifndef DEG2RAD - #define DEG2RAD (PI/180.0f) -#endif -#ifndef RAD2DEG - #define RAD2DEG (180.0f/PI) -#endif - -// Camera mouse movement sensitivity -#define CAMERA_MOUSE_MOVE_SENSITIVITY 0.003f -#define CAMERA_MOUSE_SCROLL_SENSITIVITY 1.5f - -// FREE_CAMERA -#define CAMERA_FREE_MOUSE_SENSITIVITY 0.01f -#define CAMERA_FREE_DISTANCE_MIN_CLAMP 0.3f -#define CAMERA_FREE_DISTANCE_MAX_CLAMP 120.0f -#define CAMERA_FREE_MIN_CLAMP 85.0f -#define CAMERA_FREE_MAX_CLAMP -85.0f -#define CAMERA_FREE_SMOOTH_ZOOM_SENSITIVITY 0.05f -#define CAMERA_FREE_PANNING_DIVIDER 5.1f - -// ORBITAL_CAMERA -#define CAMERA_ORBITAL_SPEED 0.01f // Radians per frame - -// FIRST_PERSON -//#define CAMERA_FIRST_PERSON_MOUSE_SENSITIVITY 0.003f -#define CAMERA_FIRST_PERSON_FOCUS_DISTANCE 25.0f -#define CAMERA_FIRST_PERSON_MIN_CLAMP 89.0f -#define CAMERA_FIRST_PERSON_MAX_CLAMP -89.0f - -#define CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER 8.0f -#define CAMERA_FIRST_PERSON_STEP_DIVIDER 30.0f -#define CAMERA_FIRST_PERSON_WAVING_DIVIDER 200.0f - -// THIRD_PERSON -//#define CAMERA_THIRD_PERSON_MOUSE_SENSITIVITY 0.003f -#define CAMERA_THIRD_PERSON_DISTANCE_CLAMP 1.2f -#define CAMERA_THIRD_PERSON_MIN_CLAMP 5.0f -#define CAMERA_THIRD_PERSON_MAX_CLAMP -85.0f -#define CAMERA_THIRD_PERSON_OFFSET (Vector3){ 0.4f, 0.0f, 0.0f } - -// PLAYER (used by camera) -#define PLAYER_MOVEMENT_SENSITIVITY 20.0f - -//---------------------------------------------------------------------------------- -// Types and Structures Definition -//---------------------------------------------------------------------------------- -// Camera move modes (first person and third person cameras) -typedef enum { - MOVE_FRONT = 0, - MOVE_BACK, - MOVE_RIGHT, - MOVE_LEFT, - MOVE_UP, - MOVE_DOWN -} CameraMove; - -// Camera global state context data [56 bytes] -typedef struct { - unsigned int mode; // Current camera mode - float targetDistance; // Camera distance from position to target - float playerEyesPosition; // Player eyes position from ground (in meters) - Vector2 angle; // Camera angle in plane XZ - Vector2 previousMousePosition; // Previous mouse position - - // Camera movement control keys - int moveControl[6]; // Move controls (CAMERA_FIRST_PERSON) - int smoothZoomControl; // Smooth zoom control key - int altControl; // Alternative control key - int panControl; // Pan view control key -} CameraData; - -//---------------------------------------------------------------------------------- -// Global Variables Definition -//---------------------------------------------------------------------------------- -static CameraData CAMERA = { // Global CAMERA state context - .mode = 0, - .targetDistance = 0, - .playerEyesPosition = 1.85f, - .angle = { 0 }, - .previousMousePosition = { 0 }, - .moveControl = { 'W', 'S', 'D', 'A', 'E', 'Q' }, - .smoothZoomControl = 341, // raylib: KEY_LEFT_CONTROL - .altControl = 342, // raylib: KEY_LEFT_ALT - .panControl = 2 // raylib: MOUSE_BUTTON_MIDDLE -}; - -//---------------------------------------------------------------------------------- -// Module specific Functions Declaration -//---------------------------------------------------------------------------------- -#if defined(CAMERA_STANDALONE) -// NOTE: Camera controls depend on some raylib input functions -static void EnableCursor() {} // Unlock cursor -static void DisableCursor() {} // Lock cursor - -static int IsKeyDown(int key) { return 0; } - -static int IsMouseButtonDown(int button) { return 0;} -static float GetMouseWheelMove() { return 0.0f; } -static Vector2 GetMousePosition() { return (Vector2){ 0.0f, 0.0f }; } -#endif - -//---------------------------------------------------------------------------------- -// Module Functions Definition -//---------------------------------------------------------------------------------- - -// Select camera mode (multiple camera modes available) -void SetCameraMode(Camera camera, int mode) -{ - Vector3 v1 = camera.position; - Vector3 v2 = camera.target; - - float dx = v2.x - v1.x; - float dy = v2.y - v1.y; - float dz = v2.z - v1.z; - - CAMERA.targetDistance = sqrtf(dx*dx + dy*dy + dz*dz); // Distance to target - - // Camera angle calculation - CAMERA.angle.x = atan2f(dx, dz); // Camera angle in plane XZ (0 aligned with Z, move positive CCW) - CAMERA.angle.y = atan2f(dy, sqrtf(dx*dx + dz*dz)); // Camera angle in plane XY (0 aligned with X, move positive CW) - - CAMERA.playerEyesPosition = camera.position.y; // Init player eyes position to camera Y position - - CAMERA.previousMousePosition = GetMousePosition(); // Init mouse position - - // Lock cursor for first person and third person cameras - if ((mode == CAMERA_FIRST_PERSON) || (mode == CAMERA_THIRD_PERSON)) DisableCursor(); - else EnableCursor(); - - CAMERA.mode = mode; -} - -// Update camera depending on selected mode -// NOTE: Camera controls depend on some raylib functions: -// System: EnableCursor(), DisableCursor() -// Mouse: IsMouseButtonDown(), GetMousePosition(), GetMouseWheelMove() -// Keys: IsKeyDown() -void UpdateCamera(Camera *camera) -{ - static int swingCounter = 0; // Used for 1st person swinging movement - - // TODO: Compute CAMERA.targetDistance and CAMERA.angle here (?) - - // Mouse movement detection - Vector2 mousePositionDelta = { 0.0f, 0.0f }; - Vector2 mousePosition = GetMousePosition(); - float mouseWheelMove = GetMouseWheelMove(); - - // Keys input detection - // TODO: Input detection is raylib-dependant, it could be moved outside the module - bool keyPan = IsMouseButtonDown(CAMERA.panControl); - bool keyAlt = IsKeyDown(CAMERA.altControl); - bool szoomKey = IsKeyDown(CAMERA.smoothZoomControl); - bool direction[6] = { IsKeyDown(CAMERA.moveControl[MOVE_FRONT]), - IsKeyDown(CAMERA.moveControl[MOVE_BACK]), - IsKeyDown(CAMERA.moveControl[MOVE_RIGHT]), - IsKeyDown(CAMERA.moveControl[MOVE_LEFT]), - IsKeyDown(CAMERA.moveControl[MOVE_UP]), - IsKeyDown(CAMERA.moveControl[MOVE_DOWN]) }; - - if (CAMERA.mode != CAMERA_CUSTOM) - { - mousePositionDelta.x = mousePosition.x - CAMERA.previousMousePosition.x; - mousePositionDelta.y = mousePosition.y - CAMERA.previousMousePosition.y; - - CAMERA.previousMousePosition = mousePosition; - } - - // Support for multiple automatic camera modes - // NOTE: In case of CAMERA_CUSTOM nothing happens here, user must update it manually - switch (CAMERA.mode) - { - case CAMERA_FREE: // Camera free controls, using standard 3d-content-creation scheme - { - // Camera zoom - if ((CAMERA.targetDistance < CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0)) - { - CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY); - if (CAMERA.targetDistance > CAMERA_FREE_DISTANCE_MAX_CLAMP) CAMERA.targetDistance = CAMERA_FREE_DISTANCE_MAX_CLAMP; - } - - // Camera looking down - else if ((camera->position.y > camera->target.y) && (CAMERA.targetDistance == CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0)) - { - camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; - camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; - camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; - } - else if ((camera->position.y > camera->target.y) && (camera->target.y >= 0)) - { - camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; - camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; - camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; - - // if (camera->target.y < 0) camera->target.y = -0.001; - } - else if ((camera->position.y > camera->target.y) && (camera->target.y < 0) && (mouseWheelMove > 0)) - { - CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY); - if (CAMERA.targetDistance < CAMERA_FREE_DISTANCE_MIN_CLAMP) CAMERA.targetDistance = CAMERA_FREE_DISTANCE_MIN_CLAMP; - } - // Camera looking up - else if ((camera->position.y < camera->target.y) && (CAMERA.targetDistance == CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0)) - { - camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; - camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; - camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; - } - else if ((camera->position.y < camera->target.y) && (camera->target.y <= 0)) - { - camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; - camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; - camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; - - // if (camera->target.y > 0) camera->target.y = 0.001; - } - else if ((camera->position.y < camera->target.y) && (camera->target.y > 0) && (mouseWheelMove > 0)) - { - CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY); - if (CAMERA.targetDistance < CAMERA_FREE_DISTANCE_MIN_CLAMP) CAMERA.targetDistance = CAMERA_FREE_DISTANCE_MIN_CLAMP; - } - - // Input keys checks - if (keyPan) - { - if (keyAlt) // Alternative key behaviour - { - if (szoomKey) - { - // Camera smooth zoom - CAMERA.targetDistance += (mousePositionDelta.y*CAMERA_FREE_SMOOTH_ZOOM_SENSITIVITY); - } - else - { - // Camera rotation - CAMERA.angle.x += mousePositionDelta.x*-CAMERA_FREE_MOUSE_SENSITIVITY; - CAMERA.angle.y += mousePositionDelta.y*-CAMERA_FREE_MOUSE_SENSITIVITY; - - // Angle clamp - if (CAMERA.angle.y > CAMERA_FREE_MIN_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FREE_MIN_CLAMP*DEG2RAD; - else if (CAMERA.angle.y < CAMERA_FREE_MAX_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FREE_MAX_CLAMP*DEG2RAD; - } - } - else - { - // Camera panning - camera->target.x += ((mousePositionDelta.x*CAMERA_FREE_MOUSE_SENSITIVITY)*cosf(CAMERA.angle.x) + (mousePositionDelta.y*-CAMERA_FREE_MOUSE_SENSITIVITY)*sinf(CAMERA.angle.x)*sinf(CAMERA.angle.y))*(CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER); - camera->target.y += ((mousePositionDelta.y*CAMERA_FREE_MOUSE_SENSITIVITY)*cosf(CAMERA.angle.y))*(CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER); - camera->target.z += ((mousePositionDelta.x*-CAMERA_FREE_MOUSE_SENSITIVITY)*sinf(CAMERA.angle.x) + (mousePositionDelta.y*-CAMERA_FREE_MOUSE_SENSITIVITY)*cosf(CAMERA.angle.x)*sinf(CAMERA.angle.y))*(CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER); - } - } - - // Update camera position with changes - camera->position.x = -sinf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.x; - camera->position.y = -sinf(CAMERA.angle.y)*CAMERA.targetDistance + camera->target.y; - camera->position.z = -cosf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.z; - - } break; - case CAMERA_ORBITAL: // Camera just orbits around target, only zoom allowed - { - CAMERA.angle.x += CAMERA_ORBITAL_SPEED; // Camera orbit angle - CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY); // Camera zoom - - // Camera distance clamp - if (CAMERA.targetDistance < CAMERA_THIRD_PERSON_DISTANCE_CLAMP) CAMERA.targetDistance = CAMERA_THIRD_PERSON_DISTANCE_CLAMP; - - // Update camera position with changes - camera->position.x = sinf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.x; - camera->position.y = ((CAMERA.angle.y <= 0.0f)? 1 : -1)*sinf(CAMERA.angle.y)*CAMERA.targetDistance*sinf(CAMERA.angle.y) + camera->target.y; - camera->position.z = cosf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.z; - - } break; - case CAMERA_FIRST_PERSON: // Camera moves as in a first-person game, controls are configurable - { - camera->position.x += (sinf(CAMERA.angle.x)*direction[MOVE_BACK] - - sinf(CAMERA.angle.x)*direction[MOVE_FRONT] - - cosf(CAMERA.angle.x)*direction[MOVE_LEFT] + - cosf(CAMERA.angle.x)*direction[MOVE_RIGHT])/PLAYER_MOVEMENT_SENSITIVITY; - - camera->position.y += (sinf(CAMERA.angle.y)*direction[MOVE_FRONT] - - sinf(CAMERA.angle.y)*direction[MOVE_BACK] + - 1.0f*direction[MOVE_UP] - 1.0f*direction[MOVE_DOWN])/PLAYER_MOVEMENT_SENSITIVITY; - - camera->position.z += (cosf(CAMERA.angle.x)*direction[MOVE_BACK] - - cosf(CAMERA.angle.x)*direction[MOVE_FRONT] + - sinf(CAMERA.angle.x)*direction[MOVE_LEFT] - - sinf(CAMERA.angle.x)*direction[MOVE_RIGHT])/PLAYER_MOVEMENT_SENSITIVITY; - - // Camera orientation calculation - CAMERA.angle.x += (mousePositionDelta.x*-CAMERA_MOUSE_MOVE_SENSITIVITY); - CAMERA.angle.y += (mousePositionDelta.y*-CAMERA_MOUSE_MOVE_SENSITIVITY); - - // Angle clamp - if (CAMERA.angle.y > CAMERA_FIRST_PERSON_MIN_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FIRST_PERSON_MIN_CLAMP*DEG2RAD; - else if (CAMERA.angle.y < CAMERA_FIRST_PERSON_MAX_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FIRST_PERSON_MAX_CLAMP*DEG2RAD; - - // Calculate translation matrix - Matrix matTranslation = { 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, (CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER), - 0.0f, 0.0f, 0.0f, 1.0f }; - - // Calculate rotation matrix - Matrix matRotation = { 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f }; - - float cosz = cosf(0.0f); - float sinz = sinf(0.0f); - float cosy = cosf(-(PI*2 - CAMERA.angle.x)); - float siny = sinf(-(PI*2 - CAMERA.angle.x)); - float cosx = cosf(-(PI*2 - CAMERA.angle.y)); - float sinx = sinf(-(PI*2 - CAMERA.angle.y)); - - matRotation.m0 = cosz*cosy; - matRotation.m4 = (cosz*siny*sinx) - (sinz*cosx); - matRotation.m8 = (cosz*siny*cosx) + (sinz*sinx); - matRotation.m1 = sinz*cosy; - matRotation.m5 = (sinz*siny*sinx) + (cosz*cosx); - matRotation.m9 = (sinz*siny*cosx) - (cosz*sinx); - matRotation.m2 = -siny; - matRotation.m6 = cosy*sinx; - matRotation.m10= cosy*cosx; - - // Multiply translation and rotation matrices - Matrix matTransform = { 0 }; - matTransform.m0 = matTranslation.m0*matRotation.m0 + matTranslation.m1*matRotation.m4 + matTranslation.m2*matRotation.m8 + matTranslation.m3*matRotation.m12; - matTransform.m1 = matTranslation.m0*matRotation.m1 + matTranslation.m1*matRotation.m5 + matTranslation.m2*matRotation.m9 + matTranslation.m3*matRotation.m13; - matTransform.m2 = matTranslation.m0*matRotation.m2 + matTranslation.m1*matRotation.m6 + matTranslation.m2*matRotation.m10 + matTranslation.m3*matRotation.m14; - matTransform.m3 = matTranslation.m0*matRotation.m3 + matTranslation.m1*matRotation.m7 + matTranslation.m2*matRotation.m11 + matTranslation.m3*matRotation.m15; - matTransform.m4 = matTranslation.m4*matRotation.m0 + matTranslation.m5*matRotation.m4 + matTranslation.m6*matRotation.m8 + matTranslation.m7*matRotation.m12; - matTransform.m5 = matTranslation.m4*matRotation.m1 + matTranslation.m5*matRotation.m5 + matTranslation.m6*matRotation.m9 + matTranslation.m7*matRotation.m13; - matTransform.m6 = matTranslation.m4*matRotation.m2 + matTranslation.m5*matRotation.m6 + matTranslation.m6*matRotation.m10 + matTranslation.m7*matRotation.m14; - matTransform.m7 = matTranslation.m4*matRotation.m3 + matTranslation.m5*matRotation.m7 + matTranslation.m6*matRotation.m11 + matTranslation.m7*matRotation.m15; - matTransform.m8 = matTranslation.m8*matRotation.m0 + matTranslation.m9*matRotation.m4 + matTranslation.m10*matRotation.m8 + matTranslation.m11*matRotation.m12; - matTransform.m9 = matTranslation.m8*matRotation.m1 + matTranslation.m9*matRotation.m5 + matTranslation.m10*matRotation.m9 + matTranslation.m11*matRotation.m13; - matTransform.m10 = matTranslation.m8*matRotation.m2 + matTranslation.m9*matRotation.m6 + matTranslation.m10*matRotation.m10 + matTranslation.m11*matRotation.m14; - matTransform.m11 = matTranslation.m8*matRotation.m3 + matTranslation.m9*matRotation.m7 + matTranslation.m10*matRotation.m11 + matTranslation.m11*matRotation.m15; - matTransform.m12 = matTranslation.m12*matRotation.m0 + matTranslation.m13*matRotation.m4 + matTranslation.m14*matRotation.m8 + matTranslation.m15*matRotation.m12; - matTransform.m13 = matTranslation.m12*matRotation.m1 + matTranslation.m13*matRotation.m5 + matTranslation.m14*matRotation.m9 + matTranslation.m15*matRotation.m13; - matTransform.m14 = matTranslation.m12*matRotation.m2 + matTranslation.m13*matRotation.m6 + matTranslation.m14*matRotation.m10 + matTranslation.m15*matRotation.m14; - matTransform.m15 = matTranslation.m12*matRotation.m3 + matTranslation.m13*matRotation.m7 + matTranslation.m14*matRotation.m11 + matTranslation.m15*matRotation.m15; - - camera->target.x = camera->position.x - matTransform.m12; - camera->target.y = camera->position.y - matTransform.m13; - camera->target.z = camera->position.z - matTransform.m14; - - // If movement detected (some key pressed), increase swinging - for (int i = 0; i < 6; i++) if (direction[i]) { swingCounter++; break; } - - // Camera position update - // NOTE: On CAMERA_FIRST_PERSON player Y-movement is limited to player 'eyes position' - camera->position.y = CAMERA.playerEyesPosition - sinf(swingCounter/CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER)/CAMERA_FIRST_PERSON_STEP_DIVIDER; - - camera->up.x = sinf(swingCounter/(CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER*2))/CAMERA_FIRST_PERSON_WAVING_DIVIDER; - camera->up.z = -sinf(swingCounter/(CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER*2))/CAMERA_FIRST_PERSON_WAVING_DIVIDER; - - } break; - case CAMERA_THIRD_PERSON: // Camera moves as in a third-person game, following target at a distance, controls are configurable - { - camera->position.x += (sinf(CAMERA.angle.x)*direction[MOVE_BACK] - - sinf(CAMERA.angle.x)*direction[MOVE_FRONT] - - cosf(CAMERA.angle.x)*direction[MOVE_LEFT] + - cosf(CAMERA.angle.x)*direction[MOVE_RIGHT])/PLAYER_MOVEMENT_SENSITIVITY; - - camera->position.y += (sinf(CAMERA.angle.y)*direction[MOVE_FRONT] - - sinf(CAMERA.angle.y)*direction[MOVE_BACK] + - 1.0f*direction[MOVE_UP] - 1.0f*direction[MOVE_DOWN])/PLAYER_MOVEMENT_SENSITIVITY; - - camera->position.z += (cosf(CAMERA.angle.x)*direction[MOVE_BACK] - - cosf(CAMERA.angle.x)*direction[MOVE_FRONT] + - sinf(CAMERA.angle.x)*direction[MOVE_LEFT] - - sinf(CAMERA.angle.x)*direction[MOVE_RIGHT])/PLAYER_MOVEMENT_SENSITIVITY; - - // Camera orientation calculation - CAMERA.angle.x += (mousePositionDelta.x*-CAMERA_MOUSE_MOVE_SENSITIVITY); - CAMERA.angle.y += (mousePositionDelta.y*-CAMERA_MOUSE_MOVE_SENSITIVITY); - - // Angle clamp - if (CAMERA.angle.y > CAMERA_THIRD_PERSON_MIN_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_THIRD_PERSON_MIN_CLAMP*DEG2RAD; - else if (CAMERA.angle.y < CAMERA_THIRD_PERSON_MAX_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_THIRD_PERSON_MAX_CLAMP*DEG2RAD; - - // Camera zoom - CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY); - - // Camera distance clamp - if (CAMERA.targetDistance < CAMERA_THIRD_PERSON_DISTANCE_CLAMP) CAMERA.targetDistance = CAMERA_THIRD_PERSON_DISTANCE_CLAMP; - - camera->position.x = sinf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.x; - - if (CAMERA.angle.y <= 0.0f) camera->position.y = sinf(CAMERA.angle.y)*CAMERA.targetDistance*sinf(CAMERA.angle.y) + camera->target.y; - else camera->position.y = -sinf(CAMERA.angle.y)*CAMERA.targetDistance*sinf(CAMERA.angle.y) + camera->target.y; - - camera->position.z = cosf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.z; - - } break; - case CAMERA_CUSTOM: break; - default: break; - } -} - -// Set camera pan key to combine with mouse movement (free camera) -void SetCameraPanControl(int keyPan) { CAMERA.panControl = keyPan; } - -// Set camera alt key to combine with mouse movement (free camera) -void SetCameraAltControl(int keyAlt) { CAMERA.altControl = keyAlt; } - -// Set camera smooth zoom key to combine with mouse (free camera) -void SetCameraSmoothZoomControl(int szoomKey) { CAMERA.smoothZoomControl = szoomKey; } - -// Set camera move controls (1st person and 3rd person cameras) -void SetCameraMoveControls(int keyFront, int keyBack, int keyRight, int keyLeft, int keyUp, int keyDown) -{ - CAMERA.moveControl[MOVE_FRONT] = keyFront; - CAMERA.moveControl[MOVE_BACK] = keyBack; - CAMERA.moveControl[MOVE_RIGHT] = keyRight; - CAMERA.moveControl[MOVE_LEFT] = keyLeft; - CAMERA.moveControl[MOVE_UP] = keyUp; - CAMERA.moveControl[MOVE_DOWN] = keyDown; -} - -#endif // CAMERA_IMPLEMENTATION From a7f81b06b93a4305186999e407b32bcb2ba78f04 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 13 Mar 2023 12:08:23 +0100 Subject: [PATCH 168/192] Remove trailing spaces --- CHANGELOG | 6 +++--- ROADMAP.md | 17 ++++++++++------- src/rmodels.c | 4 ++-- src/rtext.c | 4 ++-- src/rtextures.c | 2 +- 5 files changed, 18 insertions(+), 15 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 36c8bd2820af..fa89b3ba5479 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -38,7 +38,7 @@ Detailed changes: [core] REVIEWED: GetKeyPressed(), out of range issue (#2814) by @daipom [core] REVIEWED: GetTime(), renamed variable 'time' to 'nanoSeconds' (#2816) by @jtainer [core] REVIEWED: LoadShaderFromMemory(), issue with shader linkage -[core] REVIEWED: Avoid possible gamepad index as -1 (#2839) +[core] REVIEWED: Avoid possible gamepad index as -1 (#2839) [core] REVIEWED: SetShaderValue*(), avoid setup uniforms for invalid locations [core] REVIEWED: GetClipboardText() on PLATFORM_WEB, permissions issues [core] REVIEWED: Initial window position for display-sized fullscreen (#2742) by @daipom @@ -60,7 +60,7 @@ Detailed changes: [rlgl] ADDED: RL_TEXTURE_MIPMAP_BIAS_RATIO support to `rlTextureParameters()` for OpenGL 3.3 #2674 [rlgl] ADDED: rlCubemapParameters() (#2862) by @GithubPrankster [rlgl] ADDED: rlSetCullFace() (#2797) by @jtainer -[rlgl] REMOVED: Mipmaps software generation for OpenGL 1.1 +[rlgl] REMOVED: Mipmaps software generation for OpenGL 1.1 [rlgl] REVIEWED: Check for extensions before enabling them (#2706) by @Not-Nik [rlgl] REVIEWED: SSBO usage to avoid long long data types [rlgl] REVIEWED: Enable DXT compression on __APPLE__ targets (#2694) by @Not-Nik @@ -85,7 +85,7 @@ Detailed changes: [textures] ADDED: ImageBlurGaussian() (#2770) by @nobytesgiven [textures] REVIEWED: Image fileformat support: PIC, PNM [textures] REVIEWED: ImageTextEx() and ImageDrawTextEx() scaling (#2756) by @hatkidchan -[textures] `WARNING`: REMOVED: DrawTextureQuad() +[textures] `WARNING`: REMOVED: DrawTextureQuad() [textures] `WARNING`: REMOVED: DrawTexturePoly(), function moved to example: `textures_polygon` [textures] `WARNING`: REMOVED: DrawTextureTiled(),function implementation moved to the textures_tiled.c [text] ADDED: GetCodepointPrevious() diff --git a/ROADMAP.md b/ROADMAP.md index 0d126c86f62a..4c7c965e9529 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -3,8 +3,11 @@ Here it is a wishlist with features and ideas to improve the library. Note that features listed here are usually long term improvements or just describe a route to follow for the library. There are also some additional places to look for raylib improvements and ideas: - [GitHub Issues](https://github.com/raysan5/raylib/issues) has several open issues for possible improvements or bugs to fix. - - [raylib source code](https://github.com/raysan5/raylib/tree/master/src) has multiple *TODO* comments around code with pending things to review or improve. - - raylib wishlists discussions (https://github.com/raysan5/raylib/discussions/1502, https://github.com/raysan5/raylib/discussions/2272) are open to everyone to ask for improvements, feel free to check and comment. + - [raylib source code](https://github.com/raysan5/raylib/tree/master/src) has multiple *TODO* comments around code with pending things to review or improve. + - raylib wishlists discussions are open to everyone to ask for improvements, feel free to check and comment: + - [raylib wishlist 2021](https://github.com/raysan5/raylib/discussions/1502) + - [raylib wishlist 2022](https://github.com/raysan5/raylib/discussions/2272) + - [raylib 5.0 wishlist](https://github.com/raysan5/raylib/discussions/2952) _Current version of raylib is complete and functional but there is always room for improvements._ @@ -23,23 +26,23 @@ _Current version of raylib is complete and functional but there is always room f - Basic CPU/GPU stats system (memory, draws, time...) ([#1295](https://github.com/raysan5/raylib/issues/1295)) - _DISCARDED_ - Software rendering backend (avoiding OpenGL) ([#1370](https://github.com/raysan5/raylib/issues/1370)) - _DISCARDED_ - Network module (UDP): `rnet` ([#753](https://github.com/raysan5/raylib/issues/753)) - _DISCARDED_ - Use [nbnet](https://github.com/nathhB/nbnet). - + **raylib 3.0** - [x] Custom memory allocators support - [x] Global variables moved to global context - [x] Optimize data structures for pass-by-value - [x] Trace log messages redesign ([#1065](https://github.com/raysan5/raylib/issues/1065)) - [x] Continuous Integration using GitHub Actions - + **raylib 2.5** - [x] Support Animated models - [x] Support glTF models file format - [x] Unicode support on text drawing - + **raylib 2.0** - [x] Removed external dependencies (GLFW3 and OpenAL) - [x] Support TCC compiler (32bit and 64bit) - + **raylib 1.8** - [x] Improved Materials system with PBR support - [x] Procedural image generation functions (spot, gradient, noise...) @@ -50,7 +53,7 @@ _Current version of raylib is complete and functional but there is always room f - [x] Support configuration flags - [x] Improved build system for Android - [x] Gamepad support on HTML5 - + **raylib 1.6** - [x] Lua scripting support (raylib Lua wrapper) - [x] Redesigned audio module diff --git a/src/rmodels.c b/src/rmodels.c index 8ab923421323..2b1d0f9361dc 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -1117,8 +1117,8 @@ bool IsModelReady(Model model) (model.meshMaterial != NULL) && // Validate mesh-material linkage (model.meshCount > 0) && // Validate mesh count (model.materialCount > 0)); // Validate material count - - // NOTE: This is a very general model validation, many elements could be validated from a model... + + // NOTE: This is a very general model validation, many elements could be validated from a model... } // Unload model (meshes/materials) from memory (RAM and/or VRAM) diff --git a/src/rtext.c b/src/rtext.c index 2d47bdf6c836..9eec0059fc33 100644 --- a/src/rtext.c +++ b/src/rtext.c @@ -543,8 +543,8 @@ bool IsFontReady(Font font) (font.glyphCount > 0) && // Validate font contains some glyph (font.recs != NULL) && // Validate font recs defining glyphs on texture atlas (font.glyphs != NULL)); // Validate glyph data is loaded - - // NOTE: Further validations could be done to verify if recs count and glyphs count + + // NOTE: Further validations could be done to verify if recs count and glyphs count // match glyphCount and to verify that data contained is valid (glyphs values, metrics...) } diff --git a/src/rtextures.c b/src/rtextures.c index 12bca8a8e48f..b5f9998a9e22 100644 --- a/src/rtextures.c +++ b/src/rtextures.c @@ -3364,7 +3364,7 @@ bool IsRenderTextureReady(RenderTexture2D target) { return ((target.id > 0) && // Validate OpenGL id IsTextureReady(target.depth) && // Validate FBO depth texture/renderbuffer - IsTextureReady(target.texture)); // Validate FBO texture + IsTextureReady(target.texture)); // Validate FBO texture } // Unload render texture from GPU memory (VRAM) From 90ec0d52e045b4b3be9e2a7cd8d18a742882e457 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 13 Mar 2023 23:12:23 +0100 Subject: [PATCH 169/192] Reviewed filename --- examples/models/models_loading_m3d.c | 2 +- .../models/m3d/{CesiumMan.m3d => cesium_man.m3d} | Bin 2 files changed, 1 insertion(+), 1 deletion(-) rename examples/models/resources/models/m3d/{CesiumMan.m3d => cesium_man.m3d} (100%) diff --git a/examples/models/models_loading_m3d.c b/examples/models/models_loading_m3d.c index 18c8e1afcb05..b9674b6f626d 100644 --- a/examples/models/models_loading_m3d.c +++ b/examples/models/models_loading_m3d.c @@ -41,7 +41,7 @@ int main(void) Vector3 position = { 0.0f, 0.0f, 0.0f }; // Set model position - char modelFileName[128] = "resources/models/m3d/CesiumMan.m3d"; + char modelFileName[128] = "resources/models/m3d/cesium_man.m3d"; bool drawMesh = 1; bool drawSkeleton = 1; bool animPlaying = false; // Store anim state, what to draw diff --git a/examples/models/resources/models/m3d/CesiumMan.m3d b/examples/models/resources/models/m3d/cesium_man.m3d similarity index 100% rename from examples/models/resources/models/m3d/CesiumMan.m3d rename to examples/models/resources/models/m3d/cesium_man.m3d From 5a2c49b9541493b446291f2ff6a241522432b478 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 13 Mar 2023 23:13:02 +0100 Subject: [PATCH 170/192] Updated Makefiles to include all missing new examples --- examples/Makefile | 10 +++-- examples/Makefile.Web | 90 ++++++++++++++++++++++++++++++------------- src/Makefile | 10 +++-- 3 files changed, 76 insertions(+), 34 deletions(-) diff --git a/examples/Makefile b/examples/Makefile index 6b0b4a848ea5..04bd14e659f3 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -30,7 +30,7 @@ PLATFORM ?= PLATFORM_DESKTOP # Define required raylib variables PROJECT_NAME ?= raylib_examples -RAYLIB_VERSION ?= 4.2.0 +RAYLIB_VERSION ?= 4.5.0 RAYLIB_PATH ?= .. # Locations of raylib.h and libraylib.a/libraylib.so @@ -129,7 +129,7 @@ endif RAYLIB_RELEASE_PATH ?= $(RAYLIB_PATH)/src ifeq ($(PLATFORM),PLATFORM_WEB) - ifeq ($(PLATFORM_OS),WINDOWS) + ifeq ($(PLATFORM_OS),WINDOWS) # Emscripten required variables EMSDK_PATH ?= C:/emsdk EMSCRIPTEN_PATH ?= $(EMSDK_PATH)/upstream/emscripten @@ -137,7 +137,7 @@ ifeq ($(PLATFORM),PLATFORM_WEB) PYTHON_PATH = $(EMSDK_PATH)/python/3.9.2-1_64bit NODE_PATH = $(EMSDK_PATH)/node/14.15.5_64bit/bin export PATH = $(EMSDK_PATH);$(EMSCRIPTEN_PATH);$(CLANG_PATH);$(NODE_PATH);$(PYTHON_PATH):$$(PATH) - endif + endif endif # Define default C compiler: CC @@ -489,6 +489,7 @@ MODELS = \ models/models_billboard \ models/models_box_collisions \ models/models_cubicmap \ + models/models_draw_cube_texture \ models/models_first_person_maze \ models/models_geometric_shapes \ models/models_mesh_generation \ @@ -531,7 +532,8 @@ AUDIO = \ audio/audio_music_stream \ audio/audio_raw_stream \ audio/audio_sound_loading \ - audio/audio_stream_effects + audio/audio_stream_effects \ + audio/audio_mixed_processor CURRENT_MAKEFILE = $(lastword $(MAKEFILE_LIST)) diff --git a/examples/Makefile.Web b/examples/Makefile.Web index 063530fb3707..6af43758aa7c 100644 --- a/examples/Makefile.Web +++ b/examples/Makefile.Web @@ -30,7 +30,7 @@ PLATFORM ?= PLATFORM_WEB # Define required raylib variables PROJECT_NAME ?= raylib_examples -RAYLIB_VERSION ?= 4.2.0 +RAYLIB_VERSION ?= 4.5.0 RAYLIB_PATH ?= .. # Locations of raylib.h and libraylib.a/libraylib.so @@ -60,8 +60,8 @@ ifeq ($(PLATFORM),PLATFORM_RPI) endif endif -# Determine PLATFORM_OS in case PLATFORM_DESKTOP selected -ifeq ($(PLATFORM),PLATFORM_DESKTOP) +# Determine PLATFORM_OS in case PLATFORM_DESKTOP or PLATFORM_WEB selected +ifeq ($(PLATFORM),$(filter $(PLATFORM),PLATFORM_DESKTOP PLATFORM_WEB)) # No uname.exe on MinGW!, but OS=Windows_NT on Windows! # ifeq ($(UNAME),Msys) -> Windows ifeq ($(OS),Windows_NT) @@ -119,16 +119,18 @@ ifeq ($(PLATFORM),PLATFORM_DRM) endif # Define raylib release directory for compiled library -RAYLIB_RELEASE_PATH ?= $(RAYLIB_PATH)/src +RAYLIB_RELEASE_PATH ?= $(RAYLIB_PATH)/src ifeq ($(PLATFORM),PLATFORM_WEB) - # Emscripten required variables - EMSDK_PATH ?= C:/emsdk - EMSCRIPTEN_PATH ?= $(EMSDK_PATH)/upstream/emscripten - CLANG_PATH = $(EMSDK_PATH)/upstream/bin - PYTHON_PATH = $(EMSDK_PATH)/python/3.9.2-1_64bit - NODE_PATH = $(EMSDK_PATH)/node/14.15.5_64bit/bin - export PATH = $(EMSDK_PATH);$(EMSCRIPTEN_PATH);$(CLANG_PATH);$(NODE_PATH);$(PYTHON_PATH):$$(PATH) + ifeq ($(PLATFORM_OS),WINDOWS) + # Emscripten required variables + EMSDK_PATH ?= C:/emsdk + EMSCRIPTEN_PATH ?= $(EMSDK_PATH)/upstream/emscripten + CLANG_PATH = $(EMSDK_PATH)/upstream/bin + PYTHON_PATH = $(EMSDK_PATH)/python/3.9.2-1_64bit + NODE_PATH = $(EMSDK_PATH)/node/14.15.5_64bit/bin + export PATH = $(EMSDK_PATH);$(EMSCRIPTEN_PATH);$(CLANG_PATH);$(NODE_PATH);$(PYTHON_PATH):$$(PATH) + endif endif # Define default C compiler: CC @@ -195,9 +197,13 @@ ifeq ($(BUILD_MODE),DEBUG) endif else ifeq ($(PLATFORM),PLATFORM_WEB) - CFLAGS += -Os + ifeq ($(BUILD_WEB_ASYNCIFY),TRUE) + CFLAGS += -O3 + else + CFLAGS += -Os + endif else - CFLAGS += -s -O1 + CFLAGS += -s -O2 endif endif @@ -329,7 +335,7 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP) ifeq ($(RAYLIB_LIBTYPE),SHARED) LDLIBS += -lc endif - + # NOTE: On ARM 32bit arch, miniaudio requires atomics library LDLIBS += -latomic endif @@ -394,13 +400,13 @@ CORE = \ core/core_scissor_test \ core/core_storage_values \ core/core_vr_simulator \ - core/core_loading_thread \ core/core_window_flags \ core/core_window_letterbox \ core/core_window_should_close \ core/core_split_screen \ core/core_smooth_pixelperfect \ - core/core_custom_frame_control + core/core_custom_frame_control \ + core/core_loading_thread SHAPES = \ shapes/shapes_basic_shapes \ @@ -437,6 +443,7 @@ TEXTURES = \ textures/textures_sprite_anim \ textures/textures_sprite_button \ textures/textures_sprite_explosion \ + textures/textures_textured_curve \ textures/textures_bunnymark \ textures/textures_blend_modes \ textures/textures_draw_tiled \ @@ -463,6 +470,7 @@ MODELS = \ models/models_billboard \ models/models_box_collisions \ models/models_cubicmap \ + models/models_draw_cube_texture \ models/models_first_person_maze \ models/models_geometric_shapes \ models/models_mesh_generation \ @@ -496,14 +504,17 @@ SHADERS = \ shaders/shaders_spotlight \ shaders/shaders_hot_reloading \ shaders/shaders_mesh_instancing \ - shaders/shaders_multi_sample2d + shaders/shaders_multi_sample2d \ + shaders/shaders_write_depth \ + shaders/shaders_hybrid_render AUDIO = \ audio/audio_module_playing \ audio/audio_music_stream \ audio/audio_raw_stream \ audio/audio_sound_loading \ - audio/audio_stream_effects + audio/audio_stream_effects \ + audio/audio_mixed_processor CURRENT_MAKEFILE = $(lastword $(MAKEFILE_LIST)) @@ -593,13 +604,6 @@ core/core_vr_simulator: core/core_vr_simulator.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \ --preload-file core/resources/distortion100.fs@resources/distortion100.fs -# NOTE: To use multi-threading raylib must be compiled with multi-theading support (-s USE_PTHREADS=1) -# WARNING: For security reasons multi-threading is not supported on browsers, it requires cross-origin isolation (Oct.2021) -# WARNING: It requires raylib to be compiled using -pthread, so atomic operations and thread-local data (if any) -# in its source were transformed to non-atomic operations and non-thread-local data -core/core_loading_thread: core/core_loading_thread.c - $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) -s USE_PTHREADS=1 - core/core_window_flags: core/core_window_flags.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) @@ -614,6 +618,14 @@ core/core_custom_frame_control: core/core_custom_frame_control.c core/core_window_should_close: core/core_window_should_close.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) + +# NOTE: To use multi-threading raylib must be compiled with multi-theading support (-s USE_PTHREADS=1) +# WARNING: For security reasons multi-threading is not supported on browsers, it requires cross-origin isolation (Oct.2021) +# WARNING: It requires raylib to be compiled using -pthread, so atomic operations and thread-local data (if any) +# in its source were transformed to non-atomic operations and non-thread-local data +core/core_loading_thread: core/core_loading_thread.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) -s USE_PTHREADS=1 + # Compile SHAPES examples shapes/shapes_basic_shapes: shapes/shapes_basic_shapes.c @@ -733,6 +745,10 @@ textures/textures_sprite_explosion: textures/textures_sprite_explosion.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \ --preload-file textures/resources/explosion.png@resources/explosion.png \ --preload-file textures/resources/boom.wav@resources/boom.wav + +textures/textures_textured_curve: textures/textures_textured_curve.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \ + --preload-file textures/resources/road.png@resources/road.png textures/textures_bunnymark: textures/textures_bunnymark.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \ @@ -839,6 +855,10 @@ models/models_cubicmap: models/models_cubicmap.c --preload-file models/resources/cubicmap.png@resources/cubicmap.png \ --preload-file models/resources/cubicmap_atlas.png@resources/cubicmap_atlas.png +models/models_draw_cube_texture: models/models_draw_cube_texture.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \ + --preload-file models/resources/cubicmap_atlas.png@resources/cubicmap_atlas.png + models/models_first_person_maze: models/models_first_person_maze.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \ --preload-file models/resources/cubicmap.png@resources/cubicmap.png \ @@ -869,6 +889,10 @@ models/models_loading_vox: models/models_loading_vox.c models/models_loading_gltf: models/models_loading_gltf.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) -s TOTAL_MEMORY=67108864 \ --preload-file models/resources/models/gltf/robot.glb@resources/models/gltf/robot.glb + +models/models_loading_m3d: models/models_loading_m3d.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) -s TOTAL_MEMORY=67108864 \ + --preload-file models/resources/models/m3d/cesium_man.m3d@resources/models/m3d/cesium_man.m3d models/models_orthographic_projection: models/models_orthographic_projection.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) @@ -987,7 +1011,16 @@ shaders/shaders_texture_outline: shaders/shaders_texture_outline.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \ --preload-file shaders/resources/shaders/glsl100/outline.fs@resources/shaders/glsl100/outline.fs \ --preload-file shaders/resources/fudesumi.png@resources/fudesumi.png - + +shaders/shaders_write_depth: shaders/shaders_write_depth.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \ + --preload-file shaders/resources/shaders/glsl100/write_depth.fs@resources/shaders/glsl100/write_depth.fs + +shaders/shaders_hybrid_render: shaders/shaders_hybrid_render.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \ + --preload-file shaders/resources/shaders/glsl100/hybrid_raymarch.fs@resources/shaders/glsl100/hybrid_raymarch.fs \ + --preload-file shaders/resources/shaders/glsl100/hybrid_raster.fs@resources/shaders/glsl100/hybrid_raster.fs + # Compile AUDIO examples audio/audio_module_playing: audio/audio_module_playing.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \ @@ -1008,6 +1041,11 @@ audio/audio_sound_loading: audio/audio_sound_loading.c audio/audio_stream_effects: audio/audio_stream_effects.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) -s TOTAL_MEMORY=67108864 \ --preload-file audio/resources/country.mp3@resources/country.mp3 + +audio/audio_mixed_processor: audio/audio_mixed_processor.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) -s TOTAL_MEMORY=67108864 \ + --preload-file audio/resources/country.mp3@resources/country.mp3 \ + --preload-file audio/resources/coin.wav@resources/coin.wav # Clean everything clean: diff --git a/src/Makefile b/src/Makefile index 4d9c8723b73f..1667a97441f3 100644 --- a/src/Makefile +++ b/src/Makefile @@ -45,8 +45,8 @@ PLATFORM ?= PLATFORM_DESKTOP # Define required raylib variables -RAYLIB_VERSION = 4.2.0 -RAYLIB_API_VERSION = 420 +RAYLIB_VERSION = 4.5.0 +RAYLIB_API_VERSION = 450 # Define raylib source code path RAYLIB_SRC_PATH ?= ../src @@ -231,8 +231,10 @@ endif ifeq ($(PLATFORM),PLATFORM_DESKTOP) # By default use OpenGL 3.3 on desktop platforms 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_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 ($(PLATFORM),PLATFORM_RPI) # On RPI OpenGL ES 2.0 must be used From 1a361fdfe2629235a0c14ebe58fc78678e033738 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 13 Mar 2023 23:24:30 +0100 Subject: [PATCH 171/192] Update Makefile.Web --- examples/Makefile.Web | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/examples/Makefile.Web b/examples/Makefile.Web index 6af43758aa7c..499eb3eaa4f3 100644 --- a/examples/Makefile.Web +++ b/examples/Makefile.Web @@ -974,13 +974,13 @@ shaders/shaders_basic_lighting: shaders/shaders_basic_lighting.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \ --preload-file shaders/resources/texel_checker.png@resources/texel_checker.png \ --preload-file shaders/resources/shaders/glsl100/lighting.fs@resources/shaders/glsl100/lighting.fs \ - --preload-file shaders/resources/shaders/glsl100/base_lighting.vs@resources/shaders/glsl100/base_lighting.vs + --preload-file shaders/resources/shaders/glsl100/lighting.vs@resources/shaders/glsl100/lighting.vs shaders/shaders_fog: shaders/shaders_fog.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \ --preload-file shaders/resources/texel_checker.png@resources/texel_checker.png \ --preload-file shaders/resources/shaders/glsl100/fog.fs@resources/shaders/glsl100/fog.fs \ - --preload-file shaders/resources/shaders/glsl100/base_lighting.vs@resources/shaders/glsl100/base_lighting.vs + --preload-file shaders/resources/shaders/glsl100/lighting.vs@resources/shaders/glsl100/lighting.vs shaders/shaders_simple_mask: shaders/shaders_simple_mask.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \ @@ -999,10 +999,9 @@ shaders/shaders_hot_reloading: shaders/shaders_hot_reloading.c 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/base_lighting_instanced.vs@resources/shaders/glsl100/base_lighting_instanced.vs \ + --preload-file shaders/resources/shaders/glsl100/lighting_instancing.vs@resources/shaders/glsl100/lighting_instancing.vs \ --preload-file shaders/resources/shaders/glsl100/lighting.fs@resources/shaders/glsl100/lighting.fs - shaders/shaders_multi_sample2d: shaders/shaders_multi_sample2d.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \ --preload-file shaders/resources/shaders/glsl100/color_mix.fs@resources/shaders/glsl100/color_mix.fs From a6300d828ae77c3021655fcd88d26c4bf8f69de1 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 14 Mar 2023 13:05:58 +0100 Subject: [PATCH 172/192] Update CHANGELOG --- CHANGELOG | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index fa89b3ba5479..10c96f7b4a68 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -7,13 +7,13 @@ Current Release: raylib 4.5.0 (16 March 2023) Release: raylib 4.5 (16 March 2023) ------------------------------------------------------------------------- KEY CHANGES: - - ADDED: M3D model format support with animations - - ADDED: GLTF animation support - - ADDED: QOA audio format support (import/export) - - REDESIGNED: rcamera module, new implementation from scratch, simpler and more extendable - - REDESIGNED: rlgl module to avoid render batch triangles limits pre-check: rlCheckRenderBatchLimit() - - REDESIGNED: rshapes module to minimize the rlgl dependency, now only 6 low-level functions required! - - ADDED: rl_gputex self-contained module for compressed textures loading, used by rtextures module + - ADDED: Improved ANGLE support on Desktop platforms + - ADDED: rcamera module, simpler and more extendable + - ADDED: Support for M3D models and M3D/GLTF animations + - ADDED: Support QOA audio format (import/export) + - ADDED: rl_gputex module for compressed textures loading + - REDESIGNED: rlgl module for automatic render-batch limits checking + - REDESIGNED: rshapes module to minimize the rlgl dependency Detailed changes: [core] ADDED: RAYLIB_VERSION_* values to raylib.h (#2856) by @RobLoach @@ -122,8 +122,11 @@ Detailed changes: [multi] REVIEWED: Grammar mistakes and typos (#2914) by @stickM4N [multi] REVIEWED: Use TRACELOG() macro instead of TraceLog() in internal modules (#2881) by @RobLoach [examples] ADDED: textures_textured_curve (#2821) by @JeffM2501 +[examples] ADDED: models_draw_cube_texture +[examples] ADDED: models_loading_m3d (#2648) by @bztsrc [examples] ADDED: shaders_write_depth (#2836) by @BugraAlptekinSari [examples] ADDED: shaders_hybrid_render (#2919) by @BugraAlptekinSari +[examples] REMOVED: audio_multichannel_sound [examples] RENAMED: Several shaders for naming consistency (#2707) [examples] RENAMED: lighting_instanced.fs to lighting_instancing.fs (glsl100) (#2805) by @gtrxAC [examples] REVIEWED: core_custom_logging.c (#2692) by @hartmannathan From 975c70d2b790cab053ca2d5fa84e42809a4aeeee Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 14 Mar 2023 13:06:17 +0100 Subject: [PATCH 173/192] 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 66a34964524f..86208de4c7f7 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -1,6 +1,6 @@ /********************************************************************************************** * -* rlgl v4.2 - A multi-OpenGL abstraction layer with an immediate-mode style API +* rlgl v4.5 - A multi-OpenGL abstraction layer with an immediate-mode style API * * An abstraction layer for multiple OpenGL versions (1.1, 2.1, 3.3 Core, 4.3 Core, ES 2.0) * that provides a pseudo-OpenGL 1.1 immediate-mode style API (rlVertex, rlTranslate, rlRotate...) @@ -106,7 +106,7 @@ #ifndef RLGL_H #define RLGL_H -#define RLGL_VERSION "4.2" +#define RLGL_VERSION "4.5" // 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 From 2b9ef7d15c532e89b8a1b15f699b030acfdcda73 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 14 Mar 2023 13:06:22 +0100 Subject: [PATCH 174/192] Update ROADMAP.md --- ROADMAP.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 4c7c965e9529..61c6b56e30d8 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -12,10 +12,12 @@ Here it is a wishlist with features and ideas to improve the library. Note that _Current version of raylib is complete and functional but there is always room for improvements._ **raylib 4.x** - - [x] Redesign camera module (more flexible) ([#1143](https://github.com/raysan5/raylib/issues/1143), https://github.com/raysan5/raylib/discussions/2507) + - [ ] Split core module into separate platforms? + - [ ] Basic 2d software renderer, using `Image` provided API - [ ] Redesign gestures system, improve touch inputs management - - [ ] Redesign raudio module, implement miniaudio high-level provided features - - [x] Better documentation and improved examples + - [ ] Redesign audio module, implement miniaudio high-level provided features + - [x] Redesign camera module (more flexible) ([#1143](https://github.com/raysan5/raylib/issues/1143), https://github.com/raysan5/raylib/discussions/2507) + - [x] Better documentation and improved examples, reviewed webpage with examples complexity level - [x] Focus on HTML5 ([raylib 5k gamejam](https://itch.io/jam/raylib-5k-gamejam)) and embedded platforms (RPI and similar SOCs) - [x] Additional support libraries: [raygui](https://github.com/raysan5/raygui), [rres](https://github.com/raysan5/rres) From 7ac2b4a226f2bba358f62dc0f680131aad88ed45 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 14 Mar 2023 13:07:24 +0100 Subject: [PATCH 175/192] Update HISTORY.md --- HISTORY.md | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/HISTORY.md b/HISTORY.md index 0b722b1a3a32..253a94c90c7a 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -409,4 +409,26 @@ Some numbers for this release: - **+40** functions REVIEWED/REDESIGNED - **+40** new contributors (for a TOTAL of **405**!) --WIP- +Highlights for `raylib 4.5`: + + - **`NEW` Improved ANGLE support on Desktop platforms**: Support for OpenGL ES 2.0 on Desktop platforms (Windows, Linux, macOS) has been reviewed by @wtnbgo GitHub user. Now raylib can be compiled on desktop for OpenGL ES 2.0 and linked against [`ANGLE`](). This _small_ addition open the door to building raylib for all **ANGLE supported backends: Direct3D 11, Vulkan and Metal**. Please note that this new feature is still experimental and requires further testing! + + - **`NEW` Camera module**: A brand new implementation from scratch for `rcamera` module, contributed by @Crydsch GitHub user! **New camera system is simpler, more flexible, more granular and more extendable**. Specific camera math transformations (movement/rotation) have been moved to individual functions, exposing them to users if required. Global state has been removed from the module and standalone usage has been greatly improved; now `rcamera.h` single-file header-only library can be used externally, independently of raylib. A new `UpdateCameraPro()` function has been added to address input-dependency of `UpdateCamera()`, now advance users have **full control over camera inputs and movement/rotation speeds**! + + - **`NEW` Support for M3D models and M3D/GLTF animations**: 3d models animations support has been a limited aspect of raylib for long time, some versions ago IQM animations were supported but raylib 4.5 also adds support for the brand new [M3D file format](), including animations and the long expected support for **GLTF animations**! The new M3D file format is **simple, portable, feature complete, extensible and open source**. It also provides a complete set of tools to export/visualize M3D models from/to Blender! Now raylib supports up to **3 model file-formats with animations**: `IQM`, `GLTF` and `M3D`. + + - **`NEW` Support QOA audio format (import/export)**: Just a couple of months ago the new [QOA file format]() was published, a very simple, portable and open source quite-ok-audio file format. raylib already supports it, added to `raudio` module and including audio loading from file, loading from memory, streaming from file, streaming from memory and **exporting to QOA** audio format. **Because simplicity really matters to raylib!** + + - **`NEW` Module for compressed textures loading**: `rl_gputex.h`, a portable single-file header-only small library to load compressed texture file-formats (DDS, PKM, KTX, PVR, ASTC). Provided functionality is not new to raylib but it was part of the raylib `rtextures` module, now it has been moved into a separate self-contained library, **improving portability**. Note that this module is only intended to **load compressed data from files, ready to be uploaded to GPU**, no compression/decompression functionality is provided. This change is a first step towards a better modularization of raylib library. + + - **Reviewed `rlgl` module for automatic limits checking**: Again, [`rlgl`]() has been reviewed to simplify usage. Now users do not need to worry about reaching the internal render-batch limits when they send their triangles to draw 2d/3d, `rlgl` manages it automatically! This change allows a **great simplification for other modules** like `rshapes`, `rtextures` and `rmodels` that do not need to worry about bufffer overflows and can just define as many vertex as desired! + + - **Reviewed `rshapes` module to minimize the rlgl dependency**: Now `rshapes` 2d shapes drawing functions **only depend on 6 low-level functions**: `rlBegin()`, `rlEnd()`, `rlVertex3f()`, `rlTexCoord2f()`, `rlNormal3f()`, `rlSetTexture()`. With only those pseudo-OpenGl 1.1 minimal functionality, everything can be drawn! This improvement converts `rshapes` module in a **self-contained, portable shapes-drawing library that can be used independently of raylib**, as far as entry points for those 6 functions are provided by the user. It even allows to be used for software rendering, with the proper backend! + + - **Added data structures validation functions**: Multiple functions have been added by @RobLoach GitHub user to ease the validation of raylib data structures: `IsImageReady()`, `IsTextureReady()`, `IsSoundReady()`... Now users have a simple mechanism to **make sure data has been correctly loaded**, instead of checking internal structure values by themselfs. + +As usual, those are only some highlights but there is much more! New image generators, new color transformation functionality, improved blending support for color/alpha, etc... Make sure to check raylib [CHANGELOG](CHANGELOG) for a detailed list of changes! Please, note that all breaking changes have been flagged with a `WARNING` in the CHANGELOG, specially useful for binding creators! + +**raylib keeps improving one more version** with a special focus on maintainability and sustainability. Always working towards making the library more **simple and easy-to-use**. + +Let's keep **enjoying games/tools/graphics programming!** :) From 3d64598e11ecb9dc8f09440fba49ffbfe460c0d3 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 14 Mar 2023 13:14:19 +0100 Subject: [PATCH 176/192] Update Makefile --- examples/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/Makefile b/examples/Makefile index 04bd14e659f3..cc9ef2395e7f 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -210,7 +210,7 @@ else CFLAGS += -Os endif else - CFLAGS += -s -O2 + CFLAGS += -O2 endif endif From 54ccb18e87645b6330960f1f88d5473f3171904d Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 14 Mar 2023 13:39:33 +0100 Subject: [PATCH 177/192] Update write_depth.fs --- .../shaders/resources/shaders/glsl330/write_depth.fs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/examples/shaders/resources/shaders/glsl330/write_depth.fs b/examples/shaders/resources/shaders/glsl330/write_depth.fs index 88a4113ff698..f0e07beecdb5 100644 --- a/examples/shaders/resources/shaders/glsl330/write_depth.fs +++ b/examples/shaders/resources/shaders/glsl330/write_depth.fs @@ -1,15 +1,20 @@ #version 330 +// Input vertex attributes (from vertex shader) in vec2 fragTexCoord; in vec4 fragColor; +// Input uniform values uniform sampler2D texture0; uniform vec4 colDiffuse; +// Output fragment color +out vec4 finalColor; + void main() { - vec4 texelColor = texture2D(texture0, fragTexCoord); + vec4 texelColor = texture(texture0, fragTexCoord); - gl_FragColor = texelColor*colDiffuse*fragColor; - gl_FragDepth = 1.0 - gl_FragCoord.z; + finalColor = texelColor*colDiffuse*fragColor; + gl_FragDepth = 1.0 - finalColor.z; } From 796d96408bfd6dab9f255d45abc47d22373b6d82 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 14 Mar 2023 14:06:37 +0100 Subject: [PATCH 178/192] Update HISTORY.md --- HISTORY.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index 253a94c90c7a..5ae12c05c241 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -411,23 +411,23 @@ Some numbers for this release: Highlights for `raylib 4.5`: - - **`NEW` Improved ANGLE support on Desktop platforms**: Support for OpenGL ES 2.0 on Desktop platforms (Windows, Linux, macOS) has been reviewed by @wtnbgo GitHub user. Now raylib can be compiled on desktop for OpenGL ES 2.0 and linked against [`ANGLE`](). This _small_ addition open the door to building raylib for all **ANGLE supported backends: Direct3D 11, Vulkan and Metal**. Please note that this new feature is still experimental and requires further testing! + - **`NEW` Improved ANGLE support on Desktop platforms**: Support for OpenGL ES 2.0 on Desktop platforms (Windows, Linux, macOS) has been reviewed by @wtnbgo GitHub user. Now raylib can be compiled on desktop for OpenGL ES 2.0 and linked against [`ANGLE`](https://github.com/google/angle). This _small_ addition open the door to building raylib for all **ANGLE supported backends: Direct3D 11, Vulkan and Metal**. Please note that this new feature is still experimental and requires further testing! - **`NEW` Camera module**: A brand new implementation from scratch for `rcamera` module, contributed by @Crydsch GitHub user! **New camera system is simpler, more flexible, more granular and more extendable**. Specific camera math transformations (movement/rotation) have been moved to individual functions, exposing them to users if required. Global state has been removed from the module and standalone usage has been greatly improved; now `rcamera.h` single-file header-only library can be used externally, independently of raylib. A new `UpdateCameraPro()` function has been added to address input-dependency of `UpdateCamera()`, now advance users have **full control over camera inputs and movement/rotation speeds**! - - **`NEW` Support for M3D models and M3D/GLTF animations**: 3d models animations support has been a limited aspect of raylib for long time, some versions ago IQM animations were supported but raylib 4.5 also adds support for the brand new [M3D file format](), including animations and the long expected support for **GLTF animations**! The new M3D file format is **simple, portable, feature complete, extensible and open source**. It also provides a complete set of tools to export/visualize M3D models from/to Blender! Now raylib supports up to **3 model file-formats with animations**: `IQM`, `GLTF` and `M3D`. + - **`NEW` Support for M3D models and M3D/GLTF animations**: 3d models animations support has been a limited aspect of raylib for long time, some versions ago IQM animations were supported but raylib 4.5 also adds support for the brand new [M3D file format](https://bztsrc.gitlab.io/model3d/), including animations and the long expected support for **GLTF animations**! The new M3D file format is **simple, portable, feature complete, extensible and open source**. It also provides a complete set of tools to export/visualize M3D models from/to Blender! Now raylib supports up to **3 model file-formats with animations**: `IQM`, `GLTF` and `M3D`. - - **`NEW` Support QOA audio format (import/export)**: Just a couple of months ago the new [QOA file format]() was published, a very simple, portable and open source quite-ok-audio file format. raylib already supports it, added to `raudio` module and including audio loading from file, loading from memory, streaming from file, streaming from memory and **exporting to QOA** audio format. **Because simplicity really matters to raylib!** + - **`NEW` Support QOA audio format (import/export)**: Just a couple of months ago the new [QOA file format](https://qoaformat.org/) was published, a very simple, portable and open source quite-ok-audio file format. raylib already supports it, added to `raudio` module and including audio loading from file, loading from memory, streaming from file, streaming from memory and **exporting to QOA** audio format. **Because simplicity really matters to raylib!** - - **`NEW` Module for compressed textures loading**: `rl_gputex.h`, a portable single-file header-only small library to load compressed texture file-formats (DDS, PKM, KTX, PVR, ASTC). Provided functionality is not new to raylib but it was part of the raylib `rtextures` module, now it has been moved into a separate self-contained library, **improving portability**. Note that this module is only intended to **load compressed data from files, ready to be uploaded to GPU**, no compression/decompression functionality is provided. This change is a first step towards a better modularization of raylib library. + - **`NEW` Module for compressed textures loading**: [`rl_gputex`](https://github.com/raysan5/raylib/blob/master/src/external/rl_gputex.h), a portable single-file header-only small library to load compressed texture file-formats (DDS, PKM, KTX, PVR, ASTC). Provided functionality is not new to raylib but it was part of the raylib `rtextures` module, now it has been moved into a separate self-contained library, **improving portability**. Note that this module is only intended to **load compressed data from files, ready to be uploaded to GPU**, no compression/decompression functionality is provided. This change is a first step towards a better modularization of raylib library. - - **Reviewed `rlgl` module for automatic limits checking**: Again, [`rlgl`]() has been reviewed to simplify usage. Now users do not need to worry about reaching the internal render-batch limits when they send their triangles to draw 2d/3d, `rlgl` manages it automatically! This change allows a **great simplification for other modules** like `rshapes`, `rtextures` and `rmodels` that do not need to worry about bufffer overflows and can just define as many vertex as desired! + - **Reviewed `rlgl` module for automatic limits checking**: Again, [`rlgl`](https://github.com/raysan5/raylib/blob/master/src/rlgl.h) has been reviewed to simplify usage. Now users do not need to worry about reaching the internal render-batch limits when they send their triangles to draw 2d/3d, `rlgl` manages it automatically! This change allows a **great simplification for other modules** like `rshapes`, `rtextures` and `rmodels` that do not need to worry about bufffer overflows and can just define as many vertex as desired! - **Reviewed `rshapes` module to minimize the rlgl dependency**: Now `rshapes` 2d shapes drawing functions **only depend on 6 low-level functions**: `rlBegin()`, `rlEnd()`, `rlVertex3f()`, `rlTexCoord2f()`, `rlNormal3f()`, `rlSetTexture()`. With only those pseudo-OpenGl 1.1 minimal functionality, everything can be drawn! This improvement converts `rshapes` module in a **self-contained, portable shapes-drawing library that can be used independently of raylib**, as far as entry points for those 6 functions are provided by the user. It even allows to be used for software rendering, with the proper backend! - **Added data structures validation functions**: Multiple functions have been added by @RobLoach GitHub user to ease the validation of raylib data structures: `IsImageReady()`, `IsTextureReady()`, `IsSoundReady()`... Now users have a simple mechanism to **make sure data has been correctly loaded**, instead of checking internal structure values by themselfs. -As usual, those are only some highlights but there is much more! New image generators, new color transformation functionality, improved blending support for color/alpha, etc... Make sure to check raylib [CHANGELOG](CHANGELOG) for a detailed list of changes! Please, note that all breaking changes have been flagged with a `WARNING` in the CHANGELOG, specially useful for binding creators! +As usual, those are only some highlights but there is much more! New image generators, new color transformation functionality, improved blending support for color/alpha, etc... Make sure to check raylib [CHANGELOG]([CHANGELOG](https://github.com/raysan5/raylib/blob/master/CHANGELOG)) for a detailed list of changes! Please, note that all breaking changes have been flagged with a `WARNING` in the CHANGELOG, specially useful for binding creators! **raylib keeps improving one more version** with a special focus on maintainability and sustainability. Always working towards making the library more **simple and easy-to-use**. From cf04425bc2afcf8da998d8c5d24a320cf8a076bb Mon Sep 17 00:00:00 2001 From: veins1 <19636663+veins1@users.noreply.github.com> Date: Tue, 14 Mar 2023 23:23:17 +0500 Subject: [PATCH 179/192] Spelling (#2957) --- src/raudio.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/raudio.c b/src/raudio.c index 4bdbede9ebe0..d7ee183a882d 100644 --- a/src/raudio.c +++ b/src/raudio.c @@ -1790,9 +1790,9 @@ void UpdateMusicStream(Music music) { while (true) { - int frameCountRed = (int)drwav_read_pcm_frames_s16((drwav *)music.ctxData, frameCountStillNeeded, (short *)((char *)AUDIO.System.pcmBuffer + frameCountReadTotal*frameSize)); - frameCountReadTotal += frameCountRed; - frameCountStillNeeded -= frameCountRed; + int frameCountRead = (int)drwav_read_pcm_frames_s16((drwav *)music.ctxData, frameCountStillNeeded, (short *)((char *)AUDIO.System.pcmBuffer + frameCountReadTotal*frameSize)); + frameCountReadTotal += frameCountRead; + frameCountStillNeeded -= frameCountRead; if (frameCountStillNeeded == 0) break; else drwav_seek_to_first_pcm_frame((drwav *)music.ctxData); } @@ -1801,9 +1801,9 @@ void UpdateMusicStream(Music music) { while (true) { - int frameCountRed = (int)drwav_read_pcm_frames_f32((drwav *)music.ctxData, frameCountStillNeeded, (float *)((char *)AUDIO.System.pcmBuffer + frameCountReadTotal*frameSize)); - frameCountReadTotal += frameCountRed; - frameCountStillNeeded -= frameCountRed; + int frameCountRead = (int)drwav_read_pcm_frames_f32((drwav *)music.ctxData, frameCountStillNeeded, (float *)((char *)AUDIO.System.pcmBuffer + frameCountReadTotal*frameSize)); + frameCountReadTotal += frameCountRead; + frameCountStillNeeded -= frameCountRead; if (frameCountStillNeeded == 0) break; else drwav_seek_to_first_pcm_frame((drwav *)music.ctxData); } @@ -1815,9 +1815,9 @@ void UpdateMusicStream(Music music) { while (true) { - int frameCountRed = stb_vorbis_get_samples_short_interleaved((stb_vorbis *)music.ctxData, music.stream.channels, (short *)((char *)AUDIO.System.pcmBuffer + frameCountReadTotal*frameSize), frameCountStillNeeded*music.stream.channels); - frameCountReadTotal += frameCountRed; - frameCountStillNeeded -= frameCountRed; + int frameCountRead = stb_vorbis_get_samples_short_interleaved((stb_vorbis *)music.ctxData, music.stream.channels, (short *)((char *)AUDIO.System.pcmBuffer + frameCountReadTotal*frameSize), frameCountStillNeeded*music.stream.channels); + frameCountReadTotal += frameCountRead; + frameCountStillNeeded -= frameCountRead; if (frameCountStillNeeded == 0) break; else stb_vorbis_seek_start((stb_vorbis *)music.ctxData); } From ad2067340ffd601873b8c0d658a16e1ef3a98624 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 15 Mar 2023 13:03:55 +0100 Subject: [PATCH 180/192] REVIEWED: `TraceLog()`, avoid possible buffer overflow --- src/utils.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/utils.c b/src/utils.c index 6843bd946e68..771271d357aa 100644 --- a/src/utils.c +++ b/src/utils.c @@ -54,7 +54,7 @@ // Defines and Macros //---------------------------------------------------------------------------------- #ifndef MAX_TRACELOG_MSG_LENGTH - #define MAX_TRACELOG_MSG_LENGTH 128 // Max length of one trace-log message + #define MAX_TRACELOG_MSG_LENGTH 256 // Max length of one trace-log message #endif //---------------------------------------------------------------------------------- @@ -145,7 +145,8 @@ void TraceLog(int logType, const char *text, ...) default: break; } - strcat(buffer, text); + unsigned int textSize = strlen(text); + memcpy(buffer + strlen(buffer), text, (textSize < (MAX_TRACELOG_MSG_LENGTH - 12))? textSize : (MAX_TRACELOG_MSG_LENGTH - 12)); strcat(buffer, "\n"); vprintf(buffer, args); fflush(stdout); From 159e6b6f247beb7164e5e3e8c1ea61d52fc7a2f9 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 15 Mar 2023 13:13:48 +0100 Subject: [PATCH 181/192] UPDATED: raylib-parser output files (TXT, XML, JSON, LUA) --- parser/output/raylib_api.json | 592 ++++++++------- parser/output/raylib_api.lua | 361 +++++---- parser/output/raylib_api.txt | 1288 +++++++++++++++++---------------- parser/output/raylib_api.xml | 184 ++--- 4 files changed, 1319 insertions(+), 1106 deletions(-) diff --git a/parser/output/raylib_api.json b/parser/output/raylib_api.json index d9a548128b8d..62d9f4401050 100644 --- a/parser/output/raylib_api.json +++ b/parser/output/raylib_api.json @@ -6,10 +6,28 @@ "value": "", "description": "" }, + { + "name": "RAYLIB_VERSION_MAJOR", + "type": "INT", + "value": 4, + "description": "" + }, + { + "name": "RAYLIB_VERSION_MINOR", + "type": "INT", + "value": 5, + "description": "" + }, + { + "name": "RAYLIB_VERSION_PATCH", + "type": "INT", + "value": 0, + "description": "" + }, { "name": "RAYLIB_VERSION", "type": "STRING", - "value": "4.5-dev", + "value": "4.5", "description": "" }, { @@ -385,7 +403,7 @@ }, { "name": "Matrix", - "description": "Matrix, 4x4 components, column major, OpenGL style, right handed", + "description": "Matrix, 4x4 components, column major, OpenGL style, right-handed", "fields": [ { "type": "float", @@ -1045,12 +1063,12 @@ { "type": "float", "name": "distance", - "description": "Distance to nearest hit" + "description": "Distance to the nearest hit" }, { "type": "Vector3", "name": "point", - "description": "Point of nearest hit" + "description": "Point of the nearest hit" }, { "type": "Vector3", @@ -2112,7 +2130,7 @@ { "name": "MOUSE_CURSOR_RESIZE_ALL", "value": 9, - "description": "The omni-directional resize/move cursor shape" + "description": "The omnidirectional resize/move cursor shape" }, { "name": "MOUSE_CURSOR_NOT_ALLOWED", @@ -2717,7 +2735,7 @@ { "name": "CUBEMAP_LAYOUT_LINE_HORIZONTAL", "value": 2, - "description": "Layout is defined by an horizontal line with faces" + "description": "Layout is defined by a horizontal line with faces" }, { "name": "CUBEMAP_LAYOUT_CROSS_THREE_BY_FOUR", @@ -2732,7 +2750,7 @@ { "name": "CUBEMAP_LAYOUT_PANORAMA", "value": 5, - "description": "Layout is defined by a panorama image (equirectangular map)" + "description": "Layout is defined by a panorama image (equirrectangular map)" } ] }, @@ -2794,12 +2812,12 @@ { "name": "BLEND_CUSTOM", "value": 6, - "description": "Blend textures using custom src/dst factors (use rlSetBlendMode())" + "description": "Blend textures using custom src/dst factors (use rlSetBlendFactors())" }, { "name": "BLEND_CUSTOM_SEPARATE", "value": 7, - "description": "Blend textures using custom rgb/alpha separate src/dst factors (use rlSetBlendModeSeparate())" + "description": "Blend textures using custom rgb/alpha separate src/dst factors (use rlSetBlendFactorsSeparate())" } ] }, @@ -3149,7 +3167,7 @@ }, { "name": "SetWindowIcon", - "description": "Set icon for window (only PLATFORM_DESKTOP)", + "description": "Set icon for window (single image, RGBA 32bit, only PLATFORM_DESKTOP)", "returnType": "void", "params": [ { @@ -3158,6 +3176,21 @@ } ] }, + { + "name": "SetWindowIcons", + "description": "Set icon for window (multiple images, RGBA 32bit, only PLATFORM_DESKTOP)", + "returnType": "void", + "params": [ + { + "type": "Image *", + "name": "images" + }, + { + "type": "int", + "name": "count" + } + ] + }, { "name": "SetWindowTitle", "description": "Set title for window (only PLATFORM_DESKTOP)", @@ -3632,6 +3665,17 @@ } ] }, + { + "name": "IsShaderReady", + "description": "Check if a shader is ready", + "returnType": "bool", + "params": [ + { + "type": "Shader", + "name": "shader" + } + ] + }, { "name": "GetShaderLocation", "description": "Get shader uniform location", @@ -4124,7 +4168,7 @@ "returnType": "bool", "params": [ { - "type": "const char *", + "type": "const unsigned char *", "name": "data" }, { @@ -4863,12 +4907,12 @@ "returnType": "float" }, { - "name": "SetCameraMode", - "description": "Set camera mode (multiple camera modes available)", + "name": "UpdateCamera", + "description": "Update camera position for selected mode", "returnType": "void", "params": [ { - "type": "Camera", + "type": "Camera *", "name": "camera" }, { @@ -4878,77 +4922,25 @@ ] }, { - "name": "UpdateCamera", - "description": "Update camera position for selected mode", + "name": "UpdateCameraPro", + "description": "Update camera movement/rotation", "returnType": "void", "params": [ { "type": "Camera *", "name": "camera" - } - ] - }, - { - "name": "SetCameraPanControl", - "description": "Set camera pan key to combine with mouse movement (free camera)", - "returnType": "void", - "params": [ - { - "type": "int", - "name": "keyPan" - } - ] - }, - { - "name": "SetCameraAltControl", - "description": "Set camera alt key to combine with mouse movement (free camera)", - "returnType": "void", - "params": [ - { - "type": "int", - "name": "keyAlt" - } - ] - }, - { - "name": "SetCameraSmoothZoomControl", - "description": "Set camera smooth zoom key to combine with mouse (free camera)", - "returnType": "void", - "params": [ - { - "type": "int", - "name": "keySmoothZoom" - } - ] - }, - { - "name": "SetCameraMoveControls", - "description": "Set camera move controls (1st person and 3rd person cameras)", - "returnType": "void", - "params": [ - { - "type": "int", - "name": "keyFront" - }, - { - "type": "int", - "name": "keyBack" - }, - { - "type": "int", - "name": "keyRight" }, { - "type": "int", - "name": "keyLeft" + "type": "Vector3", + "name": "movement" }, { - "type": "int", - "name": "keyUp" + "type": "Vector3", + "name": "rotation" }, { - "type": "int", - "name": "keyDown" + "type": "float", + "name": "zoom" } ] }, @@ -6172,6 +6164,17 @@ "description": "Load image from screen buffer and (screenshot)", "returnType": "Image" }, + { + "name": "IsImageReady", + "description": "Check if an image is ready", + "returnType": "bool", + "params": [ + { + "type": "Image", + "name": "image" + } + ] + }, { "name": "UnloadImage", "description": "Unload image from CPU memory (RAM)", @@ -6401,6 +6404,25 @@ } ] }, + { + "name": "GenImageText", + "description": "Generate image: grayscale image from text data", + "returnType": "Image", + "params": [ + { + "type": "int", + "name": "width" + }, + { + "type": "int", + "name": "height" + }, + { + "type": "const char *", + "name": "text" + } + ] + }, { "name": "ImageCopy", "description": "Create an image duplicate (useful for transformations)", @@ -6578,6 +6600,21 @@ } ] }, + { + "name": "ImageBlurGaussian", + "description": "Apply Gaussian blur using a box blur approximation", + "returnType": "void", + "params": [ + { + "type": "Image *", + "name": "image" + }, + { + "type": "int", + "name": "blurSize" + } + ] + }, { "name": "ImageResize", "description": "Resize image (Bicubic scaling algorithm)", @@ -7353,6 +7390,17 @@ } ] }, + { + "name": "IsTextureReady", + "description": "Check if a texture is ready", + "returnType": "bool", + "params": [ + { + "type": "Texture2D", + "name": "texture" + } + ] + }, { "name": "UnloadTexture", "description": "Unload texture from GPU memory (VRAM)", @@ -7364,6 +7412,17 @@ } ] }, + { + "name": "IsRenderTextureReady", + "description": "Check if a render texture is ready", + "returnType": "bool", + "params": [ + { + "type": "RenderTexture2D", + "name": "target" + } + ] + }, { "name": "UnloadRenderTexture", "description": "Unload render texture from GPU memory (VRAM)", @@ -7542,68 +7601,6 @@ } ] }, - { - "name": "DrawTextureQuad", - "description": "Draw texture quad with tiling and offset parameters", - "returnType": "void", - "params": [ - { - "type": "Texture2D", - "name": "texture" - }, - { - "type": "Vector2", - "name": "tiling" - }, - { - "type": "Vector2", - "name": "offset" - }, - { - "type": "Rectangle", - "name": "quad" - }, - { - "type": "Color", - "name": "tint" - } - ] - }, - { - "name": "DrawTextureTiled", - "description": "Draw part of a texture (defined by a rectangle) with rotation and scale tiled into dest.", - "returnType": "void", - "params": [ - { - "type": "Texture2D", - "name": "texture" - }, - { - "type": "Rectangle", - "name": "source" - }, - { - "type": "Rectangle", - "name": "dest" - }, - { - "type": "Vector2", - "name": "origin" - }, - { - "type": "float", - "name": "rotation" - }, - { - "type": "float", - "name": "scale" - }, - { - "type": "Color", - "name": "tint" - } - ] - }, { "name": "DrawTexturePro", "description": "Draw a part of a texture defined by a rectangle with 'pro' parameters", @@ -7666,37 +7663,6 @@ } ] }, - { - "name": "DrawTexturePoly", - "description": "Draw a textured polygon", - "returnType": "void", - "params": [ - { - "type": "Texture2D", - "name": "texture" - }, - { - "type": "Vector2", - "name": "center" - }, - { - "type": "Vector2 *", - "name": "points" - }, - { - "type": "Vector2 *", - "name": "texcoords" - }, - { - "type": "int", - "name": "pointCount" - }, - { - "type": "Color", - "name": "tint" - } - ] - }, { "name": "Fade", "description": "Get color with alpha applied, alpha goes from 0.0f to 1.0f", @@ -7775,6 +7741,51 @@ } ] }, + { + "name": "ColorTint", + "description": "Get color multiplied with another color", + "returnType": "Color", + "params": [ + { + "type": "Color", + "name": "color" + }, + { + "type": "Color", + "name": "tint" + } + ] + }, + { + "name": "ColorBrightness", + "description": "Get color with brightness correction, brightness factor goes from -1.0f to 1.0f", + "returnType": "Color", + "params": [ + { + "type": "Color", + "name": "color" + }, + { + "type": "float", + "name": "factor" + } + ] + }, + { + "name": "ColorContrast", + "description": "Get color with contrast correction, contrast values between -1.0f and 1.0f", + "returnType": "Color", + "params": [ + { + "type": "Color", + "name": "color" + }, + { + "type": "float", + "name": "contrast" + } + ] + }, { "name": "ColorAlpha", "description": "Get color with alpha applied, alpha goes from 0.0f to 1.0f", @@ -7962,6 +7973,17 @@ } ] }, + { + "name": "IsFontReady", + "description": "Check if a font is ready", + "returnType": "bool", + "params": [ + { + "type": "Font", + "name": "font" + } + ] + }, { "name": "LoadFontData", "description": "Load font data for further use", @@ -8869,72 +8891,6 @@ } ] }, - { - "name": "DrawCubeTexture", - "description": "Draw cube textured", - "returnType": "void", - "params": [ - { - "type": "Texture2D", - "name": "texture" - }, - { - "type": "Vector3", - "name": "position" - }, - { - "type": "float", - "name": "width" - }, - { - "type": "float", - "name": "height" - }, - { - "type": "float", - "name": "length" - }, - { - "type": "Color", - "name": "color" - } - ] - }, - { - "name": "DrawCubeTextureRec", - "description": "Draw cube with a region of a texture", - "returnType": "void", - "params": [ - { - "type": "Texture2D", - "name": "texture" - }, - { - "type": "Rectangle", - "name": "source" - }, - { - "type": "Vector3", - "name": "position" - }, - { - "type": "float", - "name": "width" - }, - { - "type": "float", - "name": "height" - }, - { - "type": "float", - "name": "length" - }, - { - "type": "Color", - "name": "color" - } - ] - }, { "name": "DrawSphere", "description": "Draw sphere", @@ -9132,6 +9088,68 @@ } ] }, + { + "name": "DrawCapsule", + "description": "Draw a capsule with the center of its sphere caps at startPos and endPos", + "returnType": "void", + "params": [ + { + "type": "Vector3", + "name": "startPos" + }, + { + "type": "Vector3", + "name": "endPos" + }, + { + "type": "float", + "name": "radius" + }, + { + "type": "int", + "name": "slices" + }, + { + "type": "int", + "name": "rings" + }, + { + "type": "Color", + "name": "color" + } + ] + }, + { + "name": "DrawCapsuleWires", + "description": "Draw capsule wireframe with the center of its sphere caps at startPos and endPos", + "returnType": "void", + "params": [ + { + "type": "Vector3", + "name": "startPos" + }, + { + "type": "Vector3", + "name": "endPos" + }, + { + "type": "float", + "name": "radius" + }, + { + "type": "int", + "name": "slices" + }, + { + "type": "int", + "name": "rings" + }, + { + "type": "Color", + "name": "color" + } + ] + }, { "name": "DrawPlane", "description": "Draw a plane XZ", @@ -9204,9 +9222,9 @@ ] }, { - "name": "UnloadModel", - "description": "Unload model (including meshes) from memory (RAM and/or VRAM)", - "returnType": "void", + "name": "IsModelReady", + "description": "Check if a model is ready", + "returnType": "bool", "params": [ { "type": "Model", @@ -9215,8 +9233,8 @@ ] }, { - "name": "UnloadModelKeepMeshes", - "description": "Unload model (but not meshes) from memory (RAM and/or VRAM)", + "name": "UnloadModel", + "description": "Unload model (including meshes) from memory (RAM and/or VRAM)", "returnType": "void", "params": [ { @@ -9821,6 +9839,17 @@ "description": "Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps)", "returnType": "Material" }, + { + "name": "IsMaterialReady", + "description": "Check if a material is ready", + "returnType": "bool", + "params": [ + { + "type": "Material", + "name": "material" + } + ] + }, { "name": "UnloadMaterial", "description": "Unload material from GPU memory (VRAM)", @@ -10161,6 +10190,17 @@ } ] }, + { + "name": "IsWaveReady", + "description": "Checks if wave data is ready", + "returnType": "bool", + "params": [ + { + "type": "Wave", + "name": "wave" + } + ] + }, { "name": "LoadSound", "description": "Load sound from file", @@ -10183,6 +10223,17 @@ } ] }, + { + "name": "IsSoundReady", + "description": "Checks if a sound is ready", + "returnType": "bool", + "params": [ + { + "type": "Sound", + "name": "sound" + } + ] + }, { "name": "UpdateSound", "description": "Update sound buffer with new data", @@ -10298,27 +10349,6 @@ } ] }, - { - "name": "PlaySoundMulti", - "description": "Play a sound (using multichannel buffer pool)", - "returnType": "void", - "params": [ - { - "type": "Sound", - "name": "sound" - } - ] - }, - { - "name": "StopSoundMulti", - "description": "Stop any sound playing (using multichannel buffer pool)", - "returnType": "void" - }, - { - "name": "GetSoundsPlaying", - "description": "Get number of sounds playing in the multichannel", - "returnType": "int" - }, { "name": "IsSoundPlaying", "description": "Check if a sound is currently playing", @@ -10480,6 +10510,17 @@ } ] }, + { + "name": "IsMusicReady", + "description": "Checks if a music stream is ready", + "returnType": "bool", + "params": [ + { + "type": "Music", + "name": "music" + } + ] + }, { "name": "UnloadMusicStream", "description": "Unload music stream", @@ -10658,6 +10699,17 @@ } ] }, + { + "name": "IsAudioStreamReady", + "description": "Checks if an audio stream is ready", + "returnType": "bool", + "params": [ + { + "type": "AudioStream", + "name": "stream" + } + ] + }, { "name": "UnloadAudioStream", "description": "Unload audio stream and free memory", @@ -10854,6 +10906,28 @@ "name": "processor" } ] + }, + { + "name": "AttachAudioMixedProcessor", + "description": "Attach audio stream processor to the entire audio pipeline", + "returnType": "void", + "params": [ + { + "type": "AudioCallback", + "name": "processor" + } + ] + }, + { + "name": "DetachAudioMixedProcessor", + "description": "Detach audio stream processor from the entire audio pipeline", + "returnType": "void", + "params": [ + { + "type": "AudioCallback", + "name": "processor" + } + ] } ] } diff --git a/parser/output/raylib_api.lua b/parser/output/raylib_api.lua index a7b68f1c3291..0a1b95856599 100644 --- a/parser/output/raylib_api.lua +++ b/parser/output/raylib_api.lua @@ -6,10 +6,28 @@ return { value = "", description = "" }, + { + name = "RAYLIB_VERSION_MAJOR", + type = "INT", + value = 4, + description = "" + }, + { + name = "RAYLIB_VERSION_MINOR", + type = "INT", + value = 5, + description = "" + }, + { + name = "RAYLIB_VERSION_PATCH", + type = "INT", + value = 0, + description = "" + }, { name = "RAYLIB_VERSION", type = "STRING", - value = "4.5-dev", + value = "4.5", description = "" }, { @@ -385,7 +403,7 @@ return { }, { name = "Matrix", - description = "Matrix, 4x4 components, column major, OpenGL style, right handed", + description = "Matrix, 4x4 components, column major, OpenGL style, right-handed", fields = { { type = "float", @@ -1045,12 +1063,12 @@ return { { type = "float", name = "distance", - description = "Distance to nearest hit" + description = "Distance to the nearest hit" }, { type = "Vector3", name = "point", - description = "Point of nearest hit" + description = "Point of the nearest hit" }, { type = "Vector3", @@ -2112,7 +2130,7 @@ return { { name = "MOUSE_CURSOR_RESIZE_ALL", value = 9, - description = "The omni-directional resize/move cursor shape" + description = "The omnidirectional resize/move cursor shape" }, { name = "MOUSE_CURSOR_NOT_ALLOWED", @@ -2717,7 +2735,7 @@ return { { name = "CUBEMAP_LAYOUT_LINE_HORIZONTAL", value = 2, - description = "Layout is defined by an horizontal line with faces" + description = "Layout is defined by a horizontal line with faces" }, { name = "CUBEMAP_LAYOUT_CROSS_THREE_BY_FOUR", @@ -2732,7 +2750,7 @@ return { { name = "CUBEMAP_LAYOUT_PANORAMA", value = 5, - description = "Layout is defined by a panorama image (equirectangular map)" + description = "Layout is defined by a panorama image (equirrectangular map)" } } }, @@ -2794,12 +2812,12 @@ return { { name = "BLEND_CUSTOM", value = 6, - description = "Blend textures using custom src/dst factors (use rlSetBlendMode())" + description = "Blend textures using custom src/dst factors (use rlSetBlendFactors())" }, { name = "BLEND_CUSTOM_SEPARATE", value = 7, - description = "Blend textures using custom rgb/alpha separate src/dst factors (use rlSetBlendModeSeparate())" + description = "Blend textures using custom rgb/alpha separate src/dst factors (use rlSetBlendFactorsSeparate())" } } }, @@ -3092,12 +3110,21 @@ return { }, { name = "SetWindowIcon", - description = "Set icon for window (only PLATFORM_DESKTOP)", + description = "Set icon for window (single image, RGBA 32bit, only PLATFORM_DESKTOP)", returnType = "void", params = { {type = "Image", name = "image"} } }, + { + name = "SetWindowIcons", + description = "Set icon for window (multiple images, RGBA 32bit, only PLATFORM_DESKTOP)", + returnType = "void", + params = { + {type = "Image *", name = "images"}, + {type = "int", name = "count"} + } + }, { name = "SetWindowTitle", description = "Set title for window (only PLATFORM_DESKTOP)", @@ -3467,6 +3494,14 @@ return { {type = "const char *", name = "fsCode"} } }, + { + name = "IsShaderReady", + description = "Check if a shader is ready", + returnType = "bool", + params = { + {type = "Shader", name = "shader"} + } + }, { name = "GetShaderLocation", description = "Get shader uniform location", @@ -3778,7 +3813,7 @@ return { description = "Export data to code (.h), returns true on success", returnType = "bool", params = { - {type = "const char *", name = "data"}, + {type = "const unsigned char *", name = "data"}, {type = "unsigned int", name = "size"}, {type = "const char *", name = "fileName"} } @@ -4304,58 +4339,24 @@ return { description = "Get gesture pinch angle", returnType = "float" }, - { - name = "SetCameraMode", - description = "Set camera mode (multiple camera modes available)", - returnType = "void", - params = { - {type = "Camera", name = "camera"}, - {type = "int", name = "mode"} - } - }, { name = "UpdateCamera", description = "Update camera position for selected mode", returnType = "void", params = { - {type = "Camera *", name = "camera"} - } - }, - { - name = "SetCameraPanControl", - description = "Set camera pan key to combine with mouse movement (free camera)", - returnType = "void", - params = { - {type = "int", name = "keyPan"} - } - }, - { - name = "SetCameraAltControl", - description = "Set camera alt key to combine with mouse movement (free camera)", - returnType = "void", - params = { - {type = "int", name = "keyAlt"} - } - }, - { - name = "SetCameraSmoothZoomControl", - description = "Set camera smooth zoom key to combine with mouse (free camera)", - returnType = "void", - params = { - {type = "int", name = "keySmoothZoom"} + {type = "Camera *", name = "camera"}, + {type = "int", name = "mode"} } }, { - name = "SetCameraMoveControls", - description = "Set camera move controls (1st person and 3rd person cameras)", + name = "UpdateCameraPro", + description = "Update camera movement/rotation", returnType = "void", params = { - {type = "int", name = "keyFront"}, - {type = "int", name = "keyBack"}, - {type = "int", name = "keyRight"}, - {type = "int", name = "keyLeft"}, - {type = "int", name = "keyUp"}, - {type = "int", name = "keyDown"} + {type = "Camera *", name = "camera"}, + {type = "Vector3", name = "movement"}, + {type = "Vector3", name = "rotation"}, + {type = "float", name = "zoom"} } }, { @@ -4945,6 +4946,14 @@ return { description = "Load image from screen buffer and (screenshot)", returnType = "Image" }, + { + name = "IsImageReady", + description = "Check if an image is ready", + returnType = "bool", + params = { + {type = "Image", name = "image"} + } + }, { name = "UnloadImage", description = "Unload image from CPU memory (RAM)", @@ -5060,6 +5069,16 @@ return { {type = "int", name = "tileSize"} } }, + { + name = "GenImageText", + description = "Generate image: grayscale image from text data", + returnType = "Image", + params = { + {type = "int", name = "width"}, + {type = "int", name = "height"}, + {type = "const char *", name = "text"} + } + }, { name = "ImageCopy", description = "Create an image duplicate (useful for transformations)", @@ -5162,6 +5181,15 @@ return { {type = "Image *", name = "image"} } }, + { + name = "ImageBlurGaussian", + description = "Apply Gaussian blur using a box blur approximation", + returnType = "void", + params = { + {type = "Image *", name = "image"}, + {type = "int", name = "blurSize"} + } + }, { name = "ImageResize", description = "Resize image (Bicubic scaling algorithm)", @@ -5571,6 +5599,14 @@ return { {type = "int", name = "height"} } }, + { + name = "IsTextureReady", + description = "Check if a texture is ready", + returnType = "bool", + params = { + {type = "Texture2D", name = "texture"} + } + }, { name = "UnloadTexture", description = "Unload texture from GPU memory (VRAM)", @@ -5579,6 +5615,14 @@ return { {type = "Texture2D", name = "texture"} } }, + { + name = "IsRenderTextureReady", + description = "Check if a render texture is ready", + returnType = "bool", + params = { + {type = "RenderTexture2D", name = "target"} + } + }, { name = "UnloadRenderTexture", description = "Unload render texture from GPU memory (VRAM)", @@ -5676,32 +5720,6 @@ return { {type = "Color", name = "tint"} } }, - { - name = "DrawTextureQuad", - description = "Draw texture quad with tiling and offset parameters", - returnType = "void", - params = { - {type = "Texture2D", name = "texture"}, - {type = "Vector2", name = "tiling"}, - {type = "Vector2", name = "offset"}, - {type = "Rectangle", name = "quad"}, - {type = "Color", name = "tint"} - } - }, - { - name = "DrawTextureTiled", - description = "Draw part of a texture (defined by a rectangle) with rotation and scale tiled into dest.", - returnType = "void", - params = { - {type = "Texture2D", name = "texture"}, - {type = "Rectangle", name = "source"}, - {type = "Rectangle", name = "dest"}, - {type = "Vector2", name = "origin"}, - {type = "float", name = "rotation"}, - {type = "float", name = "scale"}, - {type = "Color", name = "tint"} - } - }, { name = "DrawTexturePro", description = "Draw a part of a texture defined by a rectangle with 'pro' parameters", @@ -5728,19 +5746,6 @@ return { {type = "Color", name = "tint"} } }, - { - name = "DrawTexturePoly", - description = "Draw a textured polygon", - returnType = "void", - params = { - {type = "Texture2D", name = "texture"}, - {type = "Vector2", name = "center"}, - {type = "Vector2 *", name = "points"}, - {type = "Vector2 *", name = "texcoords"}, - {type = "int", name = "pointCount"}, - {type = "Color", name = "tint"} - } - }, { name = "Fade", description = "Get color with alpha applied, alpha goes from 0.0f to 1.0f", @@ -5792,6 +5797,33 @@ return { {type = "float", name = "value"} } }, + { + name = "ColorTint", + description = "Get color multiplied with another color", + returnType = "Color", + params = { + {type = "Color", name = "color"}, + {type = "Color", name = "tint"} + } + }, + { + name = "ColorBrightness", + description = "Get color with brightness correction, brightness factor goes from -1.0f to 1.0f", + returnType = "Color", + params = { + {type = "Color", name = "color"}, + {type = "float", name = "factor"} + } + }, + { + name = "ColorContrast", + description = "Get color with contrast correction, contrast values between -1.0f and 1.0f", + returnType = "Color", + params = { + {type = "Color", name = "color"}, + {type = "float", name = "contrast"} + } + }, { name = "ColorAlpha", description = "Get color with alpha applied, alpha goes from 0.0f to 1.0f", @@ -5895,6 +5927,14 @@ return { {type = "int", name = "glyphCount"} } }, + { + name = "IsFontReady", + description = "Check if a font is ready", + returnType = "bool", + params = { + {type = "Font", name = "font"} + } + }, { name = "LoadFontData", description = "Load font data for further use", @@ -6379,33 +6419,6 @@ return { {type = "Color", name = "color"} } }, - { - name = "DrawCubeTexture", - description = "Draw cube textured", - returnType = "void", - params = { - {type = "Texture2D", name = "texture"}, - {type = "Vector3", name = "position"}, - {type = "float", name = "width"}, - {type = "float", name = "height"}, - {type = "float", name = "length"}, - {type = "Color", name = "color"} - } - }, - { - name = "DrawCubeTextureRec", - description = "Draw cube with a region of a texture", - returnType = "void", - params = { - {type = "Texture2D", name = "texture"}, - {type = "Rectangle", name = "source"}, - {type = "Vector3", name = "position"}, - {type = "float", name = "width"}, - {type = "float", name = "height"}, - {type = "float", name = "length"}, - {type = "Color", name = "color"} - } - }, { name = "DrawSphere", description = "Draw sphere", @@ -6492,6 +6505,32 @@ return { {type = "Color", name = "color"} } }, + { + name = "DrawCapsule", + description = "Draw a capsule with the center of its sphere caps at startPos and endPos", + returnType = "void", + params = { + {type = "Vector3", name = "startPos"}, + {type = "Vector3", name = "endPos"}, + {type = "float", name = "radius"}, + {type = "int", name = "slices"}, + {type = "int", name = "rings"}, + {type = "Color", name = "color"} + } + }, + { + name = "DrawCapsuleWires", + description = "Draw capsule wireframe with the center of its sphere caps at startPos and endPos", + returnType = "void", + params = { + {type = "Vector3", name = "startPos"}, + {type = "Vector3", name = "endPos"}, + {type = "float", name = "radius"}, + {type = "int", name = "slices"}, + {type = "int", name = "rings"}, + {type = "Color", name = "color"} + } + }, { name = "DrawPlane", description = "Draw a plane XZ", @@ -6537,16 +6576,16 @@ return { } }, { - name = "UnloadModel", - description = "Unload model (including meshes) from memory (RAM and/or VRAM)", - returnType = "void", + name = "IsModelReady", + description = "Check if a model is ready", + returnType = "bool", params = { {type = "Model", name = "model"} } }, { - name = "UnloadModelKeepMeshes", - description = "Unload model (but not meshes) from memory (RAM and/or VRAM)", + name = "UnloadModel", + description = "Unload model (including meshes) from memory (RAM and/or VRAM)", returnType = "void", params = { {type = "Model", name = "model"} @@ -6857,6 +6896,14 @@ return { description = "Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps)", returnType = "Material" }, + { + name = "IsMaterialReady", + description = "Check if a material is ready", + returnType = "bool", + params = { + {type = "Material", name = "material"} + } + }, { name = "UnloadMaterial", description = "Unload material from GPU memory (VRAM)", @@ -7053,6 +7100,14 @@ return { {type = "int", name = "dataSize"} } }, + { + name = "IsWaveReady", + description = "Checks if wave data is ready", + returnType = "bool", + params = { + {type = "Wave", name = "wave"} + } + }, { name = "LoadSound", description = "Load sound from file", @@ -7069,6 +7124,14 @@ return { {type = "Wave", name = "wave"} } }, + { + name = "IsSoundReady", + description = "Checks if a sound is ready", + returnType = "bool", + params = { + {type = "Sound", name = "sound"} + } + }, { name = "UpdateSound", description = "Update sound buffer with new data", @@ -7145,24 +7208,6 @@ return { {type = "Sound", name = "sound"} } }, - { - name = "PlaySoundMulti", - description = "Play a sound (using multichannel buffer pool)", - returnType = "void", - params = { - {type = "Sound", name = "sound"} - } - }, - { - name = "StopSoundMulti", - description = "Stop any sound playing (using multichannel buffer pool)", - returnType = "void" - }, - { - name = "GetSoundsPlaying", - description = "Get number of sounds playing in the multichannel", - returnType = "int" - }, { name = "IsSoundPlaying", description = "Check if a sound is currently playing", @@ -7261,6 +7306,14 @@ return { {type = "int", name = "dataSize"} } }, + { + name = "IsMusicReady", + description = "Checks if a music stream is ready", + returnType = "bool", + params = { + {type = "Music", name = "music"} + } + }, { name = "UnloadMusicStream", description = "Unload music stream", @@ -7379,6 +7432,14 @@ return { {type = "unsigned int", name = "channels"} } }, + { + name = "IsAudioStreamReady", + description = "Checks if an audio stream is ready", + returnType = "bool", + params = { + {type = "AudioStream", name = "stream"} + } + }, { name = "UnloadAudioStream", description = "Unload audio stream and free memory", @@ -7506,6 +7567,22 @@ return { {type = "AudioStream", name = "stream"}, {type = "AudioCallback", name = "processor"} } + }, + { + name = "AttachAudioMixedProcessor", + description = "Attach audio stream processor to the entire audio pipeline", + returnType = "void", + params = { + {type = "AudioCallback", name = "processor"} + } + }, + { + name = "DetachAudioMixedProcessor", + description = "Detach audio stream processor from the entire audio pipeline", + returnType = "void", + params = { + {type = "AudioCallback", name = "processor"} + } } } } diff --git a/parser/output/raylib_api.txt b/parser/output/raylib_api.txt index c53e292d0b2a..4b13bc3b4e52 100644 --- a/parser/output/raylib_api.txt +++ b/parser/output/raylib_api.txt @@ -1,267 +1,282 @@ -Defines found: 53 +Defines found: 56 Define 001: RAYLIB_H Name: RAYLIB_H Type: GUARD Value: Description: -Define 002: RAYLIB_VERSION +Define 002: RAYLIB_VERSION_MAJOR + Name: RAYLIB_VERSION_MAJOR + Type: INT + Value: 4 + Description: +Define 003: RAYLIB_VERSION_MINOR + Name: RAYLIB_VERSION_MINOR + Type: INT + Value: 5 + Description: +Define 004: RAYLIB_VERSION_PATCH + Name: RAYLIB_VERSION_PATCH + Type: INT + Value: 0 + Description: +Define 005: RAYLIB_VERSION Name: RAYLIB_VERSION Type: STRING - Value: "4.5-dev" + Value: "4.5" Description: -Define 003: __declspec(x) +Define 006: __declspec(x) Name: __declspec(x) Type: MACRO Value: __attribute__((x)) Description: -Define 004: RLAPI +Define 007: RLAPI Name: RLAPI Type: UNKNOWN Value: __declspec(dllexport) Description: We are building the library as a Win32 shared library (.dll) -Define 005: PI +Define 008: PI Name: PI Type: FLOAT Value: 3.14159265358979323846 Description: -Define 006: DEG2RAD +Define 009: DEG2RAD Name: DEG2RAD Type: FLOAT_MATH Value: (PI/180.0f) Description: -Define 007: RAD2DEG +Define 010: RAD2DEG Name: RAD2DEG Type: FLOAT_MATH Value: (180.0f/PI) Description: -Define 008: RL_MALLOC(sz) +Define 011: RL_MALLOC(sz) Name: RL_MALLOC(sz) Type: MACRO Value: malloc(sz) Description: -Define 009: RL_CALLOC(n,sz) +Define 012: RL_CALLOC(n,sz) Name: RL_CALLOC(n,sz) Type: MACRO Value: calloc(n,sz) Description: -Define 010: RL_REALLOC(ptr,sz) +Define 013: RL_REALLOC(ptr,sz) Name: RL_REALLOC(ptr,sz) Type: MACRO Value: realloc(ptr,sz) Description: -Define 011: RL_FREE(ptr) +Define 014: RL_FREE(ptr) Name: RL_FREE(ptr) Type: MACRO Value: free(ptr) Description: -Define 012: CLITERAL(type) +Define 015: CLITERAL(type) Name: CLITERAL(type) Type: MACRO Value: type Description: -Define 013: RL_COLOR_TYPE +Define 016: RL_COLOR_TYPE Name: RL_COLOR_TYPE Type: GUARD Value: Description: -Define 014: RL_RECTANGLE_TYPE +Define 017: RL_RECTANGLE_TYPE Name: RL_RECTANGLE_TYPE Type: GUARD Value: Description: -Define 015: RL_VECTOR2_TYPE +Define 018: RL_VECTOR2_TYPE Name: RL_VECTOR2_TYPE Type: GUARD Value: Description: -Define 016: RL_VECTOR3_TYPE +Define 019: RL_VECTOR3_TYPE Name: RL_VECTOR3_TYPE Type: GUARD Value: Description: -Define 017: RL_VECTOR4_TYPE +Define 020: RL_VECTOR4_TYPE Name: RL_VECTOR4_TYPE Type: GUARD Value: Description: -Define 018: RL_QUATERNION_TYPE +Define 021: RL_QUATERNION_TYPE Name: RL_QUATERNION_TYPE Type: GUARD Value: Description: -Define 019: RL_MATRIX_TYPE +Define 022: RL_MATRIX_TYPE Name: RL_MATRIX_TYPE Type: GUARD Value: Description: -Define 020: LIGHTGRAY +Define 023: LIGHTGRAY Name: LIGHTGRAY Type: COLOR Value: CLITERAL(Color){ 200, 200, 200, 255 } Description: Light Gray -Define 021: GRAY +Define 024: GRAY Name: GRAY Type: COLOR Value: CLITERAL(Color){ 130, 130, 130, 255 } Description: Gray -Define 022: DARKGRAY +Define 025: DARKGRAY Name: DARKGRAY Type: COLOR Value: CLITERAL(Color){ 80, 80, 80, 255 } Description: Dark Gray -Define 023: YELLOW +Define 026: YELLOW Name: YELLOW Type: COLOR Value: CLITERAL(Color){ 253, 249, 0, 255 } Description: Yellow -Define 024: GOLD +Define 027: GOLD Name: GOLD Type: COLOR Value: CLITERAL(Color){ 255, 203, 0, 255 } Description: Gold -Define 025: ORANGE +Define 028: ORANGE Name: ORANGE Type: COLOR Value: CLITERAL(Color){ 255, 161, 0, 255 } Description: Orange -Define 026: PINK +Define 029: PINK Name: PINK Type: COLOR Value: CLITERAL(Color){ 255, 109, 194, 255 } Description: Pink -Define 027: RED +Define 030: RED Name: RED Type: COLOR Value: CLITERAL(Color){ 230, 41, 55, 255 } Description: Red -Define 028: MAROON +Define 031: MAROON Name: MAROON Type: COLOR Value: CLITERAL(Color){ 190, 33, 55, 255 } Description: Maroon -Define 029: GREEN +Define 032: GREEN Name: GREEN Type: COLOR Value: CLITERAL(Color){ 0, 228, 48, 255 } Description: Green -Define 030: LIME +Define 033: LIME Name: LIME Type: COLOR Value: CLITERAL(Color){ 0, 158, 47, 255 } Description: Lime -Define 031: DARKGREEN +Define 034: DARKGREEN Name: DARKGREEN Type: COLOR Value: CLITERAL(Color){ 0, 117, 44, 255 } Description: Dark Green -Define 032: SKYBLUE +Define 035: SKYBLUE Name: SKYBLUE Type: COLOR Value: CLITERAL(Color){ 102, 191, 255, 255 } Description: Sky Blue -Define 033: BLUE +Define 036: BLUE Name: BLUE Type: COLOR Value: CLITERAL(Color){ 0, 121, 241, 255 } Description: Blue -Define 034: DARKBLUE +Define 037: DARKBLUE Name: DARKBLUE Type: COLOR Value: CLITERAL(Color){ 0, 82, 172, 255 } Description: Dark Blue -Define 035: PURPLE +Define 038: PURPLE Name: PURPLE Type: COLOR Value: CLITERAL(Color){ 200, 122, 255, 255 } Description: Purple -Define 036: VIOLET +Define 039: VIOLET Name: VIOLET Type: COLOR Value: CLITERAL(Color){ 135, 60, 190, 255 } Description: Violet -Define 037: DARKPURPLE +Define 040: DARKPURPLE Name: DARKPURPLE Type: COLOR Value: CLITERAL(Color){ 112, 31, 126, 255 } Description: Dark Purple -Define 038: BEIGE +Define 041: BEIGE Name: BEIGE Type: COLOR Value: CLITERAL(Color){ 211, 176, 131, 255 } Description: Beige -Define 039: BROWN +Define 042: BROWN Name: BROWN Type: COLOR Value: CLITERAL(Color){ 127, 106, 79, 255 } Description: Brown -Define 040: DARKBROWN +Define 043: DARKBROWN Name: DARKBROWN Type: COLOR Value: CLITERAL(Color){ 76, 63, 47, 255 } Description: Dark Brown -Define 041: WHITE +Define 044: WHITE Name: WHITE Type: COLOR Value: CLITERAL(Color){ 255, 255, 255, 255 } Description: White -Define 042: BLACK +Define 045: BLACK Name: BLACK Type: COLOR Value: CLITERAL(Color){ 0, 0, 0, 255 } Description: Black -Define 043: BLANK +Define 046: BLANK Name: BLANK Type: COLOR Value: CLITERAL(Color){ 0, 0, 0, 0 } Description: Blank (Transparent) -Define 044: MAGENTA +Define 047: MAGENTA Name: MAGENTA Type: COLOR Value: CLITERAL(Color){ 255, 0, 255, 255 } Description: Magenta -Define 045: RAYWHITE +Define 048: RAYWHITE Name: RAYWHITE Type: COLOR Value: CLITERAL(Color){ 245, 245, 245, 255 } Description: My own White (raylib logo) -Define 046: RL_BOOL_TYPE +Define 049: RL_BOOL_TYPE Name: RL_BOOL_TYPE Type: GUARD Value: Description: -Define 047: MOUSE_LEFT_BUTTON +Define 050: MOUSE_LEFT_BUTTON Name: MOUSE_LEFT_BUTTON Type: UNKNOWN Value: MOUSE_BUTTON_LEFT Description: -Define 048: MOUSE_RIGHT_BUTTON +Define 051: MOUSE_RIGHT_BUTTON Name: MOUSE_RIGHT_BUTTON Type: UNKNOWN Value: MOUSE_BUTTON_RIGHT Description: -Define 049: MOUSE_MIDDLE_BUTTON +Define 052: MOUSE_MIDDLE_BUTTON Name: MOUSE_MIDDLE_BUTTON Type: UNKNOWN Value: MOUSE_BUTTON_MIDDLE Description: -Define 050: MATERIAL_MAP_DIFFUSE +Define 053: MATERIAL_MAP_DIFFUSE Name: MATERIAL_MAP_DIFFUSE Type: UNKNOWN Value: MATERIAL_MAP_ALBEDO Description: -Define 051: MATERIAL_MAP_SPECULAR +Define 054: MATERIAL_MAP_SPECULAR Name: MATERIAL_MAP_SPECULAR Type: UNKNOWN Value: MATERIAL_MAP_METALNESS Description: -Define 052: SHADER_LOC_MAP_DIFFUSE +Define 055: SHADER_LOC_MAP_DIFFUSE Name: SHADER_LOC_MAP_DIFFUSE Type: UNKNOWN Value: SHADER_LOC_MAP_ALBEDO Description: -Define 053: SHADER_LOC_MAP_SPECULAR +Define 056: SHADER_LOC_MAP_SPECULAR Name: SHADER_LOC_MAP_SPECULAR Type: UNKNOWN Value: SHADER_LOC_MAP_METALNESS @@ -289,7 +304,7 @@ Struct 03: Vector4 (4 fields) Field[4]: float w // Vector w component Struct 04: Matrix (16 fields) Name: Matrix - Description: Matrix, 4x4 components, column major, OpenGL style, right handed + Description: Matrix, 4x4 components, column major, OpenGL style, right-handed Field[1]: float m0 // Matrix first row (4 components) Field[2]: float m4 // Matrix first row (4 components) Field[3]: float m8 // Matrix first row (4 components) @@ -457,8 +472,8 @@ Struct 24: RayCollision (4 fields) Name: RayCollision Description: RayCollision, ray hit information Field[1]: bool hit // Did the ray hit something? - Field[2]: float distance // Distance to nearest hit - Field[3]: Vector3 point // Point of nearest hit + Field[2]: float distance // Distance to the nearest hit + Field[3]: Vector3 point // Point of the nearest hit Field[4]: Vector3 normal // Surface normal of hit Struct 25: BoundingBox (2 fields) Name: BoundingBox @@ -948,7 +963,7 @@ Callback 006: AudioCallback() (2 input parameters) Param[1]: bufferData (type: void *) Param[2]: frames (type: unsigned int) -Functions found: 509 +Functions found: 517 Function 001: InitWindow() (3 input parameters) Name: InitWindow @@ -1040,252 +1055,258 @@ Function 017: RestoreWindow() (0 input parameters) Function 018: SetWindowIcon() (1 input parameters) Name: SetWindowIcon Return type: void - Description: Set icon for window (only PLATFORM_DESKTOP) + Description: Set icon for window (single image, RGBA 32bit, only PLATFORM_DESKTOP) Param[1]: image (type: Image) -Function 019: SetWindowTitle() (1 input parameters) +Function 019: SetWindowIcons() (2 input parameters) + Name: SetWindowIcons + Return type: void + Description: Set icon for window (multiple images, RGBA 32bit, only PLATFORM_DESKTOP) + Param[1]: images (type: Image *) + Param[2]: count (type: int) +Function 020: SetWindowTitle() (1 input parameters) Name: SetWindowTitle Return type: void Description: Set title for window (only PLATFORM_DESKTOP) Param[1]: title (type: const char *) -Function 020: SetWindowPosition() (2 input parameters) +Function 021: SetWindowPosition() (2 input parameters) Name: SetWindowPosition Return type: void Description: Set window position on screen (only PLATFORM_DESKTOP) Param[1]: x (type: int) Param[2]: y (type: int) -Function 021: SetWindowMonitor() (1 input parameters) +Function 022: SetWindowMonitor() (1 input parameters) Name: SetWindowMonitor Return type: void Description: Set monitor for the current window (fullscreen mode) Param[1]: monitor (type: int) -Function 022: SetWindowMinSize() (2 input parameters) +Function 023: SetWindowMinSize() (2 input parameters) Name: SetWindowMinSize Return type: void Description: Set window minimum dimensions (for FLAG_WINDOW_RESIZABLE) Param[1]: width (type: int) Param[2]: height (type: int) -Function 023: SetWindowSize() (2 input parameters) +Function 024: SetWindowSize() (2 input parameters) Name: SetWindowSize Return type: void Description: Set window dimensions Param[1]: width (type: int) Param[2]: height (type: int) -Function 024: SetWindowOpacity() (1 input parameters) +Function 025: SetWindowOpacity() (1 input parameters) Name: SetWindowOpacity Return type: void Description: Set window opacity [0.0f..1.0f] (only PLATFORM_DESKTOP) Param[1]: opacity (type: float) -Function 025: GetWindowHandle() (0 input parameters) +Function 026: GetWindowHandle() (0 input parameters) Name: GetWindowHandle Return type: void * Description: Get native window handle No input parameters -Function 026: GetScreenWidth() (0 input parameters) +Function 027: GetScreenWidth() (0 input parameters) Name: GetScreenWidth Return type: int Description: Get current screen width No input parameters -Function 027: GetScreenHeight() (0 input parameters) +Function 028: GetScreenHeight() (0 input parameters) Name: GetScreenHeight Return type: int Description: Get current screen height No input parameters -Function 028: GetRenderWidth() (0 input parameters) +Function 029: GetRenderWidth() (0 input parameters) Name: GetRenderWidth Return type: int Description: Get current render width (it considers HiDPI) No input parameters -Function 029: GetRenderHeight() (0 input parameters) +Function 030: GetRenderHeight() (0 input parameters) Name: GetRenderHeight Return type: int Description: Get current render height (it considers HiDPI) No input parameters -Function 030: GetMonitorCount() (0 input parameters) +Function 031: GetMonitorCount() (0 input parameters) Name: GetMonitorCount Return type: int Description: Get number of connected monitors No input parameters -Function 031: GetCurrentMonitor() (0 input parameters) +Function 032: GetCurrentMonitor() (0 input parameters) Name: GetCurrentMonitor Return type: int Description: Get current connected monitor No input parameters -Function 032: GetMonitorPosition() (1 input parameters) +Function 033: GetMonitorPosition() (1 input parameters) Name: GetMonitorPosition Return type: Vector2 Description: Get specified monitor position Param[1]: monitor (type: int) -Function 033: GetMonitorWidth() (1 input parameters) +Function 034: GetMonitorWidth() (1 input parameters) Name: GetMonitorWidth Return type: int Description: Get specified monitor width (current video mode used by monitor) Param[1]: monitor (type: int) -Function 034: GetMonitorHeight() (1 input parameters) +Function 035: GetMonitorHeight() (1 input parameters) Name: GetMonitorHeight Return type: int Description: Get specified monitor height (current video mode used by monitor) Param[1]: monitor (type: int) -Function 035: GetMonitorPhysicalWidth() (1 input parameters) +Function 036: GetMonitorPhysicalWidth() (1 input parameters) Name: GetMonitorPhysicalWidth Return type: int Description: Get specified monitor physical width in millimetres Param[1]: monitor (type: int) -Function 036: GetMonitorPhysicalHeight() (1 input parameters) +Function 037: GetMonitorPhysicalHeight() (1 input parameters) Name: GetMonitorPhysicalHeight Return type: int Description: Get specified monitor physical height in millimetres Param[1]: monitor (type: int) -Function 037: GetMonitorRefreshRate() (1 input parameters) +Function 038: GetMonitorRefreshRate() (1 input parameters) Name: GetMonitorRefreshRate Return type: int Description: Get specified monitor refresh rate Param[1]: monitor (type: int) -Function 038: GetWindowPosition() (0 input parameters) +Function 039: GetWindowPosition() (0 input parameters) Name: GetWindowPosition Return type: Vector2 Description: Get window position XY on monitor No input parameters -Function 039: GetWindowScaleDPI() (0 input parameters) +Function 040: GetWindowScaleDPI() (0 input parameters) Name: GetWindowScaleDPI Return type: Vector2 Description: Get window scale DPI factor No input parameters -Function 040: GetMonitorName() (1 input parameters) +Function 041: GetMonitorName() (1 input parameters) Name: GetMonitorName Return type: const char * Description: Get the human-readable, UTF-8 encoded name of the primary monitor Param[1]: monitor (type: int) -Function 041: SetClipboardText() (1 input parameters) +Function 042: SetClipboardText() (1 input parameters) Name: SetClipboardText Return type: void Description: Set clipboard text content Param[1]: text (type: const char *) -Function 042: GetClipboardText() (0 input parameters) +Function 043: GetClipboardText() (0 input parameters) Name: GetClipboardText Return type: const char * Description: Get clipboard text content No input parameters -Function 043: EnableEventWaiting() (0 input parameters) +Function 044: EnableEventWaiting() (0 input parameters) Name: EnableEventWaiting Return type: void Description: Enable waiting for events on EndDrawing(), no automatic event polling No input parameters -Function 044: DisableEventWaiting() (0 input parameters) +Function 045: DisableEventWaiting() (0 input parameters) Name: DisableEventWaiting Return type: void Description: Disable waiting for events on EndDrawing(), automatic events polling No input parameters -Function 045: SwapScreenBuffer() (0 input parameters) +Function 046: SwapScreenBuffer() (0 input parameters) Name: SwapScreenBuffer Return type: void Description: Swap back buffer with front buffer (screen drawing) No input parameters -Function 046: PollInputEvents() (0 input parameters) +Function 047: PollInputEvents() (0 input parameters) Name: PollInputEvents Return type: void Description: Register all input events No input parameters -Function 047: WaitTime() (1 input parameters) +Function 048: WaitTime() (1 input parameters) Name: WaitTime Return type: void Description: Wait for some time (halt program execution) Param[1]: seconds (type: double) -Function 048: ShowCursor() (0 input parameters) +Function 049: ShowCursor() (0 input parameters) Name: ShowCursor Return type: void Description: Shows cursor No input parameters -Function 049: HideCursor() (0 input parameters) +Function 050: HideCursor() (0 input parameters) Name: HideCursor Return type: void Description: Hides cursor No input parameters -Function 050: IsCursorHidden() (0 input parameters) +Function 051: IsCursorHidden() (0 input parameters) Name: IsCursorHidden Return type: bool Description: Check if cursor is not visible No input parameters -Function 051: EnableCursor() (0 input parameters) +Function 052: EnableCursor() (0 input parameters) Name: EnableCursor Return type: void Description: Enables cursor (unlock cursor) No input parameters -Function 052: DisableCursor() (0 input parameters) +Function 053: DisableCursor() (0 input parameters) Name: DisableCursor Return type: void Description: Disables cursor (lock cursor) No input parameters -Function 053: IsCursorOnScreen() (0 input parameters) +Function 054: IsCursorOnScreen() (0 input parameters) Name: IsCursorOnScreen Return type: bool Description: Check if cursor is on the screen No input parameters -Function 054: ClearBackground() (1 input parameters) +Function 055: ClearBackground() (1 input parameters) Name: ClearBackground Return type: void Description: Set background color (framebuffer clear color) Param[1]: color (type: Color) -Function 055: BeginDrawing() (0 input parameters) +Function 056: BeginDrawing() (0 input parameters) Name: BeginDrawing Return type: void Description: Setup canvas (framebuffer) to start drawing No input parameters -Function 056: EndDrawing() (0 input parameters) +Function 057: EndDrawing() (0 input parameters) Name: EndDrawing Return type: void Description: End canvas drawing and swap buffers (double buffering) No input parameters -Function 057: BeginMode2D() (1 input parameters) +Function 058: BeginMode2D() (1 input parameters) Name: BeginMode2D Return type: void Description: Begin 2D mode with custom camera (2D) Param[1]: camera (type: Camera2D) -Function 058: EndMode2D() (0 input parameters) +Function 059: EndMode2D() (0 input parameters) Name: EndMode2D Return type: void Description: Ends 2D mode with custom camera No input parameters -Function 059: BeginMode3D() (1 input parameters) +Function 060: BeginMode3D() (1 input parameters) Name: BeginMode3D Return type: void Description: Begin 3D mode with custom camera (3D) Param[1]: camera (type: Camera3D) -Function 060: EndMode3D() (0 input parameters) +Function 061: EndMode3D() (0 input parameters) Name: EndMode3D Return type: void Description: Ends 3D mode and returns to default 2D orthographic mode No input parameters -Function 061: BeginTextureMode() (1 input parameters) +Function 062: BeginTextureMode() (1 input parameters) Name: BeginTextureMode Return type: void Description: Begin drawing to render texture Param[1]: target (type: RenderTexture2D) -Function 062: EndTextureMode() (0 input parameters) +Function 063: EndTextureMode() (0 input parameters) Name: EndTextureMode Return type: void Description: Ends drawing to render texture No input parameters -Function 063: BeginShaderMode() (1 input parameters) +Function 064: BeginShaderMode() (1 input parameters) Name: BeginShaderMode Return type: void Description: Begin custom shader drawing Param[1]: shader (type: Shader) -Function 064: EndShaderMode() (0 input parameters) +Function 065: EndShaderMode() (0 input parameters) Name: EndShaderMode Return type: void Description: End custom shader drawing (use default shader) No input parameters -Function 065: BeginBlendMode() (1 input parameters) +Function 066: BeginBlendMode() (1 input parameters) Name: BeginBlendMode Return type: void Description: Begin blending mode (alpha, additive, multiplied, subtract, custom) Param[1]: mode (type: int) -Function 066: EndBlendMode() (0 input parameters) +Function 067: EndBlendMode() (0 input parameters) Name: EndBlendMode Return type: void Description: End blending mode (reset to default: alpha blending) No input parameters -Function 067: BeginScissorMode() (4 input parameters) +Function 068: BeginScissorMode() (4 input parameters) Name: BeginScissorMode Return type: void Description: Begin scissor mode (define screen area for following drawing) @@ -1293,56 +1314,61 @@ Function 067: BeginScissorMode() (4 input parameters) Param[2]: y (type: int) Param[3]: width (type: int) Param[4]: height (type: int) -Function 068: EndScissorMode() (0 input parameters) +Function 069: EndScissorMode() (0 input parameters) Name: EndScissorMode Return type: void Description: End scissor mode No input parameters -Function 069: BeginVrStereoMode() (1 input parameters) +Function 070: BeginVrStereoMode() (1 input parameters) Name: BeginVrStereoMode Return type: void Description: Begin stereo rendering (requires VR simulator) Param[1]: config (type: VrStereoConfig) -Function 070: EndVrStereoMode() (0 input parameters) +Function 071: EndVrStereoMode() (0 input parameters) Name: EndVrStereoMode Return type: void Description: End stereo rendering (requires VR simulator) No input parameters -Function 071: LoadVrStereoConfig() (1 input parameters) +Function 072: LoadVrStereoConfig() (1 input parameters) Name: LoadVrStereoConfig Return type: VrStereoConfig Description: Load VR stereo config for VR simulator device parameters Param[1]: device (type: VrDeviceInfo) -Function 072: UnloadVrStereoConfig() (1 input parameters) +Function 073: UnloadVrStereoConfig() (1 input parameters) Name: UnloadVrStereoConfig Return type: void Description: Unload VR stereo config Param[1]: config (type: VrStereoConfig) -Function 073: LoadShader() (2 input parameters) +Function 074: LoadShader() (2 input parameters) Name: LoadShader Return type: Shader Description: Load shader from files and bind default locations Param[1]: vsFileName (type: const char *) Param[2]: fsFileName (type: const char *) -Function 074: LoadShaderFromMemory() (2 input parameters) +Function 075: LoadShaderFromMemory() (2 input parameters) Name: LoadShaderFromMemory Return type: Shader Description: Load shader from code strings and bind default locations Param[1]: vsCode (type: const char *) Param[2]: fsCode (type: const char *) -Function 075: GetShaderLocation() (2 input parameters) +Function 076: IsShaderReady() (1 input parameters) + Name: IsShaderReady + Return type: bool + Description: Check if a shader is ready + Param[1]: shader (type: Shader) +Function 077: GetShaderLocation() (2 input parameters) Name: GetShaderLocation Return type: int Description: Get shader uniform location Param[1]: shader (type: Shader) Param[2]: uniformName (type: const char *) -Function 076: GetShaderLocationAttrib() (2 input parameters) +Function 078: GetShaderLocationAttrib() (2 input parameters) Name: GetShaderLocationAttrib Return type: int Description: Get shader attribute location Param[1]: shader (type: Shader) Param[2]: attribName (type: const char *) -Function 077: SetShaderValue() (4 input parameters) +Function 079: SetShaderValue() (4 input parameters) Name: SetShaderValue Return type: void Description: Set shader uniform value @@ -1350,7 +1376,7 @@ Function 077: SetShaderValue() (4 input parameters) Param[2]: locIndex (type: int) Param[3]: value (type: const void *) Param[4]: uniformType (type: int) -Function 078: SetShaderValueV() (5 input parameters) +Function 080: SetShaderValueV() (5 input parameters) Name: SetShaderValueV Return type: void Description: Set shader uniform value vector @@ -1359,54 +1385,54 @@ Function 078: SetShaderValueV() (5 input parameters) Param[3]: value (type: const void *) Param[4]: uniformType (type: int) Param[5]: count (type: int) -Function 079: SetShaderValueMatrix() (3 input parameters) +Function 081: SetShaderValueMatrix() (3 input parameters) Name: SetShaderValueMatrix Return type: void Description: Set shader uniform value (matrix 4x4) Param[1]: shader (type: Shader) Param[2]: locIndex (type: int) Param[3]: mat (type: Matrix) -Function 080: SetShaderValueTexture() (3 input parameters) +Function 082: SetShaderValueTexture() (3 input parameters) Name: SetShaderValueTexture Return type: void Description: Set shader uniform value for texture (sampler2d) Param[1]: shader (type: Shader) Param[2]: locIndex (type: int) Param[3]: texture (type: Texture2D) -Function 081: UnloadShader() (1 input parameters) +Function 083: UnloadShader() (1 input parameters) Name: UnloadShader Return type: void Description: Unload shader from GPU memory (VRAM) Param[1]: shader (type: Shader) -Function 082: GetMouseRay() (2 input parameters) +Function 084: GetMouseRay() (2 input parameters) Name: GetMouseRay Return type: Ray Description: Get a ray trace from mouse position Param[1]: mousePosition (type: Vector2) Param[2]: camera (type: Camera) -Function 083: GetCameraMatrix() (1 input parameters) +Function 085: GetCameraMatrix() (1 input parameters) Name: GetCameraMatrix Return type: Matrix Description: Get camera transform matrix (view matrix) Param[1]: camera (type: Camera) -Function 084: GetCameraMatrix2D() (1 input parameters) +Function 086: GetCameraMatrix2D() (1 input parameters) Name: GetCameraMatrix2D Return type: Matrix Description: Get camera 2d transform matrix Param[1]: camera (type: Camera2D) -Function 085: GetWorldToScreen() (2 input parameters) +Function 087: GetWorldToScreen() (2 input parameters) Name: GetWorldToScreen Return type: Vector2 Description: Get the screen space position for a 3d world space position Param[1]: position (type: Vector3) Param[2]: camera (type: Camera) -Function 086: GetScreenToWorld2D() (2 input parameters) +Function 088: GetScreenToWorld2D() (2 input parameters) Name: GetScreenToWorld2D Return type: Vector2 Description: Get the world space position for a 2d camera screen space position Param[1]: position (type: Vector2) Param[2]: camera (type: Camera2D) -Function 087: GetWorldToScreenEx() (4 input parameters) +Function 089: GetWorldToScreenEx() (4 input parameters) Name: GetWorldToScreenEx Return type: Vector2 Description: Get size position for a 3d world space position @@ -1414,566 +1440,544 @@ Function 087: GetWorldToScreenEx() (4 input parameters) Param[2]: camera (type: Camera) Param[3]: width (type: int) Param[4]: height (type: int) -Function 088: GetWorldToScreen2D() (2 input parameters) +Function 090: GetWorldToScreen2D() (2 input parameters) Name: GetWorldToScreen2D Return type: Vector2 Description: Get the screen space position for a 2d camera world space position Param[1]: position (type: Vector2) Param[2]: camera (type: Camera2D) -Function 089: SetTargetFPS() (1 input parameters) +Function 091: SetTargetFPS() (1 input parameters) Name: SetTargetFPS Return type: void Description: Set target FPS (maximum) Param[1]: fps (type: int) -Function 090: GetFPS() (0 input parameters) +Function 092: GetFPS() (0 input parameters) Name: GetFPS Return type: int Description: Get current FPS No input parameters -Function 091: GetFrameTime() (0 input parameters) +Function 093: GetFrameTime() (0 input parameters) Name: GetFrameTime Return type: float Description: Get time in seconds for last frame drawn (delta time) No input parameters -Function 092: GetTime() (0 input parameters) +Function 094: GetTime() (0 input parameters) Name: GetTime Return type: double Description: Get elapsed time in seconds since InitWindow() No input parameters -Function 093: GetRandomValue() (2 input parameters) +Function 095: GetRandomValue() (2 input parameters) Name: GetRandomValue Return type: int Description: Get a random value between min and max (both included) Param[1]: min (type: int) Param[2]: max (type: int) -Function 094: SetRandomSeed() (1 input parameters) +Function 096: SetRandomSeed() (1 input parameters) Name: SetRandomSeed Return type: void Description: Set the seed for the random number generator Param[1]: seed (type: unsigned int) -Function 095: TakeScreenshot() (1 input parameters) +Function 097: TakeScreenshot() (1 input parameters) Name: TakeScreenshot Return type: void Description: Takes a screenshot of current screen (filename extension defines format) Param[1]: fileName (type: const char *) -Function 096: SetConfigFlags() (1 input parameters) +Function 098: SetConfigFlags() (1 input parameters) Name: SetConfigFlags Return type: void Description: Setup init configuration flags (view FLAGS) Param[1]: flags (type: unsigned int) -Function 097: TraceLog() (3 input parameters) +Function 099: TraceLog() (3 input parameters) Name: TraceLog Return type: void Description: Show trace log messages (LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERROR...) Param[1]: logLevel (type: int) Param[2]: text (type: const char *) Param[3]: args (type: ...) -Function 098: SetTraceLogLevel() (1 input parameters) +Function 100: SetTraceLogLevel() (1 input parameters) Name: SetTraceLogLevel Return type: void Description: Set the current threshold (minimum) log level Param[1]: logLevel (type: int) -Function 099: MemAlloc() (1 input parameters) +Function 101: MemAlloc() (1 input parameters) Name: MemAlloc Return type: void * Description: Internal memory allocator Param[1]: size (type: unsigned int) -Function 100: MemRealloc() (2 input parameters) +Function 102: MemRealloc() (2 input parameters) Name: MemRealloc Return type: void * Description: Internal memory reallocator Param[1]: ptr (type: void *) Param[2]: size (type: unsigned int) -Function 101: MemFree() (1 input parameters) +Function 103: MemFree() (1 input parameters) Name: MemFree Return type: void Description: Internal memory free Param[1]: ptr (type: void *) -Function 102: OpenURL() (1 input parameters) +Function 104: OpenURL() (1 input parameters) Name: OpenURL Return type: void Description: Open URL with default system browser (if available) Param[1]: url (type: const char *) -Function 103: SetTraceLogCallback() (1 input parameters) +Function 105: SetTraceLogCallback() (1 input parameters) Name: SetTraceLogCallback Return type: void Description: Set custom trace log Param[1]: callback (type: TraceLogCallback) -Function 104: SetLoadFileDataCallback() (1 input parameters) +Function 106: SetLoadFileDataCallback() (1 input parameters) Name: SetLoadFileDataCallback Return type: void Description: Set custom file binary data loader Param[1]: callback (type: LoadFileDataCallback) -Function 105: SetSaveFileDataCallback() (1 input parameters) +Function 107: SetSaveFileDataCallback() (1 input parameters) Name: SetSaveFileDataCallback Return type: void Description: Set custom file binary data saver Param[1]: callback (type: SaveFileDataCallback) -Function 106: SetLoadFileTextCallback() (1 input parameters) +Function 108: SetLoadFileTextCallback() (1 input parameters) Name: SetLoadFileTextCallback Return type: void Description: Set custom file text data loader Param[1]: callback (type: LoadFileTextCallback) -Function 107: SetSaveFileTextCallback() (1 input parameters) +Function 109: SetSaveFileTextCallback() (1 input parameters) Name: SetSaveFileTextCallback Return type: void Description: Set custom file text data saver Param[1]: callback (type: SaveFileTextCallback) -Function 108: LoadFileData() (2 input parameters) +Function 110: LoadFileData() (2 input parameters) Name: LoadFileData Return type: unsigned char * Description: Load file data as byte array (read) Param[1]: fileName (type: const char *) Param[2]: bytesRead (type: unsigned int *) -Function 109: UnloadFileData() (1 input parameters) +Function 111: UnloadFileData() (1 input parameters) Name: UnloadFileData Return type: void Description: Unload file data allocated by LoadFileData() Param[1]: data (type: unsigned char *) -Function 110: SaveFileData() (3 input parameters) +Function 112: SaveFileData() (3 input parameters) Name: SaveFileData Return type: bool Description: Save data to file from byte array (write), returns true on success Param[1]: fileName (type: const char *) Param[2]: data (type: void *) Param[3]: bytesToWrite (type: unsigned int) -Function 111: ExportDataAsCode() (3 input parameters) +Function 113: ExportDataAsCode() (3 input parameters) Name: ExportDataAsCode Return type: bool Description: Export data to code (.h), returns true on success - Param[1]: data (type: const char *) + Param[1]: data (type: const unsigned char *) Param[2]: size (type: unsigned int) Param[3]: fileName (type: const char *) -Function 112: LoadFileText() (1 input parameters) +Function 114: LoadFileText() (1 input parameters) Name: LoadFileText Return type: char * Description: Load text data from file (read), returns a '\0' terminated string Param[1]: fileName (type: const char *) -Function 113: UnloadFileText() (1 input parameters) +Function 115: UnloadFileText() (1 input parameters) Name: UnloadFileText Return type: void Description: Unload file text data allocated by LoadFileText() Param[1]: text (type: char *) -Function 114: SaveFileText() (2 input parameters) +Function 116: SaveFileText() (2 input parameters) Name: SaveFileText Return type: bool 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: char *) -Function 115: FileExists() (1 input parameters) +Function 117: FileExists() (1 input parameters) Name: FileExists Return type: bool Description: Check if file exists Param[1]: fileName (type: const char *) -Function 116: DirectoryExists() (1 input parameters) +Function 118: DirectoryExists() (1 input parameters) Name: DirectoryExists Return type: bool Description: Check if a directory path exists Param[1]: dirPath (type: const char *) -Function 117: IsFileExtension() (2 input parameters) +Function 119: IsFileExtension() (2 input parameters) Name: IsFileExtension Return type: bool Description: Check file extension (including point: .png, .wav) Param[1]: fileName (type: const char *) Param[2]: ext (type: const char *) -Function 118: GetFileLength() (1 input parameters) +Function 120: 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 119: GetFileExtension() (1 input parameters) +Function 121: 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 120: GetFileName() (1 input parameters) +Function 122: 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 121: GetFileNameWithoutExt() (1 input parameters) +Function 123: 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 122: GetDirectoryPath() (1 input parameters) +Function 124: 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 123: GetPrevDirectoryPath() (1 input parameters) +Function 125: 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 124: GetWorkingDirectory() (0 input parameters) +Function 126: GetWorkingDirectory() (0 input parameters) Name: GetWorkingDirectory Return type: const char * Description: Get current working directory (uses static string) No input parameters -Function 125: GetApplicationDirectory() (0 input parameters) +Function 127: GetApplicationDirectory() (0 input parameters) Name: GetApplicationDirectory Return type: const char * Description: Get the directory if the running application (uses static string) No input parameters -Function 126: ChangeDirectory() (1 input parameters) +Function 128: ChangeDirectory() (1 input parameters) Name: ChangeDirectory Return type: bool Description: Change working directory, return true on success Param[1]: dir (type: const char *) -Function 127: IsPathFile() (1 input parameters) +Function 129: 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 128: LoadDirectoryFiles() (1 input parameters) +Function 130: LoadDirectoryFiles() (1 input parameters) Name: LoadDirectoryFiles Return type: FilePathList Description: Load directory filepaths Param[1]: dirPath (type: const char *) -Function 129: LoadDirectoryFilesEx() (3 input parameters) +Function 131: LoadDirectoryFilesEx() (3 input parameters) Name: LoadDirectoryFilesEx Return type: FilePathList Description: Load directory filepaths with extension filtering and recursive directory scan Param[1]: basePath (type: const char *) Param[2]: filter (type: const char *) Param[3]: scanSubdirs (type: bool) -Function 130: UnloadDirectoryFiles() (1 input parameters) +Function 132: UnloadDirectoryFiles() (1 input parameters) Name: UnloadDirectoryFiles Return type: void Description: Unload filepaths Param[1]: files (type: FilePathList) -Function 131: IsFileDropped() (0 input parameters) +Function 133: IsFileDropped() (0 input parameters) Name: IsFileDropped Return type: bool Description: Check if a file has been dropped into window No input parameters -Function 132: LoadDroppedFiles() (0 input parameters) +Function 134: LoadDroppedFiles() (0 input parameters) Name: LoadDroppedFiles Return type: FilePathList Description: Load dropped filepaths No input parameters -Function 133: UnloadDroppedFiles() (1 input parameters) +Function 135: UnloadDroppedFiles() (1 input parameters) Name: UnloadDroppedFiles Return type: void Description: Unload dropped filepaths Param[1]: files (type: FilePathList) -Function 134: GetFileModTime() (1 input parameters) +Function 136: 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: CompressData() (3 input parameters) +Function 137: 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 136: DecompressData() (3 input parameters) +Function 138: 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 137: EncodeDataBase64() (3 input parameters) +Function 139: EncodeDataBase64() (3 input parameters) Name: EncodeDataBase64 Return type: char * Description: Encode data to Base64 string, memory must be MemFree() Param[1]: data (type: const unsigned char *) Param[2]: dataSize (type: int) Param[3]: outputSize (type: int *) -Function 138: DecodeDataBase64() (2 input parameters) +Function 140: DecodeDataBase64() (2 input parameters) Name: DecodeDataBase64 Return type: unsigned char * Description: Decode Base64 string data, memory must be MemFree() Param[1]: data (type: const unsigned char *) Param[2]: outputSize (type: int *) -Function 139: IsKeyPressed() (1 input parameters) +Function 141: IsKeyPressed() (1 input parameters) Name: IsKeyPressed Return type: bool Description: Check if a key has been pressed once Param[1]: key (type: int) -Function 140: IsKeyDown() (1 input parameters) +Function 142: IsKeyDown() (1 input parameters) Name: IsKeyDown Return type: bool Description: Check if a key is being pressed Param[1]: key (type: int) -Function 141: IsKeyReleased() (1 input parameters) +Function 143: IsKeyReleased() (1 input parameters) Name: IsKeyReleased Return type: bool Description: Check if a key has been released once Param[1]: key (type: int) -Function 142: IsKeyUp() (1 input parameters) +Function 144: IsKeyUp() (1 input parameters) Name: IsKeyUp Return type: bool Description: Check if a key is NOT being pressed Param[1]: key (type: int) -Function 143: SetExitKey() (1 input parameters) +Function 145: 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 144: GetKeyPressed() (0 input parameters) +Function 146: 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 145: GetCharPressed() (0 input parameters) +Function 147: 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 146: IsGamepadAvailable() (1 input parameters) +Function 148: IsGamepadAvailable() (1 input parameters) Name: IsGamepadAvailable Return type: bool Description: Check if a gamepad is available Param[1]: gamepad (type: int) -Function 147: GetGamepadName() (1 input parameters) +Function 149: GetGamepadName() (1 input parameters) Name: GetGamepadName Return type: const char * Description: Get gamepad internal name id Param[1]: gamepad (type: int) -Function 148: IsGamepadButtonPressed() (2 input parameters) +Function 150: 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 149: IsGamepadButtonDown() (2 input parameters) +Function 151: 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 150: IsGamepadButtonReleased() (2 input parameters) +Function 152: 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 151: IsGamepadButtonUp() (2 input parameters) +Function 153: 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 152: GetGamepadButtonPressed() (0 input parameters) +Function 154: GetGamepadButtonPressed() (0 input parameters) Name: GetGamepadButtonPressed Return type: int Description: Get the last gamepad button pressed No input parameters -Function 153: GetGamepadAxisCount() (1 input parameters) +Function 155: GetGamepadAxisCount() (1 input parameters) Name: GetGamepadAxisCount Return type: int Description: Get gamepad axis count for a gamepad Param[1]: gamepad (type: int) -Function 154: GetGamepadAxisMovement() (2 input parameters) +Function 156: GetGamepadAxisMovement() (2 input parameters) Name: GetGamepadAxisMovement Return type: float Description: Get axis movement value for a gamepad axis Param[1]: gamepad (type: int) Param[2]: axis (type: int) -Function 155: SetGamepadMappings() (1 input parameters) +Function 157: SetGamepadMappings() (1 input parameters) Name: SetGamepadMappings Return type: int Description: Set internal gamepad mappings (SDL_GameControllerDB) Param[1]: mappings (type: const char *) -Function 156: IsMouseButtonPressed() (1 input parameters) +Function 158: 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 157: IsMouseButtonDown() (1 input parameters) +Function 159: IsMouseButtonDown() (1 input parameters) Name: IsMouseButtonDown Return type: bool Description: Check if a mouse button is being pressed Param[1]: button (type: int) -Function 158: IsMouseButtonReleased() (1 input parameters) +Function 160: 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 159: IsMouseButtonUp() (1 input parameters) +Function 161: 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 160: GetMouseX() (0 input parameters) +Function 162: GetMouseX() (0 input parameters) Name: GetMouseX Return type: int Description: Get mouse position X No input parameters -Function 161: GetMouseY() (0 input parameters) +Function 163: GetMouseY() (0 input parameters) Name: GetMouseY Return type: int Description: Get mouse position Y No input parameters -Function 162: GetMousePosition() (0 input parameters) +Function 164: GetMousePosition() (0 input parameters) Name: GetMousePosition Return type: Vector2 Description: Get mouse position XY No input parameters -Function 163: GetMouseDelta() (0 input parameters) +Function 165: GetMouseDelta() (0 input parameters) Name: GetMouseDelta Return type: Vector2 Description: Get mouse delta between frames No input parameters -Function 164: SetMousePosition() (2 input parameters) +Function 166: 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 165: SetMouseOffset() (2 input parameters) +Function 167: SetMouseOffset() (2 input parameters) Name: SetMouseOffset Return type: void Description: Set mouse offset Param[1]: offsetX (type: int) Param[2]: offsetY (type: int) -Function 166: SetMouseScale() (2 input parameters) +Function 168: SetMouseScale() (2 input parameters) Name: SetMouseScale Return type: void Description: Set mouse scaling Param[1]: scaleX (type: float) Param[2]: scaleY (type: float) -Function 167: GetMouseWheelMove() (0 input parameters) +Function 169: 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 168: GetMouseWheelMoveV() (0 input parameters) +Function 170: GetMouseWheelMoveV() (0 input parameters) Name: GetMouseWheelMoveV Return type: Vector2 Description: Get mouse wheel movement for both X and Y No input parameters -Function 169: SetMouseCursor() (1 input parameters) +Function 171: SetMouseCursor() (1 input parameters) Name: SetMouseCursor Return type: void Description: Set mouse cursor Param[1]: cursor (type: int) -Function 170: GetTouchX() (0 input parameters) +Function 172: 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 171: GetTouchY() (0 input parameters) +Function 173: 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 172: GetTouchPosition() (1 input parameters) +Function 174: 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 173: GetTouchPointId() (1 input parameters) +Function 175: GetTouchPointId() (1 input parameters) Name: GetTouchPointId Return type: int Description: Get touch point identifier for given index Param[1]: index (type: int) -Function 174: GetTouchPointCount() (0 input parameters) +Function 176: GetTouchPointCount() (0 input parameters) Name: GetTouchPointCount Return type: int Description: Get number of touch points No input parameters -Function 175: SetGesturesEnabled() (1 input parameters) +Function 177: SetGesturesEnabled() (1 input parameters) Name: SetGesturesEnabled Return type: void Description: Enable a set of gestures using flags Param[1]: flags (type: unsigned int) -Function 176: IsGestureDetected() (1 input parameters) +Function 178: IsGestureDetected() (1 input parameters) Name: IsGestureDetected Return type: bool Description: Check if a gesture have been detected Param[1]: gesture (type: int) -Function 177: GetGestureDetected() (0 input parameters) +Function 179: GetGestureDetected() (0 input parameters) Name: GetGestureDetected Return type: int Description: Get latest detected gesture No input parameters -Function 178: GetGestureHoldDuration() (0 input parameters) +Function 180: GetGestureHoldDuration() (0 input parameters) Name: GetGestureHoldDuration Return type: float Description: Get gesture hold time in milliseconds No input parameters -Function 179: GetGestureDragVector() (0 input parameters) +Function 181: GetGestureDragVector() (0 input parameters) Name: GetGestureDragVector Return type: Vector2 Description: Get gesture drag vector No input parameters -Function 180: GetGestureDragAngle() (0 input parameters) +Function 182: GetGestureDragAngle() (0 input parameters) Name: GetGestureDragAngle Return type: float Description: Get gesture drag angle No input parameters -Function 181: GetGesturePinchVector() (0 input parameters) +Function 183: GetGesturePinchVector() (0 input parameters) Name: GetGesturePinchVector Return type: Vector2 Description: Get gesture pinch delta No input parameters -Function 182: GetGesturePinchAngle() (0 input parameters) +Function 184: GetGesturePinchAngle() (0 input parameters) Name: GetGesturePinchAngle Return type: float Description: Get gesture pinch angle No input parameters -Function 183: SetCameraMode() (2 input parameters) - Name: SetCameraMode - Return type: void - Description: Set camera mode (multiple camera modes available) - Param[1]: camera (type: Camera) - Param[2]: mode (type: int) -Function 184: UpdateCamera() (1 input parameters) +Function 185: UpdateCamera() (2 input parameters) Name: UpdateCamera Return type: void Description: Update camera position for selected mode Param[1]: camera (type: Camera *) -Function 185: SetCameraPanControl() (1 input parameters) - Name: SetCameraPanControl - Return type: void - Description: Set camera pan key to combine with mouse movement (free camera) - Param[1]: keyPan (type: int) -Function 186: SetCameraAltControl() (1 input parameters) - Name: SetCameraAltControl - Return type: void - Description: Set camera alt key to combine with mouse movement (free camera) - Param[1]: keyAlt (type: int) -Function 187: SetCameraSmoothZoomControl() (1 input parameters) - Name: SetCameraSmoothZoomControl - Return type: void - Description: Set camera smooth zoom key to combine with mouse (free camera) - Param[1]: keySmoothZoom (type: int) -Function 188: SetCameraMoveControls() (6 input parameters) - Name: SetCameraMoveControls - Return type: void - Description: Set camera move controls (1st person and 3rd person cameras) - Param[1]: keyFront (type: int) - Param[2]: keyBack (type: int) - Param[3]: keyRight (type: int) - Param[4]: keyLeft (type: int) - Param[5]: keyUp (type: int) - Param[6]: keyDown (type: int) -Function 189: SetShapesTexture() (2 input parameters) + Param[2]: mode (type: int) +Function 186: UpdateCameraPro() (4 input parameters) + Name: UpdateCameraPro + Return type: void + Description: Update camera movement/rotation + Param[1]: camera (type: Camera *) + Param[2]: movement (type: Vector3) + Param[3]: rotation (type: Vector3) + Param[4]: zoom (type: float) +Function 187: 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 190: DrawPixel() (3 input parameters) +Function 188: DrawPixel() (3 input parameters) Name: DrawPixel Return type: void Description: Draw a pixel Param[1]: posX (type: int) Param[2]: posY (type: int) Param[3]: color (type: Color) -Function 191: DrawPixelV() (2 input parameters) +Function 189: DrawPixelV() (2 input parameters) Name: DrawPixelV Return type: void Description: Draw a pixel (Vector version) Param[1]: position (type: Vector2) Param[2]: color (type: Color) -Function 192: DrawLine() (5 input parameters) +Function 190: DrawLine() (5 input parameters) Name: DrawLine Return type: void Description: Draw a line @@ -1982,14 +1986,14 @@ Function 192: DrawLine() (5 input parameters) Param[3]: endPosX (type: int) Param[4]: endPosY (type: int) Param[5]: color (type: Color) -Function 193: DrawLineV() (3 input parameters) +Function 191: DrawLineV() (3 input parameters) Name: DrawLineV Return type: void Description: Draw a line (Vector version) Param[1]: startPos (type: Vector2) Param[2]: endPos (type: Vector2) Param[3]: color (type: Color) -Function 194: DrawLineEx() (4 input parameters) +Function 192: DrawLineEx() (4 input parameters) Name: DrawLineEx Return type: void Description: Draw a line defining thickness @@ -1997,7 +2001,7 @@ Function 194: DrawLineEx() (4 input parameters) Param[2]: endPos (type: Vector2) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 195: DrawLineBezier() (4 input parameters) +Function 193: DrawLineBezier() (4 input parameters) Name: DrawLineBezier Return type: void Description: Draw a line using cubic-bezier curves in-out @@ -2005,7 +2009,7 @@ Function 195: DrawLineBezier() (4 input parameters) Param[2]: endPos (type: Vector2) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 196: DrawLineBezierQuad() (5 input parameters) +Function 194: DrawLineBezierQuad() (5 input parameters) Name: DrawLineBezierQuad Return type: void Description: Draw line using quadratic bezier curves with a control point @@ -2014,7 +2018,7 @@ Function 196: DrawLineBezierQuad() (5 input parameters) Param[3]: controlPos (type: Vector2) Param[4]: thick (type: float) Param[5]: color (type: Color) -Function 197: DrawLineBezierCubic() (6 input parameters) +Function 195: DrawLineBezierCubic() (6 input parameters) Name: DrawLineBezierCubic Return type: void Description: Draw line using cubic bezier curves with 2 control points @@ -2024,14 +2028,14 @@ Function 197: DrawLineBezierCubic() (6 input parameters) Param[4]: endControlPos (type: Vector2) Param[5]: thick (type: float) Param[6]: color (type: Color) -Function 198: DrawLineStrip() (3 input parameters) +Function 196: DrawLineStrip() (3 input parameters) Name: DrawLineStrip Return type: void Description: Draw lines sequence Param[1]: points (type: Vector2 *) Param[2]: pointCount (type: int) Param[3]: color (type: Color) -Function 199: DrawCircle() (4 input parameters) +Function 197: DrawCircle() (4 input parameters) Name: DrawCircle Return type: void Description: Draw a color-filled circle @@ -2039,7 +2043,7 @@ Function 199: DrawCircle() (4 input parameters) Param[2]: centerY (type: int) Param[3]: radius (type: float) Param[4]: color (type: Color) -Function 200: DrawCircleSector() (6 input parameters) +Function 198: DrawCircleSector() (6 input parameters) Name: DrawCircleSector Return type: void Description: Draw a piece of a circle @@ -2049,7 +2053,7 @@ Function 200: DrawCircleSector() (6 input parameters) Param[4]: endAngle (type: float) Param[5]: segments (type: int) Param[6]: color (type: Color) -Function 201: DrawCircleSectorLines() (6 input parameters) +Function 199: DrawCircleSectorLines() (6 input parameters) Name: DrawCircleSectorLines Return type: void Description: Draw circle sector outline @@ -2059,7 +2063,7 @@ Function 201: DrawCircleSectorLines() (6 input parameters) Param[4]: endAngle (type: float) Param[5]: segments (type: int) Param[6]: color (type: Color) -Function 202: DrawCircleGradient() (5 input parameters) +Function 200: DrawCircleGradient() (5 input parameters) Name: DrawCircleGradient Return type: void Description: Draw a gradient-filled circle @@ -2068,14 +2072,14 @@ Function 202: DrawCircleGradient() (5 input parameters) Param[3]: radius (type: float) Param[4]: color1 (type: Color) Param[5]: color2 (type: Color) -Function 203: DrawCircleV() (3 input parameters) +Function 201: 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 204: DrawCircleLines() (4 input parameters) +Function 202: DrawCircleLines() (4 input parameters) Name: DrawCircleLines Return type: void Description: Draw circle outline @@ -2083,7 +2087,7 @@ Function 204: DrawCircleLines() (4 input parameters) Param[2]: centerY (type: int) Param[3]: radius (type: float) Param[4]: color (type: Color) -Function 205: DrawEllipse() (5 input parameters) +Function 203: DrawEllipse() (5 input parameters) Name: DrawEllipse Return type: void Description: Draw ellipse @@ -2092,7 +2096,7 @@ Function 205: DrawEllipse() (5 input parameters) Param[3]: radiusH (type: float) Param[4]: radiusV (type: float) Param[5]: color (type: Color) -Function 206: DrawEllipseLines() (5 input parameters) +Function 204: DrawEllipseLines() (5 input parameters) Name: DrawEllipseLines Return type: void Description: Draw ellipse outline @@ -2101,7 +2105,7 @@ Function 206: DrawEllipseLines() (5 input parameters) Param[3]: radiusH (type: float) Param[4]: radiusV (type: float) Param[5]: color (type: Color) -Function 207: DrawRing() (7 input parameters) +Function 205: DrawRing() (7 input parameters) Name: DrawRing Return type: void Description: Draw ring @@ -2112,7 +2116,7 @@ Function 207: DrawRing() (7 input parameters) Param[5]: endAngle (type: float) Param[6]: segments (type: int) Param[7]: color (type: Color) -Function 208: DrawRingLines() (7 input parameters) +Function 206: DrawRingLines() (7 input parameters) Name: DrawRingLines Return type: void Description: Draw ring outline @@ -2123,7 +2127,7 @@ Function 208: DrawRingLines() (7 input parameters) Param[5]: endAngle (type: float) Param[6]: segments (type: int) Param[7]: color (type: Color) -Function 209: DrawRectangle() (5 input parameters) +Function 207: DrawRectangle() (5 input parameters) Name: DrawRectangle Return type: void Description: Draw a color-filled rectangle @@ -2132,20 +2136,20 @@ Function 209: DrawRectangle() (5 input parameters) Param[3]: width (type: int) Param[4]: height (type: int) Param[5]: color (type: Color) -Function 210: DrawRectangleV() (3 input parameters) +Function 208: 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 211: DrawRectangleRec() (2 input parameters) +Function 209: 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 212: DrawRectanglePro() (4 input parameters) +Function 210: DrawRectanglePro() (4 input parameters) Name: DrawRectanglePro Return type: void Description: Draw a color-filled rectangle with pro parameters @@ -2153,7 +2157,7 @@ Function 212: DrawRectanglePro() (4 input parameters) Param[2]: origin (type: Vector2) Param[3]: rotation (type: float) Param[4]: color (type: Color) -Function 213: DrawRectangleGradientV() (6 input parameters) +Function 211: DrawRectangleGradientV() (6 input parameters) Name: DrawRectangleGradientV Return type: void Description: Draw a vertical-gradient-filled rectangle @@ -2163,7 +2167,7 @@ Function 213: DrawRectangleGradientV() (6 input parameters) Param[4]: height (type: int) Param[5]: color1 (type: Color) Param[6]: color2 (type: Color) -Function 214: DrawRectangleGradientH() (6 input parameters) +Function 212: DrawRectangleGradientH() (6 input parameters) Name: DrawRectangleGradientH Return type: void Description: Draw a horizontal-gradient-filled rectangle @@ -2173,7 +2177,7 @@ Function 214: DrawRectangleGradientH() (6 input parameters) Param[4]: height (type: int) Param[5]: color1 (type: Color) Param[6]: color2 (type: Color) -Function 215: DrawRectangleGradientEx() (5 input parameters) +Function 213: DrawRectangleGradientEx() (5 input parameters) Name: DrawRectangleGradientEx Return type: void Description: Draw a gradient-filled rectangle with custom vertex colors @@ -2182,7 +2186,7 @@ Function 215: DrawRectangleGradientEx() (5 input parameters) Param[3]: col2 (type: Color) Param[4]: col3 (type: Color) Param[5]: col4 (type: Color) -Function 216: DrawRectangleLines() (5 input parameters) +Function 214: DrawRectangleLines() (5 input parameters) Name: DrawRectangleLines Return type: void Description: Draw rectangle outline @@ -2191,14 +2195,14 @@ Function 216: DrawRectangleLines() (5 input parameters) Param[3]: width (type: int) Param[4]: height (type: int) Param[5]: color (type: Color) -Function 217: DrawRectangleLinesEx() (3 input parameters) +Function 215: 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 218: DrawRectangleRounded() (4 input parameters) +Function 216: DrawRectangleRounded() (4 input parameters) Name: DrawRectangleRounded Return type: void Description: Draw rectangle with rounded edges @@ -2206,7 +2210,7 @@ Function 218: DrawRectangleRounded() (4 input parameters) Param[2]: roundness (type: float) Param[3]: segments (type: int) Param[4]: color (type: Color) -Function 219: DrawRectangleRoundedLines() (5 input parameters) +Function 217: DrawRectangleRoundedLines() (5 input parameters) Name: DrawRectangleRoundedLines Return type: void Description: Draw rectangle with rounded edges outline @@ -2215,7 +2219,7 @@ Function 219: DrawRectangleRoundedLines() (5 input parameters) Param[3]: segments (type: int) Param[4]: lineThick (type: float) Param[5]: color (type: Color) -Function 220: DrawTriangle() (4 input parameters) +Function 218: DrawTriangle() (4 input parameters) Name: DrawTriangle Return type: void Description: Draw a color-filled triangle (vertex in counter-clockwise order!) @@ -2223,7 +2227,7 @@ Function 220: DrawTriangle() (4 input parameters) Param[2]: v2 (type: Vector2) Param[3]: v3 (type: Vector2) Param[4]: color (type: Color) -Function 221: DrawTriangleLines() (4 input parameters) +Function 219: DrawTriangleLines() (4 input parameters) Name: DrawTriangleLines Return type: void Description: Draw triangle outline (vertex in counter-clockwise order!) @@ -2231,21 +2235,21 @@ Function 221: DrawTriangleLines() (4 input parameters) Param[2]: v2 (type: Vector2) Param[3]: v3 (type: Vector2) Param[4]: color (type: Color) -Function 222: DrawTriangleFan() (3 input parameters) +Function 220: 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: Vector2 *) Param[2]: pointCount (type: int) Param[3]: color (type: Color) -Function 223: DrawTriangleStrip() (3 input parameters) +Function 221: DrawTriangleStrip() (3 input parameters) Name: DrawTriangleStrip Return type: void Description: Draw a triangle strip defined by points Param[1]: points (type: Vector2 *) Param[2]: pointCount (type: int) Param[3]: color (type: Color) -Function 224: DrawPoly() (5 input parameters) +Function 222: DrawPoly() (5 input parameters) Name: DrawPoly Return type: void Description: Draw a regular polygon (Vector version) @@ -2254,7 +2258,7 @@ Function 224: DrawPoly() (5 input parameters) Param[3]: radius (type: float) Param[4]: rotation (type: float) Param[5]: color (type: Color) -Function 225: DrawPolyLines() (5 input parameters) +Function 223: DrawPolyLines() (5 input parameters) Name: DrawPolyLines Return type: void Description: Draw a polygon outline of n sides @@ -2263,7 +2267,7 @@ Function 225: DrawPolyLines() (5 input parameters) Param[3]: radius (type: float) Param[4]: rotation (type: float) Param[5]: color (type: Color) -Function 226: DrawPolyLinesEx() (6 input parameters) +Function 224: DrawPolyLinesEx() (6 input parameters) Name: DrawPolyLinesEx Return type: void Description: Draw a polygon outline of n sides with extended parameters @@ -2273,13 +2277,13 @@ Function 226: DrawPolyLinesEx() (6 input parameters) Param[4]: rotation (type: float) Param[5]: lineThick (type: float) Param[6]: color (type: Color) -Function 227: CheckCollisionRecs() (2 input parameters) +Function 225: 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 228: CheckCollisionCircles() (4 input parameters) +Function 226: CheckCollisionCircles() (4 input parameters) Name: CheckCollisionCircles Return type: bool Description: Check collision between two circles @@ -2287,27 +2291,27 @@ Function 228: CheckCollisionCircles() (4 input parameters) Param[2]: radius1 (type: float) Param[3]: center2 (type: Vector2) Param[4]: radius2 (type: float) -Function 229: CheckCollisionCircleRec() (3 input parameters) +Function 227: 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 230: CheckCollisionPointRec() (2 input parameters) +Function 228: 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 231: CheckCollisionPointCircle() (3 input parameters) +Function 229: 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 232: CheckCollisionPointTriangle() (4 input parameters) +Function 230: CheckCollisionPointTriangle() (4 input parameters) Name: CheckCollisionPointTriangle Return type: bool Description: Check if point is inside a triangle @@ -2315,14 +2319,14 @@ Function 232: CheckCollisionPointTriangle() (4 input parameters) Param[2]: p1 (type: Vector2) Param[3]: p2 (type: Vector2) Param[4]: p3 (type: Vector2) -Function 233: CheckCollisionPointPoly() (3 input parameters) +Function 231: 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: Vector2 *) Param[3]: pointCount (type: int) -Function 234: CheckCollisionLines() (5 input parameters) +Function 232: 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 @@ -2331,7 +2335,7 @@ Function 234: CheckCollisionLines() (5 input parameters) Param[3]: startPos2 (type: Vector2) Param[4]: endPos2 (type: Vector2) Param[5]: collisionPoint (type: Vector2 *) -Function 235: CheckCollisionPointLine() (4 input parameters) +Function 233: 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] @@ -2339,18 +2343,18 @@ Function 235: CheckCollisionPointLine() (4 input parameters) Param[2]: p1 (type: Vector2) Param[3]: p2 (type: Vector2) Param[4]: threshold (type: int) -Function 236: GetCollisionRec() (2 input parameters) +Function 234: 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 237: LoadImage() (1 input parameters) +Function 235: 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 238: LoadImageRaw() (5 input parameters) +Function 236: LoadImageRaw() (5 input parameters) Name: LoadImageRaw Return type: Image Description: Load image from RAW file data @@ -2359,54 +2363,59 @@ Function 238: LoadImageRaw() (5 input parameters) Param[3]: height (type: int) Param[4]: format (type: int) Param[5]: headerSize (type: int) -Function 239: LoadImageAnim() (2 input parameters) +Function 237: 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 240: LoadImageFromMemory() (3 input parameters) +Function 238: 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 241: LoadImageFromTexture() (1 input parameters) +Function 239: LoadImageFromTexture() (1 input parameters) Name: LoadImageFromTexture Return type: Image Description: Load image from GPU texture data Param[1]: texture (type: Texture2D) -Function 242: LoadImageFromScreen() (0 input parameters) +Function 240: LoadImageFromScreen() (0 input parameters) Name: LoadImageFromScreen Return type: Image Description: Load image from screen buffer and (screenshot) No input parameters -Function 243: UnloadImage() (1 input parameters) +Function 241: IsImageReady() (1 input parameters) + Name: IsImageReady + Return type: bool + Description: Check if an image is ready + Param[1]: image (type: Image) +Function 242: UnloadImage() (1 input parameters) Name: UnloadImage Return type: void Description: Unload image from CPU memory (RAM) Param[1]: image (type: Image) -Function 244: ExportImage() (2 input parameters) +Function 243: 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 245: ExportImageAsCode() (2 input parameters) +Function 244: 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 246: GenImageColor() (3 input parameters) +Function 245: 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 247: GenImageGradientV() (4 input parameters) +Function 246: GenImageGradientV() (4 input parameters) Name: GenImageGradientV Return type: Image Description: Generate image: vertical gradient @@ -2414,7 +2423,7 @@ Function 247: GenImageGradientV() (4 input parameters) Param[2]: height (type: int) Param[3]: top (type: Color) Param[4]: bottom (type: Color) -Function 248: GenImageGradientH() (4 input parameters) +Function 247: GenImageGradientH() (4 input parameters) Name: GenImageGradientH Return type: Image Description: Generate image: horizontal gradient @@ -2422,7 +2431,7 @@ Function 248: GenImageGradientH() (4 input parameters) Param[2]: height (type: int) Param[3]: left (type: Color) Param[4]: right (type: Color) -Function 249: GenImageGradientRadial() (5 input parameters) +Function 248: GenImageGradientRadial() (5 input parameters) Name: GenImageGradientRadial Return type: Image Description: Generate image: radial gradient @@ -2431,7 +2440,7 @@ Function 249: GenImageGradientRadial() (5 input parameters) Param[3]: density (type: float) Param[4]: inner (type: Color) Param[5]: outer (type: Color) -Function 250: GenImageChecked() (6 input parameters) +Function 249: GenImageChecked() (6 input parameters) Name: GenImageChecked Return type: Image Description: Generate image: checked @@ -2441,14 +2450,14 @@ Function 250: GenImageChecked() (6 input parameters) Param[4]: checksY (type: int) Param[5]: col1 (type: Color) Param[6]: col2 (type: Color) -Function 251: GenImageWhiteNoise() (3 input parameters) +Function 250: 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 252: GenImagePerlinNoise() (5 input parameters) +Function 251: GenImagePerlinNoise() (5 input parameters) Name: GenImagePerlinNoise Return type: Image Description: Generate image: perlin noise @@ -2457,13 +2466,20 @@ Function 252: GenImagePerlinNoise() (5 input parameters) Param[3]: offsetX (type: int) Param[4]: offsetY (type: int) Param[5]: scale (type: float) -Function 253: GenImageCellular() (3 input parameters) +Function 252: 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 253: 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 254: ImageCopy() (1 input parameters) Name: ImageCopy Return type: Image @@ -2533,21 +2549,27 @@ Function 264: ImageAlphaPremultiply() (1 input parameters) Return type: void Description: Premultiply alpha channel Param[1]: image (type: Image *) -Function 265: ImageResize() (3 input parameters) +Function 265: 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 266: 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 266: ImageResizeNN() (3 input parameters) +Function 267: 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 267: ImageResizeCanvas() (6 input parameters) +Function 268: ImageResizeCanvas() (6 input parameters) Name: ImageResizeCanvas Return type: void Description: Resize canvas and fill with color @@ -2557,12 +2579,12 @@ Function 267: ImageResizeCanvas() (6 input parameters) Param[4]: offsetX (type: int) Param[5]: offsetY (type: int) Param[6]: fill (type: Color) -Function 268: ImageMipmaps() (1 input parameters) +Function 269: ImageMipmaps() (1 input parameters) Name: ImageMipmaps Return type: void Description: Compute all mipmap levels for a provided image Param[1]: image (type: Image *) -Function 269: ImageDither() (5 input parameters) +Function 270: ImageDither() (5 input parameters) Name: ImageDither Return type: void Description: Dither image data to 16bpp or lower (Floyd-Steinberg dithering) @@ -2571,103 +2593,103 @@ Function 269: ImageDither() (5 input parameters) Param[3]: gBpp (type: int) Param[4]: bBpp (type: int) Param[5]: aBpp (type: int) -Function 270: ImageFlipVertical() (1 input parameters) +Function 271: ImageFlipVertical() (1 input parameters) Name: ImageFlipVertical Return type: void Description: Flip image vertically Param[1]: image (type: Image *) -Function 271: ImageFlipHorizontal() (1 input parameters) +Function 272: ImageFlipHorizontal() (1 input parameters) Name: ImageFlipHorizontal Return type: void Description: Flip image horizontally Param[1]: image (type: Image *) -Function 272: ImageRotateCW() (1 input parameters) +Function 273: ImageRotateCW() (1 input parameters) Name: ImageRotateCW Return type: void Description: Rotate image clockwise 90deg Param[1]: image (type: Image *) -Function 273: ImageRotateCCW() (1 input parameters) +Function 274: ImageRotateCCW() (1 input parameters) Name: ImageRotateCCW Return type: void Description: Rotate image counter-clockwise 90deg Param[1]: image (type: Image *) -Function 274: ImageColorTint() (2 input parameters) +Function 275: 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 275: ImageColorInvert() (1 input parameters) +Function 276: ImageColorInvert() (1 input parameters) Name: ImageColorInvert Return type: void Description: Modify image color: invert Param[1]: image (type: Image *) -Function 276: ImageColorGrayscale() (1 input parameters) +Function 277: ImageColorGrayscale() (1 input parameters) Name: ImageColorGrayscale Return type: void Description: Modify image color: grayscale Param[1]: image (type: Image *) -Function 277: ImageColorContrast() (2 input parameters) +Function 278: 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 278: ImageColorBrightness() (2 input parameters) +Function 279: 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 279: ImageColorReplace() (3 input parameters) +Function 280: 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 280: LoadImageColors() (1 input parameters) +Function 281: 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 281: LoadImagePalette() (3 input parameters) +Function 282: 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 282: UnloadImageColors() (1 input parameters) +Function 283: UnloadImageColors() (1 input parameters) Name: UnloadImageColors Return type: void Description: Unload color data loaded with LoadImageColors() Param[1]: colors (type: Color *) -Function 283: UnloadImagePalette() (1 input parameters) +Function 284: UnloadImagePalette() (1 input parameters) Name: UnloadImagePalette Return type: void Description: Unload colors palette loaded with LoadImagePalette() Param[1]: colors (type: Color *) -Function 284: GetImageAlphaBorder() (2 input parameters) +Function 285: 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 285: GetImageColor() (3 input parameters) +Function 286: 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 286: ImageClearBackground() (2 input parameters) +Function 287: 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 287: ImageDrawPixel() (4 input parameters) +Function 288: ImageDrawPixel() (4 input parameters) Name: ImageDrawPixel Return type: void Description: Draw pixel within an image @@ -2675,14 +2697,14 @@ Function 287: ImageDrawPixel() (4 input parameters) Param[2]: posX (type: int) Param[3]: posY (type: int) Param[4]: color (type: Color) -Function 288: ImageDrawPixelV() (3 input parameters) +Function 289: 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 289: ImageDrawLine() (6 input parameters) +Function 290: ImageDrawLine() (6 input parameters) Name: ImageDrawLine Return type: void Description: Draw line within an image @@ -2692,7 +2714,7 @@ Function 289: ImageDrawLine() (6 input parameters) Param[4]: endPosX (type: int) Param[5]: endPosY (type: int) Param[6]: color (type: Color) -Function 290: ImageDrawLineV() (4 input parameters) +Function 291: ImageDrawLineV() (4 input parameters) Name: ImageDrawLineV Return type: void Description: Draw line within an image (Vector version) @@ -2700,7 +2722,7 @@ Function 290: ImageDrawLineV() (4 input parameters) Param[2]: start (type: Vector2) Param[3]: end (type: Vector2) Param[4]: color (type: Color) -Function 291: ImageDrawCircle() (5 input parameters) +Function 292: ImageDrawCircle() (5 input parameters) Name: ImageDrawCircle Return type: void Description: Draw a filled circle within an image @@ -2709,7 +2731,7 @@ Function 291: ImageDrawCircle() (5 input parameters) Param[3]: centerY (type: int) Param[4]: radius (type: int) Param[5]: color (type: Color) -Function 292: ImageDrawCircleV() (4 input parameters) +Function 293: ImageDrawCircleV() (4 input parameters) Name: ImageDrawCircleV Return type: void Description: Draw a filled circle within an image (Vector version) @@ -2717,7 +2739,7 @@ Function 292: ImageDrawCircleV() (4 input parameters) Param[2]: center (type: Vector2) Param[3]: radius (type: int) Param[4]: color (type: Color) -Function 293: ImageDrawCircleLines() (5 input parameters) +Function 294: ImageDrawCircleLines() (5 input parameters) Name: ImageDrawCircleLines Return type: void Description: Draw circle outline within an image @@ -2726,7 +2748,7 @@ Function 293: ImageDrawCircleLines() (5 input parameters) Param[3]: centerY (type: int) Param[4]: radius (type: int) Param[5]: color (type: Color) -Function 294: ImageDrawCircleLinesV() (4 input parameters) +Function 295: ImageDrawCircleLinesV() (4 input parameters) Name: ImageDrawCircleLinesV Return type: void Description: Draw circle outline within an image (Vector version) @@ -2734,7 +2756,7 @@ Function 294: ImageDrawCircleLinesV() (4 input parameters) Param[2]: center (type: Vector2) Param[3]: radius (type: int) Param[4]: color (type: Color) -Function 295: ImageDrawRectangle() (6 input parameters) +Function 296: ImageDrawRectangle() (6 input parameters) Name: ImageDrawRectangle Return type: void Description: Draw rectangle within an image @@ -2744,7 +2766,7 @@ Function 295: ImageDrawRectangle() (6 input parameters) Param[4]: width (type: int) Param[5]: height (type: int) Param[6]: color (type: Color) -Function 296: ImageDrawRectangleV() (4 input parameters) +Function 297: ImageDrawRectangleV() (4 input parameters) Name: ImageDrawRectangleV Return type: void Description: Draw rectangle within an image (Vector version) @@ -2752,14 +2774,14 @@ Function 296: ImageDrawRectangleV() (4 input parameters) Param[2]: position (type: Vector2) Param[3]: size (type: Vector2) Param[4]: color (type: Color) -Function 297: ImageDrawRectangleRec() (3 input parameters) +Function 298: 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 298: ImageDrawRectangleLines() (4 input parameters) +Function 299: ImageDrawRectangleLines() (4 input parameters) Name: ImageDrawRectangleLines Return type: void Description: Draw rectangle lines within an image @@ -2767,7 +2789,7 @@ Function 298: ImageDrawRectangleLines() (4 input parameters) Param[2]: rec (type: Rectangle) Param[3]: thick (type: int) Param[4]: color (type: Color) -Function 299: ImageDraw() (5 input parameters) +Function 300: ImageDraw() (5 input parameters) Name: ImageDraw Return type: void Description: Draw a source image within a destination image (tint applied to source) @@ -2776,7 +2798,7 @@ Function 299: ImageDraw() (5 input parameters) Param[3]: srcRec (type: Rectangle) Param[4]: dstRec (type: Rectangle) Param[5]: tint (type: Color) -Function 300: ImageDrawText() (6 input parameters) +Function 301: ImageDrawText() (6 input parameters) Name: ImageDrawText Return type: void Description: Draw text (using default font) within an image (destination) @@ -2786,7 +2808,7 @@ Function 300: ImageDrawText() (6 input parameters) Param[4]: posY (type: int) Param[5]: fontSize (type: int) Param[6]: color (type: Color) -Function 301: ImageDrawTextEx() (7 input parameters) +Function 302: ImageDrawTextEx() (7 input parameters) Name: ImageDrawTextEx Return type: void Description: Draw text (custom sprite font) within an image (destination) @@ -2797,69 +2819,79 @@ Function 301: ImageDrawTextEx() (7 input parameters) Param[5]: fontSize (type: float) Param[6]: spacing (type: float) Param[7]: tint (type: Color) -Function 302: LoadTexture() (1 input parameters) +Function 303: 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 303: LoadTextureFromImage() (1 input parameters) +Function 304: LoadTextureFromImage() (1 input parameters) Name: LoadTextureFromImage Return type: Texture2D Description: Load texture from image data Param[1]: image (type: Image) -Function 304: LoadTextureCubemap() (2 input parameters) +Function 305: 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 305: LoadRenderTexture() (2 input parameters) +Function 306: 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 306: UnloadTexture() (1 input parameters) +Function 307: IsTextureReady() (1 input parameters) + Name: IsTextureReady + Return type: bool + Description: Check if a texture is ready + Param[1]: texture (type: Texture2D) +Function 308: UnloadTexture() (1 input parameters) Name: UnloadTexture Return type: void Description: Unload texture from GPU memory (VRAM) Param[1]: texture (type: Texture2D) -Function 307: UnloadRenderTexture() (1 input parameters) +Function 309: IsRenderTextureReady() (1 input parameters) + Name: IsRenderTextureReady + Return type: bool + Description: Check if a render texture is ready + Param[1]: target (type: RenderTexture2D) +Function 310: UnloadRenderTexture() (1 input parameters) Name: UnloadRenderTexture Return type: void Description: Unload render texture from GPU memory (VRAM) Param[1]: target (type: RenderTexture2D) -Function 308: UpdateTexture() (2 input parameters) +Function 311: UpdateTexture() (2 input parameters) Name: UpdateTexture Return type: void Description: Update GPU texture with new data Param[1]: texture (type: Texture2D) Param[2]: pixels (type: const void *) -Function 309: UpdateTextureRec() (3 input parameters) +Function 312: UpdateTextureRec() (3 input parameters) Name: UpdateTextureRec Return type: void Description: Update GPU texture rectangle with new data Param[1]: texture (type: Texture2D) Param[2]: rec (type: Rectangle) Param[3]: pixels (type: const void *) -Function 310: GenTextureMipmaps() (1 input parameters) +Function 313: GenTextureMipmaps() (1 input parameters) Name: GenTextureMipmaps Return type: void Description: Generate GPU mipmaps for a texture Param[1]: texture (type: Texture2D *) -Function 311: SetTextureFilter() (2 input parameters) +Function 314: 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 312: SetTextureWrap() (2 input parameters) +Function 315: 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 313: DrawTexture() (4 input parameters) +Function 316: DrawTexture() (4 input parameters) Name: DrawTexture Return type: void Description: Draw a Texture2D @@ -2867,14 +2899,14 @@ Function 313: DrawTexture() (4 input parameters) Param[2]: posX (type: int) Param[3]: posY (type: int) Param[4]: tint (type: Color) -Function 314: DrawTextureV() (3 input parameters) +Function 317: 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 315: DrawTextureEx() (5 input parameters) +Function 318: DrawTextureEx() (5 input parameters) Name: DrawTextureEx Return type: void Description: Draw a Texture2D with extended parameters @@ -2883,7 +2915,7 @@ Function 315: DrawTextureEx() (5 input parameters) Param[3]: rotation (type: float) Param[4]: scale (type: float) Param[5]: tint (type: Color) -Function 316: DrawTextureRec() (4 input parameters) +Function 319: DrawTextureRec() (4 input parameters) Name: DrawTextureRec Return type: void Description: Draw a part of a texture defined by a rectangle @@ -2891,27 +2923,7 @@ Function 316: DrawTextureRec() (4 input parameters) Param[2]: source (type: Rectangle) Param[3]: position (type: Vector2) Param[4]: tint (type: Color) -Function 317: DrawTextureQuad() (5 input parameters) - Name: DrawTextureQuad - Return type: void - Description: Draw texture quad with tiling and offset parameters - Param[1]: texture (type: Texture2D) - Param[2]: tiling (type: Vector2) - Param[3]: offset (type: Vector2) - Param[4]: quad (type: Rectangle) - Param[5]: tint (type: Color) -Function 318: DrawTextureTiled() (7 input parameters) - Name: DrawTextureTiled - Return type: void - Description: Draw part of a texture (defined by a rectangle) with rotation and scale tiled into dest. - Param[1]: texture (type: Texture2D) - Param[2]: source (type: Rectangle) - Param[3]: dest (type: Rectangle) - Param[4]: origin (type: Vector2) - Param[5]: rotation (type: float) - Param[6]: scale (type: float) - Param[7]: tint (type: Color) -Function 319: DrawTexturePro() (6 input parameters) +Function 320: DrawTexturePro() (6 input parameters) Name: DrawTexturePro Return type: void Description: Draw a part of a texture defined by a rectangle with 'pro' parameters @@ -2921,7 +2933,7 @@ Function 319: DrawTexturePro() (6 input parameters) Param[4]: origin (type: Vector2) Param[5]: rotation (type: float) Param[6]: tint (type: Color) -Function 320: DrawTextureNPatch() (6 input parameters) +Function 321: DrawTextureNPatch() (6 input parameters) Name: DrawTextureNPatch Return type: void Description: Draws a texture (or part of it) that stretches or shrinks nicely @@ -2931,16 +2943,6 @@ Function 320: DrawTextureNPatch() (6 input parameters) Param[4]: origin (type: Vector2) Param[5]: rotation (type: float) Param[6]: tint (type: Color) -Function 321: DrawTexturePoly() (6 input parameters) - Name: DrawTexturePoly - Return type: void - Description: Draw a textured polygon - Param[1]: texture (type: Texture2D) - Param[2]: center (type: Vector2) - Param[3]: points (type: Vector2 *) - Param[4]: texcoords (type: Vector2 *) - Param[5]: pointCount (type: int) - Param[6]: tint (type: Color) Function 322: Fade() (2 input parameters) Name: Fade Return type: Color @@ -2974,55 +2976,73 @@ Function 327: ColorFromHSV() (3 input parameters) Param[1]: hue (type: float) Param[2]: saturation (type: float) Param[3]: value (type: float) -Function 328: ColorAlpha() (2 input parameters) +Function 328: 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 329: 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 330: 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 331: 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 329: ColorAlphaBlend() (3 input parameters) +Function 332: 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 330: GetColor() (1 input parameters) +Function 333: GetColor() (1 input parameters) Name: GetColor Return type: Color Description: Get Color structure from hexadecimal value Param[1]: hexValue (type: unsigned int) -Function 331: GetPixelColor() (2 input parameters) +Function 334: 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 332: SetPixelColor() (3 input parameters) +Function 335: 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 333: GetPixelDataSize() (3 input parameters) +Function 336: 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 334: GetFontDefault() (0 input parameters) +Function 337: GetFontDefault() (0 input parameters) Name: GetFontDefault Return type: Font Description: Get the default Font No input parameters -Function 335: LoadFont() (1 input parameters) +Function 338: 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 336: LoadFontEx() (4 input parameters) +Function 339: LoadFontEx() (4 input parameters) Name: LoadFontEx Return type: Font Description: Load font from file with extended parameters, use NULL for fontChars and 0 for glyphCount to load the default character set @@ -3030,14 +3050,14 @@ Function 336: LoadFontEx() (4 input parameters) Param[2]: fontSize (type: int) Param[3]: fontChars (type: int *) Param[4]: glyphCount (type: int) -Function 337: LoadFontFromImage() (3 input parameters) +Function 340: 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 338: LoadFontFromMemory() (6 input parameters) +Function 341: LoadFontFromMemory() (6 input parameters) Name: LoadFontFromMemory Return type: Font Description: Load font from memory buffer, fileType refers to extension: i.e. '.ttf' @@ -3047,7 +3067,12 @@ Function 338: LoadFontFromMemory() (6 input parameters) Param[4]: fontSize (type: int) Param[5]: fontChars (type: int *) Param[6]: glyphCount (type: int) -Function 339: LoadFontData() (6 input parameters) +Function 342: IsFontReady() (1 input parameters) + Name: IsFontReady + Return type: bool + Description: Check if a font is ready + Param[1]: font (type: Font) +Function 343: LoadFontData() (6 input parameters) Name: LoadFontData Return type: GlyphInfo * Description: Load font data for further use @@ -3057,7 +3082,7 @@ Function 339: LoadFontData() (6 input parameters) Param[4]: fontChars (type: int *) Param[5]: glyphCount (type: int) Param[6]: type (type: int) -Function 340: GenImageFontAtlas() (6 input parameters) +Function 344: GenImageFontAtlas() (6 input parameters) Name: GenImageFontAtlas Return type: Image Description: Generate image font atlas using chars info @@ -3067,30 +3092,30 @@ Function 340: GenImageFontAtlas() (6 input parameters) Param[4]: fontSize (type: int) Param[5]: padding (type: int) Param[6]: packMethod (type: int) -Function 341: UnloadFontData() (2 input parameters) +Function 345: UnloadFontData() (2 input parameters) Name: UnloadFontData Return type: void Description: Unload font chars info data (RAM) Param[1]: chars (type: GlyphInfo *) Param[2]: glyphCount (type: int) -Function 342: UnloadFont() (1 input parameters) +Function 346: UnloadFont() (1 input parameters) Name: UnloadFont Return type: void Description: Unload font from GPU memory (VRAM) Param[1]: font (type: Font) -Function 343: ExportFontAsCode() (2 input parameters) +Function 347: 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 344: DrawFPS() (2 input parameters) +Function 348: DrawFPS() (2 input parameters) Name: DrawFPS Return type: void Description: Draw current FPS Param[1]: posX (type: int) Param[2]: posY (type: int) -Function 345: DrawText() (5 input parameters) +Function 349: DrawText() (5 input parameters) Name: DrawText Return type: void Description: Draw text (using default font) @@ -3099,7 +3124,7 @@ Function 345: DrawText() (5 input parameters) Param[3]: posY (type: int) Param[4]: fontSize (type: int) Param[5]: color (type: Color) -Function 346: DrawTextEx() (6 input parameters) +Function 350: DrawTextEx() (6 input parameters) Name: DrawTextEx Return type: void Description: Draw text using font and additional parameters @@ -3109,7 +3134,7 @@ Function 346: DrawTextEx() (6 input parameters) Param[4]: fontSize (type: float) Param[5]: spacing (type: float) Param[6]: tint (type: Color) -Function 347: DrawTextPro() (8 input parameters) +Function 351: DrawTextPro() (8 input parameters) Name: DrawTextPro Return type: void Description: Draw text using Font and pro parameters (rotation) @@ -3121,7 +3146,7 @@ Function 347: DrawTextPro() (8 input parameters) Param[6]: fontSize (type: float) Param[7]: spacing (type: float) Param[8]: tint (type: Color) -Function 348: DrawTextCodepoint() (5 input parameters) +Function 352: DrawTextCodepoint() (5 input parameters) Name: DrawTextCodepoint Return type: void Description: Draw one character (codepoint) @@ -3130,7 +3155,7 @@ Function 348: DrawTextCodepoint() (5 input parameters) Param[3]: position (type: Vector2) Param[4]: fontSize (type: float) Param[5]: tint (type: Color) -Function 349: DrawTextCodepoints() (7 input parameters) +Function 353: DrawTextCodepoints() (7 input parameters) Name: DrawTextCodepoints Return type: void Description: Draw multiple character (codepoint) @@ -3141,13 +3166,13 @@ Function 349: DrawTextCodepoints() (7 input parameters) Param[5]: fontSize (type: float) Param[6]: spacing (type: float) Param[7]: tint (type: Color) -Function 350: MeasureText() (2 input parameters) +Function 354: 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 351: MeasureTextEx() (4 input parameters) +Function 355: MeasureTextEx() (4 input parameters) Name: MeasureTextEx Return type: Vector2 Description: Measure string size for Font @@ -3155,180 +3180,180 @@ Function 351: MeasureTextEx() (4 input parameters) Param[2]: text (type: const char *) Param[3]: fontSize (type: float) Param[4]: spacing (type: float) -Function 352: GetGlyphIndex() (2 input parameters) +Function 356: 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 353: GetGlyphInfo() (2 input parameters) +Function 357: 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 354: GetGlyphAtlasRec() (2 input parameters) +Function 358: 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 355: LoadUTF8() (2 input parameters) +Function 359: 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 356: UnloadUTF8() (1 input parameters) +Function 360: UnloadUTF8() (1 input parameters) Name: UnloadUTF8 Return type: void Description: Unload UTF-8 text encoded from codepoints array Param[1]: text (type: char *) -Function 357: LoadCodepoints() (2 input parameters) +Function 361: 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 358: UnloadCodepoints() (1 input parameters) +Function 362: UnloadCodepoints() (1 input parameters) Name: UnloadCodepoints Return type: void Description: Unload codepoints data from memory Param[1]: codepoints (type: int *) -Function 359: GetCodepointCount() (1 input parameters) +Function 363: 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 360: GetCodepoint() (2 input parameters) +Function 364: 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 361: GetCodepointNext() (2 input parameters) +Function 365: 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 362: GetCodepointPrevious() (2 input parameters) +Function 366: 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 363: CodepointToUTF8() (2 input parameters) +Function 367: 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 364: TextCopy() (2 input parameters) +Function 368: 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 365: TextIsEqual() (2 input parameters) +Function 369: 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 366: TextLength() (1 input parameters) +Function 370: 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 367: TextFormat() (2 input parameters) +Function 371: 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 368: TextSubtext() (3 input parameters) +Function 372: 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 369: TextReplace() (3 input parameters) +Function 373: TextReplace() (3 input parameters) Name: TextReplace Return type: char * Description: Replace text string (WARNING: memory must be freed!) Param[1]: text (type: char *) Param[2]: replace (type: const char *) Param[3]: by (type: const char *) -Function 370: TextInsert() (3 input parameters) +Function 374: 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 371: TextJoin() (3 input parameters) +Function 375: TextJoin() (3 input parameters) Name: TextJoin Return type: const char * Description: Join text strings with delimiter Param[1]: textList (type: const char **) Param[2]: count (type: int) Param[3]: delimiter (type: const char *) -Function 372: TextSplit() (3 input parameters) +Function 376: TextSplit() (3 input parameters) Name: TextSplit Return type: const char ** Description: Split text into multiple strings Param[1]: text (type: const char *) Param[2]: delimiter (type: char) Param[3]: count (type: int *) -Function 373: TextAppend() (3 input parameters) +Function 377: 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 374: TextFindIndex() (2 input parameters) +Function 378: TextFindIndex() (2 input parameters) Name: TextFindIndex Return type: int Description: Find first text occurrence within a string Param[1]: text (type: const char *) Param[2]: find (type: const char *) -Function 375: TextToUpper() (1 input parameters) +Function 379: TextToUpper() (1 input parameters) Name: TextToUpper Return type: const char * Description: Get upper case version of provided string Param[1]: text (type: const char *) -Function 376: TextToLower() (1 input parameters) +Function 380: TextToLower() (1 input parameters) Name: TextToLower Return type: const char * Description: Get lower case version of provided string Param[1]: text (type: const char *) -Function 377: TextToPascal() (1 input parameters) +Function 381: TextToPascal() (1 input parameters) Name: TextToPascal Return type: const char * Description: Get Pascal case notation version of provided string Param[1]: text (type: const char *) -Function 378: TextToInteger() (1 input parameters) +Function 382: TextToInteger() (1 input parameters) Name: TextToInteger Return type: int Description: Get integer value from text (negative values not supported) Param[1]: text (type: const char *) -Function 379: DrawLine3D() (3 input parameters) +Function 383: 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 380: DrawPoint3D() (2 input parameters) +Function 384: 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 381: DrawCircle3D() (5 input parameters) +Function 385: DrawCircle3D() (5 input parameters) Name: DrawCircle3D Return type: void Description: Draw a circle in 3D world space @@ -3337,7 +3362,7 @@ Function 381: DrawCircle3D() (5 input parameters) Param[3]: rotationAxis (type: Vector3) Param[4]: rotationAngle (type: float) Param[5]: color (type: Color) -Function 382: DrawTriangle3D() (4 input parameters) +Function 386: DrawTriangle3D() (4 input parameters) Name: DrawTriangle3D Return type: void Description: Draw a color-filled triangle (vertex in counter-clockwise order!) @@ -3345,14 +3370,14 @@ Function 382: DrawTriangle3D() (4 input parameters) Param[2]: v2 (type: Vector3) Param[3]: v3 (type: Vector3) Param[4]: color (type: Color) -Function 383: DrawTriangleStrip3D() (3 input parameters) +Function 387: DrawTriangleStrip3D() (3 input parameters) Name: DrawTriangleStrip3D Return type: void Description: Draw a triangle strip defined by points Param[1]: points (type: Vector3 *) Param[2]: pointCount (type: int) Param[3]: color (type: Color) -Function 384: DrawCube() (5 input parameters) +Function 388: DrawCube() (5 input parameters) Name: DrawCube Return type: void Description: Draw cube @@ -3361,14 +3386,14 @@ Function 384: DrawCube() (5 input parameters) Param[3]: height (type: float) Param[4]: length (type: float) Param[5]: color (type: Color) -Function 385: DrawCubeV() (3 input parameters) +Function 389: 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 386: DrawCubeWires() (5 input parameters) +Function 390: DrawCubeWires() (5 input parameters) Name: DrawCubeWires Return type: void Description: Draw cube wires @@ -3377,42 +3402,21 @@ Function 386: DrawCubeWires() (5 input parameters) Param[3]: height (type: float) Param[4]: length (type: float) Param[5]: color (type: Color) -Function 387: DrawCubeWiresV() (3 input parameters) +Function 391: 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 388: DrawCubeTexture() (6 input parameters) - Name: DrawCubeTexture - Return type: void - Description: Draw cube textured - Param[1]: texture (type: Texture2D) - Param[2]: position (type: Vector3) - Param[3]: width (type: float) - Param[4]: height (type: float) - Param[5]: length (type: float) - Param[6]: color (type: Color) -Function 389: DrawCubeTextureRec() (7 input parameters) - Name: DrawCubeTextureRec - Return type: void - Description: Draw cube with a region of a texture - Param[1]: texture (type: Texture2D) - Param[2]: source (type: Rectangle) - Param[3]: position (type: Vector3) - Param[4]: width (type: float) - Param[5]: height (type: float) - Param[6]: length (type: float) - Param[7]: color (type: Color) -Function 390: DrawSphere() (3 input parameters) +Function 392: 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 391: DrawSphereEx() (5 input parameters) +Function 393: DrawSphereEx() (5 input parameters) Name: DrawSphereEx Return type: void Description: Draw sphere with extended parameters @@ -3421,7 +3425,7 @@ Function 391: DrawSphereEx() (5 input parameters) Param[3]: rings (type: int) Param[4]: slices (type: int) Param[5]: color (type: Color) -Function 392: DrawSphereWires() (5 input parameters) +Function 394: DrawSphereWires() (5 input parameters) Name: DrawSphereWires Return type: void Description: Draw sphere wires @@ -3430,7 +3434,7 @@ Function 392: DrawSphereWires() (5 input parameters) Param[3]: rings (type: int) Param[4]: slices (type: int) Param[5]: color (type: Color) -Function 393: DrawCylinder() (6 input parameters) +Function 395: DrawCylinder() (6 input parameters) Name: DrawCylinder Return type: void Description: Draw a cylinder/cone @@ -3440,7 +3444,7 @@ Function 393: DrawCylinder() (6 input parameters) Param[4]: height (type: float) Param[5]: slices (type: int) Param[6]: color (type: Color) -Function 394: DrawCylinderEx() (6 input parameters) +Function 396: DrawCylinderEx() (6 input parameters) Name: DrawCylinderEx Return type: void Description: Draw a cylinder with base at startPos and top at endPos @@ -3450,7 +3454,7 @@ Function 394: DrawCylinderEx() (6 input parameters) Param[4]: endRadius (type: float) Param[5]: sides (type: int) Param[6]: color (type: Color) -Function 395: DrawCylinderWires() (6 input parameters) +Function 397: DrawCylinderWires() (6 input parameters) Name: DrawCylinderWires Return type: void Description: Draw a cylinder/cone wires @@ -3460,7 +3464,7 @@ Function 395: DrawCylinderWires() (6 input parameters) Param[4]: height (type: float) Param[5]: slices (type: int) Param[6]: color (type: Color) -Function 396: DrawCylinderWiresEx() (6 input parameters) +Function 398: DrawCylinderWiresEx() (6 input parameters) Name: DrawCylinderWiresEx Return type: void Description: Draw a cylinder wires with base at startPos and top at endPos @@ -3470,51 +3474,71 @@ Function 396: DrawCylinderWiresEx() (6 input parameters) Param[4]: endRadius (type: float) Param[5]: sides (type: int) Param[6]: color (type: Color) -Function 397: DrawPlane() (3 input parameters) +Function 399: DrawCapsule() (6 input parameters) + Name: DrawCapsule + Return type: void + Description: Draw a capsule with the center of its sphere caps at startPos and endPos + Param[1]: startPos (type: Vector3) + Param[2]: endPos (type: Vector3) + Param[3]: radius (type: float) + Param[4]: slices (type: int) + Param[5]: rings (type: int) + Param[6]: color (type: Color) +Function 400: DrawCapsuleWires() (6 input parameters) + Name: DrawCapsuleWires + Return type: void + Description: Draw capsule wireframe with the center of its sphere caps at startPos and endPos + Param[1]: startPos (type: Vector3) + Param[2]: endPos (type: Vector3) + Param[3]: radius (type: float) + Param[4]: slices (type: int) + Param[5]: rings (type: int) + Param[6]: color (type: Color) +Function 401: 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 398: DrawRay() (2 input parameters) +Function 402: 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 399: DrawGrid() (2 input parameters) +Function 403: 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 400: LoadModel() (1 input parameters) +Function 404: LoadModel() (1 input parameters) Name: LoadModel Return type: Model Description: Load model from files (meshes and materials) Param[1]: fileName (type: const char *) -Function 401: LoadModelFromMesh() (1 input parameters) +Function 405: LoadModelFromMesh() (1 input parameters) Name: LoadModelFromMesh Return type: Model Description: Load model from generated mesh (default material) Param[1]: mesh (type: Mesh) -Function 402: UnloadModel() (1 input parameters) +Function 406: IsModelReady() (1 input parameters) + Name: IsModelReady + Return type: bool + Description: Check if a model is ready + Param[1]: model (type: Model) +Function 407: 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 403: UnloadModelKeepMeshes() (1 input parameters) - Name: UnloadModelKeepMeshes - Return type: void - Description: Unload model (but not meshes) from memory (RAM and/or VRAM) - Param[1]: model (type: Model) -Function 404: GetModelBoundingBox() (1 input parameters) +Function 408: GetModelBoundingBox() (1 input parameters) Name: GetModelBoundingBox Return type: BoundingBox Description: Compute model bounding box limits (considers all meshes) Param[1]: model (type: Model) -Function 405: DrawModel() (4 input parameters) +Function 409: DrawModel() (4 input parameters) Name: DrawModel Return type: void Description: Draw a model (with texture if set) @@ -3522,7 +3546,7 @@ Function 405: DrawModel() (4 input parameters) Param[2]: position (type: Vector3) Param[3]: scale (type: float) Param[4]: tint (type: Color) -Function 406: DrawModelEx() (6 input parameters) +Function 410: DrawModelEx() (6 input parameters) Name: DrawModelEx Return type: void Description: Draw a model with extended parameters @@ -3532,7 +3556,7 @@ Function 406: DrawModelEx() (6 input parameters) Param[4]: rotationAngle (type: float) Param[5]: scale (type: Vector3) Param[6]: tint (type: Color) -Function 407: DrawModelWires() (4 input parameters) +Function 411: DrawModelWires() (4 input parameters) Name: DrawModelWires Return type: void Description: Draw a model wires (with texture if set) @@ -3540,7 +3564,7 @@ Function 407: DrawModelWires() (4 input parameters) Param[2]: position (type: Vector3) Param[3]: scale (type: float) Param[4]: tint (type: Color) -Function 408: DrawModelWiresEx() (6 input parameters) +Function 412: DrawModelWiresEx() (6 input parameters) Name: DrawModelWiresEx Return type: void Description: Draw a model wires (with texture if set) with extended parameters @@ -3550,13 +3574,13 @@ Function 408: DrawModelWiresEx() (6 input parameters) Param[4]: rotationAngle (type: float) Param[5]: scale (type: Vector3) Param[6]: tint (type: Color) -Function 409: DrawBoundingBox() (2 input parameters) +Function 413: 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 410: DrawBillboard() (5 input parameters) +Function 414: DrawBillboard() (5 input parameters) Name: DrawBillboard Return type: void Description: Draw a billboard texture @@ -3565,7 +3589,7 @@ Function 410: DrawBillboard() (5 input parameters) Param[3]: position (type: Vector3) Param[4]: size (type: float) Param[5]: tint (type: Color) -Function 411: DrawBillboardRec() (6 input parameters) +Function 415: DrawBillboardRec() (6 input parameters) Name: DrawBillboardRec Return type: void Description: Draw a billboard texture defined by source @@ -3575,7 +3599,7 @@ Function 411: DrawBillboardRec() (6 input parameters) Param[4]: position (type: Vector3) Param[5]: size (type: Vector2) Param[6]: tint (type: Color) -Function 412: DrawBillboardPro() (9 input parameters) +Function 416: DrawBillboardPro() (9 input parameters) Name: DrawBillboardPro Return type: void Description: Draw a billboard texture defined by source and rotation @@ -3588,13 +3612,13 @@ Function 412: DrawBillboardPro() (9 input parameters) Param[7]: origin (type: Vector2) Param[8]: rotation (type: float) Param[9]: tint (type: Color) -Function 413: UploadMesh() (2 input parameters) +Function 417: 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 414: UpdateMeshBuffer() (5 input parameters) +Function 418: UpdateMeshBuffer() (5 input parameters) Name: UpdateMeshBuffer Return type: void Description: Update mesh vertex data in GPU for a specific buffer index @@ -3603,19 +3627,19 @@ Function 414: UpdateMeshBuffer() (5 input parameters) Param[3]: data (type: const void *) Param[4]: dataSize (type: int) Param[5]: offset (type: int) -Function 415: UnloadMesh() (1 input parameters) +Function 419: UnloadMesh() (1 input parameters) Name: UnloadMesh Return type: void Description: Unload mesh data from CPU and GPU Param[1]: mesh (type: Mesh) -Function 416: DrawMesh() (3 input parameters) +Function 420: 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 417: DrawMeshInstanced() (4 input parameters) +Function 421: DrawMeshInstanced() (4 input parameters) Name: DrawMeshInstanced Return type: void Description: Draw multiple mesh instances with material and different transforms @@ -3623,29 +3647,29 @@ Function 417: DrawMeshInstanced() (4 input parameters) Param[2]: material (type: Material) Param[3]: transforms (type: const Matrix *) Param[4]: instances (type: int) -Function 418: ExportMesh() (2 input parameters) +Function 422: 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 419: GetMeshBoundingBox() (1 input parameters) +Function 423: GetMeshBoundingBox() (1 input parameters) Name: GetMeshBoundingBox Return type: BoundingBox Description: Compute mesh bounding box limits Param[1]: mesh (type: Mesh) -Function 420: GenMeshTangents() (1 input parameters) +Function 424: GenMeshTangents() (1 input parameters) Name: GenMeshTangents Return type: void Description: Compute mesh tangents Param[1]: mesh (type: Mesh *) -Function 421: GenMeshPoly() (2 input parameters) +Function 425: GenMeshPoly() (2 input parameters) Name: GenMeshPoly Return type: Mesh Description: Generate polygonal mesh Param[1]: sides (type: int) Param[2]: radius (type: float) -Function 422: GenMeshPlane() (4 input parameters) +Function 426: GenMeshPlane() (4 input parameters) Name: GenMeshPlane Return type: Mesh Description: Generate plane mesh (with subdivisions) @@ -3653,42 +3677,42 @@ Function 422: GenMeshPlane() (4 input parameters) Param[2]: length (type: float) Param[3]: resX (type: int) Param[4]: resZ (type: int) -Function 423: GenMeshCube() (3 input parameters) +Function 427: 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 424: GenMeshSphere() (3 input parameters) +Function 428: 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 425: GenMeshHemiSphere() (3 input parameters) +Function 429: 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 426: GenMeshCylinder() (3 input parameters) +Function 430: 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 427: GenMeshCone() (3 input parameters) +Function 431: 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 428: GenMeshTorus() (4 input parameters) +Function 432: GenMeshTorus() (4 input parameters) Name: GenMeshTorus Return type: Mesh Description: Generate torus mesh @@ -3696,7 +3720,7 @@ Function 428: GenMeshTorus() (4 input parameters) Param[2]: size (type: float) Param[3]: radSeg (type: int) Param[4]: sides (type: int) -Function 429: GenMeshKnot() (4 input parameters) +Function 433: GenMeshKnot() (4 input parameters) Name: GenMeshKnot Return type: Mesh Description: Generate trefoil knot mesh @@ -3704,79 +3728,84 @@ Function 429: GenMeshKnot() (4 input parameters) Param[2]: size (type: float) Param[3]: radSeg (type: int) Param[4]: sides (type: int) -Function 430: GenMeshHeightmap() (2 input parameters) +Function 434: 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 431: GenMeshCubicmap() (2 input parameters) +Function 435: 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 432: LoadMaterials() (2 input parameters) +Function 436: 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 433: LoadMaterialDefault() (0 input parameters) +Function 437: LoadMaterialDefault() (0 input parameters) Name: LoadMaterialDefault Return type: Material Description: Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps) No input parameters -Function 434: UnloadMaterial() (1 input parameters) +Function 438: IsMaterialReady() (1 input parameters) + Name: IsMaterialReady + Return type: bool + Description: Check if a material is ready + Param[1]: material (type: Material) +Function 439: UnloadMaterial() (1 input parameters) Name: UnloadMaterial Return type: void Description: Unload material from GPU memory (VRAM) Param[1]: material (type: Material) -Function 435: SetMaterialTexture() (3 input parameters) +Function 440: 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 436: SetModelMeshMaterial() (3 input parameters) +Function 441: 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 437: LoadModelAnimations() (2 input parameters) +Function 442: 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: unsigned int *) -Function 438: UpdateModelAnimation() (3 input parameters) +Function 443: UpdateModelAnimation() (3 input parameters) Name: UpdateModelAnimation Return type: void Description: Update model animation pose Param[1]: model (type: Model) Param[2]: anim (type: ModelAnimation) Param[3]: frame (type: int) -Function 439: UnloadModelAnimation() (1 input parameters) +Function 444: UnloadModelAnimation() (1 input parameters) Name: UnloadModelAnimation Return type: void Description: Unload animation data Param[1]: anim (type: ModelAnimation) -Function 440: UnloadModelAnimations() (2 input parameters) +Function 445: UnloadModelAnimations() (2 input parameters) Name: UnloadModelAnimations Return type: void Description: Unload animation array data Param[1]: animations (type: ModelAnimation *) Param[2]: count (type: unsigned int) -Function 441: IsModelAnimationValid() (2 input parameters) +Function 446: 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 442: CheckCollisionSpheres() (4 input parameters) +Function 447: CheckCollisionSpheres() (4 input parameters) Name: CheckCollisionSpheres Return type: bool Description: Check collision between two spheres @@ -3784,40 +3813,40 @@ Function 442: CheckCollisionSpheres() (4 input parameters) Param[2]: radius1 (type: float) Param[3]: center2 (type: Vector3) Param[4]: radius2 (type: float) -Function 443: CheckCollisionBoxes() (2 input parameters) +Function 448: 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 444: CheckCollisionBoxSphere() (3 input parameters) +Function 449: 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 445: GetRayCollisionSphere() (3 input parameters) +Function 450: 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 446: GetRayCollisionBox() (2 input parameters) +Function 451: 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 447: GetRayCollisionMesh() (3 input parameters) +Function 452: 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 448: GetRayCollisionTriangle() (4 input parameters) +Function 453: GetRayCollisionTriangle() (4 input parameters) Name: GetRayCollisionTriangle Return type: RayCollision Description: Get collision info between ray and triangle @@ -3825,7 +3854,7 @@ Function 448: GetRayCollisionTriangle() (4 input parameters) Param[2]: p1 (type: Vector3) Param[3]: p2 (type: Vector3) Param[4]: p3 (type: Vector3) -Function 449: GetRayCollisionQuad() (5 input parameters) +Function 454: GetRayCollisionQuad() (5 input parameters) Name: GetRayCollisionQuad Return type: RayCollision Description: Get collision info between ray and quad @@ -3834,148 +3863,143 @@ Function 449: GetRayCollisionQuad() (5 input parameters) Param[3]: p2 (type: Vector3) Param[4]: p3 (type: Vector3) Param[5]: p4 (type: Vector3) -Function 450: InitAudioDevice() (0 input parameters) +Function 455: InitAudioDevice() (0 input parameters) Name: InitAudioDevice Return type: void Description: Initialize audio device and context No input parameters -Function 451: CloseAudioDevice() (0 input parameters) +Function 456: CloseAudioDevice() (0 input parameters) Name: CloseAudioDevice Return type: void Description: Close the audio device and context No input parameters -Function 452: IsAudioDeviceReady() (0 input parameters) +Function 457: IsAudioDeviceReady() (0 input parameters) Name: IsAudioDeviceReady Return type: bool Description: Check if audio device has been initialized successfully No input parameters -Function 453: SetMasterVolume() (1 input parameters) +Function 458: SetMasterVolume() (1 input parameters) Name: SetMasterVolume Return type: void Description: Set master volume (listener) Param[1]: volume (type: float) -Function 454: LoadWave() (1 input parameters) +Function 459: LoadWave() (1 input parameters) Name: LoadWave Return type: Wave Description: Load wave data from file Param[1]: fileName (type: const char *) -Function 455: LoadWaveFromMemory() (3 input parameters) +Function 460: 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 456: LoadSound() (1 input parameters) +Function 461: IsWaveReady() (1 input parameters) + Name: IsWaveReady + Return type: bool + Description: Checks if wave data is ready + Param[1]: wave (type: Wave) +Function 462: LoadSound() (1 input parameters) Name: LoadSound Return type: Sound Description: Load sound from file Param[1]: fileName (type: const char *) -Function 457: LoadSoundFromWave() (1 input parameters) +Function 463: LoadSoundFromWave() (1 input parameters) Name: LoadSoundFromWave Return type: Sound Description: Load sound from wave data Param[1]: wave (type: Wave) -Function 458: UpdateSound() (3 input parameters) +Function 464: IsSoundReady() (1 input parameters) + Name: IsSoundReady + Return type: bool + Description: Checks if a sound is ready + Param[1]: sound (type: Sound) +Function 465: UpdateSound() (3 input parameters) Name: UpdateSound Return type: void Description: Update sound buffer with new data Param[1]: sound (type: Sound) Param[2]: data (type: const void *) Param[3]: sampleCount (type: int) -Function 459: UnloadWave() (1 input parameters) +Function 466: UnloadWave() (1 input parameters) Name: UnloadWave Return type: void Description: Unload wave data Param[1]: wave (type: Wave) -Function 460: UnloadSound() (1 input parameters) +Function 467: UnloadSound() (1 input parameters) Name: UnloadSound Return type: void Description: Unload sound Param[1]: sound (type: Sound) -Function 461: ExportWave() (2 input parameters) +Function 468: 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 462: ExportWaveAsCode() (2 input parameters) +Function 469: 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 463: PlaySound() (1 input parameters) +Function 470: PlaySound() (1 input parameters) Name: PlaySound Return type: void Description: Play a sound Param[1]: sound (type: Sound) -Function 464: StopSound() (1 input parameters) +Function 471: StopSound() (1 input parameters) Name: StopSound Return type: void Description: Stop playing a sound Param[1]: sound (type: Sound) -Function 465: PauseSound() (1 input parameters) +Function 472: PauseSound() (1 input parameters) Name: PauseSound Return type: void Description: Pause a sound Param[1]: sound (type: Sound) -Function 466: ResumeSound() (1 input parameters) +Function 473: ResumeSound() (1 input parameters) Name: ResumeSound Return type: void Description: Resume a paused sound Param[1]: sound (type: Sound) -Function 467: PlaySoundMulti() (1 input parameters) - Name: PlaySoundMulti - Return type: void - Description: Play a sound (using multichannel buffer pool) - Param[1]: sound (type: Sound) -Function 468: StopSoundMulti() (0 input parameters) - Name: StopSoundMulti - Return type: void - Description: Stop any sound playing (using multichannel buffer pool) - No input parameters -Function 469: GetSoundsPlaying() (0 input parameters) - Name: GetSoundsPlaying - Return type: int - Description: Get number of sounds playing in the multichannel - No input parameters -Function 470: IsSoundPlaying() (1 input parameters) +Function 474: IsSoundPlaying() (1 input parameters) Name: IsSoundPlaying Return type: bool Description: Check if a sound is currently playing Param[1]: sound (type: Sound) -Function 471: SetSoundVolume() (2 input parameters) +Function 475: 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 472: SetSoundPitch() (2 input parameters) +Function 476: 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 473: SetSoundPan() (2 input parameters) +Function 477: 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 474: WaveCopy() (1 input parameters) +Function 478: WaveCopy() (1 input parameters) Name: WaveCopy Return type: Wave Description: Copy a wave to a new wave Param[1]: wave (type: Wave) -Function 475: WaveCrop() (3 input parameters) +Function 479: WaveCrop() (3 input parameters) Name: WaveCrop Return type: void Description: Crop a wave to defined samples range Param[1]: wave (type: Wave *) Param[2]: initSample (type: int) Param[3]: finalSample (type: int) -Function 476: WaveFormat() (4 input parameters) +Function 480: WaveFormat() (4 input parameters) Name: WaveFormat Return type: void Description: Convert wave data to desired format @@ -3983,184 +4007,204 @@ Function 476: WaveFormat() (4 input parameters) Param[2]: sampleRate (type: int) Param[3]: sampleSize (type: int) Param[4]: channels (type: int) -Function 477: LoadWaveSamples() (1 input parameters) +Function 481: 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 478: UnloadWaveSamples() (1 input parameters) +Function 482: UnloadWaveSamples() (1 input parameters) Name: UnloadWaveSamples Return type: void Description: Unload samples data loaded with LoadWaveSamples() Param[1]: samples (type: float *) -Function 479: LoadMusicStream() (1 input parameters) +Function 483: LoadMusicStream() (1 input parameters) Name: LoadMusicStream Return type: Music Description: Load music stream from file Param[1]: fileName (type: const char *) -Function 480: LoadMusicStreamFromMemory() (3 input parameters) +Function 484: 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 481: UnloadMusicStream() (1 input parameters) +Function 485: IsMusicReady() (1 input parameters) + Name: IsMusicReady + Return type: bool + Description: Checks if a music stream is ready + Param[1]: music (type: Music) +Function 486: UnloadMusicStream() (1 input parameters) Name: UnloadMusicStream Return type: void Description: Unload music stream Param[1]: music (type: Music) -Function 482: PlayMusicStream() (1 input parameters) +Function 487: PlayMusicStream() (1 input parameters) Name: PlayMusicStream Return type: void Description: Start music playing Param[1]: music (type: Music) -Function 483: IsMusicStreamPlaying() (1 input parameters) +Function 488: IsMusicStreamPlaying() (1 input parameters) Name: IsMusicStreamPlaying Return type: bool Description: Check if music is playing Param[1]: music (type: Music) -Function 484: UpdateMusicStream() (1 input parameters) +Function 489: UpdateMusicStream() (1 input parameters) Name: UpdateMusicStream Return type: void Description: Updates buffers for music streaming Param[1]: music (type: Music) -Function 485: StopMusicStream() (1 input parameters) +Function 490: StopMusicStream() (1 input parameters) Name: StopMusicStream Return type: void Description: Stop music playing Param[1]: music (type: Music) -Function 486: PauseMusicStream() (1 input parameters) +Function 491: PauseMusicStream() (1 input parameters) Name: PauseMusicStream Return type: void Description: Pause music playing Param[1]: music (type: Music) -Function 487: ResumeMusicStream() (1 input parameters) +Function 492: ResumeMusicStream() (1 input parameters) Name: ResumeMusicStream Return type: void Description: Resume playing paused music Param[1]: music (type: Music) -Function 488: SeekMusicStream() (2 input parameters) +Function 493: 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 489: SetMusicVolume() (2 input parameters) +Function 494: 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 490: SetMusicPitch() (2 input parameters) +Function 495: 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 491: SetMusicPan() (2 input parameters) +Function 496: 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 492: GetMusicTimeLength() (1 input parameters) +Function 497: GetMusicTimeLength() (1 input parameters) Name: GetMusicTimeLength Return type: float Description: Get music time length (in seconds) Param[1]: music (type: Music) -Function 493: GetMusicTimePlayed() (1 input parameters) +Function 498: GetMusicTimePlayed() (1 input parameters) Name: GetMusicTimePlayed Return type: float Description: Get current music time played (in seconds) Param[1]: music (type: Music) -Function 494: LoadAudioStream() (3 input parameters) +Function 499: 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 495: UnloadAudioStream() (1 input parameters) +Function 500: IsAudioStreamReady() (1 input parameters) + Name: IsAudioStreamReady + Return type: bool + Description: Checks if an audio stream is ready + Param[1]: stream (type: AudioStream) +Function 501: UnloadAudioStream() (1 input parameters) Name: UnloadAudioStream Return type: void Description: Unload audio stream and free memory Param[1]: stream (type: AudioStream) -Function 496: UpdateAudioStream() (3 input parameters) +Function 502: 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 497: IsAudioStreamProcessed() (1 input parameters) +Function 503: IsAudioStreamProcessed() (1 input parameters) Name: IsAudioStreamProcessed Return type: bool Description: Check if any audio stream buffers requires refill Param[1]: stream (type: AudioStream) -Function 498: PlayAudioStream() (1 input parameters) +Function 504: PlayAudioStream() (1 input parameters) Name: PlayAudioStream Return type: void Description: Play audio stream Param[1]: stream (type: AudioStream) -Function 499: PauseAudioStream() (1 input parameters) +Function 505: PauseAudioStream() (1 input parameters) Name: PauseAudioStream Return type: void Description: Pause audio stream Param[1]: stream (type: AudioStream) -Function 500: ResumeAudioStream() (1 input parameters) +Function 506: ResumeAudioStream() (1 input parameters) Name: ResumeAudioStream Return type: void Description: Resume audio stream Param[1]: stream (type: AudioStream) -Function 501: IsAudioStreamPlaying() (1 input parameters) +Function 507: IsAudioStreamPlaying() (1 input parameters) Name: IsAudioStreamPlaying Return type: bool Description: Check if audio stream is playing Param[1]: stream (type: AudioStream) -Function 502: StopAudioStream() (1 input parameters) +Function 508: StopAudioStream() (1 input parameters) Name: StopAudioStream Return type: void Description: Stop audio stream Param[1]: stream (type: AudioStream) -Function 503: SetAudioStreamVolume() (2 input parameters) +Function 509: 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 504: SetAudioStreamPitch() (2 input parameters) +Function 510: 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 505: SetAudioStreamPan() (2 input parameters) +Function 511: 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 506: SetAudioStreamBufferSizeDefault() (1 input parameters) +Function 512: SetAudioStreamBufferSizeDefault() (1 input parameters) Name: SetAudioStreamBufferSizeDefault Return type: void Description: Default size for new audio streams Param[1]: size (type: int) -Function 507: SetAudioStreamCallback() (2 input parameters) +Function 513: 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 508: AttachAudioStreamProcessor() (2 input parameters) +Function 514: AttachAudioStreamProcessor() (2 input parameters) Name: AttachAudioStreamProcessor Return type: void Description: Attach audio stream processor to stream Param[1]: stream (type: AudioStream) Param[2]: processor (type: AudioCallback) -Function 509: DetachAudioStreamProcessor() (2 input parameters) +Function 515: 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 516: AttachAudioMixedProcessor() (1 input parameters) + Name: AttachAudioMixedProcessor + Return type: void + Description: Attach audio stream processor to the entire audio pipeline + Param[1]: processor (type: AudioCallback) +Function 517: DetachAudioMixedProcessor() (1 input parameters) + Name: DetachAudioMixedProcessor + Return type: void + Description: Detach audio stream processor from the entire audio pipeline + Param[1]: processor (type: AudioCallback) diff --git a/parser/output/raylib_api.xml b/parser/output/raylib_api.xml index a28cd779e6f5..45305951f8ca 100644 --- a/parser/output/raylib_api.xml +++ b/parser/output/raylib_api.xml @@ -1,8 +1,11 @@ - + - + + + + @@ -71,7 +74,7 @@ - + @@ -219,8 +222,8 @@ - - + + @@ -446,7 +449,7 @@ - + @@ -575,10 +578,10 @@ - + - + @@ -592,8 +595,8 @@ - - + + @@ -652,7 +655,7 @@ - + @@ -693,9 +696,13 @@ - + + + + + @@ -843,6 +850,9 @@ + + + @@ -976,7 +986,7 @@ - + @@ -1190,29 +1200,15 @@ - - + + - + - - - - - - - - - - - - - - - - - + + + @@ -1533,6 +1529,9 @@ + + + @@ -1593,6 +1592,11 @@ + + + + + @@ -1640,6 +1644,10 @@ + + + + @@ -1844,9 +1852,15 @@ + + + + + + @@ -1894,22 +1908,6 @@ - - - - - - - - - - - - - - - - @@ -1926,14 +1924,6 @@ - - - - - - - - @@ -1955,6 +1945,18 @@ + + + + + + + + + + + + @@ -2005,6 +2007,9 @@ + + + @@ -2244,23 +2249,6 @@ - - - - - - - - - - - - - - - - - @@ -2312,6 +2300,22 @@ + + + + + + + + + + + + + + + + @@ -2331,10 +2335,10 @@ - + - + @@ -2494,6 +2498,9 @@ + + + @@ -2586,12 +2593,18 @@ + + + + + + @@ -2623,13 +2636,6 @@ - - - - - - - @@ -2673,6 +2679,9 @@ + + + @@ -2721,6 +2730,9 @@ + + + @@ -2774,5 +2786,11 @@ + + + + + + From 3b4f9faebc42a9110d9ca9d918edddff9f6d0667 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 15 Mar 2023 13:17:14 +0100 Subject: [PATCH 182/192] UPDATED: Notepad++ instellisense data --- .../raylib_npp_parser/raylib_npp.xml | 305 +++++++++++------- .../raylib_npp_parser/raylib_to_parse.h | 85 +++-- 2 files changed, 244 insertions(+), 146 deletions(-) diff --git a/projects/Notepad++/raylib_npp_parser/raylib_npp.xml b/projects/Notepad++/raylib_npp_parser/raylib_npp.xml index 521c8a76825f..e764a1b6363f 100644 --- a/projects/Notepad++/raylib_npp_parser/raylib_npp.xml +++ b/projects/Notepad++/raylib_npp_parser/raylib_npp.xml @@ -65,10 +65,16 @@ - + + + + + + + @@ -181,7 +187,7 @@ - + @@ -313,6 +319,11 @@ + + + + + @@ -459,7 +470,7 @@ - + @@ -521,7 +532,7 @@ - + @@ -878,41 +889,18 @@ - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + @@ -1287,6 +1275,13 @@ + + + + + + + @@ -1316,7 +1311,7 @@ - + @@ -1352,6 +1347,11 @@ + + + + + @@ -1420,6 +1420,15 @@ + + + + + + + + + @@ -1427,6 +1436,13 @@ + + + + + + + @@ -1498,6 +1514,12 @@ + + + + + + @@ -1669,7 +1691,7 @@ - + @@ -1678,7 +1700,24 @@ - + + + + + + + + + + + + + + + + + + @@ -1773,11 +1812,21 @@ + + + + + + + + + + @@ -1849,26 +1898,6 @@ - - - - - - - - - - - - - - - - - - - - @@ -1889,16 +1918,6 @@ - - - - - - - - - - @@ -1934,6 +1953,24 @@ + + + + + + + + + + + + + + + + + + @@ -2004,6 +2041,11 @@ + + + + + @@ -2136,6 +2178,17 @@ + + + + + + + + + + + @@ -2155,19 +2208,25 @@ - + + + + + + + + + + + + + - - - - - - - + @@ -2339,27 +2398,6 @@ - - - - - - - - - - - - - - - - - - - - - @@ -2425,6 +2463,26 @@ + + + + + + + + + + + + + + + + + + + + @@ -2460,13 +2518,13 @@ - - + + - - + + @@ -2694,6 +2752,11 @@ + + + + + @@ -2839,6 +2902,11 @@ + + + + + @@ -2849,6 +2917,11 @@ + + + + + @@ -2900,17 +2973,6 @@ - - - - - - - - - - - @@ -2978,6 +3040,11 @@ + + + + + @@ -3056,6 +3123,11 @@ + + + + + @@ -3141,4 +3213,15 @@ + + + + + + + + + + + diff --git a/projects/Notepad++/raylib_npp_parser/raylib_to_parse.h b/projects/Notepad++/raylib_npp_parser/raylib_to_parse.h index 4a9daf896063..96732e3193cd 100644 --- a/projects/Notepad++/raylib_npp_parser/raylib_to_parse.h +++ b/projects/Notepad++/raylib_npp_parser/raylib_to_parse.h @@ -20,7 +20,8 @@ RLAPI void ToggleFullscreen(void); // Toggle wind RLAPI void MaximizeWindow(void); // Set window state: maximized, if resizable (only PLATFORM_DESKTOP) RLAPI void MinimizeWindow(void); // Set window state: minimized, if resizable (only PLATFORM_DESKTOP) RLAPI void RestoreWindow(void); // Set window state: not minimized/maximized (only PLATFORM_DESKTOP) -RLAPI void SetWindowIcon(Image image); // Set icon for window (only PLATFORM_DESKTOP) +RLAPI void SetWindowIcon(Image image); // Set icon for window (single image, RGBA 32bit, only PLATFORM_DESKTOP) +RLAPI void SetWindowIcons(Image *images, int count); // Set icon for window (multiple images, RGBA 32bit, only PLATFORM_DESKTOP) RLAPI void SetWindowTitle(const char *title); // Set title for window (only PLATFORM_DESKTOP) RLAPI void SetWindowPosition(int x, int y); // Set window position on screen (only PLATFORM_DESKTOP) RLAPI void SetWindowMonitor(int monitor); // Set monitor for the current window (fullscreen mode) @@ -50,7 +51,7 @@ RLAPI void DisableEventWaiting(void); // Disable wai // Custom frame control functions // NOTE: Those functions are intended for advance users that want full control over the frame processing -// By default EndDrawing() does this job: draws everything + SwapScreenBuffer() + manage frame timming + PollInputEvents() +// By default EndDrawing() does this job: draws everything + SwapScreenBuffer() + manage frame timing + PollInputEvents() // To avoid that behaviour and control frame processes manually, enable in config.h: SUPPORT_CUSTOM_FRAME_CONTROL RLAPI void SwapScreenBuffer(void); // Swap back buffer with front buffer (screen drawing) RLAPI void PollInputEvents(void); // Register all input events @@ -91,6 +92,7 @@ RLAPI void UnloadVrStereoConfig(VrStereoConfig config); // Unload VR s // NOTE: Shader functionality is not available on OpenGL 1.1 RLAPI Shader LoadShader(const char *vsFileName, const char *fsFileName); // Load shader from files and bind default locations RLAPI Shader LoadShaderFromMemory(const char *vsCode, const char *fsCode); // Load shader from code strings and bind default locations +RLAPI bool IsShaderReady(Shader shader); // Check if a shader is ready RLAPI int GetShaderLocation(Shader shader, const char *uniformName); // Get shader uniform location RLAPI int GetShaderLocationAttrib(Shader shader, const char *attribName); // Get shader attribute location RLAPI void SetShaderValue(Shader shader, int locIndex, const void *value, int uniformType); // Set shader uniform value @@ -122,8 +124,8 @@ RLAPI void SetConfigFlags(unsigned int flags); // Setup init RLAPI void TraceLog(int logLevel, const char *text, ...); // Show trace log messages (LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERROR...) RLAPI void SetTraceLogLevel(int logLevel); // Set the current threshold (minimum) log level -RLAPI void *MemAlloc(int size); // Internal memory allocator -RLAPI void *MemRealloc(void *ptr, int size); // Internal memory reallocator +RLAPI void *MemAlloc(unsigned int size); // Internal memory allocator +RLAPI void *MemRealloc(void *ptr, unsigned int size); // Internal memory reallocator RLAPI void MemFree(void *ptr); // Internal memory free RLAPI void OpenURL(const char *url); // Open URL with default system browser (if available) @@ -140,7 +142,7 @@ RLAPI void SetSaveFileTextCallback(SaveFileTextCallback callback); // Set custom RLAPI unsigned char *LoadFileData(const char *fileName, unsigned int *bytesRead); // Load file data as byte array (read) RLAPI void UnloadFileData(unsigned char *data); // Unload file data allocated by LoadFileData() RLAPI bool SaveFileData(const char *fileName, void *data, unsigned int bytesToWrite); // Save data to file from byte array (write), returns true on success -RLAPI bool ExportDataAsCode(const char *data, unsigned int size, const char *fileName); // Export data to code (.h), returns true on success +RLAPI bool ExportDataAsCode(const unsigned char *data, unsigned int size, 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, char *text); // Save text data to file (write), string must be '\0' terminated, returns true on success @@ -234,13 +236,8 @@ RLAPI float GetGesturePinchAngle(void); // Get gesture pinch ang //------------------------------------------------------------------------------------ // Camera System Functions (Module: rcamera) //------------------------------------------------------------------------------------ -RLAPI void SetCameraMode(Camera camera, int mode); // Set camera mode (multiple camera modes available) -RLAPI void UpdateCamera(Camera *camera); // Update camera position for selected mode - -RLAPI void SetCameraPanControl(int keyPan); // Set camera pan key to combine with mouse movement (free camera) -RLAPI void SetCameraAltControl(int keyAlt); // Set camera alt key to combine with mouse movement (free camera) -RLAPI void SetCameraSmoothZoomControl(int keySmoothZoom); // Set camera smooth zoom key to combine with mouse (free camera) -RLAPI void SetCameraMoveControls(int keyFront, int keyBack, int keyRight, int keyLeft, int keyUp, int keyDown); // Set camera move controls (1st person and 3rd person cameras) +RLAPI void UpdateCamera(Camera *camera, int mode); // Update camera position for selected mode +RLAPI void UpdateCameraPro(Camera *camera, Vector3 movement, Vector3 rotation, float zoom); // Update camera movement/rotation //------------------------------------------------------------------------------------ // Basic Shapes Drawing Functions (Module: shapes) @@ -296,6 +293,7 @@ RLAPI bool CheckCollisionCircleRec(Vector2 center, float radius, Rectangle rec); RLAPI bool CheckCollisionPointRec(Vector2 point, Rectangle rec); // Check if point is inside rectangle RLAPI bool CheckCollisionPointCircle(Vector2 point, Vector2 center, float radius); // Check if point is inside circle RLAPI bool CheckCollisionPointTriangle(Vector2 point, Vector2 p1, Vector2 p2, Vector2 p3); // Check if point is inside a triangle +RLAPI bool CheckCollisionPointPoly(Vector2 point, Vector2 *points, int pointCount); // Check if point is within a polygon described by array of vertices RLAPI bool CheckCollisionLines(Vector2 startPos1, Vector2 endPos1, Vector2 startPos2, Vector2 endPos2, Vector2 *collisionPoint); // Check the collision between two lines defined by two points each, returns collision point by reference RLAPI bool CheckCollisionPointLine(Vector2 point, Vector2 p1, Vector2 p2, int threshold); // Check if point belongs to line created between two points [p1] and [p2] with defined margin in pixels [threshold] RLAPI Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2); // Get collision rectangle for two rectangles collision @@ -305,13 +303,14 @@ RLAPI Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2); //------------------------------------------------------------------------------------ // Image loading functions -// NOTE: This functions do not require GPU access +// NOTE: These functions do not require GPU access RLAPI Image LoadImage(const char *fileName); // Load image from file into CPU memory (RAM) RLAPI Image LoadImageRaw(const char *fileName, int width, int height, int format, int headerSize); // Load image from RAW file data RLAPI Image LoadImageAnim(const char *fileName, int *frames); // Load image sequence from file (frames appended to image.data) RLAPI Image LoadImageFromMemory(const char *fileType, const unsigned char *fileData, int dataSize); // Load image from memory buffer, fileType refers to extension: i.e. '.png' RLAPI Image LoadImageFromTexture(Texture2D texture); // Load image from GPU texture data RLAPI Image LoadImageFromScreen(void); // Load image from screen buffer and (screenshot) +RLAPI bool IsImageReady(Image image); // Check if an image is ready RLAPI void UnloadImage(Image image); // Unload image from CPU memory (RAM) RLAPI bool ExportImage(Image image, const char *fileName); // Export image data to file, returns true on success RLAPI bool ExportImageAsCode(Image image, const char *fileName); // Export image as code file defining an array of bytes, returns true on success @@ -323,7 +322,9 @@ RLAPI Image GenImageGradientH(int width, int height, Color left, Color right); RLAPI Image GenImageGradientRadial(int width, int height, float density, Color inner, Color outer); // Generate image: radial gradient RLAPI Image GenImageChecked(int width, int height, int checksX, int checksY, Color col1, Color col2); // Generate image: checked RLAPI Image GenImageWhiteNoise(int width, int height, float factor); // Generate image: white noise +RLAPI Image GenImagePerlinNoise(int width, int height, int offsetX, int offsetY, float scale); // Generate image: perlin noise RLAPI Image GenImageCellular(int width, int height, int tileSize); // Generate image: cellular algorithm, bigger tileSize means bigger cells +RLAPI Image GenImageText(int width, int height, const char *text); // Generate image: grayscale image from text data // Image manipulation functions RLAPI Image ImageCopy(Image image); // Create an image duplicate (useful for transformations) @@ -337,6 +338,7 @@ RLAPI void ImageAlphaCrop(Image *image, float threshold); RLAPI void ImageAlphaClear(Image *image, Color color, float threshold); // Clear alpha channel to desired color RLAPI void ImageAlphaMask(Image *image, Image alphaMask); // Apply alpha mask to image RLAPI void ImageAlphaPremultiply(Image *image); // Premultiply alpha channel +RLAPI void ImageBlurGaussian(Image *image, int blurSize); // Apply Gaussian blur using a box blur approximation RLAPI void ImageResize(Image *image, int newWidth, int newHeight); // Resize image (Bicubic scaling algorithm) RLAPI void ImageResizeNN(Image *image, int newWidth,int newHeight); // Resize image (Nearest-Neighbor scaling algorithm) RLAPI void ImageResizeCanvas(Image *image, int newWidth, int newHeight, int offsetX, int offsetY, Color fill); // Resize canvas and fill with color @@ -366,8 +368,10 @@ RLAPI void ImageDrawPixel(Image *dst, int posX, int posY, Color color); RLAPI void ImageDrawPixelV(Image *dst, Vector2 position, Color color); // Draw pixel within an image (Vector version) RLAPI void ImageDrawLine(Image *dst, int startPosX, int startPosY, int endPosX, int endPosY, Color color); // Draw line within an image RLAPI void ImageDrawLineV(Image *dst, Vector2 start, Vector2 end, Color color); // Draw line within an image (Vector version) -RLAPI void ImageDrawCircle(Image *dst, int centerX, int centerY, int radius, Color color); // Draw circle within an image -RLAPI void ImageDrawCircleV(Image *dst, Vector2 center, int radius, Color color); // Draw circle within an image (Vector version) +RLAPI void ImageDrawCircle(Image *dst, int centerX, int centerY, int radius, Color color); // Draw a filled circle within an image +RLAPI void ImageDrawCircleV(Image *dst, Vector2 center, int radius, Color color); // Draw a filled circle within an image (Vector version) +RLAPI void ImageDrawCircleLines(Image *dst, int centerX, int centerY, int radius, Color color); // Draw circle outline within an image +RLAPI void ImageDrawCircleLinesV(Image *dst, Vector2 center, int radius, Color color); // Draw circle outline within an image (Vector version) RLAPI void ImageDrawRectangle(Image *dst, int posX, int posY, int width, int height, Color color); // Draw rectangle within an image RLAPI void ImageDrawRectangleV(Image *dst, Vector2 position, Vector2 size, Color color); // Draw rectangle within an image (Vector version) RLAPI void ImageDrawRectangleRec(Image *dst, Rectangle rec, Color color); // Draw rectangle within an image @@ -382,7 +386,9 @@ RLAPI Texture2D LoadTexture(const char *fileName); RLAPI Texture2D LoadTextureFromImage(Image image); // Load texture from image data RLAPI TextureCubemap LoadTextureCubemap(Image image, int layout); // Load cubemap from image, multiple image cubemap layouts supported RLAPI RenderTexture2D LoadRenderTexture(int width, int height); // Load texture for rendering (framebuffer) +RLAPI bool IsTextureReady(Texture2D texture); // Check if a texture is ready RLAPI void UnloadTexture(Texture2D texture); // Unload texture from GPU memory (VRAM) +RLAPI bool IsRenderTextureReady(RenderTexture2D target); // Check if a render texture is ready RLAPI void UnloadRenderTexture(RenderTexture2D target); // Unload render texture from GPU memory (VRAM) RLAPI void UpdateTexture(Texture2D texture, const void *pixels); // Update GPU texture with new data RLAPI void UpdateTextureRec(Texture2D texture, Rectangle rec, const void *pixels); // Update GPU texture rectangle with new data @@ -397,11 +403,8 @@ RLAPI void DrawTexture(Texture2D texture, int posX, int posY, Color tint); RLAPI void DrawTextureV(Texture2D texture, Vector2 position, Color tint); // Draw a Texture2D with position defined as Vector2 RLAPI void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float scale, Color tint); // Draw a Texture2D with extended parameters RLAPI void DrawTextureRec(Texture2D texture, Rectangle source, Vector2 position, Color tint); // Draw a part of a texture defined by a rectangle -RLAPI void DrawTextureQuad(Texture2D texture, Vector2 tiling, Vector2 offset, Rectangle quad, Color tint); // Draw texture quad with tiling and offset parameters -RLAPI void DrawTextureTiled(Texture2D texture, Rectangle source, Rectangle dest, Vector2 origin, float rotation, float scale, Color tint); // Draw part of a texture (defined by a rectangle) with rotation and scale tiled into dest. -RLAPI void DrawTexturePro(Texture2D texture, Rectangle source, Rectangle dest, Vector2 origin, float rotation, Color tint); // Draw a part of a texture defined by a rectangle with 'pro' parameters -RLAPI void DrawTextureNPatch(Texture2D texture, NPatchInfo nPatchInfo, Rectangle dest, Vector2 origin, float rotation, Color tint); // Draws a texture (or part of it) that stretches or shrinks nicely -RLAPI void DrawTexturePoly(Texture2D texture, Vector2 center, Vector2 *points, Vector2 *texcoords, int pointCount, Color tint); // Draw a textured polygon +RLAPI void DrawTexturePro(Texture2D texture, Rectangle source, Rectangle dest, Vector2 origin, float rotation, Color tint); // Draw a part of a texture defined by a rectangle with 'pro' parameters +RLAPI void DrawTextureNPatch(Texture2D texture, NPatchInfo nPatchInfo, Rectangle dest, Vector2 origin, float rotation, Color tint); // Draws a texture (or part of it) that stretches or shrinks nicely // Color/pixel related functions RLAPI Color Fade(Color color, float alpha); // Get color with alpha applied, alpha goes from 0.0f to 1.0f @@ -410,6 +413,9 @@ RLAPI Vector4 ColorNormalize(Color color); // G RLAPI Color ColorFromNormalized(Vector4 normalized); // Get Color from normalized values [0..1] RLAPI Vector3 ColorToHSV(Color color); // Get HSV values for a Color, hue [0..360], saturation/value [0..1] RLAPI Color ColorFromHSV(float hue, float saturation, float value); // Get a Color from HSV values, hue [0..360], saturation/value [0..1] +RLAPI Color ColorTint(Color color, Color tint); // Get color multiplied with another color +RLAPI Color ColorBrightness(Color color, float factor); // Get color with brightness correction, brightness factor goes from -1.0f to 1.0f +RLAPI Color ColorContrast(Color color, float contrast); // Get color with contrast correction, contrast values between -1.0f and 1.0f RLAPI Color ColorAlpha(Color color, float alpha); // Get color with alpha applied, alpha goes from 0.0f to 1.0f RLAPI Color ColorAlphaBlend(Color dst, Color src, Color tint); // Get src alpha-blended into dst color with tint RLAPI Color GetColor(unsigned int hexValue); // Get Color structure from hexadecimal value @@ -427,6 +433,7 @@ RLAPI Font LoadFont(const char *fileName); RLAPI Font LoadFontEx(const char *fileName, int fontSize, int *fontChars, int glyphCount); // Load font from file with extended parameters, use NULL for fontChars and 0 for glyphCount to load the default character set RLAPI Font LoadFontFromImage(Image image, Color key, int firstChar); // Load font from Image (XNA style) RLAPI Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int dataSize, int fontSize, int *fontChars, int glyphCount); // Load font from memory buffer, fileType refers to extension: i.e. '.ttf' +RLAPI bool IsFontReady(Font font); // Check if a font is ready RLAPI GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSize, int *fontChars, int glyphCount, int type); // Load font data for further use RLAPI Image GenImageFontAtlas(const GlyphInfo *chars, Rectangle **recs, int glyphCount, int fontSize, int padding, int packMethod); // Generate image font atlas using chars info RLAPI void UnloadFontData(GlyphInfo *chars, int glyphCount); // Unload font chars info data (RAM) @@ -449,12 +456,15 @@ RLAPI GlyphInfo GetGlyphInfo(Font font, int codepoint); RLAPI Rectangle GetGlyphAtlasRec(Font font, int codepoint); // Get glyph rectangle in font atlas for a codepoint (unicode character), fallback to '?' if not found // Text codepoints management functions (unicode characters) -RLAPI int *LoadCodepoints(const char *text, int *count); // Load all codepoints from a UTF-8 text string, codepoints count returned by parameter -RLAPI void UnloadCodepoints(int *codepoints); // Unload codepoints data from memory -RLAPI int GetCodepointCount(const char *text); // Get total number of codepoints in a UTF-8 encoded string -RLAPI int GetCodepoint(const char *text, int *bytesProcessed); // Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure -RLAPI const char *CodepointToUTF8(int codepoint, int *byteSize); // Encode one codepoint into UTF-8 byte array (array length returned as parameter) -RLAPI char *TextCodepointsToUTF8(const int *codepoints, int length); // Encode text as codepoints array into UTF-8 text string (WARNING: memory must be freed!) +RLAPI char *LoadUTF8(const int *codepoints, int length); // Load UTF-8 text encoded from codepoints array +RLAPI void UnloadUTF8(char *text); // Unload UTF-8 text encoded from codepoints array +RLAPI int *LoadCodepoints(const char *text, int *count); // Load all codepoints from a UTF-8 text string, codepoints count returned by parameter +RLAPI void UnloadCodepoints(int *codepoints); // Unload codepoints data from memory +RLAPI int GetCodepointCount(const char *text); // Get total number of codepoints in a UTF-8 encoded string +RLAPI int GetCodepoint(const char *text, int *codepointSize); // Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure +RLAPI int GetCodepointNext(const char *text, int *codepointSize); // Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure +RLAPI int GetCodepointPrevious(const char *text, int *codepointSize); // Get previous codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure +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) // NOTE: Some strings allocate memory internally for returned strings, just be careful! @@ -488,8 +498,6 @@ RLAPI void DrawCube(Vector3 position, float width, float height, float length, C RLAPI void DrawCubeV(Vector3 position, Vector3 size, Color color); // Draw cube (Vector version) RLAPI void DrawCubeWires(Vector3 position, float width, float height, float length, Color color); // Draw cube wires RLAPI void DrawCubeWiresV(Vector3 position, Vector3 size, Color color); // Draw cube wires (Vector version) -RLAPI void DrawCubeTexture(Texture2D texture, Vector3 position, float width, float height, float length, Color color); // Draw cube textured -RLAPI void DrawCubeTextureRec(Texture2D texture, Rectangle source, Vector3 position, float width, float height, float length, Color color); // Draw cube with a region of a texture RLAPI void DrawSphere(Vector3 centerPos, float radius, Color color); // Draw sphere RLAPI void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color color); // Draw sphere with extended parameters RLAPI void DrawSphereWires(Vector3 centerPos, float radius, int rings, int slices, Color color); // Draw sphere wires @@ -497,6 +505,8 @@ RLAPI void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, f RLAPI void DrawCylinderEx(Vector3 startPos, Vector3 endPos, float startRadius, float endRadius, int sides, Color color); // Draw a cylinder with base at startPos and top at endPos RLAPI void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, float height, int slices, Color color); // Draw a cylinder/cone wires RLAPI void DrawCylinderWiresEx(Vector3 startPos, Vector3 endPos, float startRadius, float endRadius, int sides, Color color); // Draw a cylinder wires with base at startPos and top at endPos +RLAPI void DrawCapsule(Vector3 startPos, Vector3 endPos, float radius, int slices, int rings, Color color); // Draw a capsule with the center of its sphere caps at startPos and endPos +RLAPI void DrawCapsuleWires(Vector3 startPos, Vector3 endPos, float radius, int slices, int rings, Color color); // Draw capsule wireframe with the center of its sphere caps at startPos and endPos RLAPI void DrawPlane(Vector3 centerPos, Vector2 size, Color color); // Draw a plane XZ RLAPI void DrawRay(Ray ray, Color color); // Draw a ray line RLAPI void DrawGrid(int slices, float spacing); // Draw a grid (centered at (0, 0, 0)) @@ -508,16 +518,16 @@ RLAPI void DrawGrid(int slices, float spacing); // Model management functions RLAPI Model LoadModel(const char *fileName); // Load model from files (meshes and materials) RLAPI Model LoadModelFromMesh(Mesh mesh); // Load model from generated mesh (default material) +RLAPI bool IsModelReady(Model model); // Check if a model is ready RLAPI void UnloadModel(Model model); // Unload model (including meshes) from memory (RAM and/or VRAM) -RLAPI void UnloadModelKeepMeshes(Model model); // Unload model (but not meshes) from memory (RAM and/or VRAM) RLAPI BoundingBox GetModelBoundingBox(Model model); // Compute model bounding box limits (considers all meshes) // Model drawing functions -RLAPI void DrawModel(Model model, Vector3 position, float scale, Color tint); // Draw a model (with texture if set) +RLAPI void DrawModel(Model model, Vector3 position, float scale, Color tint); // Draw a model (with texture if set) RLAPI void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model with extended parameters -RLAPI void DrawModelWires(Model model, Vector3 position, float scale, Color tint); // Draw a model wires (with texture if set) +RLAPI void DrawModelWires(Model model, Vector3 position, float scale, Color tint); // Draw a model wires (with texture if set) RLAPI void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model wires (with texture if set) with extended parameters -RLAPI void DrawBoundingBox(BoundingBox box, Color color); // Draw bounding box (wires) +RLAPI void DrawBoundingBox(BoundingBox box, Color color); // Draw bounding box (wires) RLAPI void DrawBillboard(Camera camera, Texture2D texture, Vector3 position, float size, Color tint); // Draw a billboard texture RLAPI void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector2 size, Color tint); // Draw a billboard texture defined by source RLAPI void DrawBillboardPro(Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector3 up, Vector2 size, Vector2 origin, float rotation, Color tint); // Draw a billboard texture defined by source and rotation @@ -548,6 +558,7 @@ RLAPI Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize); // Material loading/unloading functions RLAPI Material *LoadMaterials(const char *fileName, int *materialCount); // Load materials from model file RLAPI Material LoadMaterialDefault(void); // Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps) +RLAPI bool IsMaterialReady(Material material); // Check if a material is ready RLAPI void UnloadMaterial(Material material); // Unload material from GPU memory (VRAM) RLAPI void SetMaterialTexture(Material *material, int mapType, Texture2D texture); // Set texture for a material map type (MATERIAL_MAP_DIFFUSE, MATERIAL_MAP_SPECULAR...) RLAPI void SetModelMeshMaterial(Model *model, int meshId, int materialId); // Set material for a mesh @@ -583,8 +594,10 @@ RLAPI void SetMasterVolume(float volume); // Set mas // Wave/Sound loading/unloading functions RLAPI Wave LoadWave(const char *fileName); // Load wave data from file RLAPI Wave LoadWaveFromMemory(const char *fileType, const unsigned char *fileData, int dataSize); // Load wave from memory buffer, fileType refers to extension: i.e. '.wav' +RLAPI bool IsWaveReady(Wave wave); // Checks if wave data is ready RLAPI Sound LoadSound(const char *fileName); // Load sound from file RLAPI Sound LoadSoundFromWave(Wave wave); // Load sound from wave data +RLAPI bool IsSoundReady(Sound sound); // Checks if a sound is ready RLAPI void UpdateSound(Sound sound, const void *data, int sampleCount); // Update sound buffer with new data RLAPI void UnloadWave(Wave wave); // Unload wave data RLAPI void UnloadSound(Sound sound); // Unload sound @@ -596,9 +609,6 @@ RLAPI void PlaySound(Sound sound); // Play a RLAPI void StopSound(Sound sound); // Stop playing a sound RLAPI void PauseSound(Sound sound); // Pause a sound RLAPI void ResumeSound(Sound sound); // Resume a paused sound -RLAPI void PlaySoundMulti(Sound sound); // Play a sound (using multichannel buffer pool) -RLAPI void StopSoundMulti(void); // Stop any sound playing (using multichannel buffer pool) -RLAPI int GetSoundsPlaying(void); // Get number of sounds playing in the multichannel RLAPI bool IsSoundPlaying(Sound sound); // Check if a sound is currently playing RLAPI void SetSoundVolume(Sound sound, float volume); // Set volume for a sound (1.0 is max level) RLAPI void SetSoundPitch(Sound sound, float pitch); // Set pitch for a sound (1.0 is base level) @@ -612,6 +622,7 @@ RLAPI void UnloadWaveSamples(float *samples); // Unload // Music management functions RLAPI Music LoadMusicStream(const char *fileName); // Load music stream from file RLAPI Music LoadMusicStreamFromMemory(const char *fileType, const unsigned char *data, int dataSize); // Load music stream from data +RLAPI bool IsMusicReady(Music music); // Checks if a music stream is ready RLAPI void UnloadMusicStream(Music music); // Unload music stream RLAPI void PlayMusicStream(Music music); // Start music playing RLAPI bool IsMusicStreamPlaying(Music music); // Check if music is playing @@ -628,6 +639,7 @@ RLAPI float GetMusicTimePlayed(Music music); // Get cur // AudioStream management functions RLAPI AudioStream LoadAudioStream(unsigned int sampleRate, unsigned int sampleSize, unsigned int channels); // Load audio stream (to stream raw audio pcm data) +RLAPI bool IsAudioStreamReady(AudioStream stream); // Checks if an audio stream is ready RLAPI void UnloadAudioStream(AudioStream stream); // Unload audio stream and free memory RLAPI void UpdateAudioStream(AudioStream stream, const void *data, int frameCount); // Update audio stream buffers with data RLAPI bool IsAudioStreamProcessed(AudioStream stream); // Check if any audio stream buffers requires refill @@ -645,3 +657,6 @@ RLAPI void SetAudioStreamCallback(AudioStream stream, AudioCallback callback); RLAPI void AttachAudioStreamProcessor(AudioStream stream, AudioCallback processor); // Attach audio stream processor to stream RLAPI void DetachAudioStreamProcessor(AudioStream stream, AudioCallback processor); // Detach audio stream processor from stream +RLAPI void AttachAudioMixedProcessor(AudioCallback processor); // Attach audio stream processor to the entire audio pipeline +RLAPI void DetachAudioMixedProcessor(AudioCallback processor); // Detach audio stream processor from the entire audio pipeline + From 1aacefd6fabfffa69f5b1bb905263941ad2af823 Mon Sep 17 00:00:00 2001 From: ashn <60763262+ashn-dot-dev@users.noreply.github.com> Date: Wed, 15 Mar 2023 09:56:24 -0400 Subject: [PATCH 183/192] Add raylib-sunder to BINDINGS.md (#2958) --- BINDINGS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/BINDINGS.md b/BINDINGS.md index e232b1b6c37c..80d6bcec7095 100644 --- a/BINDINGS.md +++ b/BINDINGS.md @@ -70,6 +70,7 @@ Some people ported raylib to other languages in form of bindings or wrappers to | raylib-zig | **4.2** | [Zig](https://ziglang.org/) | MIT | https://github.com/Not-Nik/raylib-zig | | raylib.zig | **4.2** | [Zig](https://ziglang.org/) | MIT | https://github.com/ryupold/raylib.zig | | hare-raylib | auto | [Hare](https://harelang.org/) | Zlib | https://git.sr.ht/~evantj/hare-raylib | +| raylib-sunder | auto | [Sunder](https://github.com/ashn-dot-dev/sunder) | 0BSD | https://github.com/ashn-dot-dev/raylib-sunder | From b31c8364566c15ebc9911d86adfe10199812fd40 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 15 Mar 2023 17:51:03 +0100 Subject: [PATCH 184/192] Update CHANGELOG --- CHANGELOG | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 10c96f7b4a68..654c7bb40f76 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -50,6 +50,7 @@ Detailed changes: [core] REVIEWED: GetWindowHandle() to return Linux window (#2938) [core] REVIEWED: WindowDropCallback(), additional security check (#2943) [core] REVIEWED: Security checks for emscripten_run_script() (#2954) +[utils] REVIEWED: TraceLog() message size limit overflow [rcamera] REDESIGNED: New implementation from scratch (#2563) by @Crydsch [rcamera] REVIEWED: Make orbital camera work as expected (#2926) by @JeffM2501 [rcamera] REVIEWED: Multiple reviews on the new implementation @@ -177,7 +178,8 @@ Detailed changes: [bindings] ADDED: TurboRaylib (Object Pascal) by @turborium [bindings] ADDED: Kaylib (Kotlin/Native) by @Its-Kenta [bindings] ADDED: Raylib-Nelua (Nelua) by @Its-Kenta -[bindings] ADDED: Cyber binding by @fubark +[bindings] ADDED: Cyber (Cyber) by @fubark +[bindings] ADDED: raylib-sunder (Sunder) by @ashn-dot-dev [misc] REVIEWED: Update external libraries to latest versions ------------------------------------------------------------------------- From bf3e527dab226101dff3c97b67bf15bfa09386e2 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 15 Mar 2023 17:51:23 +0100 Subject: [PATCH 185/192] Update config.h --- src/config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config.h b/src/config.h index de9f4641a563..fbc7a5b478e4 100644 --- a/src/config.h +++ b/src/config.h @@ -239,6 +239,6 @@ // utils: Configuration values //------------------------------------------------------------------------------------ -#define MAX_TRACELOG_MSG_LENGTH 128 // Max length of one trace-log message +#define MAX_TRACELOG_MSG_LENGTH 256 // Max length of one trace-log message #endif // CONFIG_H From 7ab24b94eee690058de99359db072a9e1dbf4039 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 15 Mar 2023 19:09:27 +0100 Subject: [PATCH 186/192] Delete c_raylib.xml --- projects/Notepad++/c_raylib.xml | 3144 ------------------------------- 1 file changed, 3144 deletions(-) delete mode 100644 projects/Notepad++/c_raylib.xml diff --git a/projects/Notepad++/c_raylib.xml b/projects/Notepad++/c_raylib.xml deleted file mode 100644 index 521c8a76825f..000000000000 --- a/projects/Notepad++/c_raylib.xml +++ /dev/null @@ -1,3144 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 03516b1c689ee8fd241d646064fe15bb1fc452da Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 15 Mar 2023 19:09:30 +0100 Subject: [PATCH 187/192] Update npes_saved_w64devkit.txt --- projects/Notepad++/npes_saved_w64devkit.txt | Bin 8510 -> 8604 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/projects/Notepad++/npes_saved_w64devkit.txt b/projects/Notepad++/npes_saved_w64devkit.txt index ec5f0412f9f34b85163739bd08980121ea505cae..92375c24aec58c21a1137c86acd9d3b108a1888d 100644 GIT binary patch delta 28 icmdnzG{<>^loWRnLk>ea5bH5yOxBlD-uy~3gdG5Tk_aXM delta 12 TcmbQ^yw7Qal+@-5DHV1AAjt$Y From e06047419cc5c2e4d85b937c45d18e8a37db0129 Mon Sep 17 00:00:00 2001 From: Brian E <72316548+Brian-ED@users.noreply.github.com> Date: Thu, 16 Mar 2023 21:45:42 +0000 Subject: [PATCH 188/192] Added my BQN Library to the list (#2962) I'm the only maintainer and have been working hard recently to get my library to be as nice to use as possible. I found out about this language list, and getting a new language on it didn't seem so bad. A bonus for my efforts. --- BINDINGS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BINDINGS.md b/BINDINGS.md index 80d6bcec7095..bedf4b988796 100644 --- a/BINDINGS.md +++ b/BINDINGS.md @@ -71,7 +71,7 @@ Some people ported raylib to other languages in form of bindings or wrappers to | raylib.zig | **4.2** | [Zig](https://ziglang.org/) | MIT | https://github.com/ryupold/raylib.zig | | hare-raylib | auto | [Hare](https://harelang.org/) | Zlib | https://git.sr.ht/~evantj/hare-raylib | | raylib-sunder | auto | [Sunder](https://github.com/ashn-dot-dev/sunder) | 0BSD | https://github.com/ashn-dot-dev/raylib-sunder | - +| rayed-bqn | auto | [BQN](https://mlochbaum.github.io/BQN/) | MIT | https://github.com/Brian-ED/rayed-bqn | ### Utility Wrapers From e8a5d7b85ca76b985c0730ceffb04f3160b40401 Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 17 Mar 2023 00:05:40 +0100 Subject: [PATCH 189/192] Update CHANGELOG --- CHANGELOG | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 654c7bb40f76..43ab3ab442c5 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,10 +1,10 @@ changelog --------- -Current Release: raylib 4.5.0 (16 March 2023) +Current Release: raylib 4.5.0 (18 March 2023) ------------------------------------------------------------------------- -Release: raylib 4.5 (16 March 2023) +Release: raylib 4.5 (18 March 2023) ------------------------------------------------------------------------- KEY CHANGES: - ADDED: Improved ANGLE support on Desktop platforms @@ -180,6 +180,7 @@ Detailed changes: [bindings] ADDED: Raylib-Nelua (Nelua) by @Its-Kenta [bindings] ADDED: Cyber (Cyber) by @fubark [bindings] ADDED: raylib-sunder (Sunder) by @ashn-dot-dev +[bindings] ADDED: raylib BQN (#2962) by @Brian-ED [misc] REVIEWED: Update external libraries to latest versions ------------------------------------------------------------------------- From 18a36b3e066f5743757cfa9ecbe784bbe20d529e Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 18 Mar 2023 17:35:14 +0100 Subject: [PATCH 190/192] Update raylib.sln --- projects/VS2022/raylib.sln | 1 - 1 file changed, 1 deletion(-) diff --git a/projects/VS2022/raylib.sln b/projects/VS2022/raylib.sln index 673ccb4b3f79..f58f2ed75e26 100644 --- a/projects/VS2022/raylib.sln +++ b/projects/VS2022/raylib.sln @@ -2287,7 +2287,6 @@ Global {103B292B-049B-4B15-85A1-9F902840DB2C} = {DA049009-21FF-4AC0-84E4-830DD1BCD0CE} {0C2D2F82-AE67-400C-B19C-8C9B957B132A} = {DA049009-21FF-4AC0-84E4-830DD1BCD0CE} {E6784F91-4E4E-4956-A079-73FAB1AC7BE6} = {CC132A4D-D081-4C26-BFB9-AB11984054F8} - {9875B0C8-3893-43F8-88B2-4BAAAE3E8E6F} = {CC132A4D-D081-4C26-BFB9-AB11984054F8} {BFB22AB2-041B-4A1B-80C0-1D4BE410C8A9} = {CC132A4D-D081-4C26-BFB9-AB11984054F8} {93A1F656-0D29-4C5E-B140-11F23FF5D6AB} = {CC132A4D-D081-4C26-BFB9-AB11984054F8} {F81C5819-85B6-4D2E-B6DC-104A7634461B} = {CC132A4D-D081-4C26-BFB9-AB11984054F8} From fec96137e8d10ee6c88914fbe5e5429c13ee1dac Mon Sep 17 00:00:00 2001 From: ashn <60763262+ashn-dot-dev@users.noreply.github.com> Date: Sat, 18 Mar 2023 12:37:04 -0400 Subject: [PATCH 191/192] Update Makefile comment to indicate arm64 as a supported Linux desktop platform (#2965) --- src/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Makefile b/src/Makefile index 1667a97441f3..5d7086d8a9e8 100644 --- a/src/Makefile +++ b/src/Makefile @@ -4,7 +4,7 @@ # # Platforms supported: # PLATFORM_DESKTOP: Windows (Win32, Win64) -# PLATFORM_DESKTOP: Linux (i386, x64) +# PLATFORM_DESKTOP: Linux (arm64, i386, x64) # PLATFORM_DESKTOP: OSX/macOS (arm64, x86_64) # PLATFORM_DESKTOP: FreeBSD, OpenBSD, NetBSD, DragonFly # PLATFORM_ANDROID: Android (arm, i686, arm64, x86_64) From 2c38cad55f52a96fa3cb7b801e858ee64e442a36 Mon Sep 17 00:00:00 2001 From: Neolisk Date: Fri, 15 Sep 2023 00:16:15 -0700 Subject: [PATCH 192/192] Added Key, MouseButton and Char callbacks --- src/raylib.h | 12 ++++++++++++ src/rcore.c | 27 +++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/src/raylib.h b/src/raylib.h index 4cd9e4349e5f..9c576c9ffcda 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1094,6 +1094,18 @@ RLAPI unsigned char *DecompressData(const unsigned char *compData, int compDataS RLAPI char *EncodeDataBase64(const unsigned char *data, int dataSize, int *outputSize); // Encode data to Base64 string, memory must be MemFree() RLAPI unsigned char *DecodeDataBase64(const unsigned char *data, int *outputSize); // Decode Base64 string data, memory must be MemFree() +//------------------------------------------------------------------------------------ +// User Defined Input Callbacks (Module: core) +//------------------------------------------------------------------------------------ + +typedef void (*UserKeyCallback)(int, int, int, int); // Type for key event callback +typedef void (*UserMouseButtonCallback)(int, int, int); // Type for mouse button event callback +typedef void (*UserCharCallback)(unsigned int); // Type for char event callback + +RLAPI void SetUserKeyCallback(UserKeyCallback callback); // Set user defined callback for key events +RLAPI void SetUserMouseButtonCallback(UserMouseButtonCallback callback); // Set user defined callback for mouse button events +RLAPI void SetUserCharCallback(UserCharCallback callback); // Set user defined callback for char events + //------------------------------------------------------------------------------------ // Input Handling Functions (Module: core) //------------------------------------------------------------------------------------ diff --git a/src/rcore.c b/src/rcore.c index eae49515fcd4..f8e7cf3acecb 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -504,6 +504,11 @@ typedef struct CoreData { #endif unsigned int frameCounter; // Frame counter } Time; + struct { + UserKeyCallback keyCallback; // User defined callback for GLFW key events + UserMouseButtonCallback mouseButtonCallback; // User defined callback for GLFW mouse button events + UserCharCallback charCallback; // User defined callback for GLFW char events + } Callbacks; } CoreData; //---------------------------------------------------------------------------------- @@ -3590,6 +3595,28 @@ void OpenURL(const char *url) } } +//---------------------------------------------------------------------------------- +// User Callbacks for GLFW events +//---------------------------------------------------------------------------------- + +// Set user defined callback for key events +void SetUserKeyCallback(GLFWkeyfun callback) +{ + CORE.Callbacks.keyCallback = callback; +} + +// Set user defined callback for mouse button events +void SetUserMouseButtonCallback(GLFWmousebuttonfun callback) +{ + CORE.Callbacks.mouseButtonCallback = callback; +} + +// Set user defined callback for char events +void SetUserCharCallback(GLFWcharfun callback) +{ + CORE.Callbacks.charCallback = callback; +} + //---------------------------------------------------------------------------------- // Module Functions Definition - Input (Keyboard, Mouse, Gamepad) Functions //----------------------------------------------------------------------------------

    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